WinCE 系统下移动存贮设备Storage 的拔插检测
今天在编程检测 Storage(SD/USB) 时,使用了一个消息:WM_DEVICECHANGE 来检测,测试了一下插入/拔出 Storage 设备时确实可以接收到消息。
但后继的处理出现问题:在 Storage 设备拔出时,立刻调用 FindFirstStore/FindNextStore 和 FindFirstPartition/FindNextPartition 时正常;
但在 Storage 设备插入时,立刻调用 FindFirstStore/FindNextStore 和 FindFirstPartition/FindNextPartition 未检测到刚插入的 Storage 设备的目录(盘符)。
单步测试发现,只要在首次调用 FindFirstStore 时停一会,就正常。说明在接收到 WM_DEVICECHANGE 消息时不能立刻扫描,需要等待一会。
看了一下公司其它项目对 WM_DEVICECHANGE 消息的处理,都是采用延时如 200ms 来处理。
延时处理,个人认为不是好的办法。因为:
(1) 延时的时间不好确认
(2)在 Storage 设备拔出后,如果在延时的时间内、且设备已经拔出时出现文件操作,较难处理。
除了处理设备的插入/拔出的硬件检测消息外,是否有其它办法来检测 Storage 设备的插入/拔出?
答案是肯定的。可以采用文件系统的 MOUNT/UNMOUNT 消息来处理。
请看以下示例代码:
1 #include "pnp.h" 2 #include "storemgr.h" 3 4 #define DEVICE_QUEUE_MAX_SIZE 3 5 6 static BOOL gbExitDetectThread = FALSE; 7 8 union BufferPlusDevDetail 9 { 10 DEVDETAIL DevDetail; 11 BYTE byBuffer[sizeof(DEVDETAIL) + MAX_DEVCLASS_NAMELEN * sizeof(TCHAR)]; 12 }; 13 14 DWORD DevicePlugDetectThread(LPVOID lpPara) 15 { 16 DWORD dwObjectRet = 0; 17 MSGQUEUEOPTIONS msgQInfo = 18 { 19 sizeof(MSGQUEUEOPTIONS), 20 MSGQUEUE_ALLOW_BROKEN, 21 DEVICE_QUEUE_MAX_SIZE, 22 sizeof(BufferPlusDevDetail), 23 TRUE 24 }; 25 DWORD dwMsgSize = 0; 26 DWORD dwAlert = 0; 27 28 HANDLE hStorageMsgQueue = CreateMsgQueue(NULL, &msgQInfo); 29 if (NULL == hStorageMsgQueue) 30 { 31 return FALSE; 32 } 33 // request notification 34 HANDLE hStorageNotify = RequestDeviceNotifications(&FATFS_MOUNT_GUID, hStorageMsgQueue, FALSE); 35 if(NULL == hStorageNotify) 36 { 37 return FALSE; 38 } 39 40 while(1) 41 { 42 if(gbExitDetectThread) 43 { 44 break; 45 } 46 dwObjectRet = WaitForSingleObject(hStorageMsgQueue,1000); 47 if(WAIT_OBJECT_0 == dwObjectRet) 48 { 49 BufferPlusDevDetail DevBuff = {0}; 50 if (ReadMsgQueue(hStorageMsgQueue, &DevBuff, sizeof(DevBuff), &dwMsgSize, 0, &dwAlert)) 51 { 52 BOOL bAttached = DevBuff.DevDetail.fAttached; 53 CString csStorageName = DevBuff.DevDetail.szName; 54 RETAILMSG(1,(L"Storage:: received %s message: %s!\r\n",0 == bAttached ? L"unmount" : L"mount",csStorageName)); 55 56 COPYDATASTRUCT cs; 57 TCHAR tcStorage[MAX_PATH]; 58 59 ZeroMemory(tcStorage,sizeof(TCHAR) * MAX_PATH); 60 wsprintf(tcStorage,L"%s",csStorageName); 61 cs.dwData = 0x5050; 62 cs.cbData = sizeof(TCHAR) * wcslen(tcStorage); 63 cs.lpData = tcStorage; 64 SendMyMsgToAgent(WM_COPYDATA,bAttached,(LPARAM)&cs); 65 } 66 } 67 else if(WAIT_TIMEOUT == dwObjectRet) 68 { 69 } 70 } 71 72 StopDeviceNotifications(hStorageNotify); 73 CloseHandle(hStorageNotify); 74 75 return TRUE; 76 } 77 78 // 调用示例,直接开启线程。代码如下: 79 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)DevicePlugDetectThread, NULL, 0, NULL);