非MFC的DLL[轉載](待消化)

非MFC的DLL

1.DLL與extern  "C" 的關係
  當在生成動態鏈接庫(DLL)的時候,如果採用extern "C" 語句,則告知編譯器採用c鏈接的方式 ,結果是生成的DLL的對外部接口(函數)的名字不加處理,在動態加載(loadlibrary ,getprocaddress,freelibrary )語句的時候可以直接通過函數名字來找到此函數在DLL中的入口。
  如果不採用extern  "C"語句聲明dll外部函數的時候,則編譯器採用C++的鏈接方式,將對函數名做些處理(一般是函數名的前面加"?",後面加幾個大寫字母和@),這樣 在動態加載該DLL通過getprocaddress語句通過函數名來得到函數在DLL的入口地址時就會出問題,導致調用失敗。但是,採用C++鏈接方式 的時候,可以用靜態鏈接的方式來避免此問題,即是將與動態鏈接庫一塊生成的lib文件一塊拷到被調用的工程中,在需要調用該dll文件的時候 用#prama comment(lib,"…….lib")語句或者在工程同修改編譯連接選項的方式來靜態加載DLL,此後就可以像調用文件內部的函數通過名字來調用 dll中的外部函數了。

2.DLL與對應頭文件的關係
  首先要理解.h頭文件的作用,由於頭文件的作用只是爲了聲明函數、宏定義等目的,編譯器編譯的單位是每一個.cpp文件,聲明的目的就是告知編譯器某個函 數已經在別處被定義過了(可能是別的.cpp文件中,也可以是在同一個文件中函數被調用的後面),讓編譯通過生成obj目標文件,然後鏈接程序link在 連接的時候通過對每個obj文件的接口函數逐一的掃描,將對函數的調用與函數的實現對應起來,如果在所有的obj文件中都沒有找到已經聲明過的函數,那麼 link將報錯(link error)。.h文件時不參與編譯器的編譯過程的,#include "…….h"宏的作用就是在對應的地方原文插入對應頭文件的內容,因此頭文件的存在可是使函數聲明和實現分開,結構明白。
  動態鏈接庫dll文件是代碼的二進制形式,只要能夠找到函數的入口地址,不用對函數進行聲明就可以調(getprocaddress方式)而在利用靜態鏈 接庫.lib或者對動態鏈接庫利用其.lib文件進行靜態調用的時候,直接利用的是對應的函數名,所以需要對所調用的函數進行聲明,否則編譯器將不認識函 數標號而編譯報錯。

3.DLL與_decspec(dllexport)、_decspec(dllimport)
  DLL內的函數分爲兩種,DLL導出函數和DLL內部函數,其中用_decspec(dllexport)來聲明DLL導出函數,聲明後則此函數可以被外 部的應用程序調用,如果不加此聲明的默認爲DLL內部函數,只能在DLL內部使用,應用程序師無法調用它們的,在depends工具中也看不到此函數的。
  _decspec(dllimport)是在調用DLL內的函數的時候聲明此函數爲導入函數的(對於應用程序本身而言,調用dll的函數爲導入)

  看到一段比較經典的話:DLL導出函數的鏈接(extern "C")、導入( _decspec(dllimport) )、和導出指示符( _decspec(dllexport) )在函數第一次聲明時確定,在以後的函數聲明和定義時,函數都接受第一次的函數的鏈接、導入、導出聲明,不必再次對函數做鏈接、導入、導出聲明。
  如果導出函數聲明和定義的函數調用約定不一致(如聲明爲默認的_cdecl,而在定義的時候爲_stdcal)在編譯報錯。

4.DLL和lib文件的關係
  大的來講,dll是動態鏈接庫,而.lib爲靜態鏈接庫,應該沒有什麼關係纔對,但某中說法來講是的,但要注意到在生成dll的時候一般同時會生成一個同 名的lib文件,這就是爲上面第2點講述的爲dll的靜態調用準備的,此時聲稱的lib文件並不包含函數的二進制代碼,其中僅僅包含着函數名稱到動態鏈接 庫dll的對應函數的入口地址這個映射而已,函數的執行代碼最終還是在dll文件中。
  而靜態鏈接的lib文件則包含着函數的執行二進制代碼,每當調用該函數的時候,就在調用處拷貝一份代碼鏈接到應用程序的.exe文件中,這增加了最終生成 的.exe文件體積,但程序發佈的時候卻不必發佈.lib文件,而用到動態鏈接庫dll的程序發佈的時候要連所用到的dll文件一起發佈。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章