資訊: 在程式碼中使用 _declspec(dllimport) & _declspec(dllexport)

文章翻譯 文章翻譯
文章編號: 132044 - 檢視此文章適用的產品。
全部展開 | 全部摺疊

在此頁中

結論

這份文件補充下列文件中所涵蓋之資訊Microsoft 知識庫 」 中:
107501 取代 __declspec Visual C++ 的 32 位元中的資訊: __export
本文將告訴您的優點和機制的使用_declspec(dllimport) 和 _declspec(dllexport) 應用程式中。

其他相關資訊

32 位元版本的 Visual C++ 會使用 _declspec(dllimport),若要取代先前用於 __export 關鍵字 _declspec(dllexport)16 位元版本的 Visual C++。

您不需要要用來編譯的程式碼的 _declspec(dllimport)是否正確,但這樣做讓編譯器產生更好的程式碼。的編譯器可產生較佳的程式碼,因為它確定知道是否函式存在於 DLL、 讓編譯器可以產生代碼略過一般會在函式中的間接層級跨越 DLL 界限的呼叫。

適當的。DEF 檔匯出] 區段中,_declspec(dllexport) 不是必要項。_declspec(dllexport) 已加入至提供簡易的方式,匯出從函式。EXE 或。不使用的 DLL。DEF 檔。

這篇文章的其餘部分會提供相當的低階,徹底這些問題的討論。

Win32 可移植執行檔格式被設計來減到最少數目必須變更時間戳記來修正匯入的網頁。若要這樣做,這會造成所有匯入任何程式,在同一個地方,呼叫匯入地址的地的址資料表。這可讓載入器來修改唯一的一或兩個網頁的時機存取這些匯入。

使用 _declspec(dllimport) 函式呼叫

在下列程式碼範例中,假設 func1 所在的函式分開的 DLL。EXE 檔案,包含 main () 函式。

如果沒有 _declspec(dllimport),系統將提供此程式碼:
void main(void) {
    func1();
}
				
編譯器會產生程式碼看起來像這樣:
call func1
				
然後,連結器會將轉譯成類似這樣的呼叫:
call 0x4000000         ; The address of 'func1'.
				
如果 'func1' 存在於另一個 DLL,連結器無法解決這個問題直接因為它有沒有辦法知道何謂 'func1' 的位址。在 16 位元環境中,連結器就會將這個程式碼位址加入至清單中。EXE載入器會在執行階段以正確的地址的補充程式。在 32 位元環境中,連結器產生確實知道的 thunk地址。此 thunk 看起來如下:
   0x40000000:    jmp DWORD PTR __imp_func1
				
__Imp_func1 下面是 func1 的介面槽匯入地址的地址一覽表。EXE 檔案。因此連結器會知道所有地址。的若要更新只有載入器。在載入時間的 EXE 檔的匯入位址表若要正確執行的所有檔案。

因此,_declspec(dllimport) 最好使用,因為它是較佳如果如果沒有為連結器不會產生 thunk。Thunk 進行較大的程式碼 (在 RISC 系統上,可以是數個指令) 可以會降低您的快取效能。您告訴編譯器此函式在DLL,它可以讓您產生間接呼叫。

因此,現在這段程式碼:
__declspec(dllimport) void func1(void);

void main(void) {
    func1();
}
				
會產生這個指令:
call DWORD PTR __imp_func1
				
還有沒有 thunk 和沒有 jmp 指令,所以程式碼會較小,更快。

相反地,於 DLL 內的函式呼叫,您不想要若要使用間接呼叫。您已經知道函式的位址。時間和載入和儲存前函式的位址所需空間間接呼叫,因此直接呼叫一定是更快和較小。您只想要若要從外部呼叫 DLL 函式時使用 __declspec(dllimport)DLL 本身。不使用 __declspec(dllimport) DLL 內的函式當建立該 DLL。

使用 _declspec(dllexport)

若要允許的 16 位元的編譯器版本中引入的 Microsoft __export編譯器自動產生的匯出名稱,並將它們放置在.LIB 檔案。如此。LIB 檔可以再用靜態一樣。LIB 來連結的 DLL。

Microsoft 加入 __declspec(dllexport),要繼續這種便利性。其目的是要匯出指示詞加入至物件檔案,因此您不需要a。DEF 檔。

這種便利性時最為明顯嘗試匯出修飾 c + +函式名稱。因此是名稱裝飾無標準規格匯出函式的名稱可能會不同編譯器版本之間進行變更。如果您會使用 _declspec(dllexport),重新編譯的 DLL 和相依性。EXE 檔案是為了只帳戶有任何命名慣例的變更。

許多匯出指示詞,例如序數、 NONAME 或私用,可設定為只有在。DEF 檔,而且沒有任何方法可以指定這些屬性不需要。DEF 檔。不過,使用除了 _declspec(dllexport)使用。DEF 檔並不會導致建置錯誤。

做為參考,搜尋 Win32 WINBASE。H 標頭檔。它包含慣用的 __declspec(dllexport) 和 __declspec(dllimport) 的範例使用方式。

在資料上使用 _declspec(dllexport) 和 _declspec(dllimport)

如果資料是使用 _declspec(dllimport) 是一種便於使用項目移除一層間接取值。當您匯入資料的 dll,您仍然需要進行匯入位址表。在 Win32 天前_declspec(dllimport),這代表您必須記住要多一層存取資料時的間接取值從 DLL 匯出:
// project.h
#ifdef _DLL     // If accessing the data from inside the DLL
   ULONG ulDataInDll;

else            // If accessing the data from outside the DLL
   ULONG *ulDataInDll;
#endif
				
然後,您會將匯出中的資料程式。DEF 檔:
// project.def
LIBRARY project
EXPORTS
    ulDataInDll   CONSTANT
				
及存取權限以外的 DLL:
if (*ulDataInDll == 0L) {
   // Do stuff here
}
				
當您將標記資料為 __declspec(dllimport),編譯器自動為您產生間接取值的程式碼。您再也不必擔心上述步驟。如先前所述,請勿使用 _declspec(dllimport)在建置 DLL 時的資料上的宣告。DLL 中的函式不會使用匯入位址表來存取資料物件。因此,您將不需要額外的層級的間接取值的存在。

若要從 DLL 自動匯出資料,使用這個宣告:
__declspec(dllexport) ULONG ulDataInDLL;
				

使用。DEF 檔

如果您選擇使用並搭配的 __declspec(dllimport)。DEF 檔,您應該變更。DEF 檔,以減少使用的資料取代常數不正確的程式碼將會造成問題的可能性:
// project.def
LIBRARY project
EXPORTS
    ulDataInDll   DATA
				
下列圖表說明其原因:
Keyword     Emits in the import lib     Exports
CONSTANT    __imp_ulDataInDll           ulDataInDll
            __ulDataInDll

DATA        __imp_ulDataInDll           ulDataInDll
				
使用 _declspec (dllimport) 和常數清單的 __imp_ 版本,中的未裝飾的名稱。若要建立的 LIB DLL 匯入程式庫允許明確連結。使用 _declspec(dllimport) 與資料清單只是__imp_ 的版本名稱。

如果您使用的常數,下列程式碼建構其中一種途徑若要存取 ulDataInDll:
__declspec(dllimport) ULONG ulDataInDll; /*prototype*/ 
   if (ulDataInDll == 0L)   /*sample code fragment*/ 
				
-或者-
ULONG *ulDataInDll;      /*prototype*/ 
if (*ulDataInDll == 0L)  /*sample code fragment*/ 
				
不過,如果您在使用中的資料程式。DEF 檔,以編譯的程式碼下列定義可以存取變數 ulDataInDll:
__declspec(dllimport) ULONG ulDataInDll;
if (ulDataInDll == 0L)   /*sample code fragment*/ 
				
Constant 是較危險的因為假如您忘了使用額外的層級間接取值,您很可能會存取匯入位址表指標變數-不是變數本身。這類問題通常會明示為存取違規因為匯入位址表是目前設為唯讀 Microsoft 編譯器和連結器。

如果看到常數中的,目前 Visual C++ 的連結器會發出警告。DEF 檔,以說明這種情況。若要使用唯一的實際原因如果您無法重新編譯一些目的檔則是屬於其中的標頭檔無法列出 dllimport 原型上。

?考

Visual C++ 線上叢書提供大量的文件上的 dllexport 和 dllimport 儲存類別屬性。這包括「 Dllexport 」 和 「 dllimport 屬性 」 和 「 使用 dllimport 和在 c + + dllexport"中的 「 Microsoft 專屬修飾詞 」 章節的主題c + + 語言參考和"匯出符號"中的主題程式設計技術參考的 〈 建立 win32 的 Dll 〉 章節。如需完整清單線上叢書 》 的相關的主題],搜尋"dllimport"或者"dllexport"。

如需詳細資訊,請參閱下列文件在 Microsoft知識庫:
90530 如何將資料匯出的 DLL 或應用程式
107501 取代 __declspec Visual C++ 的 32 位元中的資訊: __export

屬性

文章編號: 132044 - 上次校閱: 2012年12月31日 - 版次: 4.0
這篇文章中的資訊適用於:
  • Microsoft Visual C++ 2.0 Professional Edition
  • Microsoft Visual C++ 5.0 Enterprise Edition
  • Microsoft Visual C++ 5.0 Professional Edition
關鍵字:?
kbcode kbcompiler kbinfo kbmt KB132044 KbMtzh
機器翻譯
重要:本文是以 Microsoft 機器翻譯軟體翻譯而成,而非使用人工翻譯而成。Microsoft 同時提供使用者人工翻譯及機器翻譯兩個版本的文章,讓使用者可以依其使用語言使用知識庫中的所有文章。但是,機器翻譯的文章可能不盡完美。這些文章中也可能出現拼字、語意或文法上的錯誤,就像外國人在使用本國語言時可能發生的錯誤。Microsoft 不為內容的翻譯錯誤或客戶對該內容的使用所產生的任何錯誤或損害負責。Microsoft也同時將不斷地就機器翻譯軟體進行更新。
按一下這裡查看此文章的英文版本:132044
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。
依現狀不再更新的知識庫內容免責聲明
本文旨在說明 Microsoft 不再提供支援的產品。因此,本文係依「現狀」提供,不會再更新。

提供意見

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com