2013-07-02 39 views
0

我正在嘗試與使用CAN的設備進行通信。爲此,我使用C++使用PCAN Basic。如何訪問C++中的dll文件中的函數

不幸的是,我對dll文件(這是提供的)訪問函數一無所知。我發現這個鏈接:

Calling a dll function from C++

,我試圖通過代碼使用調用LoadLibrary我發現這裏:

http://www.goffconcepts.com/techarticles/development/cpp/calldll.html

我的代碼:

// dll_get_func.cpp : Defines the entry point for the console application. 
// 
#include "stdafx.h" 
#include <iostream> 
#include <stdio.h> 
#include <conio.h> 
#include <time.h> 
#include <stdlib.h> 
#include <math.h> /* For sqrt() */ 
#include <windows.h> 

#define DELCLDIR __declspec("Pcan_usb.dll") 
#define PCAN_USBBUS1 0x51 
#define CAN_BAUD_1M  0x0014 // 1 MBit/s 
#define MSGTYPE_STANDARD 0x00 

typedef struct { 
    DWORD ID;  // 11/29 bit identifier 
    BYTE MSGTYPE; // Bits from MSGTYPE_* 
    BYTE LEN;  // Data Length Code of the Msg (0..8) 
    BYTE DATA[8]; // Data 0 .. 7 
} TPCANMsg; 


int hardCodeInit(void) 
{ 
    /* get handle to dll */ 
    HINSTANCE hGetProcIDDLL = LoadLibrary(_T("Pcan_usb.dll")); 

    /* get pointer to the function in the dll*/ 
    FARPROC lpfnGetProcessID = GetProcAddress(HMODULE (hGetProcIDDLL),"CAN_Init"); 

    /* 
     Define the Function in the DLL for reuse. This is just prototyping the dll's function. 
     A mock of it. Use "stdcall" for maximum compatibility. 
    */ 
    typedef int (__stdcall * pICFUNC)(WORD wBTR0BTR1, int CANMsgType); 

    pICFUNC CAN_Init; 
    CAN_Init = pICFUNC(lpfnGetProcessID); 
    //DWORD __stdcall CAN_Init(WORD wBTR0BTR1, int CANMsgType); 

    /* The actual call to the function contained in the dll */ 
    int intMyReturnVal = CAN_Init(PCAN_USBBUS1,CAN_BAUD_1M); 

    /* Release the Dll */ 
    FreeLibrary(hGetProcIDDLL); 

    /* The return val from the dll */ 
    return intMyReturnVal; 
} 
int hardCodeWrite(void) 
{ 
    HINSTANCE hGetProcIDDLL = LoadLibrary(_T("Pcan_usb.dll")); 
    FARPROC lpfnGetProcessID = GetProcAddress(HMODULE (hGetProcIDDLL),"CAN_Write"); 
    typedef int (__stdcall * pICFUNC)(WORD wBTR0BTR1, TPCANMsg CANMsgType); 
    pICFUNC CAN_Write; 
    CAN_Write = pICFUNC(lpfnGetProcessID); 

    TPCANMsg msgOut; 
    msgOut.MSGTYPE = MSGTYPE_STANDARD; 
    msgOut.LEN = 1; 
    msgOut.DATA[0] = 0x03; // 0x03 = Get ID 

    int toReturn; 
    toReturn = CAN_Write(PCAN_USBBUS1,msgOut); 
    FreeLibrary(hGetProcIDDLL); 
    return toReturn; 
} 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    int derp=hardCodeInit(); 
    int herp=hardCodeWrite(); 
    std::cout<<derp; 
    std::cout<<herp; 
    _getch(); 
    return 0; 
} 

但是,Visual Studio中說:有一個:

Unhandled exception at 0x10001D95 (Pcan_usb.dll) in dll_get_func.exe: 0xC0000005: 
Access violation reading location 0x00000051. 

我有Pcan_usb.dll和Pcan_usb.lib在同一個文件夾中,我使用的Visual Studio 2012

+1

檢查'LoadLibrary'和'GetProcAddress'的返回值。如果他們失敗了'GetLastError'說什麼? –

+0

DLL是否帶有鏈接庫文件和頭文件?然後包含頭文件並鏈接到庫中,而不必自己加載DLL或擔心函數指針。 –

+0

@ JoachimPileborg-好點,我仔細看了看,有一個.h文件。我包含了.h文件。它現在給我'錯誤錯誤LNK2019:無法解析的外部符號_CAN_Init @ 8在函數中引用_wmain \t C:\ Users \ britter \ Documents \ Visual Studio 2012 \ Projects \ dll_get_func \ dll_get_func \ dll_get_func.obj \t dll_get_func'這是猜測是一個圖書館沒有得到解決。您提到的「鏈接庫」是我需要添加的一行代碼,或者需要在Visual Studio項目中配置的選項? (如果這是脫節主題,我應該提交一個新的問題/編輯嗎?) – code11

回答

1

這裏有幾點。 LoadLibrary的簽名:

HMODULE WINAPI LoadLibrary(_In_ LPCTSTR lpFileName); 

刪除不需要的強制轉換。這將簡化閱讀和理解你的代碼。

FARPROC lpfnGetProcessID - 變量的名稱令人困惑。這可能是混淆或誤解的根源。

關於AV - 當您嘗試使用它時,CAN_Init函數的簽名是錯誤的。從你的帖子中,很難確定應該是什麼。看看手冊(如果可能),頭文件等。

要點 - 你不應該釋放圖書館。在需要這種情況的情況很少見。很可能你的情況不需要這個。很難相信你需要在啓動它和寫入之間重新加載庫(這是發生在你調用FreeLibrary/LoadLibrary時發生的事情)。

+0

我同意這個名字很混亂。我會改變這一點。但是,你說我不應該釋放圖書館,你是指這一行:'FreeLibrary(hGetProcIDDLL);'或者不同的東西? – code11

+0

是的,刪除這一行。當進程終止時,庫將自動釋放。 –

1
Access violation reading location 0x00000051. 

這告訴我的治療PCAN_USBBUS1爲指針的函數。也許:

#define PCAN_USBBUS1 0x51 

應改爲

WORD pcan_usbbus1 = 0x51; 

並調用CAN_Init應改爲:

int intMyReturnVal = CAN_Init(&pcan_usbbus1, CAN_BAUD_1M); 

函數簽名也許應該是這樣的:

typedef int (__stdcall * pICFUNC)(WORD* wBTR0BTR1, int CANMsgType); 
            ^pointer here 

我想CAN_BAUD_1M可能也需要以相同的方式進行更改,但可能不會。

+0

這修復了特定的錯誤,但造成了另一個:'運行時檢查失敗#0 - ESP的值未正確保存在一個函數呼叫。這通常是調用一個調用約定的函數聲明的結果,其函數指針用不同的調用約定聲明。「我從來沒有遇到過這樣的錯誤,其原因看起來很不一樣。什麼是「調用約定」指的是? – code11

+1

該函數可能不是'__stdcall',而是'__cdecl',這意味着調用者清理堆棧。基本上,當函數返回時,指定'__stdcall'假定被調用者正在清理堆棧,但是如果沒有發生,你的堆棧就會被清理,並且你會得到這個錯誤。 '__cdecl'說你的程序負責清理堆棧。 –

相關問題