c++builder調用VC的dll以及VC調用c++builder的dll

來源:互聯網
上載者:User

解析__cdecl,__fastcall, __stdcall 的不同:
在函數調用過程中,會使用堆棧,這三個表示不同的堆棧調用方式和釋放方式。
比如說__cdecl,它是標準的c方法的堆棧調用方式,就是在函數調用時的參數壓入堆棧是與函數的聲明順序相反的,其它兩個可以看MSDN,不過這個對我們編程沒有太大的作用
---------------------------------------------------------------
呼叫慣例
呼叫慣例(Calling convention)決定以下內容:函數參數的壓棧順序,由調用者還是被調用者把參數彈出棧,以及產生函數修飾名的方法。MFC支援以下呼叫慣例:
_cdecl
按從右至左的順序壓參數入棧,由調用者把參數彈出棧。對於"C"函數或者變數,修飾名是在函數名前加底線。對於"C++"函數,有所不同。
如函數void test(void)的修飾名是_test;對於不屬於一個類的"C++"全域函數,修飾名是_test@@ZAXXZ(怎麼感覺像亂碼??)。
這是MFC預設呼叫慣例。由於是調用者負責把參數彈出棧,所以可以給函數定義個數不定的參數,如printf函數。
_stdcall
按從右至左的順序壓參數入棧,由被調用者把參數彈出棧。對於"C"函數或者變數,修飾名以底線為首碼,然後是函數名,然後是符號"@"及參數的位元組數,如函數int func(int a, double b)的修飾名是_func@12。對於"C++"函數,則有所不同。所有的Win32 API函數都遵循該約定。
_fastcall
頭兩個DWORD類型或者占更少位元組的參數被放入ECX和EDX寄存器,其他剩下的參數按從右至左的順序壓入棧。由被調用者把參數彈出棧,對於"C"函數或者變數,修飾名以"@"為首碼,然後是函數名,接著是符號"@"及參數的位元組數,如函數int func(int a, double b)的修飾名是@func@12。對於"C++"函數,有所不同。
未來的編譯器可能使用不同的寄存器來存放參數。

Dll中用 __declspec(dllexport)聲明的函數:
__declspec(dllexport)只是表示這個函數是一個DLL匯出函數,而__stdcall是一種函數呼叫慣例,兩者應該是沒有衝突的.   
如:__declspec(dllexport)  void  __stdcall  aTry();

c++builder和vc描述符定義的區別
在c++builder中
        __cdecl的函數輸出前會帶:"_"
        __stdcall無特徵,只輸出函數名
        __fastcall函數輸出前帶:"@"
        都無"@nn"尾碼格式!
在vc中
        __cdecl無特徵,只輸出函數名
        __stdcall的函數輸出前會帶:"_"尾碼帶:"@nn"
        __fastcall函數輸出前帶:"@"尾碼帶:"@nn

c++builder調用VC的dll:
在VC中編寫DLL時,使用了.def檔案,在出口函式宣告時也在前面加上了__declspec(dllexport)說明。把VC產生的DLL檔案放在了目前的目錄下,使用BCB的命令列工具implib產生的.lib檔案,具體格式為implib bcb.lib vc.dll,再把implib根據dll產生的LIB檔案加入到工程中,再在工程中加入DLL出口函數的聲明(函數名前加上了WINAPI,即__stdcall;每個函數定義的最前面也加上了__declspec(dllimport))。
而且由於BCB和VC++成立函數名轉換的做法不同。所以在VC中最好是輸出函數為C函數的DLL,如果輸出函數是C++類,則可能無法調用。
我的解決辦法(經過本人實驗證明的,共2種)
方法1:VC編譯c檔案產生dll時匯出函數標頭檔加上extern "C"{}關鍵字,函式宣告和定義處再加呼叫慣例描述符__cdecl,然後將函式宣告和定義處都加上一個底線就沒有問題了。
EXAMPLE:
假設我VC的dll中包含int myFunction(void),.c檔案中函數實現處的正確寫法是:
__declspec(dllexport) int __cdecl _myFunction(void)
{
        // add your code here
}
.h檔案中函式宣告處的正確寫法如下
__declspec(dllexport) int __cdecl _myFunction(void);
BCB調用時只要包含lib檔案,具體操作步驟:
運行implib bcb.lib vc.dll
project->add to...下拉框中選擇.lib類型,開啟剛才通過implib和vc的dll產生的lib檔案
在工程中用到dll的.c源檔案中包含該dll的標頭檔
調用時直接寫 int i = myFunction(); 即可。

方法2:僅對VC編譯C檔案產生dll時有效,匯出函數標頭檔加上extern "C"{}關鍵字。BCB的Project->option->advanced compiler下的Calling convention中選擇Stdcall就可以直接調用VC的.c檔案編譯產生的動態連結程式庫了。

VC調用c++builder的dll: (參考:MSDN2000)
VC中無LIB時的DLL隱式連結,製作與VC++相符合的LIB函數符號輸入庫(轉)請大家注意!這種方法只能應用於輸出為C格式的__stdcall調用方式!
1.使用VC++的工具DUMPBIN將DLL中的匯出函數表匯出到一定義(.DEF)檔案
EXAMPLE:
DUMPBIN VideoDeCoder.dll /EXPORTS /OUT:VideoDeCoder.def
2.將匯出的.DEF檔案整理為一符合.DEF個數的函數匯出檔案(整理過程巨亂巨複雜,懶得舉例了,後面有簡便方法^_^)
3.使用VC++的LIB工具,帶/DEF:(.def檔案名稱) /MACHINE:IX86(80X86機器),就輸出符合VC++格式的的LIB檔案了.
EXAMPLE:
LIB/DEF:VideoDeCoder.def /MACHINE:IX86
4.串連時帶上LIB檔案連結;注意的是當有些動態庫DUMPBIN的只有函數名,無"@nn"的參數格式,如C++Builder寫的DLL,輸出就只有函數名符號,連結時就會報錯:
error LNK2002:unresolved external symbol "functionname@nn"
提示程式中引入的函數符號無法識別,這時只要將DEF檔案中相應的函數名稱改為functionname@nn方式,重建立立LIB,重新連結即可.
這樣就製作成功了符合VC調用方式的LIB了!

要值得一說的是!BORLAND C++BUILDER有一個很好的工具IMPDEF可以直接將DLL中的函數輸出到.DEF檔案中,這種方法只能應用於輸出為C格式的__stdcall調用方式,只要做一點點修改就可以成為符合VC的DEF檔案!
IMPDEF xxx.def xxx.dll
只要將BCB的DEF檔案中函數申明格式轉換為vc識別的格式就可以利用LIB工具產生LIB;要使用C分格輸出(extern "C")才是必須的!而且別忘了在DEF檔案中的函數申明不要帶“_”啊!:)不然會出現error LNK2001的連結錯誤!
vc調用bcb的我沒試過,不過可以參照上面的格式自己改改好了:)

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.