zoukankan      html  css  js  c++  java
  • 如何用C++实现安全Remove USB Device

    实现的功能: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!
        }

  • 相关阅读:
    浏览器—CORS 通信的学习总结
    前端算法
    移动端适配时对meta name="viewport" content="width=device-width,initial-scale=1.0"的理解
    react和vue的区别
    对xss攻击和csrf攻击的理解
    前端如何解决跨域
    你没那么重要
    五福
    天道
    决策
  • 原文地址:https://www.cnblogs.com/xuesong/p/1796678.html
Copyright © 2011-2022 走看看