一个可以监控U盘接入、自动拷贝文件到U盘、自动移除U盘的小程序

xiaoxiao2021-02-27  270

一个可以监控U盘接入、自动拷贝文件到U盘、自动移除U盘的小程序 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消息。 为了准确监听该消息需要注册事件: 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); } 然后响应该消息,可以获取接入U盘的盘符: 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~
转载请注明原文地址: https://www.6miu.com/read-13666.html

最新回复(0)