网上有一篇文章,介绍应用程序如何操作flash的:
http://blog.csdn.net/nanjianhui/archive/2008/03/19/2196466.aspx
按照上述文章的做法做好之后,在非multi-bin的系统下,CreateFile(_T("DSK0:"),...)是没有任何问题的,但是如果是在multi-bin的系统下,则得不到句柄,经过大量的实验方法得知,在multi-bin系统下,用hFlash = OpenStore(L"MSFlash");方能打开,这是什么原因呢?
查看MSDN得知,OpenStore是微软提供的一个关于StorageManager 的API,在ARMCE论坛的Walle大哥的帮助下,追踪了OpenStore:
HANDLE WINAPI STG_OpenStore(LPCTSTR szDeviceName, HANDLE hProc)
{
HANDLE hStore = INVALID_HANDLE_VALUE;
DEBUGMSG( ZONE_STOREAPI, (L"FSDMGR:STG_OpenStore(%s)/r/n", szDeviceName));
STOREHANDLE *pStoreHandle = new STOREHANDLE;
// NOTE: szDeviceName pointer was already mapped by filesys
if (pStoreHandle) {
LockStoreMgr();
pStoreHandle->pStore = g_pStoreRoot;
pStoreHandle->pPartition = INVALID_PARTITION;
pStoreHandle->pNext = NULL;
pStoreHandle->dwFlags = 0;
pStoreHandle->hProc = hProc;
pStoreHandle->dwSig = STORE_HANDLE_SIG;
if (hProc == reinterpret_cast<HANDLE> (GetCurrentProcessId())) {
pStoreHandle->dwFlags |= STOREHANDLE_TYPE_INTERNAL;
}
__try {
while(pStoreHandle->pStore && (pStoreHandle->pStore != INVALID_STORE)) {
if (wcsicmp( szDeviceName, pStoreHandle->pStore->m_szDeviceName) == 0) {
break;
}
pStoreHandle->pStore = pStoreHandle->pStore->m_pNextStore;
}
if (pStoreHandle->pStore && (pStoreHandle->pStore != INVALID_STORE)) {
hStore = CreateAPIHandle(g_hStoreApi, pStoreHandle);
if (hStore != INVALID_HANDLE_VALUE) {
AddHandleToList(&g_pRootHandle, pStoreHandle);
} else {
delete pStoreHandle;
pStoreHandle = NULL;
}
} else {
SetLastError(ERROR_DEVICE_NOT_AVAILABLE);
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
SetLastError(ERROR_BAD_ARGUMENTS);
}
UnlockStoreMgr();
}
if ((hStore == INVALID_HANDLE_VALUE) && pStoreHandle){
delete pStoreHandle;
}
return hStore;
}
这个API在内部是在找寻一个storehandle的链表,如果找到名字和你提供的参数名字相同的,就返回对应的handle,否则就报错。storehandle链表应该是在mountstore的时候进行一个一个创建的。找到storehandle之后,就给你再创建一个Apihandle给你用来做后续API的参数了。
BOOL MountStore (const WCHAR* pDeviceName, const GUID* pDeviceGuid, const WCHAR* pDriverPath, __out StoreDisk_t** ppStore)
{
LRESULT lResult;
LockStoreMgr ();
StoreDisk_t* pStoreNew = FindStore (pDeviceName);
if (pStoreNew && !(STORE_FLAG_DETACHED & pStoreNew->m_dwFlags)) {
// There is an attached store with the same name as the new one
// so we are unable to mount it (we can't have name conflicts).
DEBUGMSG (ZONE_ERRORS, (L"FSDMGR: Store /"%s/" already exists ...skipping/r/n", pDeviceName));
lResult = ERROR_ALREADY_EXISTS;
goto exit;
}
// Look for a currently detached store.
StoreDisk_t *pStoreExisting = g_pStoreRoot;
while (pStoreExisting) {
if (STORE_FLAG_DETACHED & pStoreExisting->m_dwFlags) {
// Found a detached store.
break;
}
pStoreExisting = pStoreExisting->m_pNextStore;
}
// Allocate a new store.
pStoreNew = new StoreDisk_t(pDeviceName, pDeviceGuid);
if (!pStoreNew) {
lResult = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
// Add the new store to our list of stores. It isn't ready for I/O yet because it
// isn't completely mounted, but we need to open a handle to it to pass to the
// partition driver so it must be on the list.
AddStore (pStoreNew);
。。。。。。。
}
void AddStore(StoreDisk_t *pStore)
{
// TODO: Add in the order of Disk Index ???
if (g_pStoreRoot) {
StoreDisk_t *pTemp = g_pStoreRoot;
while(pTemp->m_pNextStore) {
pTemp = pTemp->m_pNextStore;
}
pTemp->m_pNextStore = pStore;
} else {
g_pStoreRoot = pStore;
}
}
一般BINFS的block驱动会在device.exe加载之前被加载,微软的文件系统是用这个API来做这件事情的注意这里有调用mountstore,记住名字的参数。
static LRESULT AutoLoadBlockDevice (const WCHAR* pName, HKEY hDeviceKey)
{
WCHAR DriverPath[MAX_PATH];
if (!FsdGetRegistryString (hDeviceKey, g_szFILE_SYSTEM_DRIVER_STRING, DriverPath, MAX_PATH)) {
return ERROR_FILE_NOT_FOUND;
}
DEBUGMSG (ZONE_INIT, (L"FSDMGR!AutoLoadBlockDevice: Auto-loading block driver from /"%s/"",
DriverPath));
LRESULT lResult = ERROR_SUCCESS;
if (!MountStore (pName, &BLOCK_DRIVER_GUID, DriverPath)) {
lResult = FsdGetLastError ();
}
return lResult;
}
这是文件系统在启动初期,去读取autoload注册表项,然后决定如何加载binfs的:
static LRESULT AutoLoadFileSystem (DWORD CurrentBootPhase, HKEY hRootKey,
const WCHAR* pRootKeyName, const WCHAR* pFileSystemName)
{
HKEY hKeyFSD = NULL;
LRESULT lResult;
// Open the key for this file system under the specified root auto-load key.
lResult = FsdRegOpenSubKey (hRootKey, pFileSystemName, &hKeyFSD);
if (ERROR_SUCCESS != lResult) {
return lResult;
}
// Detect whether or not this is the proper boot phase to load this driver.
// If there is no boot phase specified in the registry, default to 1.
DWORD BootPhase = 0;
if (!FsdGetRegistryValue (hKeyFSD, g_szFSD_BOOTPHASE_STRING, &BootPhase)) {
if (CurrentBootPhase != 0) {
BootPhase = CurrentBootPhase;
} else {
BootPhase = 1;
}
RegSetValueExW (hKeyFSD, g_szFSD_BOOTPHASE_STRING, 0, REG_DWORD,
(LPBYTE)&BootPhase, sizeof(DWORD));
}
if (CurrentBootPhase != BootPhase) {
// The driver is not to be loaded during this boot phase.
lResult = ERROR_NOT_READY;
goto exit;
}
DEBUGMSG (ZONE_INIT, (L"FSDMGR!AutoLoadFileSystem: CurrentBootPhase=%u, RootKey=%s, FileSystem_t=%s/r/n",
CurrentBootPhase, pRootKeyName, pFileSystemName));
// Query the name of the FSD dll.
WCHAR FSDName[MAX_PATH];
if (FsdGetRegistryString(hKeyFSD, g_szFILE_SYSTEM_MODULE_STRING, FSDName, MAX_PATH)) {
// Get the "MountAsXXX" and/or MountFlags settings for this FSD instance.
DWORD MountFlags = 0;
g_pMountTable->GetMountSettings(hKeyFSD, &MountFlags);
// Get the name of a power manager activity event to associate with this FSD.
WCHAR ActivityName[MAX_PATH];
if (!FsdGetRegistryString(hKeyFSD, g_szACTIVITY_TIMER_STRING, ActivityName, MAX_PATH)) {
VERIFY (SUCCEEDED (StringCchCopy (ActivityName, MAX_PATH, g_szDEFAULT_ACTIVITY_NAME)));
}
// Allocate a NullDisk_t object for this FSD.
NullDisk_t* pDisk = new NullDisk_t (ActivityName);
if (!pDisk) {
lResult = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
// Use the storage path as the base root reg key.
lResult = pDisk->AddRootRegKey (g_szSTORAGE_PATH);
if (ERROR_SUCCESS != lResult) {
delete pDisk;
goto exit;
}
// The secondary registry key for this FSD is the root auto-load key.
lResult = pDisk->AddRootRegKey (pRootKeyName);
if (ERROR_SUCCESS != lResult) {
delete pDisk;
goto exit;
}
// The sub key for this FSD is the name of the file system.
lResult = pDisk->SetRegSubKey (pFileSystemName);
if (ERROR_SUCCESS != lResult) {
delete pDisk;
goto exit;
}
// Allocate a FileSystemDriver_t object.
FileSystemDriver_t* pFileSystem = new FileSystemDriver_t (pDisk, FSDName);
if (!pFileSystem) {
delete pDisk;
lResult = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
// Finally, mount the file system
lResult = MountFileSystemDriver (pDisk, pFileSystem, MountFlags, FALSE);
if (ERROR_SUCCESS != lResult) {
delete pFileSystem;
delete pDisk;
goto exit;
}
} else {
// No "FSD" was specified in the registry, so try to load as an auto-load
// block device instead.
lResult = AutoLoadBlockDevice (pFileSystemName, hKeyFSD);
}
exit:
if (hKeyFSD) {
FsdRegCloseKey (hKeyFSD);
}
return lResult;
}
所以我们看到,如果只有一个block驱动,而且有binfs的时候,系统是通过
[HKEY_LOCAL_MACHINE/System/StorageManager/AutoLoad/MSFlash]来mountstore的,名字就是MSFlash。如果在非mutibin的时候,flashdisk不会通过autoload来加载会,走普通的流程:
1.被设备管理器加载。
2.device.exe根据注册表的iclass告诉storagemanager这是个block驱动
3.存储管理器调用mountstore来加载这个块设备驱动即flashdisk
下面这个IST是storagemanager的一个监视线程,即等待设备管理器发现iclass为block的驱动后发event给这个PNPThread,这个线程会根据设备列表得到devicename为DSK0:。
DWORD PNPThread(LPVOID lParam)
{
DWORD dwFlags, dwSize;
// HKEY hDevKey;
HANDLE hReg;
DEVDETAIL * pd = (DEVDETAIL *)g_pPNPBuf;
GUID guid = {0};
HANDLE pHandles[3];
TCHAR szGuid[MAX_PATH];
HMODULE hCoreDll;
DWORD dwTimeOut = INFINITE, dwTimeOutReset = DEFAULT_TIMEOUT_RESET;
PSTOPDEVICENOT pStopDeviceNotification = NULL;
PREQUESTDEVICENOT pRequestDeviceNotification = NULL;
pHandles[0] = g_hPNPQueue;
pHandles[1] = g_hPNPUpdateEvent;
pHandles[2] = g_hAutoLoadEvent;
HKEY hKey;
if (ERROR_SUCCESS == FsdRegOpenKey( g_szSTORAGE_PATH, &hKey)) {
DWORD dwPriority;
if (!FsdGetRegistryValue(hKey, g_szReloadTimeOut, &dwTimeOutReset)) {
dwTimeOutReset = DEFAULT_TIMEOUT_RESET;
}
if (!FsdGetRegistryValue( hKey, g_szWaitDelay, &g_dwWaitIODelay)) {
g_dwWaitIODelay = dwTimeOutReset * DEFAULT_WAITIO_MULTIPLIER;
}
if (FsdGetRegistryValue( hKey, g_szPNPThreadPrio, &dwPriority)) {
CeSetThreadPriority(GetCurrentThread(), dwPriority);
}
FsdRegCloseKey( hKey);
}
DEBUGMSG( ZONE_INIT, (L"STOREMGR: Using PNP unload delay of %ld/r/n", dwTimeOutReset));
hCoreDll = (HMODULE)LoadLibrary(L"coredll.dll");
if (hCoreDll) {
pRequestDeviceNotification = (PREQUESTDEVICENOT)FsdGetProcAddress( hCoreDll, L"RequestDeviceNotifications");
pStopDeviceNotification = (PSTOPDEVICENOT)FsdGetProcAddress( hCoreDll, L"StopDeviceNotifications");
}
FreeLibrary( hCoreDll); // This is okay since we should already have a reference to coredll
if (pRequestDeviceNotification) {
DEBUGMSG( ZONE_INIT, (L"STOREMGR: PNPThread Created/r/n"));
hReg = pRequestDeviceNotification(&BLOCK_DRIVER_GUID, g_hPNPQueue, TRUE);
}
while(TRUE) {
DWORD dwWaitCode;
dwWaitCode = WaitForMultipleObjects( 3, pHandles, FALSE, dwTimeOut);
if (dwWaitCode == WAIT_TIMEOUT) {
DEBUGMSG( ZONE_INIT, (L"STOREMGR: Scavenging stores/r/n"));
LockStoreMgr();
dwTimeOut = INFINITE;
g_dwUpdateState &= ~STOREMGR_EVENT_UPDATETIMEOUT;
UnlockStoreMgr();
DetachStores(STORE_FLAG_DETACHED);
} else {
DWORD dwEvent = dwWaitCode - WAIT_OBJECT_0;
switch(dwEvent) {
case 0: {
if (ReadMsgQueue(g_hPNPQueue, pd, sizeof(g_pPNPBuf), &dwSize, INFINITE, &dwFlags)) {
FsdStringFromGuid(&pd->guidDevClass, szGuid);
DEBUGMSG( ZONE_INIT, (L"STOREMGR: Got a plug and play event %s Class(%s) Attached=%s!!!/r/n", pd->szName, szGuid, pd->fAttached ? L"TRUE":L"FALSE"));
if (memcmp( &pd->guidDevClass, &BLOCK_DRIVER_GUID, sizeof(GUID)) == 0) {
if (pd->fAttached) {
MountStore( pd->szName, pd->guidDevClass);
} else {
UnmountStore(pd->szName);
}
}
}
break;
}
case 1: {
if (g_dwUpdateState & STOREMGR_EVENT_UPDATETIMEOUT) {
dwTimeOut = dwTimeOutReset;
}
if (g_dwUpdateState & STOREMGR_EVENT_REFRESHSTORE) {
LockStoreMgr();
BOOL fRet;
CStore *pStore = g_pStoreRoot;
TCHAR szName[MAX_PATH];
while(pStore) {
if (pStore->m_dwFlags & STORE_FLAG_REFRESHED) {
CStore *pStoreTemp = pStore;
wcscpy( szName, pStore->m_szDeviceName);
pStoreTemp->Lock();
DEBUGMSG( ZONE_INIT, (L"Refreshing store %s is happenning !!!/r/n", pStore->m_szOldDeviceName));
fRet = pStoreTemp->UnmountStore();
pStoreTemp->Unlock();
pStore = pStoreTemp->m_pNextStore;
if (fRet) {
UpdateHandleFromList(g_pRootHandle, pStoreTemp, NULL);
FSDMGR_AdvertiseInterface( &STORE_MOUNT_GUID, pStoreTemp->m_szDeviceName, FALSE);
DeleteStore( pStoreTemp);
MountStore( szName, BLOCK_DRIVER_GUID);
}
} else {
pStore = pStore->m_pNextStore;
}
}
UnlockStoreMgr();
}
break;
}
case 2:
ResetEvent( g_hAutoLoadEvent);
AutoLoadFileSystems( 2, LOAD_FLAG_ASYNC);
break;
default:
break;
}
}
}
// SHould never get here !!!
if (pStopDeviceNotification)
pStopDeviceNotification(hReg);
return 0;
}
这个结构体包含device.exe动态加载的所有的驱动列表,那个的szname就是xxx0:之类的名字。
typedef struct {
GUID guidDevClass;
DWORD dwReserved;
BOOL fAttached;
int cbName;
TCHAR szName[1];
} DEVDETAIL, *PDEVDETAIL;Members
guidDevClass
Device interface identifier for this notification.
dwReserved
Do not use.
fAttached
TRUE if the device interface is present, otherwise, FALSE.
cbName
Byte count of the interface name.
szName
Beginning of the name of the interface.
Requirements
OS Versions: Windows CE .NET 4.0 and later.
Header: Pnp.h.
总结: ******************************************************************************************** 以上内容是根据Walle的指点,自己重复跟踪了下代码,有了比较深刻的理解!
只要解决了打开设备的问题,那么接下来提供接口就比较容易了,在fmd.c文件中的FMD_OEMIoControl函数中添加case即可。
|