在设备远程控制中,经常需要搜索设备上已安装端口号,例如在“计算机”→“设备”能看到的端口(COM和LPT)。本文介绍的两种方法都是通过访问注册表实现的。
方法一:仅查询端口号,如:COM1、COM2等
HKEY hkey;
LPCTSTR lpSubKey = _T("HARDWARE\\DEVICEMAP\\SERIALCOMM\\");
long retopen = (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, &hkey));
if(retopen == ERROR_SUCCESS) //打开成功,枚举串口号
{
DWORD dinx = 0;
TCHAR c_valuename[40];
TCHAR c_vari[10];
DWORD k = REG_SZ;
DWORD nsize = sizeof(c_valuename);
DWORD ncbvari = sizeof(c_vari);
//k为输出值,代表读取的数值的数据类型。串口的类型为REG_SZ,此处不做特别判断
while(RegEnumValue(hkey, dinx++, c_valuename, &nsize, NULL, &k, (LPBYTE)c_vari, &ncbvari) != ERROR_NO_MORE_ITEMS)
{
CString strInfo;
strInfo.Format(_T("Port found: %s\n"), c_vari);
OutputDebugString(strInfo); //根据需要处理获得的结果
//每次执行RegEnumValue后nSize和ncbvari的值都会被改变,需要再次赋值,否则可能出错
nsize = sizeof(c_valuename);
ncbvari = sizeof(c_vari);
}
}
else if(ERROR_FILE_NOT_FOUND == retopen)
{
AddInformation(MB_ICONWARNING, _T("计算机上没有串口!"));
}
else
{
CString strError;
strError.Format(_T("打开注册表失败,错误号%d。程序将无串口可用!"), retopen);
AfxMessageBox(strError, MB_ICONWARNING);
}
RegCloseKey(hkey); //不再需要使用hkey时,应关闭它。
方法二:利用API函数SetupDiGetClassDevs,获得端口号和端口名称
1、将C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Lib(Setupapi.lib)和C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include(Setupapi.h) 直接复制到工程目录下面。(路径可能会有不同)
2、添加:
#include <setupapi.h>
#pragma comment(lib, "Setupapi.lib")
3、
//GUID_DEVCLASS_PORTS 端口(COM 和 LPT)的GUID值,查询注册表可以获得
//注册表中路径:HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class下
GUID ClassGuid = {0x4d36e978, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}};
HDEVINFO hDevInfo = SetupDiGetClassDevs(&ClassGuid,
NULL,
NULL,
DIGCF_PRESENT); //之返回当前存在的设备
if (hDevInfo)
{
int iy = 0;
SP_DEVINFO_DATA SpDevInfo = { sizeof(SP_DEVINFO_DATA) };
for (DWORD iDevIndex = 0; SetupDiEnumDeviceInfo(hDevInfo, iDevIndex, &SpDevInfo); iDevIndex++)
{
TCHAR szName[512] = { 0 };
if (SetupDiGetDeviceRegistryProperty(hDevInfo, &SpDevInfo, SPDRP_FRIENDLYNAME,
NULL, (PBYTE)szName, sizeof(szName), NULL))
{
CString com, str, strComOpen;
str.Format(_T("%s"), szName); //获取串口的名称,如ELTIMA Virtual Serial Port(COM1->COM2)
int posBeg = str.Find('(');
int posEnd = str.Find(')');
com = str.Mid(posBeg + 1, posEnd - posBeg - 1);//获取串口的名称COM3
}
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
扩展:
HDEVINFO
SetupDiGetClassDevs(
const GUID* ClassGuid,
PCTSTR Enumerator,
HWND hwndParent,
DWORD Flags
);
PGUID ClassGuid
在创建设备列表的时候提供一个指向GUID的指针。如果设定了标志(参数Flags的值)为DIGCF_ALLCLASSES,则这个参数可以忽略,且列表结果中包括所有已经安装的设备类别。
PCTSTR Enumerator
提供包含设备实例的枚举注册表分支下的键名,可以通过它获取设备信息。如果这个参数没有指定,则要从整个枚举树中获取所有设备实例的设备信息。
HWND hwndParent
提供顶级窗口的句柄,所有用户接口可以使用它来与成员联系。
DWORD Flags
提供在设备信息结构中使用的控制选项。可以是以下数值:
DIGCF_PRESENT——只返回当前存在的设备。
DIGCF_ALLCLASSES ——返回所有已安装的设备。如果这个标志设置了,ClassGuid参数将被忽略。
DIGCF_PROFILE —— 只返回当前硬件配置文件中的设备。
DIGCF_INTERFACEDEVICE —— 返回所有支持的设备。
DIGCF_DEFAULT ——只返回与系统默认设备相关的设备。