通过MFC实现:
要调用Setupapi的接口,所以
属性-》输入-》附件依赖项:添加Setupapi.lib就可以了。
#include <afxtempl.h>
// Struct used when enumerating the available serial ports
// Holds information about an individual serial port.
struct SSerInfo {
SSerInfo() : bUsbDevice(FALSE) {}
CString strDevPath; // Device path for use with CreateFile()
CString strPortName; // Simple name (i.e. COM1)
CString strFriendlyName; // Full name to be displayed to a user
BOOL bUsbDevice; // Provided through a USB connection?
CString strPortDesc; // friendly name without the COMx
};
// Routine for enumerating the available serial ports. Throws a CString on
// failure, describing the error that occurred. If bIgnoreBusyPorts is TRUE,
// ports that can't be opened for read/write access are not included.
void EnumSerialPorts(CArray<SSerInfo,SSerInfo&> &asi, BOOL bIgnoreBusyPorts=TRUE);
.cpp文件实现:
// For MFC
#include "EnumSerial.h"
#include <setupapi.h>
#include <initguid.h>
// The following define is from ntddser.h in the DDK. It is also
// needed for serial port enumeration.
#ifndef GUID_CLASS_COMPORT
DEFINE_GUID(GUID_CLASS_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c, 0xe4, \
0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73);
#endif
void EnumSerialPorts(CArray<SSerInfo,SSerInfo&> &asi, BOOL bIgnoreBusyPorts)
{
asi.RemoveAll();
CString strErr;
GUID* guidDev = (GUID*)&GUID_CLASS_COMPORT;
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
SP_DEVICE_INTERFACE_DETAIL_DATA* pDetData = NULL;
try {
hDevInfo = SetupDiGetClassDevs(guidDev,
NULL,
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
strErr.Format(_T("SetupDiGetClassDevs failed.(err=%lx)"), GetLastError());
throw strErr;
}
BOOL bOk = TRUE;
SP_DEVICE_INTERFACE_DATA ifcData;
DWORD dwDetDataSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + 256;
pDetData = (SP_DEVICE_INTERFACE_DETAIL_DATA*)new char[dwDetDataSize];
memset(pDetData, 0, dwDetDataSize);
ifcData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
pDetData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
for (DWORD ii = 0; bOk; ii++)
{
bOk = SetupDiEnumDeviceInterfaces(hDevInfo,
NULL,
guidDev,
ii,
&ifcData);
if (bOk)
{
SP_DEVINFO_DATA devdata = { sizeof(SP_DEVINFO_DATA) };
bOk = SetupDiGetDeviceInterfaceDetail(hDevInfo,
&ifcData,
pDetData,
dwDetDataSize,
NULL,
&devdata);
if (bOk)
{
CString strDevPath(pDetData->DevicePath);
TCHAR fname[256];
TCHAR desc[256];
BOOL bSuccess = SetupDiGetDeviceRegistryProperty(hDevInfo,
&devdata,
SPDRP_FRIENDLYNAME,
NULL,
(PBYTE)fname,
sizeof(fname),
NULL);
bSuccess = bSuccess && SetupDiGetDeviceRegistryProperty(hDevInfo,
&devdata,
SPDRP_DEVICEDESC,
NULL,
(PBYTE)desc,
sizeof(desc),
NULL);
BOOL bUsbDevice = FALSE;
TCHAR locinfo[256];
if (SetupDiGetDeviceRegistryProperty(hDevInfo,
&devdata,
SPDRP_LOCATION_INFORMATION,
NULL,
(PBYTE)locinfo,
sizeof(locinfo),
NULL))
{
CString tmpstr;
tmpstr.Format(_T("%s"), locinfo);
bUsbDevice = (lstrcmpW(tmpstr.Left(3), _T("USB")) == 0);
}
if (bSuccess)
{
SSerInfo si;
si.strDevPath = strDevPath;
si.strFriendlyName = fname;
si.strPortDesc = desc;
si.bUsbDevice = bUsbDevice;
asi.Add(si);
}
}
else
{
strErr.Format(_T("SetupDiGetDeviceInterfaceDetail failed.(err=%lx)"),
GetLastError());
throw strErr;
}
}
else
{
DWORD err = GetLastError();
if (err != ERROR_NO_MORE_ITEMS)
{
strErr.Format(_T("SetupDiEnumDeviceInterfaces failed.(err=%lx)"), err);
throw strErr;
}
}
}
}
catch (CString strCatchErr)
{
strErr = strCatchErr;
}
if (pDetData != NULL)
{
delete[] (char*)pDetData;
}
if (hDevInfo != INVALID_HANDLE_VALUE)
{
SetupDiDestroyDeviceInfoList(hDevInfo);
}
if (!strErr.IsEmpty())
throw strErr;
for (int ii = 0; ii < asi.GetSize(); ii++)
{
SSerInfo& rsi = asi[ii];
if (bIgnoreBusyPorts)
{
HANDLE hCom = NULL;
hCom = CreateFile(rsi.strDevPath,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hCom == INVALID_HANDLE_VALUE)
{
asi.RemoveAt(ii);
ii--;
continue;
}
else
{
::CloseHandle(hCom);
}
}
if (rsi.strFriendlyName.IsEmpty())
{
rsi.strFriendlyName = rsi.strPortName;
}
// If there is no description, try to make one up from
// the friendly name.
if (rsi.strPortDesc.IsEmpty())
{
// If the port name is of the form "ACME Port (COM3)"
// then strip off the " (COM3)"
rsi.strPortDesc = rsi.strFriendlyName;
int startdex = rsi.strPortDesc.Find(_T("("));
int enddex = rsi.strPortDesc.Find(_T(")"));
if (startdex > 0 && enddex == (rsi.strPortDesc.GetLength() - 1))
{
rsi.strPortDesc = rsi.strPortDesc.Left(startdex);
}
}
}
}
最后按钮实现调用:
void CMFCSerialSearchDlg::OnBnClickedEnumerateButton1()
{
// TODO: 在此添加控件通知处理程序代码
CArray<SSerInfo, SSerInfo&> asi;
// Populate the list of serial ports.
EnumSerialPorts(asi, FALSE/*include all*/);
m_listPorts.ResetContent();
for (int ii = 0; ii < asi.GetSize(); ii++) {
/*if(lstrcmpW(asi[ii].strFriendlyName.Left(3), _T("USB")) == 0)*/
m_listPorts.AddString(asi[ii].strFriendlyName);
}
}