一 Windows庫
1引入庫的原因:
a.項目的復(fù)雜程度大
b.提高代碼的利益利用率
2庫的分類
2.1靜態(tài)庫: *.lib,,不能被加載的程序,,可以理解為目標(biāo)程序的歸檔,。
2.2動態(tài)庫:*.dll,,可以被應(yīng)用程序加載的程序,。
二 動態(tài)庫
1動態(tài)庫優(yōu)點
1.1可以提供模塊化的方式,方便協(xié)調(diào)開發(fā)(對于大項目,,每個人寫的東西編譯為動態(tài)庫,,直接鏈接即可)
1.2對源代碼保護
1.3減小可執(zhí)行文件大小
1.4提高代碼重用率
2動態(tài)庫的基本使用方法
2.1動態(tài)庫的創(chuàng)建
2.2加載動態(tài)庫
2.3獲取并使用庫函數(shù)、變量或類
2.4釋放動態(tài)庫
3動態(tài)庫的函數(shù)
3.1動態(tài)庫的創(chuàng)建
3.1.1創(chuàng)建DLL項目
創(chuàng)建Win32Dll項目,,創(chuàng)建DLL項目,添加*.cpp文件,。
3.1.2增加動態(tài)庫函數(shù)
3.1.3導(dǎo)出動態(tài)庫函數(shù)(告訴使用者動態(tài)庫中可提供的函數(shù),代碼示例如上)
(1)使用__declspec(dllexport)方式,在函數(shù)前增加關(guān)鍵字,。舉例如下:
- __declspec(dllexport) intDll_Add(intnLeft,intnRight){
-
- return(nLeft + nRight);
-
- }//C++方式導(dǎo)出
(2)增加extern
“C”方式,舉例如下
- extern"C" __declspec(dllexport)// 以C語言方式導(dǎo)出函數(shù)
(3)使用def方式導(dǎo)出(在項目中添加*.def文件)
//*.def文件中信息
LIBRARY dllfunc.dll //導(dǎo)出庫
EXPORTS //導(dǎo)出表
Dll_Mul @1 //導(dǎo)出函數(shù)
Dll_Div @2
(VC6中def導(dǎo)出方式與 extern “C”導(dǎo)出方式導(dǎo)出.lib文件內(nèi)容基本相同,,可用于顯式鏈接)
動態(tài)庫導(dǎo)出函數(shù)代碼示例如下:
- #include<Windows.h>
- #include <iostream>
-
- using namespace std;
-
- BOOL WINAPI DllMain(//返回值代表是否記載成功
- HINSTANCE hinstDll,//DLL句柄
- DWORD fdwReason,//DLL被調(diào)用的原因
- LPVOID lpvReserved)//保留值
- {
- cout << "DLL = " << hinstDll << endl;
- cout << "fdwReason = " << fdwReason << endl;
- return TRUE;
- }
-
-
-
- //C++導(dǎo)出方式
- extern "C" __declspec (dllexport) int Dll_Add(int nLeft, int nRight)
- {
- return (nLeft + nRight);
- }
-
-
- //C的導(dǎo)出方式
- extern "C"__declspec (dllexport) int Dll_Sub(int nLeft, int nRight)
- {
- return (nLeft - nRight);
- }
-
- //DEF導(dǎo)出方式
-
- int Dll_Mul(int nLeft, int nRight)
- {
- return (nLeft * nRight);
- }
3.2 使用
3.2.1隱式鏈接
(1)導(dǎo)入lib
a.在項目屬性->鏈接器->輸入->附加依賴項中設(shè)置即可。
b.使用#pragma導(dǎo)入,,舉例如下:
- #pragma comment (lib,"../lib/Dll_Func.lib")
(2)
定義函數(shù)原型
聲明一個和導(dǎo)出函數(shù)一致的函數(shù)原型,,如下所示:
- #pragma comment (lib,"../lib/Dll_Func.lib")
-
- extern "C" int Dll_Add(int nLeft, int nRight);
- extern "C" int Dll_Sub(int nLeft, int nRight);
(3)
使用函數(shù)(注意:生成.dll文件最好與調(diào)用其的.exe文件在同一個目錄)
直接使用函數(shù)即可,示例代碼如下:
- #include <cstdio>
-
- #pragma comment (lib,"../lib/Dll_Func.lib")
-
- extern "C" int Dll_Add(int nLeft, int nRight);
- extern "C" int Dll_Sub(int nLeft, int nRight);
- int Dll_Mul(int nLeft, int nRight);
- int main()
- {
- int nAdd = Dll_Add(100, 100);
- int nSub = Dll_Sub(100, 100);
- int nMul = 0;//Dll_Mul(100, 100);
- printf("nAdd = %d\n", nAdd);
- printf("nSub = %d \n", nSub);
- printf("nMul = %d \n", nMul);
- return 0;
- }
(4) 應(yīng)用程序查找Dll路徑(最好將要調(diào)用的動態(tài)庫與調(diào)用動態(tài)庫的.exe文件放在同一目錄下)
A查找當(dāng)前應(yīng)用程序的目錄
B當(dāng)前工作目錄
C查找Windows System32目錄
D查找Windows System的目錄
E查找Windows目錄
F查找環(huán)境變量Path指定的目錄
3.2.2顯式鏈接
(1)加載動態(tài)庫
- LoadLibraryW(
- LPCSTR lpLibFileName //DLL文件路徑
- );
(2)
定義函數(shù)原型對應(yīng)的函數(shù)指針
(3)獲取函數(shù)地址
- FARPROC GetProcAddress(//返回對應(yīng)函數(shù)地址
-
- HMODULE hModule, // DLL句柄
-
- LPCSTR lpProcName);//函數(shù)名稱
注意: a.__declspec(dllexport)導(dǎo)出的函數(shù)由于函數(shù)名稱發(fā)生變化,,所以無法使用函數(shù)名稱獲取對應(yīng)函
數(shù)地址,所以盡量采用隱式鏈接的方式,。
b. extern “C”__declspec(dllexport)方式導(dǎo)出的函數(shù)可以正常使用函數(shù)名稱獲取函數(shù)地址。
c.使用def導(dǎo)出方式在VC6.0下可使用顯示鏈接(本人在VS2013中對def導(dǎo)出方式導(dǎo)出動態(tài)庫未成功使
用,,希望哪位大神可以指點迷津)
(4)使用函數(shù)
(5)釋放動態(tài)庫
顯式鏈接示例代碼如下:
- #include <iostream>
- #include <Windows.h> /
- #include <tchar.h>
-
- using namespace std;
-
- typedef int(*DLL_ADD)(int nLeft, int nRight);
- typedef int(*DLL_SUB)(int nLeft, int nRight);
- typedef int(*DLL_MUL)(int nLeft, int nRight);
-
- void useDll()
- {
- HMODULE hDll = LoadLibrary(_T("Dll_Func.dll"));
- if (nullptr == hDll)
- {
- cout << "Load Failed!" << endl;
- return;
- }
- //定義函數(shù)指針
- DLL_ADD Dll_Add = nullptr;
- DLL_SUB Dll_Sub = nullptr;
- DLL_MUL Dll_Mul = nullptr;
-
- //獲取函數(shù)地址
-
- Dll_Add = (DLL_ADD)GetProcAddress(hDll, "Dll_Add");
- if (nullptr == Dll_Add)
- {
- cout << "Get Dll_Add Failed!" << endl;
- }
- cout << Dll_Add << endl;
- Dll_Sub = (DLL_SUB)GetProcAddress(hDll, "Dll_Sub");
- if (nullptr == Dll_Sub)
- {
- cout << "Get Dll_Sub Failed!" << endl;
- }
- cout << Dll_Sub << endl;
- Dll_Mul = (DLL_MUL)GetProcAddress(hDll, "Dll_Mul");
- if (nullptr == Dll_Mul)
- {
- cout << "Get Dll_Mul Failed!" << endl;
- }
- cout << Dll_Mul << endl;
-
- //使用函數(shù)
- int nSub = Dll_Sub(100, 100);
- int nAdd = Dll_Add(100, 100);
- cout << "Add = " << nAdd << endl;
- cout << "Sub = " << nSub << endl;
-
-
- //釋放動態(tài)庫
- FreeLibrary(hDll);
- }
-
- int main()
- {
- useDll();
- return 0;
- }
4.動態(tài)庫中的變量
4.1定義全局變量
4.2導(dǎo)出全局變量
4.2.1 __declspec(dllexport)導(dǎo)出
4.2.2 DEF導(dǎo)出
Int g_nValue1 = 100;
在DEF文件中到處列表增加 g_nValue1 @1 DATA
4.3導(dǎo)入LIB文件
4.4聲明導(dǎo)入變量
需要使用__declspec(dllimport)聲明變量,,舉例如下:
extern__declspec(dllimport)int
g_nValuel;
4.5使用變量
動態(tài)庫變量使用代碼示例如下:
- #include <iostream>
-
- using namespace std;
- #pragma comment(lib,"../lib/DllValue.lib")
-
- //聲明DLL導(dǎo)入變量
- extern __declspec(dllimport) int g_nValue1;//動態(tài)庫導(dǎo)出文件中有此全局變量,在此再次聲明此變量原型
-
- int main()
- {
- cout << "g_nValue1 = " << g_nValue1 << endl;
- return 0;
- }
5動態(tài)庫的類導(dǎo)出
5.1創(chuàng)建靜態(tài)庫并定義類
5.2導(dǎo)出類
在類名稱前__declspec(dllexport)定義:
class__declspec(dllexport)Math
{……}
導(dǎo)出類示例代碼如下:
- //**.h文件
- #ifndef _MATH_H_
- #define _MATH_H_
-
- //定義類導(dǎo)入導(dǎo)出宏,,
- #ifdef _DLLCLASS_DLL__
- #define DLLCLASS_EXT __declspec(dllexport)
- #else
- #define DLLCLASS_EXT __declspec(dllimport)
- #endif //_DLLCLASS_DLL_
-
- //增加類的導(dǎo)入 導(dǎo)出符號
- class DLLCLASS_EXT Math
- {
- public:
-
- Math()
- {
- }
-
- virtual ~Math()
- {
- }
-
- int Add(int nLeft, int nRight);
- int Sub(int nLeft, int nRight);
- };
-
- #endif
- //**.cpp文件
- #include "Math.h"
-
-
- int Math::Add(int nLeft, int nRight)
- {
- return (nLeft + nRight);
- }
- int Math::Sub(int nLeft, int nRight)
- {
- return (nLeft - nRight);
- }
5.3使用時導(dǎo)入LIB文件
5.4導(dǎo)入類
5.5使用類
5.6關(guān)于類的導(dǎo)入和導(dǎo)出
5.6.1定義一個宏,,舉例如下(避免多次編寫類頭文件,使之可在導(dǎo)出,、導(dǎo)入時使用同一個頭文件):
- #ifdef_DLLCLASS_DLL__
-
- #defineDLLCLASS_EXT __declspec(dllexport)
-
- #else
-
- #define DLLCLASS_EXT __declspec(dllimport)
-
- #endif//_DLLCLASS_DLL_
5.6.2 根據(jù)編譯項目修改_DLLCLASS_DLL__宏聲明,,對于導(dǎo)出類,需定義_DLLCLASS_DLL__,,否則,,不需要定義
_DLLCLASS_DLL__,。
在導(dǎo)出類時,項目設(shè)置如下(即定義_DLLCLASS_DLL__宏):
6 DllMain函數(shù)(用于變量初始化等操作,。使用可參照3.1.3 (3)中示例代碼)
Dll文件的入口函數(shù),,當(dāng)程序加載或者釋放動態(tài)庫的時候,會自動調(diào)用此函數(shù)
BOOL WINAPIDllMain(//返回值代表是否加載成功
HINSTANCE hinstDll;//DLL句柄
DWORD fdwReason;//DLL被調(diào)用的原因
LPVOID lpvReserved;)//保留值
FdwReason –
DLL_PROCESS_ATTACH 進程加載
DLL_THREAD_ATTACH 線程加載
DLL_PROCESS_DETACH 進程卸載
DLL_THREAD_DETACH 線程卸載
使用導(dǎo)出類代碼示例如下:
- #include <iostream>
- #include "..\DllClass\Math.h"
- using namespace std;
-
- #pragma comment(lib,"../lib/DllClass.lib")
-
- int main(int argc, char *argv[])
- {
- Math math;
- int add = math.Add(100,100);
- int sub = math.Sub(100,100);
- cout << "Add = " << add << endl;
- cout << "Sub = " << sub << endl;
- return 0;
- }
|