VS 2015 DLL的建立、靜態呼叫和動態呼叫
DLL的建立
建立步驟
檔案 -> 新建 -> 專案 -> “新建專案”對話方塊 -> “已安裝” -> 模板 -> 其他語言 -> Vistual C++ -> Win32 控制檯應用程式。
在”Win32 應用程式嚮導”對話方塊中
- “控制檯程式型別”選擇”DLL(D)”
- “附加選項”勾選”匯出符號(X)”
匯入(匯出)標記的巨集定義
下列 ifdef 塊是建立使從 DLL 匯出更簡單的巨集的標準方法。此 DLL 中的所有檔案都是用命令列上定義的DLLDEMO_EXPORTS符號編譯的。在使用此 DLL 的任何其他專案上不應定義此符號。這樣,原始檔中包含此檔案的任何其他專案都會將DLLDEMO_API 函式視為是從 DLL 匯入的,而此 DLL 則將用此巨集定義的符號視為是被匯出的。
#ifdef DLLDEMO_EXPORTS
#define DLLDEMO_API __declspec(dllexport)
#else
#define DLLDEMO_API __declspec(dllimport)
#endif
匯出符號標識的巨集定義位於:解決方案資源管理器 -> 專案屬性 -> “專案屬性頁”對話方塊 -> “配置屬性” -> C/C++ -> 前處理器 -> 前處理器定義
修改DLL專案
DllDemo.h
#ifdef DLLDEMO_EXPORTS
#define DLLDEMO_API __declspec(dllexport)
#else
#define DLLDEMO_API __declspec(dllimport)
#endif
// 此類是從 DllDemo.dll 匯出的
class DLLDEMO_API CDllDemo {
public:
CDllDemo(void);
// TODO: 在此新增您的方法。
};
extern DLLDEMO_API int nDllDemo;
extern "C" extern DLLDEMO_API int nExternCDllDemo;
DLLDEMO_API int fnDllDemo(void);
extern "C" DLLDEMO_API int fnExternCDllDemo(void);
char DLLDEMO_API fnDefault(char, int, float);
char DLLDEMO_API __stdcall fnstdcall(char, int, float);
char DLLDEMO_API __cdecl fncdecl(char, int, float);
char DLLDEMO_API __fastcall fnfastcall(char, int, float);
dllmain.cpp
// dllmain.cpp : 定義 DLL 應用程式的入口點。
#include "stdafx.h"
#include <stdio.h>
#include <tchar.h>
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
/*
獲取模組檔名,如果是dll的話,獲取的是呼叫它的可執行檔案路徑
WINBASEAPI
_Success_(return != 0)
_Ret_range_(1, nSize)
DWORD WINAPI GetModuleFileNameW(
_In_opt_ HMODULE hModule,
_Out_writes_to_(nSize, ((return < nSize) ? (return + 1) : nSize)) LPWSTR lpFilename,
_In_ DWORD nSize
);
*/
TCHAR lpFilename[MAX_PATH];
DWORD ret = GetModuleFileName(NULL, lpFilename, MAX_PATH);
if (ret) {
_tprintf(_T("GetModuleFileName -> lpFilename=%s\n"), lpFilename);
}
else {
printf("GetModuleFileName -> fail(%ld)", GetLastError());
}
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
printf("DLL_PROCESS_ATTACH\n");
break;
case DLL_THREAD_ATTACH:
printf("DLL_THREAD_ATTACH\n");
break;
case DLL_THREAD_DETACH:
printf("DLL_THREAD_DETACH\n");
break;
case DLL_PROCESS_DETACH:
printf("DLL_PROCESS_DETACH\n");
break;
}
return TRUE;
}
DllDemo.cpp
// DllDemo.cpp : 定義 DLL 應用程式的匯出函式。
#include "stdafx.h"
#include "DllDemo.h"
// 這是匯出變數的一個示例
DLLDEMO_API int nDllDemo = 1;
DLLDEMO_API int nExternCDllDemo = 2;
// 這是匯出函式的一個示例。
DLLDEMO_API int fnDllDemo(void)
{
return 42;
}
DLLDEMO_API int fnExternCDllDemo(void)
{
return 142;
}
char DLLDEMO_API fnDefault(char, int, float)
{
return 'a';
}
char DLLDEMO_API __stdcall fnstdcall(char, int, float)
{
return 'b';
}
char DLLDEMO_API __cdecl fncdecl(char, int, float)
{
return 'c';
}
char DLLDEMO_API __fastcall fnfastcall(char, int, float)
{
return 'd';
}
// 這是已匯出類的建構函式。
// 有關類定義的資訊,請參閱 DllDemo.h
CDllDemo::CDllDemo()
{
return;
}
生成DLL有以下幾種方案
- 解決方案資源管理器 -> “DLL專案”右鍵 -> 生成(U)
- 選單欄 -> 生產DLL(U)(Shift + F6)
然後會在專案的根目錄的Debug或Release資料夾下生成相應的檔案。
dumpbin檢視dll(或lib)的匯出符號
dumpbin.exe 位於 :C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin
檢視編譯後的DLL函式名用到的只是”EXPORTS”引數而已。函式名為name列等號的左側。
可以看到extern “C”修飾的函式名與原函式名一致。原因可以參看《函式過載與Extern “C”》一文: http://blog.csdn.net/chy555chy/article/details/53015808。另外說明一點,使用extern “C”修飾的C++函式不能使用C++的過載特性,因為匯出的函式符號只是原函式名,編譯器沒有將引數型別資訊加到匯出的函式名中,因此無法區分過載函式。
DLL的呼叫
匯入DLL
(1)當”DLL專案”和”可執行專案”屬於同一個解決方案時。在”DLL專案”右鍵”生成”可以在專案的Debug目錄下生成相應的DLL和LIB。然後在”可執行專案”右鍵”設為啟動專案”,然後點選”本地Windows偵錯程式”即可。
靜態呼叫
直接執行會報無法開啟LIB(不加字尾預設是LIB)或DLL
解決方案:在”可執行專案”右鍵 -> 新增(D) -> 引用(R)…
可以看到引用處多了相應的DLL檔案
動態呼叫
如果是動態呼叫,此時可正常執行
(2)如果是外部專案的dll
靜態呼叫(有以下2種方法)
#param comment("lib", "path\\*lib")
中指定其路徑。- 解決方案資源管理器 -> “可執行專案”右鍵”屬性” -> “專案屬性頁”對話方塊 -> 配置屬性 -> “連結器” -> 輸入 -> 附加依賴專案 -> 編輯 -> 輸入lib檔案的完整路徑(而不是lib的檔名)
動態呼叫
LoadLibrary(_T("path\\*.dll"));
中指定其路徑。
DLL呼叫有兩種方式,一種是靜態呼叫,另外一種是動態呼叫
靜態呼叫(同時需要標頭檔案、LIB和DLL檔案,缺一不可)
靜態呼叫是一種顯式的呼叫方式,即在程式設計的時候便知道了被呼叫的DLL中的介面函式,在編譯連結的時候將DLL與工程生成的exe相關聯。
#include "stdafx.h"
#include "../DllDemo/DllDemo.h"
//lib字尾可以省略,但不可以改為dll
#pragma comment(lib, "DllDemo.lib")
int main()
{
printf("%d\n", nDllDemo);
printf("%d\n", fnDllDemo());
printf("%d\n", fnExternCDllDemo());
_tsystem(_T("pause"));
return 0;
}
動態呼叫(僅需要DLL,不需要標頭檔案和LIB)
動態呼叫是一種隱式的呼叫方式,即程式執行過程中裝載DLL,然後獲取指定函式名稱的介面函式,然後再呼叫之。
#include "stdafx.h"
#include <Windows.h>
int main()
{
//參考 http://blog.csdn.net/g5dsk/article/details/6680698
HMODULE hModule = LoadLibrary(_T("DllDemo.dll"));// 雖然 MSDN Library 說這裡如果指定了路徑,要用 backslashes (\),不要用 forward slashes (/),但其實用二者都可以。注:如果用 \,要用 \\。
if (hModule == NULL || hModule == INVALID_HANDLE_VALUE) {
return -1;
}
/*
WINBASEAPI FARPROC WINAPI GetProcAddress(
_In_ HMODULE hModule,
_In_ LPCSTR lpProcName //這個是dump /EXPORT *.dll “name”列等號前的值
);
返回的是函式或變數的地址,即函式指標或指向變數地址的指標
*/
typedef int(*TYPE_fnDllDemo) ();
typedef int(*TYPE_fnExternCDllDemo) ();
int *nDllDemo = (int *)GetProcAddress(hModule, "?nDllDemo@@3HA");
TYPE_fnDllDemo fnDllDemo = (TYPE_fnDllDemo)GetProcAddress(hModule, "?fnDllDemo@@YAHXZ");
int *nExternCDllDemo = (int *)GetProcAddress(hModule, "nExternCDllDemo");
TYPE_fnExternCDllDemo fnExternCDllDemo = (TYPE_fnExternCDllDemo)GetProcAddress(hModule, "fnExternCDllDemo");
if(nDllDemo != NULL)
printf("*nDllDemo = %d\n", *nDllDemo);
if(fnDllDemo != NULL)
printf("fnDllDemo() = %d\n", fnDllDemo());
if (nExternCDllDemo != NULL)
printf("*nExternCDllDemo = %d\n", *nExternCDllDemo);
if(fnExternCDllDemo != NULL)
printf("fnExternCDllDemo() = %d\n", fnExternCDllDemo());
_tsystem(_T("pause"));
return 0;
}
執行截圖
注意:DLL_PROCESS_DETACH是在關閉命令列的時候被呼叫,而不是不會呼叫。這裡被system(“pause”)暫停了,並不是說程式結束。另外即使點選關閉,基本也看不到,因為列印完視窗立馬就被關閉了,這些都是一瞬間完成的。
相關推薦
VS 2015 DLL的建立、靜態呼叫和動態呼叫
DLL的建立 建立步驟 檔案 -> 新建 -> 專案 -> “新建專案”對話方塊 -> “已安裝” -> 模板 -> 其他語言 -> Vistual C++ -> Win32 控制檯應用程式。 在”W
VC中使用動態連結庫DLL:靜態呼叫和動態呼叫
VC中生成DLL的辦法見:www.codeproject.com/KB/DLL/RegDLL.aspx VC中使用DLLhttp://www.cnblogs.com/c1230v/articles/1401448.html 呼叫DLL有兩種方法:靜態呼叫和動態呼叫. (一
8_物件建立、static 關鍵字、靜態變數和成員變數的區別、文件
一、物件建立 Student s = new Student(); 步驟: (1)載入 Student.class 檔案進記憶體; (2)在棧記憶體中為 s 開闢空間; (3)在堆記憶體為學生物件開闢空間; (4)對學生物件的成員變數進行預設初始化; (5)對學生物件的成員變數進行顯示初始化
Dll 模組間(dll, exe)使用匯出變數、靜態變數和外部變數的試驗與結論
DLL檔案(Dynamic Linkable Library 即動態連結庫檔案),是一種不能單獨執行的檔案,它允許程式共享執行特殊任務所必需的程式碼和其他資源 比較大的應用程式都由很多模組組成,這些模組分別完成相對獨立的功能,它們彼此協作來完成整個軟體系統的工作。可能存在一些模組的功能較為通用,在構造其它軟
問題集合 ---- linux 靜態庫和動態庫建立、檢查、使用建議
=================================================================== linux靜態庫和動態庫分析 本文轉自 http://www.linuxeden.com/html/develop/20100326/94297.html
vs2015+opencv生成DLL並分別靜態和動態呼叫
網路上關於vs生成dll的教程很多,解決方案繁雜,令人眼花繚亂,踩坑後推薦幾篇不錯的教程,親自測試可以通過的,我的除錯環境是vs2015 enterprise版+win10+opencv3.4.1。教程1:最簡單的DLL生成與呼叫教程:作者採用了宣告類進行打包的方法來呼叫。教
靜態編譯和動態編譯(lib和dll)
weibo docs p s 獎章 com 動態編譯 lan doc sin u2瓢剮JZP匪媳51http://www.docin.com/app/user/userinfo?userid=179185213 0宰9U拔7853E5噸渭3http://www.docin
Python中的實例方法、類方法、靜態方法和普通方法
turn 屬性和方法 靜態方法 一個 def col == pre 類屬性 為了辨析它們的差別,寫了如下代碼: 1 class C: 2 3 def self_method(self, a): 4 return a 5 6
大型企業網絡構建之動態NAT、靜態NAT和華為NAT
動態NAT、靜態NAT和華為NAT動態NAT、靜態NAT和華為NAT一、NAT概述1、(network address translation )網絡地址轉換。2、NAT的工作過程:NAT設備收到內網的數據包以後,1、首先查看本地是否有去往數據包目地地址的路由;2、再次查看本地設備是否存在對應的nat轉換條目
PHP常見概念混淆(五)之PHP類常量、靜態屬性和屬性的區別
sta 支持 php5 中英文對照 ext static block 簡介 無法 最近在看手冊的時候發現PHP有好些個坑,一不註意就會掉進去,邊看邊將這些容易混淆的內容記載下來。 tips:看手冊的時候最好中英文對照著看,因為英文手冊上有好些個中文手冊沒有的東西(最新的P
詳談Apache、Nginx和tomcat的區別以及處理靜態頁面和動態頁面的方式
請求 php腳本 特點 java類 是你 源碼 proc 總結 愛好者 就目前來說,網站主要分為靜態頁面和動態頁面,純靜態頁面的網站已經比較少見了,大型網站一般使用的是靜態頁面+動態頁面的建站技術,還有一部分網站是純動態頁面。負責處理這些頁面的軟件我們通常稱之為web容器,
靜態連結庫(LIB)和動態連結庫(DLL),DLL的靜態載入和動態載入,兩種LIB檔案。
靜態連結庫(LIB)和動態連結庫(DLL),DLL的靜態載入和動態載入,兩種LIB檔案。 一、 靜態連結庫(LIB,也簡稱“靜態庫”)與動態連結庫(DLL,也簡稱“動態庫”)的區別 靜態連結庫與動態連結庫都是共享程式碼的方式,如果採用靜態連結庫,則無論你願不願意,lib 中的指令都全部被直接包含在最
【轉】Python基礎-封裝與擴充套件、靜態方法和類方法
【轉】Python基礎-封裝與擴充套件、靜態方法和類方法 一、封裝與擴充套件 封裝在於明確區分內外,使得類實現者可以修改封裝內的東西而不影響外部呼叫者的程式碼;而外部使用者只知道一個介面(函式),只要介面(函式)名、引數不變,使用者的程式碼永遠無需改變。這就提供一個良好的合作基礎——或者說,只要介面這個基
C語言函式篇(五)靜態庫和動態庫的建立和使用
使用庫函式是原始碼的一種保護?我猜的. 庫函式其實不是新鮮的東西,我們一直都在用,比如C庫. 我們執行pringf() 這個函式的時候,就是呼叫C庫的函式. 下面記錄靜態庫和動態庫的生成和使用. 靜態庫:libxxx.a 動態庫:libxxx.so
Linux 建立、刪除檔案和資料夾命令
建立資料夾【mkdir】 一、mkdir命令使用許可權 所有使用者都可以在終端使用 mkdir 命令在擁有許可權的資料夾建立資料夾或目錄。 二、mkdir命令使用格式 格式:mkdir [選項] DirName 三、mkdir命令功能 通過 mkdir 命令
python基礎知識整理5——類方法、靜態方法和繼承相關問題
類方法和靜態方法 method - 通過例項呼叫 - 可以引用類內部的任何屬性和方法 classmethod - 無需例項化 - 可以呼叫類屬性和類方法 - 無法取到普通的成員屬性和方法 staticmethod - 無需例項化 - 無法渠道類內部的任何
中序線索二叉樹的建立、線索化和遍歷(前序遍歷和後序遍歷)
線索二叉樹的概念 線索二叉樹的原理:線索二叉樹是將普通二叉樹左右孩子中的空鏈域利用起來,將左孩子空鏈域指向當前節點的線性遍歷前驅,將右孩子空鏈域指向當前節點的線性遍歷後繼,指向該線性序列中的前驅或後繼
建立、刪除檔案和資料夾命令
建立資料夾【mkdir】 一、mkdir命令使用許可權 所有使用者都可以在終端使用 mkdir 命令在擁有許可權的資料夾建立資料夾或目錄。 二、mkdir命令使用格式 格式:mkdir [選項] DirName 三、mkdir命令功能 通過 mkdir 命令可以實現在指定位置建立以 DirName(指定的檔名
Linux 學習之建立、刪除檔案和資料夾命令
今天學習了幾個命令,是建立、刪除檔案和資料夾的,在linux裡,資料夾是目錄,下面說下我學習的命令。 建立資料夾【mkdir】 一、mkdir命令使用許可權 所有使用者都可以在終端使用 mkdir 命令在擁有許可權的資料夾建立資料夾或目錄。 二
靜態庫和動態庫的相互呼叫
在windows程式設計中,經常會遇到靜態庫裡呼叫動態庫的問題。 具體方法: 1,編寫一個動態連結庫,生成。 2,編寫一個靜態連結庫,裡面包含步驟1生成的動態連結庫的標頭檔案和lib, dll。 3,在呼叫該靜態連結庫時,將步驟2中的靜態連結庫的標頭檔案,lib檔案以及動態