1.用注册表
HKEY hKEY;
LPCTSTR data_Set="HARDWARE\\DEVICEMAP\\SERIALCOMM";
long i;
int j=0;
SFC_BYTE Data_Get[10]={0};
TCHAR szValueName[255];
DWORD dwValueName = sizeof(szValueName);
LPDWORD lpType = 0;
DWORD cbData = 255;
SFC_INT Port_Num=0;
SFC_BYTE strPort[20][5]={0};
{
return -1;
}
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,data_Set, 0, KEY_READ, &hKEY)) //打开注册表
for (i=0;i<20;i++) // 缺点:必须要有确定的i值
{
memset(Data_Get,0,10);
(RegEnumValue(hKEY,i,szValueName,&dwValueName,NULL,lpType,Data_Get,&cbData));
if (Data_Get[0]!=0)
{
memcpy(strPort[j],Data_Get,sizeof(Data_Get));
Port_Num += 1;
j++;
}
}
RegCloseKey(hKEY); //关闭注册表
如果用户在装某些软硬件时在注册表中注册了虚拟串口之类的,用此法枚举得到的该类串口实际上是不能当串口用的。并且此法基本上不可能枚举出来虚拟的串口。
2.使用 EnumPort 方法
//枚举端口
long i;
int j=0;
SFC_INT Port_Num=0;
SFC_BYTE strPort[20][5]={0};
LPBYTE pBite = NULL;
DWORD pcbNeeded = 0; // bytes received or required
DWORD pcReturned = 0; // number of ports received
PORT_INFO_2 *pPort;
// 获取端口信息,能得到端口信息的大小 pcbNeeded
EnumPorts(NULL, 2, pBite, 0, &pcbNeeded, &pcReturned);
pBite =(BYTE *)malloc(pcbNeeded);
// 枚举端口,能得到端口的具体信息 pBite 以及端口的的个数 pcReturned
EnumPorts(NULL, 2, pBite, pcbNeeded, &pcbNeeded, &pcReturned);
pPort = (PORT_INFO_2*)pBite;
for ( i = 0; i < pcReturned; i++)
{
if (strstr(pPort[i].pPortName,"COM"))
{
memcpy(strPort[j],pPort[i].pPortName,sizeof(pPort[i].pPortName));
Port_Num++;
j++;
}
}
以上方法除了串口,还可以枚举所有的并口和打印机等接口,并且耗时较短,而且能找到虚拟串口(这些串口有些未使用时,在注册表和硬件设备管理器中是不能取得的)。
但是使用这种方法有一个问题,就是不能实时更新枚举的端口。例如,我现在有一个 COM5 通过Enumport 函数可以枚举出来,然后我将该COM口改为从来没有用过的COM7,再枚举的话就不会枚举到COM7,依然只会枚举到COM5,必须重新启动计算机后,再来枚举的话,才会枚举到COM7。 所以这种方法并不适用于需要经常修改COM口的设备程序使用。
3.使用最笨的一个一个打开的办法
int m_nSerialPortNum;// 串口计数
CString strSerialList[56]; // 临时定义 256 个字符串组
CString m_nSerialPortNo[56];
m_nSerialPortNum=0;// 串口计数
CString temp;
HANDLE hCom;
for (int i=1;i<=32;i++)
{
if (i<10)
{
temp.Format(_T("COM%d"),i);
hCom = CreateFile(temp, 0, 0, 0,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if(INVALID_HANDLE_VALUE == hCom )
continue;
strSerialList[m_nSerialPortNum] = temp;
m_nSerialPortNo[m_nSerialPortNum]=temp.Right(temp.GetLength()-3);
m_nSerialPortNum++;
CloseHandle(hCom);
}
if (i>=10)
{
temp.Format(_T("\\\\.\\COM%d"),i);
hCom = CreateFile(temp, 0, 0, 0,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if(INVALID_HANDLE_VALUE == hCom )
continue;
strSerialList[m_nSerialPortNum] = temp.Right(temp.GetLength()-4);
m_nSerialPortNo[m_nSerialPortNum]=temp.Right(temp.GetLength()-7);
m_nSerialPortNum++;
CloseHandle(hCom);
}
}
for (int i=0;i<m_nSerialPortNum;i++)
{
m_serialportnumtp.AddString(LPCTSTR(strSerialList[i]));
}
这个笨办法虽然耗时,但是相当的可靠,只要是设备管理器能显示出来的基本都可以找到,就算你虚拟出来很多虚拟的串口,设备管理器里显示不出来,它照样可以找到。 不过缺点也很明显,循环的话必须要有固定的值,你必须确定COM口的数量,所以动态扩展性较差。
4 、使用 SetupAPI 函数集的方法
此种方法是最简单并且有效的方法,之所以简单是因为已经有人将复杂的代码封装起来了,我只需像傻子一样调用就可以完成工作了,具体的说明请看
http://www.codeguru.com/Cpp/W-P/system/hardwareinformation/article.php/c5721/ ,下面给出本人调用该方法的例子代码:
int m_nSerialPortNum(0);// 串口计数
CString strSerialList[256]; // 临时定义 256 个字符串组
CArray<SSerInfo,SSerInfo&> asi;
EnumSerialPorts(asi,TRUE);// 参数为 TRUE 时枚举当前可以打开的串口,
// 否则枚举所有串口
m_nSerialPortNum = asi.GetSize();
for (int i=0; i<asi.GetSize(); i++)
{
CString str = asi[i].strFrien dlyName;
}
补充说明一下,使用该方法只要在你的程序中,添加“ EnumSerial.cpp ”和“ EnumSerial.h ”两个文件,并且将 Setupapi.lib 包含进你的工程文件中就行了,该方法时间上来说可能和第三种方法差不多,但该方法获取的串口完完全全就是硬件设备管理器中的串口。