==================================声明==================================
本文原创,转载请显要的注明作者和出处,并保证文章的完整性(包括本声明)。
本文不定期修改完善,为保证内容正确,建议移步原文处阅读。
本文链接: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 }