您的位置:首页 > Web前端

Remove USB Device Safely

2016-04-12 17:58 309 查看
实现的功能:Remove USB Device Safely


1.获取设备Handle

根据卷的驱动器类型和DOS设备名,使用Windows API枚举所有磁盘,包括软盘、光盘,或者其他设备。

//---------------------------------------------------------------------- 

// returns the device instance handle of a storage volume or 0 on error 

//---------------------------------------------------------------------- 

DEVINST GetDrivesDevInstByDeviceNumber(long DeviceNumber, UINT DriveType, char* szDosDeviceName) 



    bool IsFloppy = (strstr(szDosDeviceName, "\\Floppy") != NULL);

    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; 

    long 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);

            long 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 == (long)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; 

}


2.Remove Usb Device的主程序

本例中usb的盘符为G盘

    char DriveLetter = 'G'; 

    DriveLetter &= ~0x20; // uppercase

    if ( DriveLetter < 'A' || DriveLetter > 'Z' ) { 

        return 1; 

    }

    char szRootPath[] = "X:\\";   // "X:\"  -> for GetDriveType 

    szRootPath[0] = DriveLetter;

    char szDevicePath[] = "X:";   // "X:"   -> for QueryDosDevice 

    szDevicePath[0] = DriveLetter;

    char szVolumeAccessPath[] = "\\\\.\\X:";   // "\\.\X:"  -> to open the volume 

    szVolumeAccessPath[4] = DriveLetter;

    long DeviceNumber = -1;


2.1 open the storage volume

    HANDLE hVolume = CreateFile(szVolumeAccessPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL); 

    if (hVolume == INVALID_HANDLE_VALUE) { 

        return 1; 

    }


2.2 get the volume's device number

    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 ) { 

        return 1; 

    }


2.3 get the drive type

    UINT DriveType = GetDriveType(szRootPath);


2.4 get the dos device name

    char szDosDeviceName[MAX_PATH]; 

    res = QueryDosDevice(szDevicePath, szDosDeviceName, MAX_PATH); 

    if ( !res ) { 

        return 1; 

    }


2.5 get the device instance handle

    DEVINST DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber, DriveType, szDosDeviceName);

    if ( DevInst == 0 ) { 

        return 1; 

    }

    PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown; 

    WCHAR VetoNameW[MAX_PATH]; 

    VetoNameW[0] = 0; 

    bool bSuccess = false;


2.6 get drives's parent

    DEVINST DevInstParent = 0; 

    res = CM_Get_Parent(&DevInstParent, DevInst, 0);

    for ( long tries=1; tries<=3; tries++ ) { // sometimes we need try more than one times...

        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! 

    }

转自:http://www.cnblogs.com/xuesong/archive/2010/08/10/1796678.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Windows USB