我想要一个函数来枚举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注释

  • #pragma comment (lib, "Setupapi.lib")
    
  • 转到“属性”>“配置属性”>“链接器”>“输入”>“其他依赖项”,然后添加Setupapi.lib库。

  • 也可以看看 :
    https://social.msdn.microsoft.com/Forums/vstudio/en-US/e14ce1a2-08b9-4291-b035-f72171bcbdbc/error-lnk2019-unresolved-external-symbol?forum=vclanguage

    09-25 18:28