安全移除U盘,移动硬盘,读卡器等
一般先要通过DRIVE_REMOVABLE == GetDriveType(...)的方法得到USB设备的盘符DriveLetter;
然后根据DriveLetter可以用以下两个函数实现安全移除:
//It opens the volume and gets its device number
//than Get Drive`s DevInst By DeviceNumber ,remove the device
BOOL RemoveUSBDevice()
{
// "X:/" -> for GetDriveType
char szRootPath[] = "X://";
szRootPath[0] = DriveLetter;
// "X:" -> for QueryDosDevice
char szDevicePath[] = "X:";
szDevicePath[0] = DriveLetter;
// "//./X:" -> to open the volume
char szVolumeAccessPath[] = ".//X:";
szVolumeAccessPath[4] = DriveLetter;
long DeviceNumber = -1;
HANDLE hVolume = CreateFile(szVolumeAccessPath, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, NULL, NULL);
if (hVolume == INVALID_HANDLE_VALUE)
{
MessageBox(NULL,"Create File FAIL","FAIL",MB_OK+MB_TOPMOST);
return 1;
}
STORAGE_DEVICE_NUMBER sdn;
DWORD dwBytesReturned = 0;
long res = DeviceIoControl(hVolume,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0, &sdn, sizeof(sdn),
&dwBytesReturned, NULL);
if ( res )
{
DeviceNumber = sdn.DeviceNumber;
}
CloseHandle(hVolume);
if ( DeviceNumber == -1 )
{
MessageBox(NULL,"DeviceIoControl FAIL","FAIL",MB_OK+MB_TOPMOST);
return 1;
}
UINT DriveType = GetDriveType(szRootPath);
// get the dos device name (like /device/floppy0)
// to decide if it's a floppy or not
char szDosDeviceName[MAX_PATH]={0};
res = QueryDosDevice(szDevicePath,szDosDeviceName,MAX_PATH);
if ( !res )
{
MessageBox(NULL,"QueryDosDevice FAIL ","FAIL",MB_OK+MB_TOPMOST);
return 1;
}
DEVINST DevInst=GetDrivesDevInstByDeviceNumber(DeviceNumber,
DriveType, szDosDeviceName);
if ( DevInst == 0 )
{
MessageBox(NULL,"GetDrivesDevInstByDeviceNumber FAIL","FAIL",MB_OK+MB_TOPMOST);
return 1;
}
ULONG Status = 0;
ULONG ProblemNumber = 0;
PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown;
WCHAR VetoNameW[MAX_PATH]={0};
bool bSuccess = false;
// get drives's parent, e.g. the USB bridge,
// the SATA port, an IDE channel with two drives!
DEVINST DevInstParent = 0;
res = CM_Get_Parent(&DevInstParent, DevInst, 0);
for ( long tries=0; tries<MAX_TRY_TIMES; tries++ ) //#define MAX_TRY_TIMES 10
{
// sometimes we need some tries...
VetoNameW[0] = 0;
res = CM_Request_Device_EjectW(DevInstParent,
&VetoType, VetoNameW, MAX_PATH, 0);
bSuccess = (res==CR_SUCCESS &&
VetoType==PNP_VetoTypeUnknown);
if ( bSuccess )
{
break;
}
Sleep(500); // required to give the next tries a chance!
}
return 0;
}
DEVINST GetDrivesDevInstByDeviceNumber(long DeviceNumber,
UINT DriveType, char* szDosDeviceName)
{
bool IsFloppy = (strstr(szDosDeviceName,
"//Floppy") != NULL); // is there a better way?
GUID guid;
switch (DriveType)
{
case DRIVE_REMOVABLE:
if ( IsFloppy )
{
guid = GUID_DEVINTERFACE_FLOPPY;
} else
{
guid = GUID_DEVINTERFACE_DISK;
}
break;
default:
return 0;
}
// Get device interface info set handle
// for all devices attached to system
HDEVINFO hDevInfo = SetupDiGetClassDevs(&guid, NULL, NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE) {
return 0;
}
// Retrieve a context structure for a device interface
// of a device information set.
DWORD dwIndex = 0;
SP_DEVICE_INTERFACE_DATA devInterfaceData = {0};
devInterfaceData.cbSize=sizeof(SP_DEVICE_INTERFACE_DATA);
BOOL bRet = FALSE;
BYTE Buf[1024]={0};
PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd =
(PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
SP_DEVICE_INTERFACE_DATA spdid;
SP_DEVINFO_DATA spdd;
DWORD dwSize;
spdid.cbSize = sizeof(spdid);
while ( true )
{
bRet = SetupDiEnumDeviceInterfaces(hDevInfo, NULL,
&guid, dwIndex, &devInterfaceData);
if (!bRet)
{
break;
}
SetupDiEnumInterfaceDevice(hDevInfo, NULL, &guid,
dwIndex, &spdid);
dwSize = 0;
SetupDiGetDeviceInterfaceDetail(hDevInfo,
&spdid, NULL, 0, &dwSize, NULL);
if ( dwSize!=0 && dwSize<=sizeof(Buf) )
{
pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
ZeroMemory((PVOID)&spdd, sizeof(spdd));
spdd.cbSize = sizeof(spdd);
long res =
SetupDiGetDeviceInterfaceDetail(hDevInfo, &
spdid, pspdidd,
dwSize, &dwSize,
&spdd);
if ( res )
{
HANDLE hDrive = CreateFile(pspdidd->DevicePath,0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, NULL, NULL);
if ( hDrive != INVALID_HANDLE_VALUE )
{
STORAGE_DEVICE_NUMBER sdn;
DWORD dwBytesReturned = 0;
res = DeviceIoControl(hDrive,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
NULL, 0, &sdn, sizeof(sdn),
&dwBytesReturned, NULL);
if ( res )
{
if ( DeviceNumber == (long)sdn.DeviceNumber )
{
CloseHandle(hDrive);
SetupDiDestroyDeviceInfoList(hDevInfo);
return spdd.DevInst;
}
}
CloseHandle(hDrive);
}
}
}
dwIndex++;
}
SetupDiDestroyDeviceInfoList(hDevInfo);
return 0;
}
参考http://www.codeproject.com/system/RemoveDriveByLetter.asp
一般的GUID定义 :
GUID GUID_DEVINTERFACE_DISK = { 0x53f56307L,
0xb6bf,
0x11d0,
{0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b}
};
GUID GUID_DEVINTERFACE_FLOPPY ={0x53f56311L,
0xb6bf,
0x11d0,
{0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b}
};
会用到.h和.lib :
#include <stdio.h>
#include <winioctl.h>
#include <wtypes.h>
#define DWORD_PTR DWORD*
#define ULONG_PTR DWORD*
#include <cfgmgr32.h>
#pragma comment(lib,"cfgmgr32.lib")
#include <Setupapi.h>
#pragma comment (lib,"setupapi.lib")