根据盘符安全移除U盘

这个方法可以用来确定多盘符U盘的多个逻辑盘符所对应的物理U盘。根据盘符可以得到这个设备接口的句柄DevInst, 通过CM_Get_Parent函数可以得到这个句柄对应的父设备的句柄,这个父设备的句柄就是两个设备间的usb pridge, SATA port, IDE channel 。而同一个物理U盘的各个逻辑盘符的父设备的句柄则相同。

//
//http://www.codeproject.com/KB/system/RemoveDriveByLetter.aspx
//根据盘符停止U盘

BOOL CPubFunction::StopDeviceByLetter(LPCTSTR lpDisk)
{
TCHAR szRootPath[] = _T("X://"); // "X:/" -> for GetDriveType
szRootPath[0] = lpDisk[0];

TCHAR szDevicePath[] = _T("X:"); // "X:" -> for QueryDosDevice
szDevicePath[0] = lpDisk[0];

CString strLogicDisk;
strLogicDisk.Format(_T(".//%c:"), lpDisk[0]); // "//./X:"
DWORD DiskNumber = -1;

HANDLE hVolume = CreateFile(strLogicDisk, 0, FILE_SHARE_READ| FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
if(hVolume == INVALID_HANDLE_VALUE)
{
return 0;
}

STORAGE_DEVICE_NUMBER sdn;
DWORD dwBytesReturned = 0;
BOOL res = DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);
if(res)
{
DiskNumber = sdn.DeviceNumber;
}
CloseHandle(hVolume);

if(DiskNumber==-1 )
{
return 0;
}

// get the drive type which is required to match the device numbers correctely
UINT DriveType = GetDriveType(lpDisk);

// 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];
res = QueryDosDevice(szDevicePath, szDosDeviceName, MAX_PATH);
if ( !res ) {
return 0;
}

// get the device instance handle of the storage volume by means of a SetupDi enum and matching the device number
DWORD DevInst = GetDrivesDevInstByDeviceNumber(DiskNumber, DriveType, szDosDeviceName);

if ( DevInst == 0 ) {
return 0;
}

PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown;
WCHAR VetoNameW[MAX_PATH];
VetoNameW[0] = 0;
BOOL bSuccess = FALSE;

// get drives's parent, e.g. the USB bridge, the SATA port, an IDE channel with two drives!
DWORD DevInstParent = 0;
res = CM_Get_Parent(&DevInstParent, DevInst, 0);



for ( int tries=1; tries<=3; tries++ ) { // sometimes we need some tries...

VetoNameW[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_EjectW(DevInstParent, &VetoType, VetoNameW, 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 ) {
// printf("Success/n/n");
return 1;
}

//printf("failed/n");

//printf("Result=0x%2X/n", res);

//if ( VetoNameW[0] ) {
// printf("VetoName=%ws)/n/n", VetoNameW);
//}
return 0;

}
//-----------------------------------------------------------



//http://www.codeproject.com/KB/system/RemoveDriveByLetter.aspx
//----------------------------------------------------------------------
// returns the device instance handle of a storage volume or 0 on error
//----------------------------------------------------------------------
DEVINST CPubFunction::GetDrivesDevInstByDeviceNumber(DWORD DeviceNumber, UINT DriveType, TCHAR* szDosDeviceName)
{
// bool IsFloppy = (strstr(szDosDeviceName, "//Floppy") != NULL); // who knows a better way?

GUID* guid;

switch (DriveType) {
case DRIVE_REMOVABLE:
// if ( IsFloppy ) {
// guid = (GUID*)&GUID_DEVINTERFACE_FLOPPY;
// } else {
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
// }
break;
case DRIVE_FIXED:
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
break;
case DRIVE_CDROM:
guid = (GUID*)&GUID_DEVINTERFACE_CDROM;
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;
int res;

BYTE Buf[1024];
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 ) {
res = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guid, dwIndex, &spdid);
if ( !res ) {
break;
}

dwSize = 0;
SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL); // check the buffer size

if ( dwSize!=0 && dwSize<=sizeof(Buf) ) {

pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!

ZeroMemory(&spdd, sizeof(spdd));
spdd.cbSize = sizeof(spdd);

int res = SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd, dwSize, &dwSize, &spdd);
if ( res ) {

// in case you are interested in the USB serial number:
// the device id string contains the serial number if the device has one,
// otherwise a generated id that contains the '&' char...
/*
DEVINST DevInstParent = 0;
CM_Get_Parent(&DevInstParent, spdd.DevInst, 0);
char szDeviceIdString[MAX_PATH];
CM_Get_Device_ID(DevInstParent, szDeviceIdString, MAX_PATH, 0);
printf("DeviceId=%s/n", szDeviceIdString);
*/

// open the disk or cdrom or floppy
HANDLE hDrive = CreateFile(pspdidd->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if ( hDrive != INVALID_HANDLE_VALUE ) {
// get its device number
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 == (DWORD)sdn.DeviceNumber ) { // match the given device number with the one of the current device
CloseHandle(hDrive);
SetupDiDestroyDeviceInfoList(hDevInfo);
return spdd.DevInst;
}
}
CloseHandle(hDrive);
}
}
}
dwIndex++;
}

SetupDiDestroyDeviceInfoList(hDevInfo);

return 0;
}
//-----------------------------------------------------------




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值