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

一个可以监控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~





猜你喜欢

转载自blog.csdn.net/linlin003/article/details/74908832