一个可以监控U盘接入、自动拷贝文件到U盘、自动移除U盘的小程序
1,支持自动拖拽文件,并获取文件路径。
支持文件拖拽:
DragAcceptFiles(hWnd, TRUE);
调用该API后,向窗口拖拽文件就会收到 WM_DROPFILES消息。
在响应该消息的时候,可以使用DragQueryFile来获取文件数量以及文件的具体路径。
用法如下:
BOOL OnDragFiles(WPARAM wp, LPARAM lp)
{
HDROP hDrop = reinterpret_cast(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(wp);
PDEV_BROADCAST_HDR lpdb = reinterpret_cast(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(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~