2012-08-29 102 views
1

這已經在許多地方的部分討論過,但它仍然不適合我。在C++中使用delphi庫

我從Delphi源,其中出口下兩個名字一個函數編譯一個dll,檢查使用

>> dumpbin /EXPORTS MyLibrary.dll

我得到以下輸出的dll:

... 
17 3 00070A88 MyFunction 
... 
46 24 00070A88 [email protected] 
...

,所以我創建了一個文件稱爲MyLibrary.def,其內容如下:

EXPORTS 
MyFunction 
[email protected]

並生成一個導入庫使用

>> lib /def:MyLibrary.def /OUT:MyLibrary.lib /MACHINE:x86

檢查新的LIB文件與DUMPBIN我看到以下內容:

... 
_MyFunction 
... 
[email protected] 
... 

於是莫名其妙的lib應用程序函數名前面加一個下劃線。 (爲什麼?)

然後我嘗試在C++程序使用此功能,與Microsoft Visual Studio C++ 2010速成編譯(使用LIB文件):

// MyLibrary.h 
# define DllImport(Type) __declspec (dllimport) Type __stdcall 

extern "C" DllImport(void)MyFunction(...); 
// main.cpp 
#import "MyLibrary.h" 

... 
MyFunction(....); 
... 

現在,這應該工作,至於我能找到,但我得到下面的連接錯誤:

... error LNK2001: Unresolved external sympol "[email protected]". 

我不明白爲什麼這個出錯(我不明白真的整件事是如何工作的?),但我嘗試了兩種更多的東西。

  1. 改名我在MyLibrary.h功能和main.h從MyFunction的到_MyFunction
    • 結果:它的作品!但爲什麼?我不想依賴這個,因爲有些東西顯然是錯的。  
  2. 更名爲我的函數返回的MyFunction並刪除在DEF-文件下劃線,再次生成的lib文件,並試圖編譯
    • 結果:編譯成功,但在啓動程序時,我得到

MyApp - Entry Point Not Found 
--------------------------- 
The procedure entry point [email protected] could not be located 
in the dynamic link library MyLibrary.dll. 

我認爲一個人需要的lib工具和連接器的內部工作有了更深的瞭解,但我到目前爲止找不到任何有關這方面的信息。

回答

4

KB131313說明您將面臨試圖使用lib實用程序這一問題:

The only time you can use a .DEF file to create an import library from a .DLL for which you do not have the source code or object modules is if the .DLL exports functions via a C interface. Specifically, the functions need to have been declared to use the C calling convention.

你的函數使用STDCALL,沒有CDECL,因爲我們可以從函數名@告訴。儘管如此,KB文章解釋該怎麼做:

  1. 聲明功能,因爲這將是C++,但出口而不是爲進口

    你已經完成了,主要是。你有正確的調用約定,但最後的@48意味着它需要有48個字節的參數值。該函數將期望將該數據推送到堆棧,並且在返回之前,該函數將彈出那麼多。您在聲明中使用...與此不相符。

    如果你不知道具體的參數列表應該是什麼,那麼繼續,並定義12 int參數,所以至少堆棧結構是正確的。 (但是,如果你不知道列表應該是什麼,那麼你已經相當接近註定了。)

  2. 在C++中編寫一個虛擬實現。

    該實現可以爲空。唯一的要求是代碼編譯和鏈接。

  3. 從該虛擬代碼編譯您自己的MyLibrary.dll版本。

    確保它與原始DLL兼容。運行dumpbin並查看它是否至少導出了在原始DLL中看到的函數名稱的一個版本。 (你不需要;你的程序只打算使用其中一個名稱,並且如輸出所示,兩個名稱都位於二進制文件中的相同位置,因此,程序結束的名稱並不重要使用。)

  4. 扔掉DLL並保留LIB文件。

  5. 使用lib文件來鏈接真正的DLL。

如果鏈接器仍然抱怨它找不到[email protected],那麼從聲明中刪除dllimport部分。這應該刪除__imp_前綴,使名稱看起來更像Delphi名稱。


如果一切都失敗了,您可以使用運行時動態鏈接而不是加載時間。聲明函數的指針類型,然後使用LoadLibraryGetProcAddress來訪問它。

+0

+1這是非常好的。我們的產品附帶一個用Delphi編寫的DLL。我們的許多客戶都希望從C++中調用它,因此需要一個.lib文件。我們手動創建.h文件,然後使用perl腳本來執行本答案中描述的階段。這是做這件事的最好方式。 –

+0

我以爲這就是implib的意思,@David。 –

+0

這是一個Embarcadero工具(如果我們引用相同的東西),因此會生成Borland OMF格式的lib文件。我不相信它會生成所有其他編譯器供應商使用的COFF文件。還是近來有所改變?無論如何,如果你認爲implib是答案,爲什麼你沒有在你的答案中提到這一點? –