非MFC動態庫指的是不用MFC的類庫結構,直接用C語言寫的DLL,其匯出的函數是標準的C介面,能被非MFC或MFC編寫的應用程式所調用
在VC++6.0中,File-->New-->Win32
Dynamic-Link Library建立非MFC動態庫
(一)一個簡單的非MFC動態庫
在VC++中new一個Win32 Dynamic-Link Library工程DllTest。注意不要選擇MFC AppWizard(dll),因為用MFC AppWizard(dll)建立的將是後面要講述的MFC 動態連結程式庫。 在建立的工程中添加DllTest.h及DllTest.cpp檔案,原始碼如下:
//DllTest.h檔案#ifdef DLL_API#else#define DLL_API extern "C" _declspec(dllimport) // 需要在每個要匯出的函數前面添加標示符 _declspec(dllimport) //用DLL_API代替_declspec(dllimport) //一般添加 extern "C"解決名字改編問題#endifDLL_API int add(int a,int b);DLL_API int subtract(int a,int b);
//DllTest.cpp檔案#define DLL_API extern "C" _declspec(dllexport) //這裡是_declspec(dllexport) #include "DllTest.h"#include <Windows.h>#include <stdio.h>int add(int a,int b){ return a+b;}int subtract(int a,int b){ return a-b;}
直接編譯就產生了.lib .dll檔案
(二)隱式連結的方式載入DLL
再建立一個工程Test(我們隨便建一個win32 console Application),該工程只有一個Test.cpp檔案它調用DLL中的函數,代碼如下:
#include <stdio.h> #include "..\DllTest\DllTest.h"//#pragma comment( lib, "..\\DllTest\\Debug\\DllTest.lib" ) int main(int argc, char *argv[]) { printf("%d\n",add(5,3)); return 0; } 如何隱式載入,下面我們一步步的分析, 直接build會出錯 Test.obj : error LNK2001: unresolved external symbol __imp__add,,有連結的時候出錯,解決:在Test程式中,選擇Project-->Settings-->ling-->Object/library modules中輸入DllTest.lib(或者在程式中加#pragma comment(
lib, "..\\DllTest\\Debug\\DllTest.lib" ) ),然後選擇tools-->options-->directories-->library files菜單或選項,填入庫檔案路徑E:\Program Files\Microsoft Visual Studio 6.0\MyProjects\DllTest\Debug(或者直接將產生的DllTest.lib檔案拷貝到Test工程下),重新build沒有問題了。 運行,出錯提示電腦中丟失DllTest.dll,那麼我們就需要將產生的DllTest.dll檔案拷貝到Test工程目錄下,重新運行成功
(三)聲明匯出函數
在剛才的例子中給出的是在函式宣告前面加上_declspec(dllimport),同時在前面加上了extern "C" 註:1.編譯器在產生DLL時,會對匯出的函數進行名字改編,使用不同的編譯器分別產生DLL和訪問該DLL的用戶端程式的話,後者在訪問該DLL的匯出函數時就會出現問題,所以一般在定義匯出函數時,加上限定符extern "C" 2.使用extern "C"可以解決C++和C語言之間互相調用時函數命令的問題,但是不能用於匯出一個類的成員函數,只能用於匯出全域函數這種情況 3.如果函數的呼叫慣例發生了改變,即使使用了extern "C",它們的名字仍然會發生改變,那麼就有了第二周聲明匯出函數的方式,使用模組檔案(DEF) 接著我們將聲明匯出函數的另外一種方法,使用模組檔案
下面我們重建立Win32 Dynamic-Link Library工程DllTest,添加DllTest.cpp檔案,代碼如下:
int add(int a,int b){ return a+b;}int subtract(int a,int b){ return a-b;} 然後添加模組定義檔案DllTest.def,我們可以在DllTest工程目錄下建立一個空的文本取名DllTest.def,然後在[Project\Add To Project\Files...]-->Insert Files into Project,選擇DllTest.def檔案將其添加進Test工程,然後添加代碼:
LIBRARY DllTest//LIBRARY指定動態連結程式庫的內部名稱,這個必須要和產生的動態連結程式庫名稱匹配EXPORTS//指明DLL要匯出的函數addsubtractbuild 這個DllTest工程,就產生了.lib .dll檔案
自己再編譯一個測試工程,代碼如下:
#include <stdio.h> #include <windows.h> //typedef int(*lpAddFun)(int, int); // 宏定義函數指標類型int add(int a, int b);int subtract(int a , int b);int main(int argc, char *argv[]) { printf( "%d\n" ,add(5,3)); printf( "%d\n" ,subtract(5,3)); return 0; } 要像剛才隱式載入一樣的去做,才能運行成功
(四)顯示載入DLL
上面使用的都是隱式載入DLL的方法,對動態連結程式庫的訪問還可以使用顯示載入方式:完全由編程者用API函數載入和卸載DLL,程式員可以決定 DLL 檔案何時載入或不載入,顯式連結在運行時決定載入哪個DLL檔案
第一步還是建立DllTest工程,產生.lib .dll檔案, 第二步建立工程Test(我們隨便建一個win32 console Application),代碼如下:
//Test.cpp#include <stdio.h>#include <Windows.h>typedef int (*ADDPROC)(int ,int );//定義函數指標類型int main(int argc,char *argv[]){ HINSTANCE hInst; ADDPROC Add; hInst=LoadLibrary("..\\DllTest\\Debug\\DllTest.dll"); //動態載入DLL if(hInst!=NULL) { Add=(ADDPROC)GetProcAddress(hInst,"add");//擷取DLL的匯出函數 if(Add!=NULL) { int result=Add(5,3); printf("%d\n",result); } FreeLibrary(hInst); } return 0;}