根据盘符安全移除U盘

本文介绍了一种根据盘符停止U盘的方法。通过获取U盘的设备接口句柄,找到其父设备句柄,进而实现同一物理U盘上多个逻辑盘符的安全移除。
  1. //////////////////////
  2. //http://www.codeproject.com/KB/system/RemoveDriveByLetter.aspx
  3. //根据盘符停止U盘
  4. ////////////////////////
  5. BOOL  CPubFunction::StopDeviceByLetter(LPCTSTR lpDisk)  
  6. {   
  7.     TCHAR szRootPath[] = _T("X://");   // "X:/"  -> for GetDriveType
  8.     szRootPath[0] = lpDisk[0];
  9.     TCHAR szDevicePath[] = _T("X:");   // "X:"   -> for QueryDosDevice
  10.     szDevicePath[0] = lpDisk[0];
  11.     CString strLogicDisk;
  12.     strLogicDisk.Format(_T("////.//%c:"), lpDisk[0]);   //   "//./X:" 
  13.     DWORD DiskNumber   =   -1;   
  14.     HANDLE   hVolume = CreateFile(strLogicDisk, 0, FILE_SHARE_READ| FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);   
  15.     if(hVolume   ==   INVALID_HANDLE_VALUE)   
  16.     {   
  17.         return 0;   
  18.     }   
  19.     STORAGE_DEVICE_NUMBER  sdn;   
  20.     DWORD  dwBytesReturned = 0;   
  21.     BOOL res = DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);   
  22.     if(res)   
  23.     {   
  24.         DiskNumber = sdn.DeviceNumber;   
  25.     }   
  26.     CloseHandle(hVolume);   
  27.     if(DiskNumber==-1   )   
  28.     {   
  29.         return   0;   
  30.     }   
  31.     
  32.     // get the drive type which is required to match the device numbers correctely
  33.     UINT DriveType = GetDriveType(lpDisk);
  34.     // get the dos device name (like /device/floppy0) to decide if it's a floppy or not - who knows a better way?
  35.     TCHAR szDosDeviceName[MAX_PATH];
  36.     res = QueryDosDevice(szDevicePath, szDosDeviceName, MAX_PATH);
  37.     if ( !res ) {
  38.         return 0;
  39.     }
  40.     // get the device instance handle of the storage volume by means of a SetupDi enum and matching the device number
  41.     DWORD DevInst = GetDrivesDevInstByDeviceNumber(DiskNumber, DriveType, szDosDeviceName);
  42.     if ( DevInst == 0 ) {
  43.         return 0;
  44.     }
  45.     PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown; 
  46.     WCHAR VetoNameW[MAX_PATH];
  47.     VetoNameW[0] = 0;
  48.     BOOL bSuccess = FALSE;
  49.     // get drives's parent, e.g. the USB bridge, the SATA port, an IDE channel with two drives!
  50.     DWORD DevInstParent = 0;
  51.     res = CM_Get_Parent(&DevInstParent, DevInst, 0); 
  52.     for ( int tries=1; tries<=3; tries++ ) { // sometimes we need some tries...
  53.         VetoNameW[0] = 0;
  54.         // CM_Query_And_Remove_SubTree doesn't work for restricted users
  55.         //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!
  56.         //res = CM_Query_And_Remove_SubTreeW(DevInstParent, NULL, NULL, 0, CM_REMOVE_NO_RESTART);  // with messagebox (W2K, Vista) or balloon (XP)
  57.         
  58.         //res = CM_Request_Device_EjectW(DevInstParent, &VetoType, VetoNameW, MAX_PATH, 0);
  59.         res = CM_Request_Device_EjectW(DevInstParent, NULL, NULL, 0, 0); // with messagebox (W2K, Vista) or balloon (XP)
  60.         bSuccess = (res==CR_SUCCESS && VetoType==PNP_VetoTypeUnknown);
  61.         if ( bSuccess )  { 
  62.             break;
  63.         }
  64.         Sleep(500); // required to give the next tries a chance!
  65.     }
  66.     if ( bSuccess ) {
  67.     //  printf("Success/n/n");
  68.         return 1;
  69.     }
  70.     //printf("failed/n");
  71.     
  72.     //printf("Result=0x%2X/n", res);
  73.     //if ( VetoNameW[0] ) {
  74.     //  printf("VetoName=%ws)/n/n", VetoNameW);
  75.     //} 
  76.     return 0;
  77. }   
  78. //-----------------------------------------------------------   
  79. //http://www.codeproject.com/KB/system/RemoveDriveByLetter.aspx
  80. //----------------------------------------------------------------------
  81. // returns the device instance handle of a storage volume or 0 on error
  82. //----------------------------------------------------------------------
  83. DEVINST CPubFunction::GetDrivesDevInstByDeviceNumber(DWORD DeviceNumber, UINT DriveType, TCHAR* szDosDeviceName)
  84. {
  85. //  bool IsFloppy = (strstr(szDosDeviceName, "//Floppy") != NULL); // who knows a better way?
  86.     GUID* guid;
  87.     switch (DriveType) {
  88.     case DRIVE_REMOVABLE:
  89. //      if ( IsFloppy ) {
  90. //          guid = (GUID*)&GUID_DEVINTERFACE_FLOPPY;
  91. //      } else {
  92.             guid = (GUID*)&GUID_DEVINTERFACE_DISK;
  93. //      }
  94.         break;
  95.     case DRIVE_FIXED:
  96.         guid = (GUID*)&GUID_DEVINTERFACE_DISK;
  97.         break;
  98.     case DRIVE_CDROM:
  99.         guid = (GUID*)&GUID_DEVINTERFACE_CDROM;
  100.         break;
  101.     default:
  102.         return 0;
  103.     }
  104.     // Get device interface info set handle for all devices attached to system
  105.     HDEVINFO hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
  106.     if (hDevInfo == INVALID_HANDLE_VALUE)   {
  107.         return 0;
  108.     }
  109.     // Retrieve a context structure for a device interface of a device information set
  110.     DWORD dwIndex = 0;
  111.     int res;
  112.     BYTE Buf[1024];
  113.     PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
  114.     SP_DEVICE_INTERFACE_DATA         spdid;
  115.     SP_DEVINFO_DATA                  spdd;
  116.     DWORD                            dwSize;
  117.     
  118.     spdid.cbSize = sizeof(spdid);
  119.     while ( true )  {
  120.         res = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guid, dwIndex, &spdid);
  121.         if ( !res ) {
  122.             break;
  123.         }
  124.         dwSize = 0;
  125.         SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL); // check the buffer size
  126.         if ( dwSize!=0 && dwSize<=sizeof(Buf) ) {
  127.             pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
  128.             ZeroMemory(&spdd, sizeof(spdd));
  129.             spdd.cbSize = sizeof(spdd);
  130.             int res = SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd, dwSize, &dwSize, &spdd);
  131.             if ( res ) {
  132.                 // in case you are interested in the USB serial number:
  133.                 // the device id string contains the serial number if the device has one,
  134.                 // otherwise a generated id that contains the '&' char...
  135.                 /*
  136.                 DEVINST DevInstParent = 0;
  137.                 CM_Get_Parent(&DevInstParent, spdd.DevInst, 0); 
  138.                 char szDeviceIdString[MAX_PATH];
  139.                 CM_Get_Device_ID(DevInstParent, szDeviceIdString, MAX_PATH, 0);
  140.                 printf("DeviceId=%s/n", szDeviceIdString);
  141.                 */
  142.                 // open the disk or cdrom or floppy
  143.                 HANDLE hDrive = CreateFile(pspdidd->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  144.                 if ( hDrive != INVALID_HANDLE_VALUE ) {
  145.                     // get its device number
  146.                     STORAGE_DEVICE_NUMBER sdn;
  147.                     DWORD dwBytesReturned = 0;
  148.                     res = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);
  149.                     if ( res ) {
  150.                         if ( DeviceNumber == (DWORD)sdn.DeviceNumber ) {  // match the given device number with the one of the current device
  151.                             CloseHandle(hDrive);
  152.                             SetupDiDestroyDeviceInfoList(hDevInfo);
  153.                             return spdd.DevInst;
  154.                         }
  155.                     }
  156.                     CloseHandle(hDrive);
  157.                 }
  158.             }
  159.         }
  160.         dwIndex++;
  161.     }
  162.     SetupDiDestroyDeviceInfoList(hDevInfo);
  163.     return 0;
  164. }
  165. //-----------------------------------------------------------

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值