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

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

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

本文链接: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

 

 

 

 

算了还是贴代码吧。

 1 #include <windows.h>
 2 #include <vector>
 3 #include <string>
 4 
 5 std::vector<std::wstring> GetAllSerialPorts()
 6 {
 7     const int MAX_KEY_LENGTH=255;
 8     const int MAX_VALUE_NAME = 16383;
 9 
10     std::vector<std::wstring> vctTemp;
11 
12     HKEY hTestKey;
13 
14     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, KEY_READ, &hTestKey) != ERROR_SUCCESS)
15     {
16         return vctTemp;
17     }
18 
19     TCHAR    achClass[MAX_PATH] = TEXT("");  // buffer for class name 
20     DWORD    cchClassName = MAX_PATH;  // size of class string 
21     DWORD    cSubKeys = 0;               // number of subkeys 
22     DWORD    cbMaxSubKey;              // longest subkey size 
23     DWORD    cchMaxClass;              // longest class string 
24     DWORD    cValues;              // number of values for key 
25     DWORD    cchMaxValue;          // longest value name 
26     DWORD    cbMaxValueData;       // longest value data 
27     DWORD    cbSecurityDescriptor; // size of security descriptor 
28     FILETIME ftLastWriteTime;      // last write time 
29 
30     DWORD i, retCode;
31 
32     TCHAR  achValue[MAX_VALUE_NAME];
33     DWORD cchValue = MAX_VALUE_NAME;
34     BYTE byteData[MAX_VALUE_NAME];
35     DWORD dwData = MAX_VALUE_NAME;
36 
37     retCode = RegQueryInfoKey(
38         hTestKey,
39         achClass,
40         &cchClassName,
41         NULL,
42         &cSubKeys,
43         &cbMaxSubKey,
44         &cchMaxClass,
45         &cValues,
46         &cchMaxValue,
47         &cbMaxValueData,
48         &cbSecurityDescriptor,
49         &ftLastWriteTime);
50 
51     if (cValues)
52     {
53         for (i = 0, retCode = ERROR_SUCCESS; i < cValues; i++)
54         {
55             cchValue = MAX_VALUE_NAME;
56             achValue[0] = '\0';
57             dwData = MAX_VALUE_NAME;
58             byteData[0] = '\0';
59 
60             retCode = RegEnumValue(hTestKey, i,
61                 achValue,
62                 &cchValue,
63                 NULL,
64                 NULL,
65                 byteData,
66                 &dwData);
67 
68             if (retCode == ERROR_SUCCESS)
69             {
70                 std::wstring strCOM = (wchar_t*)byteData;
71                 vctTemp.push_back(strCOM);
72             }
73         }
74     }
75 
76     RegCloseKey(hTestKey);
77 
78     return vctTemp;
79 }
80 
81 int main()
82 {
83     auto a = GetAllSerialPorts();
84     return 0;
85 }