c++ - 在VS 2015中使用Microchip的mpusbapi.h会产生“LNK2005已定义”错误

标签 c++ dllimport visual-studio-2015 mpusbapi

我正在编写必须从mpusbapi.dll文件导入其某些功能的类。不幸的是,当我尝试在主文件中包含ActuatorControl.h时,出现了LNK2005已经定义的错误,

Error LNK2005
"unsigned long (__cdecl* MPUSBGetConfigurationDescriptor)(void *,unsigned char,void *,unsigned long,unsigned long *)" (?MPUSBGetConfigurationDescriptor@@3P6AKPAXE0KPAK@ZA) 
    already defined in ActuatorControl.obj
Linear Actuator 
C:\Users\Edward Harsono\Desktop\Linear Actuator\Linear Actuator\Linear Actuator.obj 
1


从mpusbapi.dll获得的其余功能也得到了相同的消息。我已经将mpusbapi.h和ActuatorControl.h的防护措施都包括在内了,这是我在Visual Studio 2015中编写的。

mpusbapi.h和mpusbapi.dll从Microchip Technology Incorporated获得。

可以帮助我吗?我已经呆了几个小时了。这是我的代码。

main.cpp

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <windows.h>

#include "ActuatorControl.h"

int main()
{   
    ActuatorControl x;    
    return 0;
}


执行器控件

#pragma once
#ifndef _ActuatorControl_H_
#define _ActuatorControl_H_

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <windows.h>
#include <Dbt.h>
#include <tchar.h>

#include "mpusbapi.h"

class ActuatorControl {
private:
    //----------------Global variables used in this application--------------------------------

public:
    ActuatorControl();
    ~ActuatorControl();
};

#endif


ActuatorControl.cpp

#include "ActuatorControl.h"

ActuatorControl::ActuatorControl() {
    HMODULE DLL = LoadLibrary(L"mpusbapi.dll");
    if (DLL) {
        MPUSBGetDLLVersion = (DWORD(*)(void)) GetProcAddress(DLL, "_MPUSBGetDLLVersion");

    }
}

ActuatorControl::~ActuatorControl() {

}

最佳答案

因此,我看了mpusbapi.h和示例应用程序(from here, MCHPFUSB 1.3)。

我假设您正在使用LoadLibrary在运行时动态加载函数,因为它们的二进制文件似乎是使用Borland的编译器构建的,因此存根LIB在VS中无法按原样工作(除非您拥有VS版本,或者只想manually generate it)。



简短的答案是:标头原样确实不适合包含在多个文件中。它可以在他们的简单示例应用程序中工作,但仅此而已,因此您必须自己动手。尽管有其“文档”的含义,但为了保持理智,您将想将mpusbapi.h视为一个示例,而不是通常有用的任何示例。



中等答案是:标头确实设计不佳。特别是,它定义了全局变量,因此包含它的每个源文件都将定义这些变量,从而也将导致您的错误。他们之所以无法使用它,是因为:他们使用Borland的工具构建了所有内容,可能包括其示例,并且与大多数其他编译器不同,多重定义只是Borland链接器的警告。因此他们可能会忽略警告,因为它仍然有效。现在,当您使用更精巧的链接器时,您就可以支付价格。 (而且该库非常老,我不记得VS在2004年或任何时候对多个定义做了什么,所以它过去也有可能接受它。)



长的答案/解决方案是:标头中的内容不是函数声明或typedef,它们是函数指针变量的实际定义(您需要使用GetProcAddress进行初始化)。您有很多选择,但是基本上,您只是想从头开始,使用当前标头中提供的功能签名作为指导。

首先,从示例应用程序中(我知道您知道这一点,但是为了普通读者的利益),这里是如何动态加载它们的方法。这也适用于一般情况:

void LoadDLL(void)
{
    libHandle = NULL;
    libHandle = LoadLibrary("mpusbapi");
    if(libHandle == NULL)
    {
        printf("Error loading mpusbapi.dll\r\n");
    }
    else
    {
        MPUSBGetDLLVersion=(DWORD(*)(void))\
                    GetProcAddress(libHandle,"_MPUSBGetDLLVersion");
        MPUSBGetDeviceCount=(DWORD(*)(PCHAR))\
                    GetProcAddress(libHandle,"_MPUSBGetDeviceCount");
        MPUSBOpen=(HANDLE(*)(DWORD,PCHAR,PCHAR,DWORD,DWORD))\
                    GetProcAddress(libHandle,"_MPUSBOpen");
        MPUSBWrite=(DWORD(*)(HANDLE,PVOID,DWORD,PDWORD,DWORD))\
                    GetProcAddress(libHandle,"_MPUSBWrite");
        MPUSBRead=(DWORD(*)(HANDLE,PVOID,DWORD,PDWORD,DWORD))\
                    GetProcAddress(libHandle,"_MPUSBRead");
        MPUSBReadInt=(DWORD(*)(HANDLE,PVOID,DWORD,PDWORD,DWORD))\
                    GetProcAddress(libHandle,"_MPUSBReadInt");
        MPUSBClose=(BOOL(*)(HANDLE))GetProcAddress(libHandle,"_MPUSBClose");

        if((MPUSBGetDeviceCount == NULL) || (MPUSBOpen == NULL) ||
            (MPUSBWrite == NULL) || (MPUSBRead == NULL) ||
            (MPUSBClose == NULL) || (MPUSBGetDLLVersion == NULL) ||
            (MPUSBReadInt == NULL))
            printf("GetProcAddress Error\r\n");
    }//end if else
}//end LoadDLL


请注意,查看该实现并将其与标头进行比较,它实际上并不会从DLL加载所有功能。它仅加载特定示例应用程序所需的那个。因此,不要忘了加载您使用的其余功能。

因此(再假设手动运行时链接,如果您有VS lib,则可以跳过所有步骤,链接到LIB,并包含_mpusbapi.h [请注意下划线],但不要包含mpusbapi.h)。

现在,就像我说的那样,有很多选择,但是它们都有相同的目标:


一次定义这些函数指针。
在标头中声明它们,以便您可以在其他地方使用它们(mpusbapi.h犯了在标头中定义它们的错误)。
程序启动时,如上述LoadLibrary实现中那样,在GetProcAddress / LoadDLL()中填充函数指针。


所以,只要您的船浮起就行。这是完成工作的一种快速而肮脏的方法:


创建一些源文件(也许与您放入LoadDLL()或等效文件的源文件相同),然后从当前mpusbapi.h中复制并粘贴所有这些函数指针定义。现在,将在这些来源中定义这些来源。
编辑mpusbapi.h并在每个定义之前添加extern,使其仅成为声明,例如:

extern DWORD (*MPUSBGetDeviceCount)(PCHAR pVID_PID);

现在,您可以在需要使用固定的mpusbapi.h的任何地方使用它们了。
在使用任何全局函数指针之前,请确保先调用LoadDLL()或使用LoadLibrary / GetProcAddress进行任何操作,以加载并初始化所有全局函数指针一次。


那应该做到的。如果您想以不同的方式组织代码,请将其全部包装在一个类中,可能使那些成员var并委派给他们,或者生成并使用LIB而不是手动加载所有函数等,那么就继续吧,只要当您完成常规步骤时,不要在多个源文件(或根本上没有)包含的标头中定义全局变量。

关于c++ - 在VS 2015中使用Microchip的mpusbapi.h会产生“LNK2005已定义”错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42405762/

相关文章:

c++ - 不要在发布时显示控制台窗口但在调试时显示

C++ lib 导入工作,除了两个构造函数

c# - 将 C 编写的 DLL 调用到 C# 时,vshost32-clr2.exe 出错

ubuntu - ubuntu 14.04 上的 dnx web 抛出 "System.Runtime.InteropServices.Marshal"异常 (1.0.0-beta8)

c++ - GCC和Clang中模板类如何继承子类

c++ - 以编程方式运行 WDS 镜像

c++ - 如何声明和初始化类中的静态成员?

C# - 在 C# 中的等效数据类型中编码(marshal) char **

c# - Visual Studio 2015、Xamarin 和目标设备

c# - 如何将/features :strict (of csc. exe 的等价物指定给 msbuild.exe 或 .csproj 文件?