列出所有串口
通常需要从 Windows 获取所有串行端口信息,你可能希望为用户选择要打开的端口,或检查你的设备是否已连接。
此外,某些端口无法使用 COMx
字符串打开,需要使用设备名称打开。当端口号为 10 或更高时,某些旧版本的 Windows 无法打开名为 COMxx
的端口。因此,使用设备编号是识别 Windows 的 COM 端口的明智方法。
串口信息保存在注册表中的关键字 HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
下
C 中的此示例显示了如何列出所有串行端口以及如何获取用于调用 CreateFile 的设备名称。
方法很简单:
- 在
HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
打开注册表 - 枚举我们在那里找到的所有键。设备名称是键名称,显示名称是键值。
与 Windows 编程通常的情况一样,大部分工作都花在了错误检查上。这可能看起来有点傻,但没有安全的方法来避免它。
#define WIN32_LEAN_AND_MEAN // excludes stuff frokm windows.h that we won't need here.
#include <Windows.h>
#include <string.h>
#include <tchar.h>
#include <malloc.h>
void ShowErrorFromLStatus(LSTATUS lResult)
{
LPTSTR psz;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
lResult,
0,
(LPTSTR)&psz,
1024,
NULL);
_tprintf(_T("Windows reports error: (0x%08X): %s\n"), lResult, (psz) ? psz : _T("(null)"));
if (psz)
{
LocalFree(psz);
}
}
int main()
{
DWORD nValues, nMaxValueNameLen, nMaxValueLen;
HKEY hKey = NULL;
LPTSTR szDeviceName = NULL;
LPTSTR szFriendlyName = NULL;
DWORD dwType = 0;
DWORD nValueNameLen = 0;
DWORD nValueLen = 0;
DWORD dwIndex = 0;
LSTATUS lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_READ, &hKey);
if (ERROR_SUCCESS != lResult)
{
printf("Failed to open key \'HARDWARE\\DEVICEMAP\\SERIALCOMM\' \n");
ShowErrorFromLStatus(lResult);
return 1;
}
lResult = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
&nValues, &nMaxValueNameLen, &nMaxValueLen, NULL, NULL);
if (ERROR_SUCCESS != lResult)
{
_tprintf(_T("Failed to RegQueryInfoKey()\n"));
ShowErrorFromLStatus(lResult);
RegCloseKey(hKey);
return 2;
}
szDeviceName = (LPTSTR)malloc(nMaxValueNameLen + sizeof(TCHAR));
if (!szDeviceName)
{
_tprintf(_T("malloc() fail\n"));
RegCloseKey(hKey);
return 3;
}
szFriendlyName = (LPTSTR)malloc(nMaxValueLen + sizeof(TCHAR));
if (!szFriendlyName)
{
free(szDeviceName);
_tprintf(_T("malloc() fail\n"));
RegCloseKey(hKey);
return 3;
}
_tprintf(_T("Found %d serial device(s) registered with PnP and active or available at the moment.\n"), nValues);
for (DWORD dwIndex = 0; dwIndex < nValues; ++dwIndex)
{
dwType = 0;
nValueNameLen = nMaxValueNameLen + sizeof(TCHAR);
nValueLen = nMaxValueLen + sizeof(TCHAR);
lResult = RegEnumValueW(hKey, dwIndex,
szDeviceName, &nValueNameLen,
NULL, &dwType,
(LPBYTE)szFriendlyName, &nValueLen);
if (ERROR_SUCCESS != lResult || REG_SZ != dwType)
{
_tprintf(_T("SerialPortEnumerator::Init() : can't process registry value, index: %d\n"), dwIndex);
ShowErrorFromLStatus(lResult);
continue;
}
_tprintf(_T("Found port \'%s\': Device name for CreateFile(): \'\\.%s\'\n"), szFriendlyName, szDeviceName);
}
free(szDeviceName);
free(szFriendlyName);
RegCloseKey(hKey);
return 0;
}
我的笔记本上的程序输出:
Found 1 serial device(s) registered with PnP and active or available at the moment.
Found port 'COM23': Device name for CreateFile(): '\.\Device\BthModem0'