最近写资料用到按照USB顺序显示所有的USB设备(设备不用按照插入顺序,只需要插入对应USB插口即可),搜了很多资料没有找到想要的实现方式,便自己动手写了一些库文件(结合USB View以及WindowsAPI函数),并且成功移植到MFC工程(我使用的是VS2010工具)。

首先看下USB View软件显示效果:

我们看到USB View软件是以树结构显示了USB所有的插口(包括以及连接设备的插口和还未连接设备的插口),但是连接的设备信息却不齐全(比如如何判断是安卓设备以及设备的容器ID和名称等)。

插入设备的数据采用WindowsAPI函数(WindowsAPI函数的缺点是只能查询到已经连接的设备信息,却不能确定设备信息对应的插口),对于这块我也纠结不少时间…

后来进行猜想,采用USB View作为USB插口的遍历,然后结合算法把遍历到的数据进行配对,可以组成完成的USB数据信息。

下面是我的实验计划:
    1.使用USB View函数库进行遍历并且保存所有的USB插口信息(保存已经插入和未插入的),其中树结构分为三级保存,第一级做为主要设备信息(USBHostControllers 主控制器),第二级做为hub设备信息(可以清楚知道hub下有几个USB插口),第三级做为当前hub下的USB插口信息。当然这只是USB View实现的功能;

2.使用WindowsAPI遍历到所有的USB信息(其中包括Hub信息);

3.根据USB View插口内的idVendor和idProduct信息进行匹配WindowAPI内所有相关的数据,配对成功后得到容器ID进行遍历剩下的设备信息确保设备信息的完整性以及不重复性,在匹配的过程中我们就可以到插入设备的名称,以及设备类型比如“Android”等,匹配成功后按照USB插口的顺序进行保存顺序(这里只按照计数的形式向后增加USB插口,不再使用树结构);

4.由于USB View使用C语言写的库文件,需要把一些不兼容MFC的部分进行修改,比如隐藏USB View自带的树结构视图等。

下面说下使用这个MFC工程的方式:

首先下载WinDDK 7600.16385.1工具包,这个网上很多下载后,安装到默认的路径:C:\WinDDK; 安装完成后需要把使用的VS2010文件夹路径下的 VC\ include内的所有文件 拷贝覆盖到C:\WinDDK\7600.16385.1\inc\api 文件夹内;

MFC工程下载地址:https://download.csdn.net/download/a29562268/10294175!

这个工程可以直接使用,也可以移植内部的文件用来使用,由于修改的文件比较多,只贴出具体实现的文件:

.h文件

/*
*李坤昱
*QQ:326087275@qq.com
*/
#include <stdio.h>
#include <vector>
#include "usbioctl.h "//枚举出所有的设备信息,然后与USB view信息合并
struct  List_all_USB_devices
{//设备类型 比如USBCString szDeviceInstanceID;//CString Device_Description;//设备描述CString szDesc;//CString Hardware_IDs;//CString pszId;//CString Bus_Reported_Device_Description;//CString Device_Manufacturer;//CString Device_Friendly_Name;//CString Device_Location_Info;//CString Device_Security_Descriptor_String;//容器IDCString ContainerId;//CString Device_Display_Category;//CString pszToken;//vidCString szVid;//pidCString szPid;//miCString szMi;//如果当前这条数据已经写入设备结构,标记为1 不再进行匹配bool bIs;List_all_USB_devices():bIs(0){}
};struct Usb_List_Data
{Usb_List_Data();//获取所有的USB设备信息bool GetAllUsbInfo(std::vector<List_all_USB_devices> & usb_Info);
private://保存所有的USB信息std::vector<List_all_USB_devices> Usb_Devices;
private://遍历USB设备void ListDevices (CONST GUID *pClassGuid, LPCTSTR pszEnumerator);
};typedef struct _STRING_DESCRIPTOR_NODE_
{struct _STRING_DESCRIPTOR_NODE *Next;UCHAR                           DescriptorIndex;USHORT                          LanguageID;USB_STRING_DESCRIPTOR           StringDescriptor[0];
} STRING_DESCRIPTOR_NODE_, *PSTRING_DESCRIPTOR_NODE_;//
struct Usb_Info
{int Count;//int deviceNameSize;//BOOLEAN LowSpeed;//BOOLEAN DeviceIsHub;//USHORT DeviceAddress;//USB_CONNECTION_STATUS ConnectionStatus;//USHORT NumberOfOpenPipes;//PSTRING_DESCRIPTOR_NODE_             stringDescs;//PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfoEx;//PUSB_DESCRIPTOR_REQUEST             configDesc;//CString leafName;//CString driverKeyName;//CString deviceDesc;
};//Hub
struct RootHub
{int Count;//int DeviceInfoType;//CString HubName;//int deviceNameSize;//CString deviceName;//CString leafName;//PUSB_NODE_INFORMATION   hubInfo;//PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfo;//PUSB_DESCRIPTOR_REQUEST ConfigDesc;//PSTRING_DESCRIPTOR_NODE_ StringDescs;std::vector<Usb_Info> Usb;
};
//主机控制器
struct HostControllers
{//标记当前是第几个主机控制器int Count;//CString DeviceInfoType;//CString DriverKeyName;//CString DeviceId;//ULONG VendorID;//ULONG DeviceID;//ULONG SubSysID;//ULONG Revision;//CString rootHubName;//CString deviceDesc;std::vector<RootHub> Hub;
};//获取计算机内树形结构形式 所有的USB相关信息,以及先后顺序(用来记录USB设备的位置)
struct Usb_Id
{bool GetAllUsbPlace(std::vector<HostControllers> & usb_host);
public://设备连接数ULONG devicesConnected;
private:void GetAllUsbPlace_();
};struct Usb_Port
{//标记是第几个USB插口int nCount;//ULONG VendorID;//ULONG ProductID;//CString Device_Description;//用来保存安卓设备名称CString Device_Description1;//CString Bus_Reported_Device_Description;//CString Device_Manufacturer;//CString Device_Location_Info;//CString ContainerId;//vidCString szVid;//pidCString szPid;//miCString szMi;//USB_CONNECTION_STATUS ConnectionStatus;
};//按循序整理出从Usb插口1开始,一直到最后的设备
struct Usb_SequenceInfo
{Usb_List_Data usb_list;Usb_Id Usb_id;bool GetUsbAllPorts(std::vector<Usb_Port> & port);
private:std::vector<Usb_Port> m_port;
private:void GetUsbPortsInfo();void WriteUsbPortsInfo(std::vector<List_all_USB_devices> usb_data,std::vector<HostControllers> usb_host);
};

.cpp文件

/*
*李坤昱
*QQ:326087275@qq.com
*/
#include "StdAfx.h"
#include "Usb_.h"#include "inc/usbview.h"
#include <windowsx.h>#include <windows.h>
#include <devguid.h>    // for GUID_DEVCLASS_CDROM etc
#include <setupapi.h>
#include <cfgmgr32.h>   // for MAX_DEVICE_ID_LEN, CM_Get_Parent and CM_Get_Device_ID
#define INITGUID
#include <tchar.h>
#include "C:\WinDDK\7600.16385.1\inc\api\devpkey.h" #pragma comment (lib, "setupapi.lib") typedef BOOL (WINAPI *FN_SetupDiGetDevicePropertyW)(  __in       HDEVINFO DeviceInfoSet,  __in       PSP_DEVINFO_DATA DeviceInfoData,  __in       const DEVPROPKEY *PropertyKey,  __out      DEVPROPTYPE *PropertyType,  __out_opt  PBYTE PropertyBuffer,  __in       DWORD PropertyBufferSize,  __out_opt  PDWORD RequiredSize,  __in       DWORD Flags  );  char *strupr(char *str);#define ARRAY_SIZE(arr)     (sizeof(arr)/sizeof(arr[0]))  Usb_List_Data::Usb_List_Data()
{}// 获取所有的USB信息
void Usb_List_Data::ListDevices (CONST GUID *pClassGuid, LPCTSTR pszEnumerator)
{  unsigned i, j;  DWORD dwSize, dwPropertyRegDataType;  DEVPROPTYPE ulPropertyType;  CONFIGRET status;  HDEVINFO hDevInfo;  SP_DEVINFO_DATA DeviceInfoData;  const static LPCTSTR arPrefix[3] = {TEXT("VID_"), TEXT("PID_"), TEXT("MI_")};  TCHAR szDeviceInstanceID [MAX_DEVICE_ID_LEN];  TCHAR szDesc[1024], szHardwareIDs[4096];  WCHAR szBuffer[4096];  LPTSTR pszToken, pszNextToken;  TCHAR szVid[MAX_DEVICE_ID_LEN], szPid[MAX_DEVICE_ID_LEN], szMi[MAX_DEVICE_ID_LEN];  FN_SetupDiGetDevicePropertyW fn_SetupDiGetDevicePropertyW = (FN_SetupDiGetDevicePropertyW)  GetProcAddress (GetModuleHandle (TEXT("Setupapi.dll")), "SetupDiGetDevicePropertyW");  // List all connected USB devices  hDevInfo = SetupDiGetClassDevs (pClassGuid, pszEnumerator, NULL,  pClassGuid != NULL ? DIGCF_PRESENT: DIGCF_ALLCLASSES | DIGCF_PRESENT);  if (hDevInfo == INVALID_HANDLE_VALUE)  return;  // Find the ones that are driverless  for (i = 0; ; i++)  {  List_all_USB_devices usb_dev;DeviceInfoData.cbSize = sizeof (DeviceInfoData);  if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData))  break;  status = CM_Get_Device_ID(DeviceInfoData.DevInst, szDeviceInstanceID , MAX_PATH, 0);  if (status != CR_SUCCESS)  continue;  // Display device instance ID  _tprintf (TEXT("%s\n"), szDeviceInstanceID );  if (SetupDiGetDeviceRegistryProperty (hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC,  &dwPropertyRegDataType, (BYTE*)szDesc,  sizeof(szDesc),   // The size, in bytes  &dwSize))  //设备名称 _tprintf (TEXT("    Device Description: \"%s\"\n"), szDesc);  usb_dev.Device_Description.Format(_T("%s"),szDesc);if (SetupDiGetDeviceRegistryProperty (hDevInfo, &DeviceInfoData, SPDRP_HARDWAREID,  &dwPropertyRegDataType, (BYTE*)szHardwareIDs,  sizeof(szHardwareIDs),    // The size, in bytes  &dwSize)) {  LPCTSTR pszId;  _tprintf (TEXT("    Hardware IDs:\n"));  for (pszId=szHardwareIDs;  *pszId != TEXT('\0') && pszId + dwSize/sizeof(TCHAR) <= szHardwareIDs + ARRAYSIZE(szHardwareIDs);  pszId += lstrlen(pszId)+1) {  _tprintf (TEXT("        \"%s\"\n"), pszId); usb_dev.pszId.Format(_T("%s"),pszId);}  }  // Retreive the device description as reported by the device itself  // On Vista and earlier, we can use only SPDRP_DEVICEDESC  // On Windows 7, the information we want ("Bus reported device description") is  // accessed through DEVPKEY_Device_BusReportedDeviceDesc  if (fn_SetupDiGetDevicePropertyW && fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc,  &ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0)) {  //设备类型if (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc,  &ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0))  _tprintf (TEXT("    Bus Reported Device Description: \"%ls\"\n"), szBuffer);  usb_dev.Bus_Reported_Device_Description = szBuffer;if (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_Manufacturer,  &ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0)) {  _tprintf (TEXT("    Device Manufacturer: \"%ls\"\n"), szBuffer); usb_dev.Device_Manufacturer = szBuffer;}  if (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_FriendlyName,  &ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0)) {  _tprintf (TEXT("    Device Friendly Name: \"%ls\"\n"), szBuffer); usb_dev.Device_Friendly_Name = szBuffer;}  if (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_LocationInfo,  &ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0)) {  _tprintf (TEXT("    Device Location Info: \"%ls\"\n"), szBuffer);  usb_dev.Device_Location_Info = szBuffer;}  if (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_SecuritySDS,  &ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0)) {  // See Security Descriptor Definition Language on MSDN  // (http://msdn.microsoft.com/en-us/library/windows/desktop/aa379567(v=vs.85).aspx)  _tprintf (TEXT("    Device Security Descriptor String: \"%ls\"\n"), szBuffer);  usb_dev.Device_Security_Descriptor_String = szBuffer;}  //容器IDif (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_ContainerId,  &ulPropertyType, (BYTE*)szDesc, sizeof(szDesc), &dwSize, 0)) {  StringFromGUID2((REFGUID)szDesc, szBuffer, ARRAY_SIZE(szBuffer));  _tprintf (TEXT("    ContainerId: \"%ls\"\n"), szBuffer);  usb_dev.ContainerId = szBuffer;}  if (fn_SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_DeviceDisplay_Category,  &ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0))  _tprintf (TEXT("    Device Display Category: \"%ls\"\n"), szBuffer); usb_dev.Device_Display_Category = szBuffer;}  pszToken = _tcstok_s (szDeviceInstanceID , TEXT("\\#&"), &pszNextToken);  while(pszToken != NULL) {  szVid[0] = TEXT('\0');  szPid[0] = TEXT('\0');  szMi[0] = TEXT('\0');  for (j = 0; j < 3; j++) {  if (_tcsncmp(pszToken, arPrefix[j], lstrlen(arPrefix[j])) == 0) {  switch(j) {  case 0:  _tcscpy_s(szVid, ARRAY_SIZE(szVid), pszToken);  break;  case 1:  _tcscpy_s(szPid, ARRAY_SIZE(szPid), pszToken);  break;  case 2:  _tcscpy_s(szMi, ARRAY_SIZE(szMi), pszToken);  break;  default:  break;  }  }  }  if (szVid[0] != TEXT('\0'))  {_tprintf (TEXT("    vid: \"%s\"\n"), szVid);  usb_dev.szVid.Format(_T("%s"),szVid);}if (szPid[0] != TEXT('\0'))  {_tprintf (TEXT("    pid: \"%s\"\n"), szPid);usb_dev.szPid.Format(_T("%s"),szPid);}if (szMi[0] != TEXT('\0'))  {_tprintf (TEXT("    mi: \"%s\"\n"), szMi);  usb_dev.szMi.Format(_T("%s"),szMi);}pszToken = _tcstok_s (NULL, TEXT("\\#&"), &pszNextToken);  }  Usb_Devices.push_back(usb_dev);}  return;
}  bool Usb_List_Data::GetAllUsbInfo(std::vector<List_all_USB_devices> & usb_Info)
{ListDevices(NULL, _T("USB"));usb_Info = Usb_Devices;return (usb_Info.size() > 0 ? true : false);
}std::vector<HostControllers> host;bool Usb_Id::GetAllUsbPlace(std::vector<HostControllers> & usb_host)
{GetAllUsbPlace_();usb_host = host;return (usb_host.size() > 0 ? true : false);
}void Usb_Id::GetAllUsbPlace_()
{host.clear();EnumerateHostControllers(0,&devicesConnected);
}void Usb_SequenceInfo::GetUsbPortsInfo()
{std::vector<List_all_USB_devices> usb_data;usb_list.GetAllUsbInfo(usb_data);std::vector<HostControllers> usb_host;Usb_id.GetAllUsbPlace(usb_host);WriteUsbPortsInfo(usb_data,usb_host);
}void Usb_SequenceInfo::WriteUsbPortsInfo(std::vector<List_all_USB_devices> usb_data,std::vector<HostControllers> usb_host)
{if (0 >= usb_data.size() && 0 >= usb_host.size()){AfxMessageBox(_T("无法获取到USB的接口位置!"));}//合并信息组成一条完整usb设备信息m_port.clear();int count = 0;for (auto it = usb_host.begin();it != usb_host.end();it++){for (auto Usb = it->Hub.begin();Usb != it->Hub.end();Usb++){for (auto UsbInfo = Usb->Usb.begin();UsbInfo != Usb->Usb.end();UsbInfo++){Usb_Port port;port.ConnectionStatus = UsbInfo->ConnectionStatus;if (DeviceConnected == port.ConnectionStatus){if ((UsbInfo->connectionInfoEx) && (NULL !=  UsbInfo->connectionInfoEx) /*&& (0 != *UsbInfo->connectionInfoEx->DeviceDescriptor)*/){port.VendorID = UsbInfo->connectionInfoEx->DeviceDescriptor.idVendor;port.ProductID = UsbInfo->connectionInfoEx->DeviceDescriptor.idProduct;//设备的id数字有的是16进制 有的是10进制CString StrVendor,StrProduct;StrVendor.Format(_T("VID_%04X"),port.VendorID);StrProduct.Format(_T("PID_%04X"),port.ProductID);CString StrVendor_,StrProduct_;StrVendor_.Format(_T("VID_%d"),port.VendorID);StrProduct_.Format(_T("PID_%d"),port.ProductID);//在所有设备信息里进行匹配for (auto data = usb_data.begin();data != usb_data.end();data++){if (data->bIs == true)continue;//进行记录数据,然后继续遍历相同容器ID的if ((data->szVid == StrVendor && data->szPid == StrProduct)|| (data->szVid == StrVendor_ && data->szPid == StrProduct_)){port.szVid = data->szVid;port.szPid = data->szPid;data->bIs = true;port.Device_Description = data->Device_Description;port.Bus_Reported_Device_Description = data->Bus_Reported_Device_Description;port.Device_Manufacturer = data->Device_Manufacturer;port.Device_Location_Info = data->Device_Location_Info;port.ContainerId = data->ContainerId;port.szMi = data->szMi;if (!port.ContainerId.IsEmpty()){//遍历一边相同容器ID的信息,找出设备名称for (auto data1 = usb_data.begin();data1 != usb_data.end();data1++){if (port.ContainerId == data1->ContainerId){if (!data1->bIs){//如果设备描述已经是Android了,那么修改为设备名称/*这么做的原因是Device_Description或Bus_Reported_Device_Description其中有一个表示设备名称,遍历的时候可能会被Android字节覆盖掉,这样可以保证保留设备名称*/if (port.Device_Description1.IsEmpty() || _T("Android") != data->Bus_Reported_Device_Description){port.Device_Description1 = data1->Device_Description;}data1->bIs = true;}}}}}}}}port.nCount = ++count;m_port.push_back(port);}}}
}bool Usb_SequenceInfo::GetUsbAllPorts(std::vector<Usb_Port> & port)
{GetUsbPortsInfo();port = m_port;return (port.size() > 0 ? true : false);
}

MFC工程下载地址:https://download.csdn.net/download/a29562268/10294175!这个项目可以顺利执行,如果有报错的情况,请参考前面配置的时候是否没有配置正确!

MFC工程按USB插口显示所有USB设备及插口(包括安卓)相关推荐

  1. STM32F103调试笔记(1)——microusb接入电脑后显示未知USB设备(代码43)

    这真的是一个很傻的错误- 由于我最近刚接触stm32,就在b站搜stm32的视频来看,现学现卖现烧程序.终于烧好了,想要用串口调试助手的时候却用不了,设备管理器显示未知USB设备(设备描述符请求失败) ...

  2. CH330显示未知USB设备(设备描述符请求失败)

    CH330接上电脑后显示未知USB设备(设备描述符请求失败),原因是:VCC脚的0.1uF退耦电容一定必不可少!!

  3. vmware虚拟机连接usb,显示:无法识别的usb设备,跟这台计算机连接的前一个usb设备工作不正常

    vmware虚拟机连接usb,显示:无法识别的usb设备,跟这台计算机连接的前一个usb设备工作不正常 前提:vmware,usb3.0设备 解决方法:vmware菜单栏☞VM☞setting☞usb ...

  4. STM32实现USB摄像头显示到LCD屏幕上

    第一章:简介 1.1 开发环境 USB摄像头型号:100w前置摄像头 主机型号:野火霸天虎开发版 外设:USB-HOST接口:连接USB摄像头设备 外部Sram:存放USB摄像头数据 LCD屏幕:显示 ...

  5. 取消usb计算机连接网络,usb连接(如何设置usb网络连接)

    手机USB连接电脑地的方法: 第一步:将USB数据线连接电脑,并确保数据线完好 第二步:打开手机系统设置------开发者选项 第三步:点开开发者选项---------USB调试 . 我不会额...教 ...

  6. 安卓USB开发教程 三 USB Accessory

    USB Accessory(配件模式) USB 配件模式允许用户连接专为 Android 设备设计的 USB 主机硬件.配件必须遵守 Android Accessory Development Kit ...

  7. 安卓USB开发教程 二 USB Host

    USB Host(主机模式) 当 Android 设备处于 USB 主机模式时,它充当 USB 主机,为总线供电,并枚举连接的 USB 设备.Android 3.1 及更高版本支持 USB 主机模式. ...

  8. 安卓USB开发教程 一 USB Host 与 Accessory

    安卓通过两种模式:USB Accessory 与 USB Host 模式支持多种 USB 外设与安卓 USB 配件(实现安卓配件协议的硬件).在 USB 配件模式下,外部 USB 硬件充当 USB 主 ...

  9. C++学习日记1:VS2015环境下,创建基于对话框的MFC工程

    VS2015环境下,创建基于对话框的MFC工程 1.新建项目 文件→新建→项目, 确定工程名称,选择工程保存路径, →确定 2.进入[当前项目设置]. →下一步 3.进入[应用程序类型]界面. 设置[ ...

最新文章

  1. 评估“不合格”!教育部暂停山东大学、复旦大学、南京师范大学部分硕士、博士学位授权点...
  2. 漫画:什么是“低代码”开发平台?
  3. 【Java】5.5 深入构造器
  4. 阿里云移动端播放器高级功能---截图和音频波形
  5. android 模糊度处理_图像处理评价指标之模糊度、清晰度(待更新)
  6. Centos6.8安装Nginx+域名转发
  7. 关于mybatis的association和collection主键映射问题
  8. 第十一届中国开源黑客松+中国程序员节重磅来袭,这里将有你不能错过的精彩。...
  9. ESP32学习笔记(46)——MQTT客户端
  10. General Partial Label Learning via Dual Bipartite Graph Autoencoder
  11. Python学习笔记(5)-集成开发环境IDLE的使用与调试
  12. 【FL攻防综述】Privacy and Robustness in Federated Learning: Attacks and Defenses
  13. 地产钢铁银行成低市盈率三剑客
  14. LIN雨量传感器:MQB平台与PQ自带的传感器类型分析
  15. 如何根据样本估计总体的均值、比例与方差?如何进行参数估计及选择对应公式?
  16. 字节跳动2020秋招笔试题
  17. 八、chmod命令详细用法
  18. win7 上配置openGL开发环境(配套openGL 超级宝典Super Bible 6th)
  19. 基于OpenCV的形状检测
  20. 鸿蒙时代实力排名,鸿蒙时期神魔不敢进入四大禁区,九天银河上榜,第一堪称黑暗禁地...

热门文章

  1. 如此沙雕的代码注释,还是程序员会玩!
  2. Linux下安装配置Nexus
  3. Windows平台下安装证书文件cer的步骤
  4. hadoop--MapReduce框架原理
  5. 蚂蚁金服ATEC城市峰会上海举行,三大发布迎接金融科技2019
  6. C++ 重载赋值运算符与11选5平台修复
  7. c++ static修饰符浅析
  8. STM32串口DMA超时接收方法,可大大节约CPU时间
  9. 文件批量传输组件作为架包使用说明
  10. 建筑工程项目管理信息化PM