资讯详情

windows USB存储检测

针对windows下USB存储设备,主要分为检测是否已插入存储设备和实时插入检测.

实时插入检测: 主要是注册windows事件,或重写Qt的nativeEvent事件.这个比较简单,因为策略是定期检测,不需要实时插入检测.

检查存储设备是否已插入: 主要分为三个步骤:

1: 通过GetLogicDrives()获取所有盘符,然后逐一使用GetDriveType如果是盘符类型,如果是DRIVE_REMOVABLE,可移动设备.

代码:

bool ExistUsbStorageDevice() { #ifdef _WIN32   DWORD all_disk = GetLogicalDrives();   std::string disk_path;   int disk_num = 0;    while (all_disk) {     if (1 == (all_disk & 0X1)) {       disk_path.clear();       disk_path.push_back(static_cast<char>('A'   disk_num));       disk_path.push_back(」;        if (DRIVE_REMOVABLE == GetDriveType(disk_path.c_str())) {         return true;       }     }     all_disk = all_disk >> 1;       disk_num;   }   return false; #else   return false; #endif // _WIN32 }

然而,这一步只能检测到U盘,移动硬盘GetDriveType返回是DRIVE_FIXED,与本机盘符类型一致

2: 通过CreateFile如果是,打开设备,然后获取设备的总线类型BusTypeUsb,即YUSB总线.可以判断它是USB存储设备.

代码:

bool ExistUsbStorageDevice() { #ifdef _WIN32   DWORD all_disk = GetLogicalDrives();   std::string disk_path;   int disk_num = 0;    while (all_disk) {     if (1 == (all_disk & 0X1)) {       disk_path.clear();       disk_path = "\\\\.\\";       disk_path.push_back(static_cast<char>('A'   disk_num));       disk_path.push_back(」;        HANDLE hDevice = CreateFile(disk_path.c_str(),         GENERIC_READ | GENERIC_WRITE,         FILE_SHARE_READ | FILE_SHARE_WRITE,         NULL,         OPEN_EXISTING, NULL, NULL);        PSTORAGE_DEVICE_DESCRIPTOR pDevDesc = (PSTORAGE_DEVICE_DESCRIPTOR)new BYTE[sizeof(STORAGE_DEVICE_DESCRIPTOR)   512 - 1];       pDevDesc->Size = sizeof(STORAGE_DEVICE_DESCRIPTOR)   512 - 1;       if (GetDisksProperty(hDevice, pDevDesc)) {         if (pDevDesc->BusType == BusTypeUsb) {           return true;         }       }     }     all_disk = all_disk >> 1;       disk_num;   }   return false; #else   return false; #endif // _WIN32 }

这一步基本成功,但手机存储设备还有一个例外。.手机连接电脑后,便携式设备在设备管理器中的分类.得不到盘符.

3.没有实现在线信息的搜索C 检测手机设备.但查到了windows portable devices这个名词.于是在msdn搜了一下.看链接:查找设备

经过一番调试,简化了代码:

bool ExistPortableDevice() { #ifdef _WIN32   HRESULT init_result = CoInitialize(NULL);   if (FAILED(init_result)) {     return false;   }    IPortableDeviceManager* portable_device_manager;   HRESULT hr = CoCreateInstance(CLSID_PortableDeviceManager,     NULL,     CLSCTX_INPROC_SERVER,     IID_PPV_ARGS(&portable_device_manager));   if (FAILED(hr)) {     return false;   }    bool exist = false;   do {   DWORD device_id_size;   hr = portable_device_manager->GetDevices(NULL, &device_id_size);   if (FAILED(hr)|| static_cast<int>(device_id_size) <= 0) {     break;   }   exist = true;   } while (0);    if (SUCCEEDED(init_result)) {     CoUninitialize();   }   return exist; #else   return false; #endif // _WIN32 }

以下是获得的设备信息描述,可用于代码调试,检查检测是否正确:

std::vector<std::string> GetPortableDevicesDescription(IPortableDeviceManager* portable_device_manager) {   std::vector<std::string> devices_description;     DWORD device_id_size;   HRESULT hr = portable_device_manager->GetDevices(NULL, &device_id_size);   if (FAILED(hr) || static_cast<int>(device_id_size) <= 0) {     return devices_description;   }      PWSTR* device_ids = new (std::nothrow) PWSTR[device_id_size];     if (device_ids == NULL) {       return devices_description;     }      do {     hr = portable_device_manager->GetDevices(device_ids, &device_id_size);     if (FAILED(hr)) {       break;     }      DWORD device_index = 0;     for (device_index = 0; device_index < device_id_size; device_index  ) {       DWORD   describe_size = 0;       hr = portable_device_manager->GetDeviceDescription(device_ids[device_index], NULL, &describe_size);       if (FAILED(hr) || static_cast<int>(describe_size) <= 0) {         break;       }       WCHAR* describe = new (std::nothrow) WCHAR[describe_size];       hr = portable_device_manager->GetDeviceDescription(device_ids[device_index], describe, &describe_size);       if (SUCCEEDED(hr)) {         devices_description.push_back(StringUtil::wstring2string(describe));       }     }      for (device_index = 0; device_index < device_id_size; device_index  ) {       CoTaskMemFree(device_ids[device_index]);       device_ids[device_index] = NULL;     }   } while (0);    delete[] device_ids;   device_ids  NULL;

  return devices_description;
}

到这一步基本上已经能完整解决需求了,但想着是不是还能精益求精. 我的手机连接USB时,可选择仅充电,或者文件传输.这两种情况下都是会检测到USB存储,是否可以再进一步检测到这点.查看到检索设备支持的功能类别,存在存储类别.结合链接:便携式设备 COM API 示例3

实现代码:

#include <iostream>

#include <windows.h>
#include <portabledeviceapi.h>
#include <atlcomcli.h>
#include <PortableDevice.h>

#pragma comment(lib,"PortableDeviceGUIDs.lib")
#define SELECTION_BUFFER_SIZE 81
#define CLIENT_NAME         L"WPD Sample Application"
#define CLIENT_MAJOR_VER    1
#define CLIENT_MINOR_VER    0
#define CLIENT_REVISION     2


bool SupportStorage(IPortableDevice* pDevice) {
  HRESULT hr = S_OK;
  CComPtr<IPortableDeviceCapabilities>            pCapabilities;
  CComPtr<IPortableDevicePropVariantCollection>   pCategories;
  DWORD dwNumCategories = 0;
  
  // Get an IPortableDeviceCapabilities interface from the IPortableDevice interface to
  // access the device capabilities-specific methods.
  hr = pDevice->Capabilities(&pCapabilities);
  if (FAILED(hr))
  {
    printf("! Failed to get IPortableDeviceCapabilities from IPortableDevice, hr = 0x%lx\n", hr);
  }

  // Get all functional categories supported by the device.
  if (SUCCEEDED(hr))
  {
    hr = pCapabilities->GetFunctionalCategories(&pCategories);
    if (FAILED(hr))
    {
      printf("! Failed to get functional categories from the device, hr = 0x%lx\n", hr);
    }
  }

  if (SUCCEEDED(hr))
  {
    hr = pCategories->GetCount(&dwNumCategories);
    if (FAILED(hr))
    {
      printf("! Failed to get number of functional categories, hr = 0x%lx\n", hr);
    }
  }

  printf("\n%d Functional Categories Found on the device\n\n", dwNumCategories);

  // Loop through each functional category and display its name
  if (SUCCEEDED(hr))
  {
    for (DWORD dwIndex = 0; dwIndex < dwNumCategories; dwIndex++)
    {
      PROPVARIANT pv = { 0 };
      PropVariantInit(&pv);
      hr = pCategories->GetAt(dwIndex, &pv);
      if (SUCCEEDED(hr))
      {
        // We have a functional category.  It is assumed that
        // functional categories are returned as VT_CLSID
        // VarTypes.

        if (pv.puuid != NULL)
        {
          // Display the functional category name
          //DisplayFunctionalCategory(*pv.puuid);
          printf("\n");
        }
      }

      PropVariantClear(&pv);
    }
  }

  return true;
}

bool ExistPortableDevices() {
  CoInitialize(NULL);
  IPortableDeviceManager* pPortableDeviceManager;
  HRESULT hr = CoCreateInstance(CLSID_PortableDeviceManager,
    NULL,
    CLSCTX_INPROC_SERVER,
    IID_PPV_ARGS(&pPortableDeviceManager));
  if (FAILED(hr))
  {
    printf("! Failed to CoCreateInstance CLSID_PortableDeviceManager, hr = 0x%lx\n", hr);
  }
  DWORD cPnPDeviceIDs;
  if (SUCCEEDED(hr))
  {
    hr = pPortableDeviceManager->GetDevices(NULL, &cPnPDeviceIDs);
    if (FAILED(hr))
    {
      printf("! Failed to get number of devices on the system, hr = 0x%lx\n", hr);
    }
  }

  // Report the number of devices found.  NOTE: we will report 0, if an error
  // occured.

  printf("\n%d Windows Portable Device(s) found on the system\n\n", cPnPDeviceIDs);

  if (SUCCEEDED(hr) && (cPnPDeviceIDs > 0))
  {
    PWSTR* pPnpDeviceIDs;
    pPnpDeviceIDs = new (std::nothrow) PWSTR[cPnPDeviceIDs];
    if (pPnpDeviceIDs != NULL)
    {
      DWORD dwIndex = 0;

      hr = pPortableDeviceManager->GetDevices(pPnpDeviceIDs, &cPnPDeviceIDs);
      if (SUCCEEDED(hr))
      {
        // For each device found, display the devices friendly name,
        // manufacturer, and description strings.
        for (dwIndex = 0; dwIndex < cPnPDeviceIDs; dwIndex++)
        {
          IPortableDeviceValues* clientInformation;
          hr = CoCreateInstance(CLSID_PortableDeviceValues,
            nullptr,
            CLSCTX_INPROC_SERVER,
            IID_PPV_ARGS(&clientInformation));
          if (SUCCEEDED(hr))
          {
            clientInformation->SetStringValue(WPD_CLIENT_NAME, CLIENT_NAME);
            clientInformation->SetUnsignedIntegerValue(WPD_CLIENT_MAJOR_VERSION, CLIENT_MAJOR_VER);
            clientInformation->SetUnsignedIntegerValue(WPD_CLIENT_MINOR_VERSION, CLIENT_MINOR_VER);
            clientInformation->SetUnsignedIntegerValue(WPD_CLIENT_REVISION, CLIENT_REVISION);
          }

          IPortableDevice* device;
          hr = CoCreateInstance(CLSID_PortableDeviceFTM,
            nullptr,
            CLSCTX_INPROC_SERVER,
            IID_PPV_ARGS(&device));
          if (SUCCEEDED(hr))
          {
            hr = (device)->Open(pPnpDeviceIDs[dwIndex], clientInformation);

            if (hr == E_ACCESSDENIED)
            {
              wprintf(L"Failed to Open the device for Read Write access, will open it for Read-only access instead\n");
              clientInformation->SetUnsignedIntegerValue(WPD_CLIENT_DESIRED_ACCESS, GENERIC_READ);
              hr = (device)->Open(pPnpDeviceIDs[dwIndex], clientInformation);
            }
            SupportStorage(device);
            if (FAILED(hr))
            {
              wprintf(L"! Failed to Open the device, hr = 0x%lx\n", hr);
              // Release the IPortableDevice interface, because we cannot proceed
              // with an unopen device.
              (device)->Release();
              device = nullptr;
            }
          }


          printf("[%d] ", dwIndex);
          WCHAR   pDeviceFriendlyName[16] = { 0 };
          DWORD   pcchDeviceFriendlyName = 0x0d;
          //          HRESULT re = pPortableDeviceManager->GetDeviceFriendlyName(pPnpDeviceIDs[dwIndex], pDeviceFriendlyName, &pcchDeviceFriendlyName);
          //           printf("    ");
          HRESULT re = pPortableDeviceManager->GetDeviceDescription(pPnpDeviceIDs[dwIndex], pDeviceFriendlyName, &pcchDeviceFriendlyName);
          //           DisplayManufacturer(pPortableDeviceManager, pPnpDeviceIDs[dwIndex]);
          //           printf("    ");
          //           DisplayDescription(pPortableDeviceManager, pPnpDeviceIDs[dwIndex]);
          printf("%s\n", pDeviceFriendlyName);
        }
      }
      else
      {
        printf("! Failed to get the device list from the system, hr = 0x%lx\n", hr);
      }

      for (dwIndex = 0; dwIndex < cPnPDeviceIDs; dwIndex++)
      {
        CoTaskMemFree(pPnpDeviceIDs[dwIndex]);
        pPnpDeviceIDs[dwIndex] = NULL;
      }

      // Delete the array of PWSTR pointers
      delete[] pPnpDeviceIDs;
      pPnpDeviceIDs = NULL;
      return true;
    }
  }

  return false;
}
int main() {
  bool res = ExistPortableDevices();
  return 0;
}

        但是在USB仅充电的情况下pv.puuid输出后是{23F05BBC-15DE-4C2A-A55B-A9AF5CE412EF}  也就是WPD_FUNCTIONAL_CATEGORY_STORAGE,应该是无法分别是仅充电还是文件传输.

        而且借用一加手机测试,第三步的代码,在USB仅充电情况下是检测不到存储设备的.这部分就不是很了解了,希望熟悉的大佬指点.

标签: 接头usb连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台