2015-10-27 64 views
0

我正在嘗試導出要調用的函數的函數指針。我所追求的是當一個DLL/EXE中的函數需要調用另一個庫導出的函數時,它將獲得函數指針並調用該函數。原因是我想提供一個掛鉤機制,我認爲函數指針是最快最簡單的方法,因爲我可以輕鬆地改變他們指向的是運行時。 所以我發現這個Exporting a function pointer from dll,我不能得到它的工作。每當我調用它來獲取函數指針,我都會得到一個錯誤,它無法找到入口點。所以錯誤並不是函數指針正在工作,而是函數指針的函數不起作用。我相信這是一個函數簽名問題。這裏有一個例子:dll導出函數指針(提供導出函數掛鉤的最佳方式)

Colors.h

#ifndef __COLORS 
#define __COLORS 

#ifdef MYDLL_EXPORTS 
/*Enabled as "export" while compiling the dll project*/ 
#define DLLEXPORT __declspec(dllexport) 
#else 
/*Enabled as "import" in the Client side for using already created dll file*/ 
#define DLLEXPORT __declspec(dllimport) 
#endif 

#include <string> 
#include <vector> 
class Colors 
{ 
private: 
    std::string myColor; 
    static DLLEXPORT std::vector<std::string> allColors; 
public: 
    Colors(){}; 
    Colors(std::string MyColor); 
    virtual DLLEXPORT std::string getMyColor(); 
    virtual DLLEXPORT void addToColors(std::string color); 
    std::vector<std::string> getAllColors(); 
}; 
typedef Colors* (*create)(std::string); 

DLLEXPORT create createColors(); 

Colors* createColors2(std::string color); 



#endif 

colors.cpp

#define MYDLL_EXPORTS 
#include "Color.h" 




std::vector<std::string> Colors::allColors; 

Colors::Colors(std::string MyColor) 
{ 
    this->myColor = MyColor; 
    this->allColors.push_back(this->myColor); 
} 

std::vector<std::string> Colors::getAllColors() 
{ 
    return this->allColors; 
} 

std::string Colors::getMyColor() 
{ 
    return this->myColor; 
} 

Colors* createColors2(std::string color) 
{ 
    return new Colors(color); 

} 

DLLEXPORT void Colors::addToColors(std::string color) 
{ 
    this->allColors.push_back(color); 
} 

DLLEXPORT create createColors() 
{ 
    return &createColors2; 
} 

的main.cpp

#define MYDLL_EXPORTS 

#include <iostream> 
#include <Windows.h> 
#include "Color.h" 



int main() 
{ 


    Colors red("red"); 
    Colors blue("blue"); 

    Colors* dlltest; 

    //Define the function prototype 
    typedef Colors* (*createNewColor)(); 

    BOOL freeResult, runTimeLinkSuccess = FALSE; 
    HINSTANCE dllHandle = NULL; 
    createNewColor dllCreateNewColor = NULL; 

    //Load the dll and keep the handle to it 
    dllHandle = LoadLibrary(L"libs/testerdll.dll"); 

    // If the handle is valid, try to get the function address. 
    if (NULL != dllHandle) 
    { 

     //Get pointer to our function using GetProcAddress: 
     dllCreateNewColor = (createNewColor)GetProcAddress(dllHandle,"createNewColor"); 

     // If the function address is valid, call the function. 
     if (runTimeLinkSuccess = (NULL != dllCreateNewColor)) 
     { 

      dlltest = dllCreateNewColor(); 
      std::cout << "Color of dll class: " << dlltest->getMyColor() << std::endl; 
     } 
     else 
     { 
      std::cout << "Failed to locate function" << std::endl; 
     } 

      //Free the library: 
      //freeResult = FreeLibrary(dllHandle); 
    } 
    else 
    { 
     std::cout << "Failed to load library" << std::endl; 
    } 

    std::vector<std::string> colorslist = red.getAllColors(); 
    for (std::string color : colorslist) 
    { 
     std::cout << color << std::endl; 
    } 
    return 0; 
} 

DLL項目 dllmain.cpp

// testerdll.cpp : Defines the exported functions for the DLL application. 


#include "stdafx.h" 


#include "Color.h" 



__declspec(dllexport) Colors* createNewColor() 
{ 
    create temp1 = createColors(); //seems to fail here 

    return nullptr; 
} 

是的我知道我有內存泄漏等,這只是一個簡單的示例代碼來複制問題。

+0

沒有必要使用'DLLEXPORT'虛擬功能 - 它們已經通過vtable中的函數指針找到:) –

+0

不使用'class DLLEXPORT Colors'請求麻煩。 –

+0

本和Dieter你能提供例子嗎?我試圖學習的DLL文件 – lesyriad

回答

0

要返回此功能,您需要獲取其地址,並返回該地址,並返回該地址,並返回該地址。

__declspec(dllexport) create createNewColor() 
{ 
    create temp1 = createColors; 

    return temp1; 
} 

然而,該系統(使用的std :: string作爲返回類型,需要的是,.exe和.dll文件使用相同的DLL基於運行時庫。

stackoverflow : passing reference to STL over function boundary

C++沒有定義文件之間的調用約定,這意味着不同的編譯器可能會略微不同地設置C++對象,Microsoft限制了COM的定義,但這仍然是可能的。在運行時間實例之間是單獨的堆(new/delete)。在鏈接到動態庫時,進程中的所有dll和exes共享此DLL。但是,他們都需要一起更新。

所以這個過程可以工作,但要警惕: -

  1. 共享C++二進制之間的類型(DLL/EXE) - 無ABI
  2. 在DLL使用新的,並在EXE刪除。 (不同的堆)。

STL對象也是有問題的,因爲它們是頭部實現(編譯成二進制)和DLL實現(編譯到C++運行時)的混合。

+0

好吧,謝謝它的工作。有沒有更好的方法來實現一個掛鉤api的函數?整個程序需要加載dll/plugins,如果其中一個需要在主exe文件上掛接一個特定的函數,以便將來來自其他插件的調用在它內部執行一個函數(hooked函數)是否有一個合適的方法去做?我只是認爲這將是通過函數指針的最佳方式。 – lesyriad