国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
關(guān)于Dll導(dǎo)出函數(shù)名

使用Dependency看DLL的導(dǎo)出函數(shù)的名字,會發(fā)現(xiàn)有一些有意思的東西,這大多是和編譯DLL時候指定DLL導(dǎo)出函數(shù)的導(dǎo)出符有關(guān)系。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
當(dāng)你使用extern "C"的情況下:  
__stdcall會使導(dǎo)出函數(shù)名字前面加一個下劃線,后面加一個@再加上參數(shù)的字節(jié)數(shù),比如_Fun@4就是4個字節(jié) 
__fastcall類似__stdcall,不過前面沒有下劃線,_fastcall應(yīng)該前面還有一個@,比如@LoadaDir@4
__cdecl則是前面僅僅有一個下劃線
如果不用extern "C"話則使用C++命名機(jī)制,涉及到C++ NameMangling,比較復(fù)雜,編譯器之間也不太一樣。
另外,__declspec(dllexport)僅會對__cdecl進(jìn)行處理,去掉前面的下劃線(對于一般全局函數(shù)來說缺省就是__cdecl),而對于其他兩種不會處理。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
extern"C"的作用是(防止C++編譯器的“名字破壞”特性),使編譯器按照C的方式生成函數(shù)名,C的方式實際的函數(shù)名和你寫的一樣。如果沒有這個,則按照C++的方式生成函數(shù)名,這樣實際的函數(shù)名(LoadLibrary方式GetProcAddress傳入的函數(shù)名)和你寫得函數(shù)名不一樣,這樣你用LoadLibrary、GetProcAddress這種方式調(diào)用dll就不成功。  
但是用引入庫(*.LIB)的方式調(diào)用,則編譯器自動轉(zhuǎn)換函數(shù)名,所以總是沒有問題。  
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
我們知道為了讓DLL導(dǎo)出一些函數(shù),需要在每一個將要被導(dǎo)出的函數(shù)前面添加標(biāo)識符:_declspec(dllexport)。例如在DLL中可以導(dǎo)出這樣的函數(shù)(方法)
#define DLL1_API _declspec(dllexport)
DLL1_API int Add(int a,int b)
{
return a+b;
}
現(xiàn)在我們解決名字改編問題,C++編譯器在生成DLL時,會對導(dǎo)出的函數(shù)進(jìn)行名字改編,并且不同的編譯器使用的改編規(guī)則不一樣,因此改編后的名字也是不同的。這樣,如果利用不同編譯器分別生成DLL和訪問DLL的客戶端程序,后者在訪問該DLL的導(dǎo)出函數(shù)時就會出現(xiàn)問題。如上例中函數(shù)Add在C++編譯器改編后的名字是?Add@@YAHHH@Z。我們希望編譯后的名字不發(fā)生改變,這里有幾種方法。
第一種是定義導(dǎo)出函數(shù)時加上限定符:extern "C"
#define DLL1_API extern "C" _declspec(dllexport)
但extern"C"只解決了C和C++語方之間調(diào)用的問題,它只能用于導(dǎo)出全局函數(shù)這種情況而不能導(dǎo)出一個類的成員函數(shù)。另外如果導(dǎo)出函數(shù)的調(diào)用約定發(fā)生改變,即使使用了extern"C",編譯后的函數(shù)名還是會發(fā)生改變。比如我們加入_stdcall關(guān)鍵字說明調(diào)用約定為C調(diào)用約定(標(biāo)準(zhǔn)調(diào)用約定,也就是WINAPI調(diào)用約定)。
#define DLL1_API extern "C" _declspec(dllexport)
DLL1_API int _stdcall Add(int a,int b)
{
return a+b;
}
編譯后函數(shù)名Add改編成了_Add@8
第二種方法是通過一個稱為模塊定義文件DEF來解決。
LIBRARY dllname
EXPORTS
Add
Subtract
LIBRARY用來指定動態(tài)鏈接庫內(nèi)部名稱。該名稱與生成的動態(tài)鏈接庫名一定在匹配,這句代碼不是必須的。EXPORTS說明了DLL將要導(dǎo)出的函數(shù),以及為這些導(dǎo)出函數(shù)指定的符號名。
通過第二種方法模塊定義文件的方式DLL編譯后導(dǎo)出函數(shù)名不會發(fā)生改變。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
傳統(tǒng)的導(dǎo)出 DLL 函數(shù)的方法是使用模塊定義文件 (.def),Visual C++ 提供了更簡潔方便的方法,即“__declspec(dllexport)” 關(guān)鍵字,例如:
__declspec(dllexport) int __stdcall MyExportFunction(intiTest);
但是通過查看工具我們可以發(fā)現(xiàn),DLL 導(dǎo)出的函數(shù)名字實際上是 _MyExportFunction@4。還好,VC提供了一個預(yù)處理指示符 “#pragma” 來指定鏈接選項,可以通過它達(dá)到我們的目的,如下:
#pragma comment(linker,"/EXPORT:MyExportFunction=_MyExportFunction@4")
這樣再看,就會發(fā)現(xiàn)導(dǎo)出的函數(shù)名字已經(jīng)成為了想要的MyExportFunction。
終于知道了,應(yīng)該把函數(shù)前面的 __declspec() 修飾去掉,也就是說,只需要第二條 pragma指令即可。而且還可以使如下形式:
#pragma comment(linker,"/EXPORT:MyExportFunction=_MyExportFunction@4,PRIVATE")
PRIVATE 的作用與其在 def 文件中的作用一樣。




__cdecl和__stdcall都是函數(shù)調(diào)用規(guī)范(還有一個__fastcall),規(guī)定了參數(shù)出入棧的順序和方法,
如果只用VC編程的話可以不用關(guān)心,但是要在C++和Pascal等其他語言通信的時候就要注意了,只有用相同的方法才能夠調(diào)用成功.
另外,像printf這樣接受可變個數(shù)參數(shù)的函數(shù)只有用cdecl才能夠?qū)崿F(xiàn).  
 
__declspec主要是用于說明DLL的引出函數(shù)的,在某些情況下用__declspec(dllexport)在DLL中生命引出函數(shù),比用傳統(tǒng)的DEF文件方便一些.在普通程序中也可以用__declspec(dllimport)說明函數(shù)是位于另一個DLL中的導(dǎo)出函數(shù).

例子不太好舉啊,其實就是在函數(shù)聲明的時候多加一個關(guān)鍵字,比如很多API函數(shù)就是象這樣聲明的:  
  int  WINAPI  MessageBoxA(HWND,LPCSTR,LPSTR,UINT);  
 而WINAPI實際上就是__stdcall.  
 大多數(shù)API都采用__stdcall調(diào)用規(guī)范,這是因為幾乎所有的語言都支持__stdcall調(diào)用.相比之下,__cdecl只有在C語言中才能用.但是__cdecl調(diào)用有一個特點,就是能夠?qū)崿F(xiàn)可變參數(shù)的函數(shù)調(diào)用,比如printf,這用__stdcall調(diào)用是不可能的.  
 __fastcall這種調(diào)用規(guī)范比較少見,但是在Borland  C++  Builder中比較多的采用了這種調(diào)用方式.  
 如果有共享代碼的需要,比如寫DLL,推薦的方法是用__stdcall調(diào)用,因為這樣適用范圍最廣.如果是C++語言寫的代碼供Delphi這樣的語言調(diào)用就必須聲明為__stdcall,因為Pascal不支持cdecl調(diào)用(或許Delphi的最新版本能夠支持也說不定,這個我不太清楚).在其他一些地方,比如寫COM組件,幾乎都用的是stdcall調(diào)用.在VC或Delphi或C++Builder里面都可以從項目設(shè)置中更改默認(rèn)的函數(shù)調(diào)用規(guī)范,當(dāng)然你也可以在函數(shù)聲明的時候加入__stdcall,__cdecl,__fastcall關(guān)鍵字來明確的指示本函數(shù)用哪種調(diào)用規(guī)范.  
 __declspec一般都是用來聲明DLL中的導(dǎo)出函數(shù).這個關(guān)鍵字也有一些其他的用法,不過非常罕見.
 
 

關(guān)于DLL的函數(shù):  
   
 動態(tài)鏈接庫中定義有兩種函數(shù):導(dǎo)出函數(shù)(export  function)和內(nèi)部函數(shù)(internal  function)。  
 導(dǎo)出函數(shù)可以被其它模塊調(diào)用,內(nèi)部函數(shù)在定義它們的DLL程序內(nèi)部使用。  
   
 輸出函數(shù)的方法有以下幾種:  
   
 1、傳統(tǒng)的方法  
   
 在模塊定義文件的EXPORT部分指定要輸入的函數(shù)或者變量。語法格式如下:  
 entryname[=internalname]  [@ordinal[NONAME]]  [DATA]  [PRIVATE]  
   
  其中:  
   
 entryname是輸出的函數(shù)或者數(shù)據(jù)被引用的名稱;  
   
 internalname同entryname;  
   
 @ordinal表示在輸出表中的順序號(index);  
   
 NONAME僅僅在按順序號輸出時被使用(不使用entryname);  
   
 DATA表示輸出的是數(shù)據(jù)項,使用DLL輸出數(shù)據(jù)的程序必須聲明該數(shù)據(jù)項為_declspec(dllimport)。  
   
 上述各項中,只有entryname項是必須的,其他可以省略。  
   
 對于“C”函數(shù)來說,entryname可以等同于函數(shù)名;但是對“C++”函數(shù)(成員函數(shù)、非成員函數(shù))  
 來說,entryname是修飾名??梢詮?map映像文件中得到要輸出函數(shù)的修飾名,或者使用  
  DUMPBIN  /SYMBOLS得到,然后把它們寫在.def文件的輸出模塊。DUMPBIN是VC提供的一個工具。  
   
 如果要輸出一個“C++”類,則把要輸出的數(shù)據(jù)和成員的修飾名都寫入.def模塊定義文件。  
   
 2、在命令行輸出  
   
 對鏈接程序LINK指定/EXPORT命令行參數(shù),輸出有關(guān)函數(shù)。  
   
 3、使用MFC提供的修飾符號_declspec(dllexport)  
   
 在要輸出的函數(shù)、類、數(shù)據(jù)的聲明前加上_declspec(dllexport)的修飾符,表示輸出。__declspec  
 (dllexport)在C調(diào)用約定、C編譯情況下可以去掉輸出函數(shù)名的下劃線前綴。extern  "C"使得在C++中  
 使用C編譯方式成為可能。在“C++”下定義“C”函數(shù),需要加extern  “C”關(guān)鍵詞。用extern  "C"來  
 指明該函數(shù)使用C編譯方式。輸出的“C”函數(shù)可以從“C”代碼里調(diào)用。  
   
 例如,在一個C++文件中,有如下函數(shù):  
  extern  "C"  {void  __declspec(dllexport)  __cdecl  Test(int  var);}  
 其輸出函數(shù)名為:Test    
   
 MFC提供了一些宏,就有這樣的作用。  
   
 AFX_CLASS_IMPORT:__declspec(dllexport)  
   
 AFX_API_IMPORT:__declspec(dllexport)  
   
 AFX_DATA_IMPORT:__declspec(dllexport)  
   
 AFX_CLASS_EXPORT:__declspec(dllexport)  
   
 AFX_API_EXPORT:__declspec(dllexport)  
   
 AFX_DATA_EXPORT:__declspec(dllexport)  
   
 AFX_EXT_CLASS:  #ifdef  _AFXEXT    
 AFX_CLASS_EXPORT  
  #else  
 AFX_CLASS_IMPORT  
   
 AFX_EXT_API:#ifdef  _AFXEXT  
 AFX_API_EXPORT  
  #else  
 AFX_API_IMPORT  
   
 AFX_EXT_DATA:#ifdef  _AFXEXT  
 AFX_DATA_EXPORT  
  #else  
 AFX_DATA_IMPORT  
   
 像AFX_EXT_CLASS這樣的宏,如果用于DLL應(yīng)用程序的實現(xiàn)中,則表示輸出(因為_AFX_EXT被定義,通  
 常是在編譯器的標(biāo)識參數(shù)中指定該選項/D_AFX_EXT);如果用于使用DLL的應(yīng)用程序中,則表示輸入  
 (_AFX_EXT沒有定義)。  
   
 要輸出整個的類,對類使用_declspec(_dllexpot);要輸出類的成員函數(shù),則對該函數(shù)使用  
 _declspec(_dllexport)。如:  
   
  class  AFX_EXT_CLASS  CTextDoc   public  CDocument  
  
  …  
  
   
  extern  "C"  AFX_EXT_API  void  WINAPI  InitMYDLL();  
   
 這幾種方法中,最好采用第三種,方便好用;其次是第一種,如果按順序號輸出,調(diào)用效率會高些;  
 最次是第二種。    
   
 六、模塊定義文件(.DEF)  
   
 模塊定義文件(.DEF)是一個或多個用于描述DLL屬性的模塊語句組成的文本文件,每個DEF文件至少必  
 須包含以下模塊定義語句:  
   
  第一個語句必須是LIBRARY語句,指出DLL的名字;  
  EXPORTS語句列出被導(dǎo)出函數(shù)的名字;將要輸出的函數(shù)修飾名羅列在EXPORTS之下,這個名字必須與  
 定義函數(shù)的名字完全一致,如此就得到一個沒有任何修飾的函數(shù)名了。  
  可以使用DESCRIPTION語句描述DLL的用途(此句可選);  
  ";"對一行進(jìn)行注釋(可選)。  
   
 七、DLL程序和調(diào)用其輸出函數(shù)的程序的關(guān)系  
   
 1、dll與進(jìn)程、線程之間的關(guān)系  
   
 DLL模塊被映射到調(diào)用它的進(jìn)程的虛擬地址空間。  
 DLL使用的內(nèi)存從調(diào)用進(jìn)程的虛擬地址空間分配,只能被該進(jìn)程的線程所訪問。  
 DLL的句柄可以被調(diào)用進(jìn)程使用;調(diào)用進(jìn)程的句柄可以被DLL使用。  
 DLL使用調(diào)用進(jìn)程的棧。  
   
 2、關(guān)于共享數(shù)據(jù)段  
   
 DLL定義的全局變量可以被調(diào)用進(jìn)程訪問;DLL可以訪問調(diào)用進(jìn)程的全局?jǐn)?shù)據(jù)。使用同一DLL的每一個  
 進(jìn)程都有自己的DLL全局變量實例。如果多個線程并發(fā)訪問同一變量,則需要使用同步機(jī)制;對一個  
 DLL的變量,如果希望每個使用DLL的線程都有自己的值,則應(yīng)該使用線程局部存儲(TLS,Thread    
  Local  Strorage)。  
   
 在程序里加入預(yù)編譯指令,或在開發(fā)環(huán)境的項目設(shè)置里也可以達(dá)到設(shè)置數(shù)據(jù)段屬性的目的.必須給  
 這些變量賦初值,否則編譯器會把沒有賦初始值的變量放在一個叫未被初始化的數(shù)據(jù)段中。  
   
 
 

   
  extern  "C"  指示編譯器用C語言方法給函數(shù)命名。  
   
 在制作DLL導(dǎo)出函數(shù)時由于C++存在函數(shù)重載,因此  
 __declspec(dllexport)  function(int,int)  在DLL會被decorate,例如被decorate成為  function_int_int,而且不同的編譯器decorate的方法不同,造成了在用GetProcAddress取得function地址時的不便,使用extern  "C"時,上述的decorate不會發(fā)生,因為C沒有函數(shù)重載,但如此一來被extern"C"修飾的函數(shù),就不具備重載能力,可以說extern  和  extern   "C"不是以回事。
 
__declspec(dllexport)  聲明一個導(dǎo)出函數(shù),是說這個函數(shù)要從本DLL導(dǎo)出。我要給別人用。一般用于dll中
__declspec(dllimport)  聲明一個導(dǎo)入函數(shù),是說這個函數(shù)是從別的DLL導(dǎo)入。我要用。一般用于使用某個dll的exe中 
_declspec(thread)可以降低程序員的負(fù)擔(dān),又能做到線程局部存儲的要求。VC++允許一個變量或結(jié)構(gòu)被聲明為“具有線程局部性”。例如,下面的聲明,如果放在一個DLL之中,將產(chǎn)生出一個全局變量,對每一個進(jìn)程而言獨一無二:  
  DWORD  gProgressCounter;  
 但是如果這樣聲明,它就是對每一個線程獨一無二:  
 _declspec(thread)    DWORD  gProgressCounter; &


本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
__cdecl __fastcall與 __stdcall
函數(shù)的調(diào)用規(guī)則(__cdecl,__stdcall,__fastcall, __pascal, __thiscall)
帶你玩轉(zhuǎn)Visual Studio——調(diào)用約定__cdecl、__stdcall和__fastcall
__cdecl __fastcall與 __stdcall
DLL(Dynamic Link Libraries)
使用c 開發(fā)excel插件 (第3章動態(tài)鏈接庫(dynamic
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服