安全移除USB设备

来源:互联网 发布:网络直播搭建 编辑:程序博客网 时间:2024/04/30 02:45

安全移除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")

原创粉丝点击