Windows DLL編程中的匯入匯出:__declspec(dllimport) ,__declspec(dllexport) ,

來源:互聯網
上載者:User

在Windows DLL編程時,可使用__declspec(dllimport)關鍵字匯入函數或者變數。

 函數的匯入     當你需要使用DLL中的函數時,往往不需要顯示地匯入函數,編譯器可自動完成。但如果你顯示地匯入函數,編譯器會產生品質更好的代碼。由於編譯器確切地知道了一個函數是否在一個DLL中,它就可以產生更好的代碼,不再需要間接的調用轉接。     Win32的PE格式(Portable Executable Format)把所有匯入地址放在一個匯入地址表中。下面用一個具體執行個體說明使用__declspec(dllimport)匯入函數和不使用的區別:     假設func是一個DLL中的函數,現在在要產生的.exe的main函數中調用func函數,並且不顯示地匯入func函數(即沒有:__declspec(dllimport)),程式碼範例如下:    int main()    {        func();    } 編譯器將產生類似這樣的調用代碼:     call func 然後,連結器把該調用翻譯為類似這樣的代碼:     call 0x40000001       ; ox40000001是"func"的地址 並且,連結器將產生一個Thunk,形如:     0x40000001: jmp DWORD PTR __imp_func 這裡的imp_func是func函數在.exe的匯入地址表中的函數槽的地址。然後,載入器只需要在載入時更新.exe的匯入地址表即可。     而如果使用了__declspec(dllimport)顯示地匯入函數,那麼連結器就不會產生Thunk(如果不被要求的話),而直接產生一個間接調用。因此,下面的代碼:    __declspec(dllimport) void func1(void);
    void main(void)
    {
        func1();
    } 將調用如下調用指令:    call DWORD PTR __imp_func1     因此,顯示地匯入函數能有效減少目標代碼(因為不產生Thunk)。另外,在DLL中使用DLL外的函數也可以這樣做,從而提高空間和時間效率。 變數的匯入     與函數不同的是,在使用DLL中的變數時,需要顯示地匯入變數。使用__declspec(dllimport)關鍵字匯入變數。若在DLL中使用.def匯出變數,則應使用DATA修飾變數,而不是使用已經被遺棄的CONSTANT。因為CONSTANT可能需要使用指標間接訪問變數,不確定什麼時候會出問題。

先看代碼:以下是在dev-c++裡建立自已的dll時的dll.h裡面的代碼,這裡面有一個:_declspec(dllexport)

#ifndef _DLL_H_
#define _DLL_H_//防重複定義

#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */

DLLIMPORT void HelloWorld (void);

#endif /* _DLL_H_ */

 

上面代碼裡面的_delcspce(dllexport)被定義為宏,這樣可以提高程式的可讀性!這個的作是是將函數定義為匯出函數,也就是說這個函數要被包含這個函數的程式之外的程式調用!本語句中就是:void Helloword(void):

摘自msdn:在 32 位編譯器版本中,可以使用 __declspec(dllexport) 關鍵字從 DLL 匯出資料、函數、類或類成員函數。__declspec(dllexport) 將匯出指令添加到對象檔案

若要匯出函數,__declspec(dllexport) 關鍵字必須出現在呼叫慣例關鍵字的左邊(如果指定了關鍵字)。例如:

__declspec(dllexport) void __cdecl Function1(void);

若要匯出類中的所有公用資料成員和成員函數,關鍵字必須出現在類名的左邊,如下所示:

class __declspec(dllexport) CExampleExport : public CObject{ ... class definition ... };

產生 DLL 時,通常建立一個包含正在匯出的函數原型和/或類的標頭檔,並將 __declspec(dllexport) 添加到標頭檔中的聲明。若要提高代碼的可讀性,請為 __declspec(dllexport) 定義一個宏並對正在匯出的每個符號使用該宏:

#define DllExport   __declspec( dllexport ) 

__declspec(dllexport) 將函數名儲存在 DLL 的匯出表中。

 

 

 

若要確定用於匯出函數的方法(.def 檔案或 __declspec(dllexport) 關鍵字),請回答下列問題:

  • 是否要一直添加附加的匯出函數?

  • 誰要使用 DLL?例如,是由許多無法重建的可執行檔使用的第三方 DLL 還是僅由可以輕鬆重建的應用程式使用的 DLL?

使用 .DEF 檔案的優缺點

在 .def 檔案中匯出函數使您得以控制匯出序號。當將附加的匯出函數添加到 DLL 時,可以給它們分配更高的序號值(高於任何其他匯出函數)。當您進行此操作時,使用隱式連結的應用程式不必與包含新函數的新匯入庫重新連結。這非常重要,例如,在設計將由許多應用程式使用的第三方 DLL 時。可以通過添加附加功能不斷地增強 DLL,同時確保現有應用程式繼續正常使用新的 DLL。MFC DLL 是使用 .def 檔案產生的。

使用 .def 檔案的另一個優點是:可以使用 NONAME 屬性匯出函數,該屬性僅將序號放到 DLL 的匯出表中。對具有大量匯出函數的 DLL,使用 NONAME 屬性可以減小 DLL 檔案的大小。有關編寫模組定義語句的資訊,請參見模組定義語句的規則。有關序號匯出的更多資訊,請參見按序號而不是按名稱從 DLL 匯出函數。

使用 .def 檔案的主要缺點是:在 C++ 檔案中匯出函數時,必須將修飾名放到 .def 檔案中,或者通過使用外部“C”用標準 C 連結定義匯出函數,以避免編譯器進行名稱修飾。

如果需要將修飾名放到 .def 檔案中,則可以通過使用 DUMPBIN 工具或 /MAP 連結器選項來擷取修飾名。請注意,編譯器產生的修飾名是編譯器特定的。如果將 Visual C++ 編譯器產生的修飾名放到 .def 檔案中,則連結到 DLL 的應用程式必須也是用相同版本的 Visual C++ 產生的,這樣調用應用程式中的修飾名才能與 DLL 的 .def 檔案中的匯出名相匹配。

使用 __declspec(dllexport) 的優缺點

使用 __declspec(dllexport) 非常方便,因為不必考慮維護 .def 檔案和擷取匯出函數的修飾名。例如,如果您設計的 DLL 供自己控制的應用程式使用,則此方法很適用。如果通過新的匯出函數重建 DLL,還必須重建應用程式,因為如果使用不同版本的編譯器進行重新編譯,則匯出的 C++ 函數的修飾名可能會發生變化。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.