1、創建DLL文件
(1) 創建一個工程CreateDll
(2) 剛創建的項目結構
(3) 在Header Files下添加一個頭文件myDll.h
文件內容
//myDll.h #ifdef MYDLL_EXPORTS #define MYDLL_API __declspec(dllexport) #else #define MYDLL_API __declspec(dllimport) #endif namespace MyNameSpace{ class MyClass { public: static MYDLL_API void printHello(); static MYDLL_API double add(double number1, double number2); static MYDLL_API char* returnString(); }; }
(4) 在Source Files下添加一個cpp文件myDll.cpp
文件內容
//myDLL.cpp #include"stdafx.h" #include"myDll.h" #include<iostream> #include<stdio.h> using namespace std; namespace MyNameSpace{ double MyNameSpace::MyClass::add(double number1, double number2){ return number1 + number2; } void MyNameSpace::MyClass::printHello(){ std::cout << "Hello World" << std::endl; } char* MyNameSpace::MyClass::returnString(){ char* returnStr = "This is my string for return"; return returnStr; } }
(5) 添加完頭文件和cpp文件后項目結構
(6) 點擊編譯或Ctrl+Shift+B
(7) 生成的Dll文件和Lib文件在Debug目錄下
2、查看生成的CreateDll.dll提供的接口
(1) 查看命令
dumpbin.exe /EXPORTS D:\AAA_CODE\Test_Code\CallDll\Debug\CreateDll.dll
(2) dumpbin.exe路徑
存放在VS2013安裝目錄下VC下的Bin里,例如:D:\VS2013\VC\bin\dumpbin.exe
(3) 運行命令,查看接口名稱
(4) 接口名說明
由圖可知,接口名稱已經不是add,printHello和returnString了。這是由於采用了C++的編譯方式,導致接口被重命名了。
2、使用DLL文件
(1) 靜態調用
① 創建一個工程CallDll
② 添加myDll.h頭文件目錄 (添加工程的頭文件目錄:工程---屬性---配置屬性---c/c++---常規---附加包含目錄:加上頭文件存放目錄。)
③ 添加CreateDll.lib目錄(添加文件引用的lib靜態庫路徑: 工程---屬性---配置屬性---鏈接器---常規---附加庫目錄:加上lib文件存放目錄。)
④ 添加CreateDll.lib的lib名稱( 添加工程引用的lib文件名:工程---屬性---配置屬性---鏈接器---輸入---附加依賴項:加上lib文件名。)
⑤ 添加一個staticCall.cpp用於寫調用代碼
#include <iostream> #include "myDll.h" using namespace std; int main() { double a = 10.0; int b = 5.0; cout << "5.0 + 10.0 = " << MyNameSpace::MyClass::add(5.0, 1.0) << endl; //命名空間::類名::函數名 MyNameSpace::MyClass::printHello(); cout << "ret:" << MyNameSpace::MyClass::returnString() << endl; cin.get(); return 0; }
⑥ 添加DLL文件到Debug目錄(沒找到Debug目錄時,可以先運行一下程序,就會自動生成)
⑦ 工程結構
⑧ 運行程序,查看結果。
(2) 動態調用
① 新建工程與靜態調用一樣。(這次直接用的同一個工程)
② 添加dynamicCall.cpp
//dynamicCall.cpp #include<iostream> #include<Windows.h> using namespace std; void addMode(){ typedef double(*add)(double number1, double number2); char* dllName = "CreateDll.dll"; HMODULE dllHandler = LoadLibrary(dllName); if (dllHandler != NULL){ //直接使用第一個函數(第二個,第三個同理) add testAdd = add(GetProcAddress(dllHandler, MAKEINTRESOURCE(1))); if (testAdd != NULL){ cout << "5.0 + 6.3 = " << testAdd(5.0, 6.3) << endl; } else{ cout << "Can not find function add" << endl; } } else { cout << "Load Library fail:" << dllName << endl; } } void printHelloMode(){ typedef void(*printHello)(); char* dllName = "CreateDll.dll"; HMODULE dllHandler = LoadLibrary(dllName); if (dllHandler != NULL){ //通過映射函數名來使用PrintHello函數(其他兩個函數同理) printHello testPrintHello = printHello(GetProcAddress(dllHandler, "?printHello@MyClass@MyNameSpace@@SAXXZ")); if (testPrintHello != NULL){ testPrintHello(); } else{ cout << "Can not find function printHello" << endl; } } else { cout << "Load Library fail:" << dllName << endl; } } void returnStrMode(){ typedef char(*returnStr)(); char* dllName = "CreateDll.dll"; HMODULE dllHandler = LoadLibrary(dllName); if (dllHandler != NULL){ //兩種方法實現returnStr returnStr testReturnStr = returnStr(GetProcAddress(dllHandler, "?returnString@MyClass@MyNameSpace@@SAPADXZ")); if (testReturnStr != NULL){ cout << "Mode by get function name:" << testReturnStr() << endl; } else{ cout << "Can not find function printHello" << endl; } returnStr testReturnStr2 = returnStr(GetProcAddress(dllHandler, MAKEINTRESOURCE(3))); if (testReturnStr2 != NULL){ cout << "Mode by get function index:" << testReturnStr2() << endl; } else{ cout << "Can not find function printHello" << endl; } } else { cout << "Load Library fail:" << dllName << endl; } } int main(){ addMode(); printHelloMode(); returnStrMode(); cin.get(); }
③ 添加DLL文件到Debug目錄(沒找到Debug目錄時,可以先運行一下程序,就會自動生成)
④ 工程結構
⑤ 運行程序,查看結果。
3、Dll文件不改變函數名
① 添加CreateDll.def文件
//CreateDll.def LIBRARY CreateDll EXPORTS add = ?add@MyClass@MyNameSpace@@SANNN@Z printHello = ?printHello@MyClass@MyNameSpace@@SAXXZ returnString = ?returnString@MyClass@MyNameSpace@@SAPADXZ
② 重新編譯后,再次查看接口名字
③ 用原來的函數名調用CreateDll.dll
//dynamicCall.cpp #include<iostream> #include<Windows.h> using namespace std; void addMode(){ typedef double(*add)(double number1, double number2); char* dllName = "CreateDll.dll"; HMODULE dllHandler = LoadLibrary(dllName); if (dllHandler != NULL){ //add testAdd = add(GetProcAddress(dllHandler, MAKEINTRESOURCE(1))); add testAdd = add(GetProcAddress(dllHandler, "add")); if (testAdd != NULL){ cout << "5.0 + 6.3 = " << testAdd(5.0, 6.3) << endl; } else{ cout << "Can not find function add" << endl; } } else { cout << "Load Library fail:" << dllName << endl; } } void printHelloMode(){ typedef void(*printHello)(); char* dllName = "CreateDll.dll"; HMODULE dllHandler = LoadLibrary(dllName); if (dllHandler != NULL){ //通過映射函數名來使用PrintHello函數(其他兩個函數同理) printHello testPrintHello = printHello(GetProcAddress(dllHandler, "printHello")); if (testPrintHello != NULL){ testPrintHello(); } else{ cout << "Can not find function printHello" << endl; } } else { cout << "Load Library fail:" << dllName << endl; } } void returnStrMode(){ typedef char(*returnStr)(); char* dllName = "CreateDll.dll"; HMODULE dllHandler = LoadLibrary(dllName); if (dllHandler != NULL){ //兩種方法實現returnStr returnStr testReturnStr = returnStr(GetProcAddress(dllHandler, "returnString")); if (testReturnStr != NULL){ cout << "Mode by get function name:" << testReturnStr() << endl; } else{ cout << "Can not find function returnString" << endl; } returnStr testReturnStr2 = returnStr(GetProcAddress(dllHandler, MAKEINTRESOURCE(3))); if (testReturnStr2 != NULL){ cout << "Mode by get function index:" << testReturnStr2() << endl; } else{ cout << "Can not find function returnString" << endl; } } else { cout << "Load Library fail:" << dllName << endl; } } int main(){ addMode(); printHelloMode(); returnStrMode(); cin.get(); }
④ 可以去除多余接口(由圖可以看出接口翻倍了,但地址沒變,現在清除函數名已被更改的接口,只要把myDll.h中__declspec(dllexport)去掉即可)
//myDll.h #ifdef MYDLL_EXPORTS #define MYDLL_API #else #define MYDLL_API #endif namespace MyNameSpace{ class MyClass { public: static MYDLL_API void printHello(); static MYDLL_API double add(double number1, double number2); static MYDLL_API char* returnString(); }; }
⑤ 再次查看接口
⑥ 調用同理(略)