一個可以監控U盤接入、自動拷貝檔案到U盤、自動移除U盤的小程式
阿新 • • 發佈:2018-11-08
一個可以監控U盤接入、自動拷貝檔案到U盤、自動移除U盤的小程式
1,支援自動拖拽檔案,並獲取檔案路徑。
支援檔案拖拽:
2,監控U盤接入。 監控U盤接入一種簡單的方法就是 監聽WM_DEVICECHANGE訊息。 為了準確監聽該訊息需要註冊事件:
知道碟符我們就可以方便的往裡面拷貝檔案了。
3,移除U盤:
有很多種方案,使用 CM_Request_Device_Eject API的好的一點就是 呼叫之後就看不到這個碟符了
可參考程式碼:
Thanks~
1,支援自動拖拽檔案,並獲取檔案路徑。
支援檔案拖拽:
DragAcceptFiles(hWnd, TRUE);
呼叫該API後,向視窗拖拽檔案就會收到 WM_DROPFILES訊息。
在響應該訊息的時候,可以使用DragQueryFile來獲取檔案數量以及檔案的具體路徑。
用法如下:
備註:如果拖拽的是一個資料夾,只會獲取到該資料夾的全路徑,資料夾的內容需要自己去遍歷。BOOL OnDragFiles(WPARAM wp, LPARAM lp) { HDROP hDrop = reinterpret_cast<HDROP>(wp); int nCount = DragQueryFile(hDrop, -1, NULL, NULL); for (int i = 0; i < nCount; i++) { TCHAR szSrcPath[MAX_PATH] = { 0 }; DragQueryFile(hDrop, i, szSrcPath, MAX_PATH - 1); g_VectSrcFilePath.push_back(szSrcPath); } return TRUE; }
2,監控U盤接入。 監控U盤接入一種簡單的方法就是 監聽WM_DEVICECHANGE訊息。 為了準確監聽該訊息需要註冊事件:
然後響應該訊息,可以獲取接入U盤的碟符:BOOL RegisterDeviceEvent(HWND hWnd) { DEV_BROADCAST_DEVICEINTERFACE DevInt; memset(&DevInt, 0, sizeof(DEV_BROADCAST_DEVICEINTERFACE)); DevInt.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); DevInt.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; DevInt.dbcc_classguid = { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } }; return (RegisterDeviceNotification(hWnd, &DevInt, DEVICE_NOTIFY_WINDOW_HANDLE) != NULL); }
TCHAR FirstDriveFromMask(ULONG unitmask) { int i; for (i = 0; i < 26; ++i) { if (unitmask & 0x1) break; unitmask = unitmask >> 1; } return (i + _T('A')); } BOOL OnDeviceChange(WPARAM wp, LPARAM lp) { DWORD dwdata = static_cast<DWORD>(wp); PDEV_BROADCAST_HDR lpdb = reinterpret_cast<PDEV_BROADCAST_HDR>(lp); switch (dwdata) { case DBT_DEVICEREMOVECOMPLETE: break; case DBT_DEVICEARRIVAL: if (lpdb != NULL) { if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) { PDEV_BROADCAST_VOLUME lpdv = reinterpret_cast<PDEV_BROADCAST_VOLUME>(lp); TCHAR cVolume = FirstDriveFromMask(lpdv->dbcv_unitmask); g_cVolume = cVolume;
知道碟符我們就可以方便的往裡面拷貝檔案了。
3,移除U盤:
有很多種方案,使用 CM_Request_Device_Eject API的好的一點就是 呼叫之後就看不到這個碟符了
可參考程式碼:
void RemoveTheUSBDisk(TCHAR DriveLetter)
{
if (DriveLetter < _T('A') || DriveLetter > _T('Z'))
{
return ;
}
TCHAR szRootPath[] = _T("X:\\"); // "X:\" -> for GetDriveType
szRootPath[0] = DriveLetter;
TCHAR szDevicePath[] = _T("X:"); // "X:" -> for QueryDosDevice
szDevicePath[0] = DriveLetter;
TCHAR szVolumeAccessPath[] = _T("\\\\.\\X:"); // "\\.\X:" -> to open the volume
szVolumeAccessPath[4] = DriveLetter;
HANDLE hDevice = CreateFile(szVolumeAccessPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, NULL, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
{
return ;
}
// get the volume's device number
STORAGE_DEVICE_NUMBER sdn;
DWORD dwBytesReturned = 0;
long DeviceNumber = -1;
long res = DeviceIoControl(hDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn,
sizeof(sdn), &dwBytesReturned, NULL);
if (res)
{
DeviceNumber = sdn.DeviceNumber;
}
CloseHandle(hDevice);
if (DeviceNumber == -1)
{
return ;
}
// get the drive type which is required to match the device numbers correctely
UINT DriveType = GetDriveType(szRootPath);
// get the dos device name (like \device\floppy0) to decide if it's a floppy or not - who knows a better way?
TCHAR szDosDeviceName[MAX_PATH] = { 0 };
res = QueryDosDevice(szDevicePath, szDosDeviceName, MAX_PATH);
if (!res)
{
return;
}
DEVINST DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber, DriveType, szDosDeviceName);
if (DevInst == 0)
{
return;
}
PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown;
TCHAR VetoName[MAX_PATH];
VetoName[0] = 0;
bool bSuccess = false;
DEVINST DevInstParent = 0;
res = CM_Get_Parent(&DevInstParent, DevInst, 0);
for (long tries = 1; tries <= 3; tries++)
{ // sometimes we need some tries...
VetoName[0] = 0;
// CM_Query_And_Remove_SubTree doesn't work for restricted users
//res = CM_Query_And_Remove_SubTreeW(DevInstParent, &VetoType, VetoNameW, MAX_PATH, CM_REMOVE_NO_RESTART); // CM_Query_And_Remove_SubTreeA is not implemented under W2K!
//res = CM_Query_And_Remove_SubTreeW(DevInstParent, NULL, NULL, 0, CM_REMOVE_NO_RESTART); // with messagebox (W2K, Vista) or balloon (XP)
res = CM_Request_Device_Eject(DevInstParent, &VetoType, VetoName, MAX_PATH, 0);
//res = CM_Request_Device_EjectW(DevInstParent, NULL, NULL, 0, 0); // with messagebox (W2K, Vista) or balloon (XP)
bSuccess = (res == CR_SUCCESS && VetoType == PNP_VetoTypeUnknown);
if (bSuccess)
{
break;
}
Sleep(500); // required to give the next tries a chance!
}
if (bSuccess)
{
return;
}
return;
}
Thanks~