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