一般,我们获取SD ID是通过2种方法(实际上市一回事,只不过是形式上不同而已),一是CreateFile(L"DSK2:", ...); 再DeviceIoControl(hFile, IOCTL_DISK_GET_STORAGEID, NULL, 0, &storeID, MAX_PAT,&dwBytesRead, NULL); 这是一种比较常用的方法,很好用,得到的结果也很正确;第二种方法就是CreateFile(L"//StorageCard//VOL:", ...); 再DeviceIoControl(hFile, IOCTL_DISK_GET_STORAGEID, NULL, 0, &storeID, MAX_PAT,&dwBytesRead, NULL); 这也是我今天要说的方法,在wince5.0 中这个运行的很好,没有错误,但到了wince6.0中这个方法就不行了,CreateFile 可以得到句柄,但是DeviceIoControl 就不行了, Why? 是DeviceIoControl 有问题还是CreateFile 有问题?所以我们就不得去找微软的代码了,可微软文件系统的代码也没有全部给出来,DeviceIoControl 没有找到实际的执行流程,如果谁知道的话,麻烦告诉我一声!找CreateFile, 根据vcleaner 的提示,找到D:/WINCE600/PRIVATE/WINCEOS/COREOS/STORAGE/FSDMGR 目录下的volumeapi.cpp文件,找到 FSDMGR_CreateFileW 函数,我加了打印语句,CreateFile(L"//StorageCard//VOL:", ...); 的确是调用了这个函数,而CreateFile(L"DSK2:", ...); 没有调用这个函数,所以说应该是CreateFile出了问题!仔细分析这个函数,感觉创建句柄的时候的确有点问题,它创建的是一个文件类型句柄,不是一个Device 类型句柄,所以调用DeviceIoControl 会失败,以下是我修改后的代码:
EXTERN_C HANDLE FSDMGR_CreateFileW (MountedVolume_t* pVolume, HANDLE hProcess,
const WCHAR* pPathName, DWORD Access, DWORD ShareMode,
SECURITY_ATTRIBUTES* pSecurityAttributes, DWORD Create,
DWORD FlagsAndAttributes, HANDLE hTemplate,
PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD SecurityDescriptorSize)
{
HANDLE h = INVALID_HANDLE_VALUE;
SECURITY_ATTRIBUTES SecurityAttributes;
DEBUGCHK (!pSecurityAttributes);
if (pSecurityDescriptor) {
SecurityAttributes.nLength = sizeof (SECURITY_ATTRIBUTES);
SecurityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
SecurityAttributes.bInheritHandle = FALSE;
pSecurityAttributes = &SecurityAttributes;
}
LRESULT lResult = pVolume->EnterWithWait ();
if (ERROR_SUCCESS == lResult) {
// Get the topmost file system object associated with the volume.
// If another filter is hooked between now and the time we call
// create file, we'll still use this one. This file system object
// will be referenced by the handle object.
FileSystem_t* pFileSystem = pVolume->GetFileSystem ();
DWORD Attributes = 0;
if (OPEN_EXISTING != Create) {
// If not trying to open an existing file, there is the
// possibility that we will create a new one. In order to
// properly generate notifications we need to detect whether or
// not the file already exists using GetFileAttributes.
Attributes = pFileSystem->GetFileAttributesW (pPathName);
}
HANDLE hInt = pFileSystem->CreateFileW (hProcess, pPathName, Access,
ShareMode, pSecurityAttributes, Create,
FlagsAndAttributes, hTemplate);
if (INVALID_HANDLE_VALUE != hInt) {
// The file system succeeded creating/opening the file, so
// allocate an FileSystemHandle_t object and associate it with the
// MountedVolume_t object.
// Indicate whether or not this is a console or psuedo-device
// handle when creating the FileSystemHandle_t object. This will dictate
// how notifications are performed on the handle.
DWORD HandleType = FileSystemHandle_t::HDL_FILE; //Hugo
//DWORD HandleType = FileSystemHandle_t::HDL_FILE | FileSystemHandle_t::HDL_PSUEDO;
if (IsPsuedoDeviceName(pPathName))
{
HandleType |= FileSystemHandle_t::HDL_PSUEDO;
}
if (IsConsoleName (pPathName)) {
HandleType |= FileSystemHandle_t::HDL_CONSOLE;
}
//RETAILMSG(1, (L"Hugo CreateFile:AllocFileHandle /r/n "));
// Allocte a new handle object to track this item.
h = pVolume->AllocFileHandle (reinterpret_cast<DWORD> (hInt),
HandleType, pFileSystem, pPathName, Access);
if (INVALID_HANDLE_VALUE != h) {
// Perform notifications only when the handle is for a real file,
// not a pseudo device handle or console handle. Devices and streams
// shouldn't ever generate notifications.
//if (FileSystemHandle_t::HDL_FILE == HandleType && hugo
//!IsPsuedoDeviceName (pPathName)) {
if (FileSystemHandle_t::HDL_FILE == HandleType ) {
// Successfully opened the file. Perform file notifications
// as required.
if (INVALID_FILE_ATTRIBUTES == Attributes) {
// The file did not previously exist; notify that it has
// been added.
pVolume->NotifyPathChange (pPathName, FALSE, FILE_ACTION_ADDED);
} else if ((CREATE_ALWAYS == Create) ||
(TRUNCATE_EXISTING == Create)) {
// The file previously existed but is being re-created or
// truncated so notify that it has changed.
pVolume->NotifyPathChange (pPathName, FALSE, FILE_ACTION_MODIFIED);
}
}
} else {
// Failed to allocate a handle object, so close the handle
// that was returned by the file system.
pFileSystem->CloseFile (reinterpret_cast<DWORD> (hInt));
}
} else if (pPathName && (wcsicmp (pPathName, L"//VOL:") == 0)) {
// TODO: Privilege check for raw disk i/o. This requires more privilege than file i/o.
// Clear error code set by the FSD when it failed to open VOL: on its own.
SetLastError (ERROR_SUCCESS);
// We failed to open the file, but if it is VOL: special case this
// and allow direct partition access.
h = pVolume->AllocFileHandle (reinterpret_cast<DWORD> (hInt),
FileSystemHandle_t::HDL_PSUEDO, pFileSystem, pPathName, Access);
}
pVolume->Exit ();
} else {
SetLastError (lResult);
}
return h;
}
上面红色的是我添加的(注意我屏蔽的那行代码,开始我没加下面if 语句,就加了屏蔽的那行代码,系统跑不起来,有谁能告诉我why?),这样就OK,一切正常,sd id 也可以正确的读出来了!不知道vcleaner 跟微软确认的怎么样了,这是不是wince6 的bug?