VS2012 建立和使用DLL
阿新 • • 發佈:2019-01-27
1.為什麼使用DLL?
我們知道提高開發效率的一個很重要的途徑就是程式碼複用,我們經常將一些常用的功能構造成相對獨立的模組,並在之後的專案重複使用,程式碼複用的方式有兩種:
- 白盒複用:如ATL、MFC等,它們都以原始碼的形式釋出,原始碼完全暴露給了程式設計師。
- 黑盒複用:如Dll,靜態連結,com元件等。與白盒複用相比,dll黑盒複用的優勢就很明顯,dll是二進位制檔案,
2.如何建立一個DLL專案?
用vs2012建立一個新的Win32 應用控制檯程式,名字取為math,要勾選dll選項。如圖:
然後新建mymath.h和mymath.cpp檔案。
mymath.h如下:
#pragma once #ifdef MATH_EXPORTS #define MATH_API __declspec(dllexport) #else #define MATH_API __declspec(dllimport) #endif namespace shun { class MATH_API Cmath { //類 public: int add(int a,int b); }; extern "C" MATH_API float pi; //變數 extern "C" MATH_API int getMax(int &,int &); //函式 }
mymath.cpp如下:
#include "stdafx.h"
#include "mymath.h"
namespace shun
{
float pi=3.1415; //變數
int getMax(int& a, int& b) //函式
{
return a > b ? a : b;
}
int Cmath::add(int a,int b) //類方法
{
return a + b;
}
}
然後生成解決方案,編譯成功後可以在debug資料夾下發現math.dll和math.lib檔案。
至此,我們已經成功建立一個dll專案了。
3.如何隱式引用 一個DLL專案?
隱式呼叫三要素,.h檔案 ,.dll檔案,.lib檔案,缺一不可。隱式呼叫的好處是可以像呼叫本地函式一樣方便。
3.1如果專案和dll專案在同一個解決方案
為此我們新建一個win32控制檯的空專案,取名useMath,然後引用dll步驟如下:- 專案->屬性->通用屬性->框架和引用->新增新引用->勾選math專案->確定
- 專案->屬性->配置屬性->VC++目錄->包含目錄->新增mymath.h所在的目錄
然後新增一個test.cpp檔案,輸入如下:
#include <iostream>
#include "mymath.h"
using namespace std;
int main(char argc, char**argv)
{
int a = 1, b = 2;
//類的使用
shun::Cmath cm;
cout<<cm.add(1,2)<<endl;
//變數
cout<<shun::pi<<endl;
//函式
cout<<shun::getMax(a,b);
getchar();
return 0;
}
執行一下我們發現呼叫dll專案了有木有。。3.2如果專案和dll專案不在同一個解決方案呢?
為此,我們先開啟一個新的vs2012,新建一個win32控制檯的空專案,取名useMath,然後引用dll步驟如下:- 專案->屬性->配置屬性->VC++ 目錄-> 在“包含目錄”裡新增標頭檔案mymath.h所在的目錄
- 專案->屬性->配置屬性->VC++ 目錄-> 在“庫目錄”裡新增標頭檔案math.lib所在的目錄
- 專案->屬性->配置屬性->連結器->輸入-> 在“附加依賴項”裡新增“math.lib”(若有多個 lib 則以空格隔開)
- 將dll專案下的debug檔案中的math.dll複製到當前專案的debug資料夾中
#include <iostream>
#include "mymath.h"
using namespace std;
int main(char argc, char**argv)
{
int a = 1, b = 2;
//類的使用
shun::Cmath cm;
cout<<cm.add(1,2)<<endl;
//變數
cout<<shun::pi<<endl;
//函式
cout<<shun::getMax(a,b);
getchar();
return 0;
}
4.如何顯示呼叫dll專案?
顯示呼叫只需要一個dll檔案。顯示呼叫好處是模組相對獨立,更新非常方便。不好的地方是使用起來稍微複雜。同之前一樣,我們新建一個win32控制檯專案,然後將math.dll放入debug資料夾中,
因為需要使用到windows api,所以要引入windows.h標頭檔案。
新增test.cpp如下:
#include <windows.h>
#include <iostream>
using namespace std;
typedef int (*Func)(int &, int &);
int main(int argc, char *argv[])
{
int a = 5, b = 10;
HMODULE hDll = LoadLibrary("math.dll");
if (hDll != NULL)
{
Func getMax = (Func)GetProcAddress(hDll, "getMax"); //函式
if (getMax != NULL)
{
cout<<getMax(a, b)<<endl;
}
float* pPi = (float*)GetProcAddress(hDll,"pi"); //變數
if(pPi != NULL)
{
cout<<*pPi<<endl;
}
FreeLibrary(hDll);
}
getchar();
}
如果對於函式指標不太熟悉的話可以點這裡:
如果要顯示呼叫類的方法的話,可以在dll中寫一個函式,由這個函式去呼叫,比如像這樣子:.
//.h檔案
extern "C" MATH_API int add_Interface(int &,int &); //函式
//.cpp檔案
int add_Interface(int &a,int &b)
{
Cmath cm;
return cm.add(a,b);
}
然後像上面呼叫函式一樣呼叫add_Interface。
5.extern "C"作用
我們知道,extern可以置於變數或者函式前,以標示變數或者函式的定義在別的檔案中,提示編譯器遇到此變數和函式時在其他模組中尋找其定義。
C++語言在編譯的時候為了解決函式的多型問題,會將函式名和引數聯合起來生成一箇中間的函式名稱。比如:
void foo( int x, int y );
該函式被C編譯器編譯後在符號庫中的名字為_foo,而C++編譯器則會產生像_foo_int_int之類的名字(不同的編譯器可能生成的名字不同)。所以我們可以在函式前使用extern "C"來告訴編譯器要採用c編譯的方式,而不是c++編譯的方式。