windows - SetupAPI(setupdi 函数)不链接

标签 windows visual-c++ linker serial-port setupapi

我想要一个函数来枚举 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);
            }
        }
    }

此代码编译失败,但如果我尝试像这样使用它

#include "SerialConnection.h"
int main()
{
    SerialConnection::enumerateSerialPorts(false);
    auto cl = SerialConnection::getPortList();
    return 0;
}

错误 LNK2019:未解析的外部符号 __imp__SetupDiDestroyDeviceInfoList@4 在函数 __catch$?enumerateSerialPorts@SerialConnection@@SAX_N@Z$0 中引用

错误 LNK2019:未解析的外部符号 __imp__SetupDiEnumDeviceInterfaces@20 在函数“public: static void __cdecl SerialConnection::enumerateSerialPorts(bool)” (?enumerateSerialPorts@SerialConnection@@SAX_N@Z) 中引用

错误 LNK2019:未解析的外部符号 __imp__SetupDiGetDeviceInterfaceDetailW@24 在函数“public: static void __cdecl SerialConnection::enumerateSerialPorts(bool)” (?enumerateSerialPorts@SerialConnection@@SAX_N@Z) 中引用

错误 LNK2019:未解析的外部符号 __imp__SetupDiGetClassDevsW@16 在函数“public: static void __cdecl SerialConnection::enumerateSerialPorts(bool)” (?enumerateSerialPorts@SerialConnection@@SAX_N@Z) 中引用

错误 LNK2019:未解析的外部符号 __imp__SetupDiGetDeviceRegistryPropertyW@28 在函数“public: static void __cdecl SerialConnection::enumerateSerialPorts(bool)” (?enumerateSerialPorts@SerialConnection@@SAX_N@Z) 中引用

我错过了什么?我使用 MVS 2013

最佳答案

您必须将您的项目与 Setupapi.lib 链接起来。您可以通过两种方式做到这一点:

  1. 使用#pragma 注释
#pragma comment (lib, "Setupapi.lib")
  1. 转到“属性”>“配置属性”>“链接器”>“输入”>“附加依赖项”并添加 Setupapi.lib 库。

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

关于windows - SetupAPI(setupdi 函数)不链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33640791/

相关文章:

c++ - 从 MFC 中的配置文件加载字符串

c++ - 与静态 c 运行时链接时内存分配/解除分配的问题

c++ - 将文件从另一个 .vcproj 链接/包含到现有 .vcproj

linux - 为什么ldconfig能够找到一个库,但是找不到Rust?

c++ - 最终链接失败 : Invalid argument when including windows. h

windows - 在 Windows 8 中创建新文件的 AutoHotKey 快捷方式

C++ Opengl,Win内存泄漏

windows - _CrtCheckMemory 使用示例

windows - OpenGL 无法在 Windows 8 上呈现

c++ - 如何解决 Visual C++ 200 5's "修饰名称长度超出,名称被截断“警告?