程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> VC法式在Win32情況下靜態鏈接庫(DLL)編程道理

VC法式在Win32情況下靜態鏈接庫(DLL)編程道理

編輯:關於C++

VC法式在Win32情況下靜態鏈接庫(DLL)編程道理。本站提示廣大學習愛好者:(VC法式在Win32情況下靜態鏈接庫(DLL)編程道理)文章只能為提供參考,不一定能成為您想要的結果。以下是VC法式在Win32情況下靜態鏈接庫(DLL)編程道理正文


本文具體講述了VC法式在Win32情況下靜態鏈接庫(DLL)編程道理。分享給年夜家供年夜家參考。詳細剖析以下:

普通比擬年夜的運用法式都由許多模塊構成,這些模塊分離完成絕對自力的功效,它們彼此協作來完成全部軟件體系的任務。個中能夠存在一些模塊的功效較為通用,在結構其它軟件體系時仍會被應用。在結構軟件體系時,假如將一切模塊的源代碼都靜態編譯到全部運用法式EXE文件中,會發生一些成績:一個缺陷是增長了運用法式的年夜小,它會占用更多的磁盤空間,法式運轉時也會消費較年夜的內存空間,形成體系資本的糟蹋;另外一個缺陷是,在編寫年夜的EXE法式時,在每次修正重建時都必需調劑編譯一切源代碼,增長了編譯進程的龐雜性,也晦氣於階段性的單位測試。

Windows體系平台上供給了一種完整分歧的較有用的編程和運轉情況,你可以將自力的法式模塊創立為較小的DLL(Dynamic Linkable Library)文件,並可對它們零丁編譯和測試。在運轉時,只要當EXE法式確切要挪用這些DLL模塊的情形下,體系才會將它們裝載到內存空間中。這類方法不只削減了EXE文件的年夜小和對內存空間的需求,並且使這些DLL模塊可以同時被多個運用法式應用。Microsoft Windows本身就將一些重要的體系功效以DLL模塊的情勢完成。例如IE中的一些根本功效就是由DLL文件完成的,它可以被其它運用法式挪用和集成。

普通來講,DLL是一種磁盤文件(平日帶有DLL擴大名),它由全局數據、辦事函數和資本構成,在運轉時被體系加載到過程的虛擬空間中,成為挪用過程的一部門。假如與其它DLL之間沒有抵觸,該文件平日映照到過程虛擬空間的統一地址上。DLL模塊中包括各類導出函數,用於向外界供給辦事。Windows在加載DLL模塊時將過程函數挪用與DLL文件的導出函數相婚配。

在Win32情況中,每一個過程都復制了本身的讀/寫全局變量。假如想要與其它過程同享內存,必需應用內存映照文件或許聲明一個同享數據段。DLL模塊須要的客棧內存都是從運轉過程的客棧平分配出來的。
DLL如今愈來愈輕易編寫。Win32曾經年夜年夜簡化了其編程形式,並有很多來自AppWizard和MFC類庫的支撐。

1、導出和導入函數的婚配

DLL文件中包括一個導出函數表。這些導出函數由它們的符號名和稱為標識號的整數與外界接洽起來。函數表中還包括了DLL中函數的地址。當運用法式加載DLL模塊不時,它其實不曉得挪用函數的現實地址,但它曉得函數的符號名和標識號。靜態鏈接進程在加載的DLL模塊時靜態樹立一個函數挪用與函數地址的對應表。假如從新編譯和重建DLL文件,其實不須要修正運用法式,除非你轉變了導出函數的符號名和參數序列。
簡略的DLL文件只為運用法式供給導出函數,比擬龐雜的DLL文件除供給導出函數之外,還挪用其它DLL文件中的函數。如許,一個特別的DLL可以既有導入函數,又有導入函數。這其實不是一個成績,由於靜態鏈接進程可以處置穿插相干的情形。
在DLL代碼中,必需像上面如許明白聲明導出函數:
__declspec(dllexport) int MyFunction(int n);
但也能夠在模塊界說(DEF)文件中列出導出函數,不外如許做經常惹起更多的費事。在運用法式方面,請求像上面如許明白聲明響應的輸出函數:
__declspec(dllimport) int MyFuncition(int n);
唯一導入和導作聲明其實不能使運用法式外部的函數挪用鏈接到響應的DLL文件上。運用法式的項目必需為鏈接法式指定所需的輸出庫(LIB文件)。並且運用法式現實上必需至多包括一個對DLL函數的挪用。

2、與DLL模塊樹立鏈接

運用法式導入函數與DLL文件中的導出函數停止鏈接有兩種方法:隱式鏈接和顯式鏈接。所謂的隱式鏈接是指在運用法式中不需指明DLL文件的現實存儲途徑,法式員不需關懷DLL文件的現實裝載。而顯式鏈接與此相反。
采取隱式鏈接方法,法式員在樹立一個DLL文件時,鏈接法式會主動生成一個與之對應的LIB導入文件。該文件包括了每個DLL導出函數的符號名和可選的標識號,然則其實不含有現實的代碼。LIB文件作為DLL的替換文件被編譯到運用法式項目中。當法式員經由過程靜態鏈接方法編譯生成運用法式時,運用法式中的挪用函數與LIB文件中導出符號相婚配,這些符號或標識號進入到生成的EXE文件中。LIB文件中也包括了對應的DLL文件名(但不是完整的途徑名),鏈接法式將其存儲在EXE文件外部。當運用法式運轉進程中須要加載DLL文件時,Windows依據這些信息發明並加載DLL,然後經由過程符號名或標識號完成對DLL函數的靜態鏈接。
顯式鏈接方法關於集成化的開辟說話(例如VB)比擬合適。有了顯式鏈接,法式員就不用再應用導入文件,而是直接挪用Win32 的LoadLibary函數,並指定DLL的途徑作為參數。LoadLibary前往HINSTANCE參數,運用法式在挪用GetProcAddress函數時應用這一參數。GetProcAddress函數將符號名或標識號轉換為DLL外部的地址。假定有一個導出以下函數的DLL文件:
extern "C" __declspec(dllexport) double SquareRoot(double d);
上面是運用法式對該導出函數的顯式鏈接的例子:
typedef double(SQRTPROC)(double);
HINSTANCE hInstance;
SQRTPROC* pFunction;
VERIFY(hInstance=::LoadLibrary("c://winnt//system32//mydll.dll"));
VERIFY(pFunction=(SQRTPROC*)::GetProcAddress(hInstance,"SquareRoot"));
double d=(*pFunction)(81.0);//挪用該DLL函數
在隱式鏈接方法中,一切被運用法式挪用的DLL文件都邑在運用法式EXE文件加載時被加載在到內存中;但假如采取顯式鏈接方法,法式員可以決議DLL文件什麼時候加載或不加載。顯式鏈接在運轉時決議加載哪一個DLL文件。例如,可以將一個帶有字符串資本的DLL模塊以英語加載,而另外一個以西班牙語加載。運用法式在用戶選擇了適合的語種後再加載與之對應的DLL文件。

3、應用符號名鏈接與標識號鏈接

在Win16情況中,符號名鏈接效力較低,一切那時標識號鏈接是重要的鏈接方法。在Win32情況中,符號名鏈接的效力獲得了改良。Microsoft如今推舉應用符號名鏈接。但在MFC庫中的DLL版本依然采取的是標識號鏈接。一個典范的MFC法式能夠會鏈接到數百個MFC DLL函數上。采取標識號鏈接的運用法式的EXE文件體絕對較小,由於它不用包括導入函數的長字符串符號名。

4、編寫DllMain函數

DllMain函數是DLL模塊的默許進口點。當Windows加載DLL模塊時挪用這一函數。體系起首挪用全局對象的結構函數,然後挪用全局函數DLLMain。DLLMain函數不只在將DLL鏈接加載到過程時被挪用,在DLL模塊與過程分別時(和其它時刻)也被挪用。上面是一個框架DLLMain函數的例子。
HINSTANCE g_hInstance;
extern "C" int APIENTRY DllMain(HINSTANCE hInstance,DWORD dwReason,LPVOID lpReserved)
{
if(dwReason==DLL_PROCESS_ATTACH)
{
TRACE0("EX22A.DLL Initializing!/n");
//在這裡停止初始化
}
else if(dwReason=DLL_PROCESS_DETACH)
{
TRACE0("EX22A.DLL Terminating!/n");
//在這裡停止消除任務
}
return 1;//勝利
}
假如法式員沒無為DLL模塊編寫一個DLLMain函數,體系會從其它運轉庫中引入一個不做任何操作的缺省DLLMain函數版本。在單個線程啟動和終止時,DLLMain函數也被挪用。正如由dwReason參數所注解的那樣。

5、模塊句柄

過程中的每一個DLL模塊被全局獨一的32字節的HINSTANCE句柄標識。過程本身還有一個HINSTANCE句柄。一切這些模塊句柄都只要在特定的過程外部有用,它們代表了DLL或EXE模塊在過程虛擬空間中的肇端地址。在Win32中,HINSTANCE和HMODULE的值是雷同的,這個兩品種型可以調換應用。過程模塊句柄簡直老是等於0x400000,而DLL模塊的加載地址的缺省句柄是0x10000000。假如法式同時應用了幾個DLL模塊,每個都邑有分歧的HINSTANCE值。這是由於在創立DLL文件時指定了分歧的基地址,或許是由於加載法式對DLL代碼停止了重定位。
模塊句柄關於加載資本特殊主要。Win32 的FindResource函數中帶有一個HINSTANCE參數。EXE和DLL都有其本身的資本。假如運用法式須要來自於DLL的資本,就將此參數指定為DLL的模塊句柄。假如須要EXE文件中包括的資本,就指定EXE的模塊句柄。
然則在應用這些句柄之前存在一個成績,你如何獲得它們呢?假如須要獲得EXE模塊句柄,挪用帶有Null參數的Win32函數GetModuleHandle;假如須要DLL模塊句柄,就挪用以DLL文件名為參數的Win32函數GetModuleHandle。

6、運用法式如何找到DLL文件

假如運用法式應用LoadLibrary顯式鏈接,那末在這個函數的參數中可以指定DLL文件的完全途徑。假如不指定途徑,或是停止隱式鏈接,Windows將遵守上面的搜刮次序來定位DLL:

1. 包括EXE文件的目次,
2. 過程確當前任務目次,
3. Windows體系目次,
4. Windows目次,
5. 列在Path情況變量中的一系列目次。

這裡有一個很輕易產生毛病的圈套。假如你應用VC++停止項目開辟,而且為DLL模塊專門創立了一個項目,然後將生成的DLL文件拷貝到體系目次下,從運用法式中挪用DLL模塊。到今朝為止,一切正常。接上去對DLL模塊做了一些修正後從新生成了新的DLL文件,但你忘卻將新的DLL文件拷貝到體系目次下。下一次當你運轉運用法式時,它仍加載了老版本的DLL文件,這可要小心!

7、調試DLL法式

Microsoft 的VC++是開辟和測試DLL的有用對象,只需從DLL項目中運轉調試法式便可。當你第一次如許操作時,調試法式會向你訊問EXE文件的途徑。爾後每次在調試法式中運轉DLL時,調試法式會主動加載該EXE文件。然後該EXE文件用下面的搜刮序列發明DLL文件,這意味著你必需設置Path情況變量讓其包括DLL文件的磁盤途徑,或許也能夠將DLL文件拷貝到搜刮序列中的目次途徑下。

願望本文所述對年夜家的VC法式設計有所贊助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved