關於__declspec的一些說明
來源:互聯網
上載者:User
關於__declspec的一些說明void DllName01(void) @DllName01$qv 因為是CPP程式碼 void _stdcall DllName02(void) @DllName02$qqsv 所以函式名都被修void _cdecl DllName03(void) @DllName03$qv 飾過。 void _pascal DllName04(void) @DLLNAME04$QVvoid _fastcall DllName05(void) @DllName05$qqrv 以上結果是否令你丈二金鋼、摸不著頭緒。這是因為我們的程式名稱若以CPP為延伸名,C++Builder會以C++ 特有的命名方式來為函式命名,這種命名方式會在函式名稱後加上其使用參數的性質,如參數類別等。這在C++ 中有一個特別的名稱,叫做mangled name,這是一種為了要實作出多載函式所發出的命名規則。(註:在C++ 中Add(int) 和Add(double) 可以同時存在,因此必須在object code區分之)。同時這種命名方式由於各個編譯器廠商使用的方式各不相同,因此在撰寫DLL時要避免使用之。為了要避開以上問題,我們改以下列的宣告方式: #define _DLLNAME01_H_ #ifndef DLLNAME #define EXTERN __declspec(dllimport) #else #define EXTERN __declspec(dllexport) #endif extern "C" {EXTERN void DllName011(void); EXTERN void _stdcall DllName022(void); EXTERN void _cdecl DllName033(void); EXTERN void _pascal DllName044(void); EXTERN void _fastcall DllName055(void); }; #endif 其中extern "C" {琕琕.}; 是用來告訴編譯器使用C的命名方式,不要使用C++ 的mangled name。若是其中只有一個函式時,你可以直接以下列方式宣告之: extern "C" void __stdcall ShowImage(); 現在我們可以檢視除去mangled name後的函式名稱: 函式定義 DLL內的函式名 摘要說明 void DllName01(void) _DllName01 名稱加底線 void _stdcall DllName02(void) DllName02 名稱未變 void _cdecl DllName03(void) _DllName03 名稱加底線 void _pascal DllName04(void) DLLNAME04 名稱大寫 void _fastcall DllName05(void) @DllName05 名稱加@ 以上我們可得知,在未加修飾字時和使用_cdecl修飾字時的名稱是一樣的。而 _pascal修飾字所產生的函式名則和16位元的標準DLL 函式名相同(這在VC++ 是不被接受的),__fastcall的函式名稱則加上 @。 其中在WIN32中使用最多的是 _stdcall修飾字,這也是你要撰寫一個可以和其他語言共同使用時所使用的修飾字,其次則為 __cdecl修飾字,這是用來傳送不定參數型別的函式如printf、sprintf等使用的。其餘兩者幾乎在DLL沒有機會使用。 結論: 由上可知,在C++Builder中撰寫DLL時必須注意以下事項: 使用 __declspec(dllimport)及 __declspec(dllexport)的標準型式。 注意C++ 的函式名稱編碼(mangled name)。 注意修飾字的使用。除非使用不定參數的函式,否則必使用 __stdcall修飾字。 (4) 不要把 __declspec的使用和 __stdcall混淆了。此二者並沒有絕對的相關性。即使是程式老手都可能栽在此處,切記,切記! 怎麽樣,在看完了以上的介紹後,是否有晃然大悟的感覺。在瞭解以上的規則後,今後不論在撰寫或是使用DLL時遭遇連結的問題時,應該難不倒你吧! 最後,我們將標準的DLL宣告方式列於後,以加深你的印象: #ifndef _SHOWIMG_H_ #define _SHOWIMG_H_ #ifndef IMGDLL #define EXTERN __declspec(dllimport) #else#define EXTERN __declspec(dllexport) #endif extern "C" EXTERN void __stdcall ShowImage(void); #endif 語言雙雄' C++Builder 和Visual C++ 連結 前面我們已經把關於C++Builder撰寫DLL所應注意到的事項介紹完了,現在我們來談另一個重點 - C++Builder和Visual C++ 的連結。若是你沒有使用過Visual C++ 的話,可以將此部份略去。若是你在程式設計時必須使用到Visual C++ 的DLL或是必須提供DLL給VC++ 或是VB使用時,也許會帶給你意想不到的收穫。 VC++ 使用C++Builder的DLL函式 在Visual C++ 中使用C++Builder的DLL的函式方法和在C++Builder中使用大同小異,唯有幾件事情必須要注意。 (一)Visual C++ 的LIB檔格式和C++Builder的LIB格式不同,因此你必須重新產生一個 LIB。不過,可惜的是VC++ 在32位元的版本中並未提供IMPLIB.EXE函式(這點一直令許多人百思不解),因此你無法很方便地產生LIB檔。解決方案有二:其一是在VC++ 內撰寫一個同名稱的空的DLL函式,令其產生LIB檔,其二則是使用 LoadLibrary、GetProcAddress式的明確來電者式。 (二)使用前面提到的標準寫法。 C++Builder中使用VC++ 的DLL函式 在C++Builder中使用VC++ 的DLL函式時要注意的是Microsoft在Visual C++ 中使用的特殊命名規則。在VC++ 中命名規則除了前面談到的幾項之外,它還使用了一個特殊的參數命名法,簡言之,就是在函數名稱後面加上參數的大小,這種命名方法會造成C++Builder,VB,Delphi使用的上的困擾。舉例來說 extern "C" _declspec(dllexport) void __stdcall ShowImage(void); 在VC++ 中產生的函式名稱為ShowImage@0(其中0表示參數大小),而不是如在C++Builder中產生的ShowImage,這是VC++ 已知的問題,這個問題也造成了很多使用non-VC++ 的使用者的問題,解決之道是在該DLL的DEF檔中加上以下的敘述 EXPORTS ShowImage=ShowImage@0 如此便可以產生正確的函式名了,若是你不想修改DEF檔,你也可以在程式中加入以下的連結指引 #pragma comment(linker,"/exports:ShowImage=ShowImage@0") 假設你不確定其正確的名稱,可以利用DumpBin或是TDump觀察之。 以上是針對VC++ 的程式設計的所作的額外說明。最後我們以一個VC++ 程式呼叫本單元的About Dialog DLL做為結束。 此程式的關鍵程式碼如下: void CVcusedllApp::OnAppAbout(){void (*ShowImage)(void); HINSTANCE hInst; hInst = LoadLibrary("DLLSAMP2.DLL"); (FARPROC &)ShowImage=GetProcAddress(hInst,"ShowImage"); ShowImage(); FreeLibrary(hInst); }