问题解决——获得当前系统已有的串口号

==================================声明==================================

本文原创,转载请显要的注明作者和出处,并保证文章的完整性(包括本声明)。

本文不定期修改完善,为保证内容正确,建议移步原文处阅读。

本文链接:http://www.cnblogs.com/wlsandwho/p/4210481.html

=======================================================================

最近做的东西要用到串口,初始化界面的时候要列出一个可用的串口列表。

=======================================================================

最初我打算枚举设备,感觉好麻烦的样子。

网上好多都在说,i从1到N,挨个打开关闭一遍……这特么在逗我?

=======================================================================

思索了一下(虚词),打算从注册表入手,毕竟所有的设备都是要在注册表里注册的。

定下了方向,就准备资料了。

=======================================================================

1 串口在注册表里的位置:HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM。

2 所使用的主要函数:RegEnumValue,这个可以参见MSDN(http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=ZH-CN&k=k%28%22WINREG%2fREGENUMVALUE%22%29;k%28REGENUMVALUE%29;k%28DevLang-%22C%2B%2B%22%29;k%28TargetOS-WINDOWS%29&rd=true),刚好这个函数给出了示例代码(http://msdn.microsoft.com/en-us/library/ms724256%28v=vs.85%29.aspx)。

=======================================================================

下面是微软的代码。

// QueryKey - Enumerates the subkeys of key and its associated values.
//     hKey - Key whose subkeys and values are to be enumerated.

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

#define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383

void QueryKey(HKEY hKey)
{
    TCHAR    achKey[MAX_KEY_LENGTH];   // buffer for subkey name
    DWORD    cbName;                   // size of name string
    TCHAR    achClass[MAX_PATH] = TEXT("");  // buffer for class name
    DWORD    cchClassName = MAX_PATH;  // size of class string
    DWORD    cSubKeys=0;               // number of subkeys
    DWORD    cbMaxSubKey;              // longest subkey size
    DWORD    cchMaxClass;              // longest class string
    DWORD    cValues;              // number of values for key
    DWORD    cchMaxValue;          // longest value name
    DWORD    cbMaxValueData;       // longest value data
    DWORD    cbSecurityDescriptor; // size of security descriptor
    FILETIME ftLastWriteTime;      // last write time 

    DWORD i, retCode; 

    TCHAR  achValue[MAX_VALUE_NAME];
    DWORD cchValue = MAX_VALUE_NAME; 

    // Get the class name and the value count.
    retCode = RegQueryInfoKey(
        hKey,                    // key handle
        achClass,                // buffer for class name
        &cchClassName,           // size of class string
        NULL,                    // reserved
        &cSubKeys,               // number of subkeys
        &cbMaxSubKey,            // longest subkey size
        &cchMaxClass,            // longest class string
        &cValues,                // number of values for this key
        &cchMaxValue,            // longest value name
        &cbMaxValueData,         // longest value data
        &cbSecurityDescriptor,   // security descriptor
        &ftLastWriteTime);       // last write time 

    // Enumerate the subkeys, until RegEnumKeyEx fails.

    if (cSubKeys)
    {
        printf( "\nNumber of subkeys: %d\n", cSubKeys);

        for (i=0; i<cSubKeys; i++)
        {
            cbName = MAX_KEY_LENGTH;
            retCode = RegEnumKeyEx(hKey, i,
                     achKey,
                     &cbName,
                     NULL,
                     NULL,
                     NULL,
                     &ftLastWriteTime);
            if (retCode == ERROR_SUCCESS)
            {
                _tprintf(TEXT("(%d) %s\n"), i+1, achKey);
            }
        }
    } 

    // Enumerate the key values. 

    if (cValues)
    {
        printf( "\nNumber of values: %d\n", cValues);

        for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++)
        {
            cchValue = MAX_VALUE_NAME;
            achValue[0] = ‘\0‘;
            retCode = RegEnumValue(hKey, i,
                achValue,
                &cchValue,
                NULL,
                NULL,
                NULL,
                NULL);

            if (retCode == ERROR_SUCCESS )
            {
                _tprintf(TEXT("(%d) %s\n"), i+1, achValue);
            }
        }
    }
}

void __cdecl _tmain(void)
{
   HKEY hTestKey;

   if( RegOpenKeyEx( HKEY_CURRENT_USER,
        TEXT("SOFTWARE\\Microsoft"),
        0,
        KEY_READ,
        &hTestKey) == ERROR_SUCCESS
      )
   {
      QueryKey(hTestKey);
   }

   RegCloseKey(hTestKey);
}

运行了下,发现这代码是2个功能的,而我现在只需要第2个功能。

于是稍微改一下代码即可。

 1 void QueryKey(HKEY hKey)
 2 {
 3     TCHAR    achClass[MAX_PATH] = TEXT("");
 4     DWORD    cchClassName = MAX_PATH;
 5     DWORD    cSubKeys=0;
 6     DWORD    cbMaxSubKey;
 7     DWORD    cchMaxClass;
 8     DWORD    cValues;
 9     DWORD    cchMaxValue;
10     DWORD    cbMaxValueData;
11     DWORD    cbSecurityDescriptor;
12     FILETIME ftLastWriteTime;
13
14     DWORD i, retCode;
15
16     TCHAR  achValue[MAX_VALUE_NAME];
17     DWORD cchValue = MAX_VALUE_NAME;
18     BYTE byteData[MAX_VALUE_NAME];
19     DWORD dwData=MAX_VALUE_NAME;
20
21     retCode = RegQueryInfoKey(
22                             hKey,
23                             achClass,
24                             &cchClassName,
25                             NULL,
26                             &cSubKeys,
27                             &cbMaxSubKey,
28                             &cchMaxClass,
29                             &cValues,
30                             &cchMaxValue,
31                             &cbMaxValueData,
32                             &cbSecurityDescriptor,
33                             &ftLastWriteTime);
34
35     if (cValues)
36     {
37         for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++)
38         {
39             cchValue = MAX_VALUE_NAME;
40             achValue[0] = ‘\0‘;
41             dwData=MAX_VALUE_NAME;
42             byteData[0] = ‘\0‘;
43
44             retCode = RegEnumValue(hKey, i,
45                 achValue,
46                 &cchValue,
47                 NULL,
48                 NULL,
49                 byteData,
50                 &dwData);
51
52             if (retCode == ERROR_SUCCESS )
53             {
54                 CString strCOM= (wchar_t*)byteData;
55             }
56         }
57     }
58 }

第54行,我取得了想要的结果。

=======================================================================

为了以后方便使用,可以将其封装到类中,比方说CEnumSerialPortWLS。

我的CEnumSerialPortWLS中有一个set,这样,把

1  CString strCOM= (wchar_t*)byteData;

后面加上insert就行了。

===============================记吃不记打==================================

有一个值得注意的地方就是,RegEnumValue函数返回的byteData,是UNICODE的,所以可以直接强制转换使用。

这个地方我犯了一个错误,我从来都是使用TCHAR之类的宏,不使用wchar_t这些东西,所以对于得到的错误结果困惑了好一阵子,

以后要记住:

已明确的强制类型转换要使用明确的类型。

================================耻辱墙===================================

http://www.cnblogs.com/wlsandwho/p/4206472.html

时间: 2024-11-25 21:38:11

问题解决——获得当前系统已有的串口号的相关文章

Visual studio C++ MFC应用程序自动探测串口号

最近学习Visual studio C++的软件开发,做个串口工具,使用combo box下拉选项选择串口号,有两种方式,第一种自动添加串口号到工具代码中,比如常见的一些串口工具可以选择COM1~COM9的串口号,只需要在代码初始化的时候,加入串口号序列就可以,或者也可以在combo box属性菜单Data中添加“COM1;COM2;COM3;……COM9;”,此种办法在实际使用的时候,会比较麻烦,因为本来只有2个串口,却要在10来个序列中选择一个. 因此还有另外一种比较常见的处理方式,这种方式

runtime-给系统已有类添加属性

在没有接触runtime之前,我们接触到的能给类进行扩展的方法有类目(category)和延展(extension)两种.类目(category)可以给系统已有类添加扩展方法但是不能添加属性,并且被添加的方法可以被此类的子类所继承:延展(extension)为我们的自定义类添加属性和方法,但是添加的属性和方法都是私有的,在此类的子类中是无法访问的.那么问题来了,如果我们想给系统已有类添加一些方便我们使用的属性要怎么办呢?上述这两种方法中能给系统已有类添加的东西的就只有类目(category)了.

Oracle EBS-SQL (SYS-11):查询系统已打的PATCH.sql

select a.patch_name,         b.DRIVER_FILE_NAME,         c.language,         b.creation_datefrom apps.ad_applied_patches    a,        apps.ad_patch_drivers      b,        apps.ad_patch_driver_langs c where a.applied_patch_id = b.applied_patch_id     

I.MX6 修改调试串口号(ttymx0 -&gt; ttymxc2)(未验证)

I.MX6 修改调试串口号(ttymx0 -> ttymxc2)(未验证) 一.参考文章: uboot修改默认调试串口ttymxc0 ->ttymxc4(imx53) http://www.xuebuyuan.com/1494436.html 二.修改调试串口 和MCU通讯的串口是ttymxc0,目录调试使用的也是此串口,所在需改成别的串口ttymxc4 1)在uboot-imx/include/configs/目录下找到你项目中所用到的配置文件:mx53_skyz7_android.h(根据

AHK 获取系统已安装字体列表

AHK 调用API获取系统已安装字体列表代码: DllCall("gdi32\EnumFontFamilies","uint",DllCall("GetDC","uint",0),"uint",0,"uint",RegisterCallback("EnumFontFamilies"),"uint",a_FontList:="")

C# 获取 串口 设备名称 与 串口号 ManagementObjectSearcher类

1.效果图: 2.代码 class Program { static void Main(string[] args) { GetComList(); } private static void GetComList() {try { using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from Win32_PnPEntity")) { Console.WriteLine(&

获取系统串口号

原来C++Builder6在XP下获取串口的方法: void TTools::GetSystemPortList(TStringList * pList) {         TRegistry *regkey=new TRegistry();         pList->Clear();         regkey->RootKey=HKEY_LOCAL_MACHINE;         TStringList *KeyNames;         KeyNames=new TStrin

windows下如何获取系统已存在的盘符

在项目开发时,使用公司的SDK给系统分区,在windows2003的系统下分区后无法自动给新分区分配盘符,当然系统重启后可以分配盘符,但是我不希望它重启,所以我的想法是通过程序自动给新分区分配盘符.分配盘符准备使用diskpart命令中的assign letter方法,但是新盘符不能和已存在的盘符冲突, 那么问题来了,如何才能获取已存在的盘符,包括给CD/DVD .U盘等分配的盘符? #include <iostream>  #include <windows.h>     usi

Android中调用系统已安装的播放器来播放网络流媒体视频

实现思路比较简单几行代码就可以搞定,在界面放一个Button或者带有播放图标的imageview,点击事件中调用本地播放器来播放. Uri uri = Uri.parse("http://218.200.69.66:8302/upload/Media/20150327/43bfda1b-7280-469c-a83b-82fa311c79d7.m4v"); // 调用系统自带的播放器来播放流媒体视频 Intent intent = new Intent(Intent.ACTION_VIE