C++ 調用.lib的方法:
一: 隱式的加載時鏈接,有兩種方法
1 設置工程的 Projects來加載DLL的lib文件
打開工程的 Projects菜單,然后在Linker/Additional Library Directories中加入lib文件所在的路徑,在Input/Additional Dependencies加入lib文件名稱,如(my.lib) ,然后在要使用該函數的地方加上該LIB的頭文件,如#include "..\lib.h"即可(沒有頭文件當然就不用了),而且應用程序運行時也需要dll文件。
2 通過程序代碼的方式
加入預編譯指令#pragma comment (lib,"*.lib"),這種方法優點是可以利用條件預編譯指令鏈接不同版本的LIB文件。因為,在Debug方式下,產生的LIB文件是Debug版本,如Regd.lib;在Release方式下,產生的LIB文件是Release版本,如Regr.lib。然后在首先要使用該函數的地方加上該LIB的頭文件,如#include "..\lib.h"即可(沒有頭文件當然就不用了)。
當應用程序對鏈接庫的LIB文件加載后,還需要把鏈接庫對應的頭文件(*.h)包含到其中,在這個頭文件中給出了鏈接庫中定義的函數原型。
具體步驟如下:
步驟一:建一個 win32解決方案,主工程(就是還有 main函數的)那個我就不說
了),DLL工程最后一步的Application type選中Dll:
步驟二:在 DLL工程中添加兩個文件: clsDLL.h, clsDLL.cpp
//clsDLL.h
#pragmaonce
#ifndef DLLEXPT
#defineDLLEXPT __declspec (dllexport)
#endif
classDLLEXPT myCls
{
public:
void test();
};
// classDLL.cpp : Defines the exported functions for the DLLapplication.
//
#include"clsDLL.h"
#include
#ifndef DLLEXPT
#defineDLLEXPT __declspec (dllexport)
#endif
voidmyCls::test()
{
printf("we are testing my program!/n");
}
步驟三:在主工程中的 main.cpp文件中,
添加#include"..//clsDLL/clsDLL.h" ,就是 include上面 DLL中頭文件。
步驟四:在主工程中的main.cpp文件中,
添加#pragma comment (lib , "..//Debug//clsDLL.lib"), 實現隱式連接。
步驟五:接下來就和使用一般 C++類沒有區別了。
Main.cpp文件內容如下:
#include
#include"..//clsDLL/clsDLL.h"
#pragmacomment(lib ,"..//Debug//clsDLL.lib")
voidmain()
{
myCls c;
c.test();
}
二, 顯式的調用鏈接庫
隱式鏈接雖然實現較簡單,但除了必須的*.dll文件外還需要DLL的*.h文件和*.lib文件,在那些只提供*.dll文件的場合就無法使用,而只能采用顯式鏈接的方式。這種方式通過調用API函數來完成對DLL的加載與卸載,能更加有效地使用內存,在編寫大型應用程序時往往采用此方式。這種方法編程具體實現步驟如下:
①使用Windows API函數Load Library或者MFC提供的AfxLoadLibrary將DLL模塊映像到進程的內存空間,對DLL模塊進行動態加載。
②使用GetProcAddress函數得到要調用DLL中的函數的指針。
③不用DLL時,用Free Library函數或者AfxFreeLibrary函數從進程的地址空間顯式卸載DLL。
例:在應用程序中調用dll文件
——在應用程序中要首先裝入dll后才能調用導出表中的函數,例如用mfc
創建基於對話框的工程test,並在對話框上放置"load"按鈕,先添加裝載代碼。
1.首先在testdlg.cpp的首部添加變量設置代碼:
//設置全局變量glibsample用於存儲dll句柄
HINSTANCE glibsample=null; //如果定義成HANDLE類型,則出錯
//第二個變量showme是指向dll
庫中showme()函數的指針
typedef int(* Showme)(void);
Showme showme;
2.利用classwizard為"load"按鈕添加裝載dll的代碼
void ctestdlg::onloadbutton()
{
//要添加的代碼如下
if(glibsample!=NULL)
{
AfxMessageBox("the sample.dll has already been load.");
return;
}
//裝載sample.dll,未加路徑,將在三個默認路徑中尋找 (1)windows的系統目錄:\windows\system;
//(2)dos中path所指出的任何目錄;
//(3)程序所在的目錄;
glibsample=Loadlibrary("sample.dll");
//返回dll中showme()函數的地址
showme=(Showme)GetProcAddress(glibsample,"showme");
包含頭文件Windows.h,原因在於程序中用到了LoadLibrary、FreeLibrary、GetProcAddress等Win32 API函數。
FUNA和FUNB是函數指針類型的聲明。
當程序不再使用dll時,應該調用FreeLibrary及時釋放它占用的內存空間。
如果在const char* dllName和funName底部出現紅色波浪線提示,說明采用的字符集不匹配,需要修改項目UseDLL的屬性CharaterSet為Not Set。
為方便項目的調試,建議修改解決方案的Startup Project屬性為Single startup project並以UseDLL為首選。
動態鏈接庫雖然一定程度上實現了“黑盒復用”,但仍存在着諸多不足,筆者能夠想到的有下面幾點。
1)dll節省了編譯期的時間,但相應延長了運行期的時間,因為在使用dll的導出函數時,不但要加載dll,而且程序將會在模塊間跳轉,
2)降低了cache的命中率。
3)若采用隱式調用,仍然需要.h、.lib、.dll文件(“三件套”),並不能有效支持模塊的更新。
顯式調用雖然很好地支持模塊的更新,但卻不能導出類和變量。
4)dll不支持Template。
1.什么是靜態連接庫,什么是動態鏈接庫
靜態鏈接庫與動態鏈接庫都是共享代碼的方式,如果采用靜態鏈接庫,則無論你願不願意,lib 中的指令都全部被直接包含在最終生成的 EXE 文件中了。但是若使用 DLL,該 DLL 不必被包含在最終 EXE 文件中,EXE 文件執行時可以“動態”地引用和卸載這個與 EXE 獨立的 DLL 文件。靜態鏈接庫和動態鏈接庫的另外一個區別在於靜態鏈接庫中不能再包含其他的動態鏈接庫或者靜態庫,而在動態鏈接庫中還可以再包含其他的動態或靜態鏈接 庫。靜態鏈接庫與靜態鏈接庫調用規則總體比較如下。
對於靜態鏈接庫(比較簡單):
首先,靜態鏈接庫的使用需要庫的開發者提供生成庫的.h頭文件和.lib文件,應用程序運行時還依賴.dll文件。
生成庫的.h頭文件中的聲明格式如下:
extern "C" 函數返回類型 函數名(參數表);
在調用程序的.cpp源代碼文件中如下:
#include "..\lib.h"
#pragma comment(lib,"..\\debug\\libTest.lib")
//指定與靜態庫一起鏈接
第二,因為靜態鏈接庫是將全部指令都包含入調用程序生成的EXE文件中。因此如果用的是靜態鏈接庫,那么也就不存在“導出某個函數提供給用戶使用”的情況,要想用就得全要!要不就都別要!:)
對於動態鏈接庫:
動態鏈接庫的使用需要庫的開發者提供生成的.lib文件,.dll文件和*.h文件或者只提供dll和*.h文件。
*.h文件主要是知道函數原型使用。
首先我們必須先注意到DLL內的函數分為兩種:
(1)DLL 導出函數,可供應用程序調用;
(2)DLL 內部函數,只能在 DLL 程序使用,應用程序無法調用它們。
因此調用程序若想調用DLL中的某個函數就要以某種形式或方式指明它到底想調用哪一個函數。
