2017-02-23 60 views
0

我正在編寫必須從mpusbapi.dll文件中導入其某些函數的類。不幸的是,當我嘗試包括ActuatorControl.h在主文件中,我得到了LNK2005已經定義的錯誤,在VS 2015中使用Microchip的mpusbapi.h會產生「LNK2005已定義」錯誤

Error LNK2005 
"unsigned long (__cdecl* MPUSBGetConfigurationDescriptor)(void *,unsigned char,void *,unsigned long,unsigned long *)" ([email protected]@[email protected]) 
    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; 
} 

ActuatorControl.h

#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() { 

} 
+0

請編輯您的問題以提供[mcve]。 –

+1

我編輯了它,幷包含一個可驗證的例子。它可以被編譯,並會給你錯誤 –

+0

我在'ActuatorControl.h'看到一個問題一個標題不應該有'#包括「stdafx.h」' – drescherjm

回答

1

所以我看了看mpusbapi.h和示例應用程序(from here, MCHPFUSB 1.3)。

我打算假設您在運行時動態加載函數LoadLibrary,因爲它看起來它們的二進制文件是用Borland編譯器構建的,因此存根LIB將不會像VS中那樣工作(除非你有一個VS版本,或者只想manually generate it)。


簡短的回答是:現在的標題並不適合從多個文件中包含。它在他們簡單的示例應用程序中有所作爲,但這只是關於它,所以你必須推出自己的應用程序。儘管他們的「文件」的影響,爲了保持你的理智,你會想要查看mpusbapi.h作爲更多的示例比任何通常有用的。


中等答案是:頭部設計的確很差。特別是它定義了全局變量,因此每個包含它的源文件都會定義這些變量,從而導致錯誤。他們逃避的原因是:他們用Borland的工具構建了所有的東西,可能包括他們的例子,並且與大多數其他編譯器不同,多重定義只是Borland的鏈接器的警告。所以他們可能會忽略警告,因爲它仍然工作。現在,您在使用更理想的鏈接器時付出代價。 (另外,圖書館是很老了,我不記得VS做了關於多個定義早在2004年或每當所以它也有可能是它用來接受這一點)


長的答案/解決方案是:該頭文件中的內容不是函數聲明或類型定義,它們是函數指針變量的實際定義(您負責使用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使得在標題定義他們的錯誤)。
  • 當程序啓動時,與上述LoadDLL()實現一樣,使用LoadLibrary/GetProcAddress填充函數指針。

因此,盡一切可能漂浮你的船。這裏有一個快速和骯髒的十歲上下的方式來完成這項工作:

  1. 創建一些源文件(或許你把LoadDLL()或等值的相同)和複製+粘貼當前所有這些函數指針的定義mpusbapi.h。這個來源現在將定義這些全局變量。
  2. 編輯mpusbapi.h並在每個定義的前面加上extern,使其成爲僅僅是一個宣言,如:

    extern DWORD (*MPUSBGetDeviceCount)(PCHAR pVID_PID); 
    
  3. 您現在可以包括您的固定mpusbapi.h任何地方,你需要使用這些。

  4. 請確保並撥打LoadDLL()或任何與LoadLibrary/GetProcAddress加載並初始化所有全局函數指針,然後再使用它們中的任何一個。

而且應該這樣做。如果你想以不同的方式組織你的代碼,把它們全部包裝到一個類中,可能使這些成員變量和委託給它們,或者生成和使用LIB,而不是手動加載所有的函數等,直到前面,只要因爲您已完成一般步驟,並且不會在由多個源文件(或者根本不包括在內)中包含的標題中定義全局變量。

+1

感謝您的全面解答。我接受了你的建議,並沒有使用mpusbapi.h文件。我做了我自己的運行時連接與mpusbapi.dll,它的工作! –

+1

@EdwardH請注意,您可能希望經歷爲VS創建相應的LIB的過程,特別是如果您計劃在不同的程序中再次使用此API。它將爲您節省手動執行所有導入操作的麻煩(導入與DLL對應的LIB實際上只是爲您執行所有'LoadLibrary' /'GetProcAddress'的存根庫)。然後,您可以使用* _mpusbapi.h *並像往常一樣調用函數。唯一使用這種導入庫的方法是,如果DLL不存在,程序將無法啓動,而不能在運行時檢測到。 –