前幾天有個(gè)朋友問(wèn)道這個(gè)問(wèn)題,結(jié)果因?yàn)橐郧皬臎](méi)搞過(guò)這個(gè),對(duì)vs2005也不熟悉,竟花了2個(gè)小時(shí)才搞定,
。
特地拿來(lái)與大家分享,希望能給像我這樣的菜鳥(niǎo)們一些幫助,O(∩_∩)O
【第一步】創(chuàng)建自己的dll
1.打開(kāi)vs2005,選擇菜單【File-New-Project】,在彈出對(duì)話(huà)框中選擇[Visual C++]下的[Win32]-[Win32 Console Application],輸入工程名后確認(rèn)。
2.在彈出的對(duì)話(huà)框中選擇[next],在Application Settiongs中選擇Application type為Dll,Additional options選擇Empty project,然后點(diǎn)Finish。
這時(shí)就創(chuàng)建了一個(gè)空的可以生成dll文件的工程。
3.在工程中添加一個(gè)頭文件(這里為dll_test.h),在頭文件中寫(xiě)入如下內(nèi)容:
1 #ifndef _DLL_TUTORIAL_H
2 #define _DLL-TUTORIAL_H
3
4 #include<iostream>
5
6 #if defined DLL_EXPORT
7 #define DECLDIR _declspec(dllexport)
8 #else
9 #define DECLDIR _declspec(dllimport)
10 #endif
11
12 extern "C"
13 {
14 DECLDIR int Add(int a, int b);
15 DECLDIR void Function(void);
16 }
17
18 #endif
這里要說(shuō)明的是:
在VC中有兩個(gè)方法來(lái)導(dǎo)出dll中定義的函數(shù):
(1) 使用__declspec,這是一個(gè)Microsoft定義的關(guān)鍵字。
(2) 創(chuàng)建一個(gè)模板定義文件(Module-Definition File,即.DEF)。
第一種方法稍稍比第二種方法簡(jiǎn)單,在這里我們使用的是第一種方法。
__declspec(dllexport)函數(shù)的作用是導(dǎo)出函數(shù)符號(hào)到在你的Dll中的一個(gè)存儲(chǔ)類(lèi)里去。
當(dāng)下面一行被定義時(shí)我定義DECLDIR宏來(lái)運(yùn)行這個(gè)函數(shù)。
#define DLL_EXPORT
在此情況下你將導(dǎo)出函數(shù)Add(int a,int b)和Function().
4.創(chuàng)建一個(gè)源文件(名字為dll_test.cpp),內(nèi)容如下:
1 #include <iostream>
2 #define DLL_EXPORT
3 #include "dll_test.h"
4
5 extern "C"
6 {
7 // 定義了(DLL中的)所有函數(shù)
8 DECLDIR int Add( int a, int b )
9 {
10 return( a + b );
11 }
12
13 DECLDIR void Function( void )
14 {
15 std::cout << "DLL Called!" << std::endl;
16 }
17 }
18
【第二步】使用創(chuàng)建好的DLL
現(xiàn)在已經(jīng)創(chuàng)建了DLL,那么如何在一個(gè)應(yīng)用程序中使用它呢?
當(dāng)DLL被生成后,它創(chuàng)建了一個(gè).dll文件和一個(gè).lib,這兩個(gè)都是使用dll時(shí)需要用到的。
在具體介紹之前先看一下dll的鏈接方式。
(1)隱式連接
這里有兩個(gè)方法來(lái)載入一個(gè)DLL,一個(gè)方法是只鏈接到.lib文件,并將.dll文件放到要使用這個(gè)DLL的項(xiàng)目路徑中。
因此,創(chuàng)建一個(gè)新的空的Win32控制臺(tái)項(xiàng)目并添加一個(gè)源文件。將我們創(chuàng)建好的DLL放入與新項(xiàng)目相同的目錄下。同時(shí)我們還必須鏈接到dll_test.lib文件。
可以在項(xiàng)目屬性中設(shè)置,也可以在源程序中用下面的語(yǔ)句來(lái)鏈接:
#pragma comment(lib, "dll_test.lib")
最后,我們還要在新的win32控制臺(tái)項(xiàng)目中包含前面的dll_test.h頭文件。可以把這個(gè)頭文件放到新建win32控制臺(tái)項(xiàng)目的目錄中然后在程序中加入語(yǔ)句:
#include "dll_test.h"
新項(xiàng)目代碼如下:
#include<iostream>
#include "DLLTutorial.h"
int main()
{
Function();
std::cout<< Add(32, 56)<< endl;
return 0;
}
(2)顯示鏈接
稍微復(fù)雜一點(diǎn)的加載DLL的方法需要用到函數(shù)指針和一些Windows函數(shù)。但是,通過(guò)這種載入DLL的方法,不需要DLL的.lib文件或頭文件,而只需要DLL即可。
下面列出一些代碼:
/****************************************************************/
#include <iostream>
#include <windows.h>
typedef int (*AddFunc)(int,int);
typedef void (*FunctionFunc)();
int main()
{
AddFunc _AddFunc;
FunctionFunc _FunctionFunc;
HINSTANCE hInstLibrary = LoadLibrary("DLL_Tutorial.dll");
if (hInstLibrary == NULL)
{
FreeLibrary(hInstLibrary);
}
_AddFunc = (AddFunc)GetProcAddress(hInstLibrary, "Add");
_FunctionFunc = (FunctionFunc)GetProcAddress(hInstLibrary, "Function");
if ((_AddFunc == NULL) || (_FunctionFunc == NULL))
{
FreeLibrary(hInstLibrary);
}
std::cout << _AddFunc(23, 43) << std::endl;
_FunctionFunc();
std::cin.get();
FreeLibrary(hInstLibrary);
return(1);
}
/*******************************************************************/
首先可以看到,這里包括進(jìn)了windows.h頭文件,同時(shí)去掉了對(duì)dll_test.h頭文件的包含。原因很簡(jiǎn)單:因?yàn)閣indows.h包含了一些Windows函數(shù),
它也包含了一些將會(huì)用到的Windows特定變量。可以去掉DLL的頭文件,因?yàn)楫?dāng)使用這個(gè)方法載入DLL時(shí)并不需要其頭文件。
下面你會(huì)看到:以下面形式的一小塊古靈精怪的代碼:
typedef int (*AddFunc)(int,int);
typedef void (*FunctionFunc)();
這是函數(shù)指針。因?yàn)檫@是一個(gè)關(guān)于DLL的自學(xué)指南,深入探究函數(shù)指針超出了本指南的范圍;因此,現(xiàn)在我們只把它們當(dāng)作DLL包含的函數(shù)的別名。
我喜歡在尾部用“Func”命名之。(int,int)部分是這個(gè)函數(shù)的參數(shù)部分,比如,Add函數(shù)要獲得兩個(gè)整數(shù);因此,你需要它們
(譯注:指(int,int)部分)作為函數(shù)指針的參數(shù)。Function函數(shù)沒(méi)有參數(shù),因此你讓它為空。main()部分中的前面兩行是聲明函數(shù)指針以使得你可
以認(rèn)為它們等同于DLL內(nèi)部的函數(shù)。我只是喜歡預(yù)先定義它們。
一個(gè)HINSTANCE是一個(gè)Windows數(shù)據(jù)類(lèi)型:是一個(gè)實(shí)例的句柄;在此情況下,這個(gè)實(shí)例將是這個(gè)DLL。你可以通過(guò)使用函數(shù)LoadLibrary()獲得DLL的
實(shí)例,它獲得一個(gè)名稱(chēng)作為參數(shù)。
在調(diào)用LoadLibrary函數(shù)后,你必需查看一下函數(shù)返回是否成功。你可以通過(guò)檢查HINSTANCE是否等于NULL(在Windows.h中定義為0或Windows.h包
含的一個(gè)頭文件)來(lái)查看其是否成功。如果其等于NULL,該句柄將是無(wú)效的,并且你必需釋放這個(gè)庫(kù)。換句話(huà)說(shuō),你必需釋放DLL獲得的內(nèi)存。
如果函數(shù)返回成功,你的HINSTANCE就包含了指向DLL的句柄。一旦你獲得了指向DLL的句柄,你現(xiàn)在可以從DLL中重新獲得函數(shù)。
為了這樣作,你必須使用函數(shù)GetProcAddress(),它將DLL的句柄(你可以使用HINSTANCE)和函數(shù)的名稱(chēng)作為參數(shù)。你可以讓函數(shù)指針獲得由
GetProcAddress()返回的值,同時(shí)你必需將GetProcAddress()轉(zhuǎn)換為那個(gè)函數(shù)定義的函數(shù)指針。舉個(gè)例子,對(duì)于Add()函數(shù),你必需將GetProcAddress()
轉(zhuǎn)換為AddFunc;這就是它知道參數(shù)及返回值的原因。現(xiàn)在,最好先確定函數(shù)指針是否等于NULL以及它們擁有DLL的函數(shù)。
這只是一個(gè)簡(jiǎn)單的if語(yǔ)句;如果其中一個(gè)等于NULL,你必需如前所述釋放庫(kù)。一旦函數(shù)指針擁有DLL的函數(shù),你現(xiàn)在就可以使用它們了,但是這里有一個(gè)
需要注意的地方:你不能使用函數(shù)的實(shí)際名稱(chēng);你必需使用函數(shù)指針來(lái)調(diào)用它們。在那以后,所有你需要做的是釋放庫(kù)如此而已。
現(xiàn)在你知道了DLL的一些基本知識(shí)。你知道如何創(chuàng)建它們,你也知道如何用兩種不同的方法鏈接它們。這里仍然有更多的東西需要我們學(xué)習(xí),但我把它們留給你們自己探索了和更棒的作者來(lái)寫(xiě)了。