我想要一个函数来枚举Windows上的串行(COM)端口。为此,我主要从http://www.codeguru.com/cpp/w-p/system/hardwareinformation/article.php/c5721/Determining-What-Serial-Ports-Are-Available-on-a-Windows-Machine.htm复制了代码
在头文件中:
#include "SerialPort.h"
#include <list>
#include <objbase.h>
#include <initguid.h>
#include <Setupapi.h>
typedef std::list<SerialPort> PortList;
class SerialConnection
{
private:
static PortList availible_ports;
public:
static void enumerateSerialPorts(bool);
static const PortList& getPortList(){ return availible_ports; }
}
执行:
void SerialConnection::enumerateSerialPorts(bool check)
{
availible_ports.clear();
CString strErr;
// Create a device information set that will be the container for
// the device interfaces.
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;
}
// Enumerate the serial ports
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];
// This is required, according to the documentation. Yes,
// it's weird.
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) {
// Got a device. Get the details.
SP_DEVINFO_DATA devdata = { sizeof(SP_DEVINFO_DATA) };
bOk = SetupDiGetDeviceInterfaceDetail(hDevInfo,
&ifcData, pDetData, dwDetDataSize, NULL, &devdata);
if (bOk) {
CString strDevPath(pDetData->DevicePath);
// Got a path to the device. Try to get some more info.
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))
{
// Just check the first three characters to determine
// if the port is connected to the USB bus. This isn't
// an infallible method; it would be better to use the
// BUS GUID. Currently, Windows doesn't let you query
// that though (SPDRP_BUSTYPEGUID seems to exist in
// documentation only).
// bUsbDevice = (strncmp(locinfo, "USB", 3) == 0);
}
if (bSuccess) {
// Add an entry to the array
SerialPort sp;
sp.full_path = strDevPath;
sp.port_name = fname;
sp.full_name = desc;
availible_ports.push_back(sp);
}
}
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;
if (check)
{
for (auto it = availible_ports.begin(); it != availible_ports.end(); it++)
{
HANDLE hCom = CreateFile(it->full_path,
GENERIC_READ | GENERIC_WRITE,
0, /* comm devices must be opened w/exclusive-access */
NULL, /* no security attrs */
OPEN_EXISTING, /* comm devices must use OPEN_EXISTING */
0, /* not overlapped I/O */
NULL /* hTemplate must be NULL for comm devices */
);
if (hCom == INVALID_HANDLE_VALUE) {
// It can't be opened; remove it.
auto erase_it = it;
it++;
availible_ports.erase(erase_it);
}
else {
// It can be opened! Close it and add it to the list
::CloseHandle(hCom);
}
}
}
此代码可编译filne,但如果我尝试像
#include "SerialConnection.h"
int main()
{
SerialConnection::enumerateSerialPorts(false);
auto cl = SerialConnection::getPortList();
return 0;
}
错误LNK2019:函数__catch $中引用了未解析的外部符号__imp__SetupDiDestroyDeviceInfoList @ 4?enumerateSerialPorts @ SerialConnection @@ SAX_N @ Z $ 0
错误LNK2019:在函数“public:static void __cdecl SerialConnection::enumerateSerialPorts(bool)”中引用的未解析的外部符号__imp__SetupDiEnumDeviceInterfaces @ 20(?enumerateSerialPorts @ SerialConnection @@ SAX_N @ Z)
错误LNK2019:未解析的外部符号__imp__SetupDiGetDeviceInterfaceDetailW @ 24在函数“公共(public):静态void __cdecl SerialConnection::enumerateSerialPorts(bool)”中引用(?enumerateSerialPorts @ SerialConnection @@ SAX_N @ Z)
错误LNK2019:在函数“公共(public):静态void __cdecl SerialConnection::enumerateSerialPorts(bool)”中引用的未解析的外部符号__imp__SetupDiGetClassDevsW @ 16(?enumerateSerialPorts @ SerialConnection @@ SAX_N @ Z)
错误LNK2019:在函数“public:static void __cdecl SerialConnection::enumerateSerialPorts(bool)”中引用的未解析的外部符号__imp__SetupDiGetDeviceRegistryPropertyW @ 28(?enumerateSerialPorts @ SerialConnection @@ SAX_N @ Z)
我错过了什么?我使用MVS 2013
最佳答案
您必须将您的项目与Setupapi.lib链接。您可以通过2种方式做到这一点:
#pragma comment (lib, "Setupapi.lib")
也可以看看 :
https://social.msdn.microsoft.com/Forums/vstudio/en-US/e14ce1a2-08b9-4291-b035-f72171bcbdbc/error-lnk2019-unresolved-external-symbol?forum=vclanguage