應用程序使用DLL可以采用兩種方式:一種是隱式鏈接,另一種是顯式鏈接。在使用DLL之前首先要知道DLL中函數的結構信息。Visual C++6.0(或者更先進的版本)在VC\bin目錄下提供了一個名為Dumpbin.exe的小程序(使用方法見VS自帶工具:dumpbin的使用),用它可以查看DLL文件中的函數結構。另外,Windows系統將遵循下面的搜索順序來定位DLL: 1.包含EXE文件的目錄,2.進程的當前工作目錄, 3.Windows系統目錄, 4.Windows目錄,5.列在Path環境變量中的一系列目錄。
1.隱式鏈接
隱式鏈接就是在程序開始執行時就將DLL文件加載到應用程序當中。實現隱式鏈接很容易,只要將導入函數關鍵字_declspec(dllimport)函數名等寫到應用程序相應的頭文件中就可以了。下面的例子通過隱式鏈接調用MyDll.dll庫中的Min函數。首先生成一個項目為TestDll,在DllTest.h、DllTest.cpp文件中分別輸入如下代碼:
1 //Dlltest.h 2 3 #include"MyDll.h" 4 #pragma comment(lib,"MyDll.lib") 5 extern "C"_declspec(dllimport) int Max(int a,int b); 6 extern "C"_declspec(dllimport) int Min(int a,int b); 7 //TestDll.cpp 8 #include"Dlltest.h" 9 void main() 10 {int a; 11 a=min(8,10) 12 printf("比較的結果為%d\n",a); 13 }
在創建DllTest.exe文件之前,要先將MyDll.dll和MyDll.lib拷貝到當前工程所在的目錄下面,也可以拷貝到windows的System目錄下。如果DLL使用的是def文件,要刪除TestDll.h文件中關鍵字extern "C"。TestDll.h文件中的關鍵字Progam commit是要Visual C+的編譯器在link時,鏈接到MyDll.lib文件,當然,開發人員也可以不使用#pragma comment(lib,"MyDll.lib")語句,而直接在工程的Setting->Link頁的Object/Moduls欄填入MyDll.lib既可。
2.顯式鏈接
顯式鏈接是應用程序在執行過程中隨時可以加載DLL文件,也可以隨時卸載DLL文件,這是隱式鏈接所無法作到的,所以顯式鏈接具有更好的靈活性,對於解釋性語言更為合適。不過實現顯式鏈接要麻煩一些。在應用程序中用LoadLibrary或MFC提供的AfxLoadLibrary顯式的將自己所做的動態鏈接庫調進來,動態鏈接庫的文件名即是上述兩個函數的參數,此后再用GetProcAddress()獲取想要引入的函數。自此,你就可以象使用如同在應用程序自定義的函數一樣來調用此引入函數了。在應用程序退出之前,應該用FreeLibrary或MFC提供的AfxFreeLibrary釋放動態鏈接庫。下面是通過顯式鏈接調用DLL中的Max函數的例子。
#include <windows.h> #include <cstdio> void main(void) { typedef int(*pMax)(int a,int b); typedef int(*pMin)(int a,int b); HINSTANCE hDLL; PMax Max HDLL=LoadLibrary("MyDll.dll");//加載動態鏈接庫MyDll.dll文件; Max=(pMax)GetProcAddress(hDLL,"Max"); A=Max(5,8); Printf("比較的結果為%d\n",a); FreeLibrary(hDLL);//卸載MyDll.dll文件; }
在上例中使用類型定義關鍵字typedef,定義指向和DLL中相同的函數原型指針,然后通過LoadLibray()將DLL加載到當前的應用程序中並返回當前DLL文件的句柄,然后通過GetProcAddress()函數獲取導入到應用程序中的函數指針,函數調用完畢后,使用FreeLibrary()卸載DLL文件。在編譯程序之前,首先要將DLL文件拷貝到工程所在的目錄或Windows系統目錄下。
使用顯式鏈接應用程序編譯時不需要使用相應的Lib文件。另外,使用GetProcAddress()函數時,可以利用MAKEINTRESOURCE()函數直接使用DLL中函數出現的順序號,如將GetProcAddress(hDLL,"Min")改為GetProcAddress(hDLL, MAKEINTRESOURCE(2))(函數Min()在DLL中的順序號是2),這樣調用DLL中的函數速度很快,但是要記住函數的使用序號,否則會發生錯誤。
注意兩點:
1.上面中提到extern "C",表明函數使用c語言的風格編譯函數,這樣后面顯式調用時,GetProcAddress第二個參數就是原來的函數名,否則如果使用C++編譯的話支持函數重載,則第二個參數會發生變化,想要知道發生了什么變化,可以使用前面提到的Dumpbin工具查看dll的生成函數。具體參考文章:http://www.cnblogs.com/laogao/archive/2012/12/07/2806528.html
2.MAKEINTRESOURCE()函數可以代替復制dll生成的函數的一大串字符串名,但是必須知道函數生成的順序,所以你也必須打開dll查看,才能知道。