找到vs2017自帶的tool窗口命令
此時什麼都沒導出來 需要在編譯器加上一句話
其中@是動態改名機制
加入extern “C” 則刪掉了動態改名機制
如果找到Debug文件夾,發現dll和lib都有 lib在動態庫中只是導入庫。裏面僅僅一些說明函數原型的東西,真正的庫代碼實現在dll裏,這是兩部分。
真正編譯之後 lib沒有作用了 就是把dll和exe的放在同一個文件夾下面。
隱式調用
DynamicLibrary.h
#pragma once
#ifdef __DLL_EXPORT_
#define EXPORT_ENTRY extern "C" __declspec(dllexport)
#else
#define EXPORT_ENTRY extern "C" __declspec(dllimport)
#endif // __DLL_EXPORT_
EXPORT_ENTRY int add(int a, int b);
EXPORT_ENTRY int subtract(int a, int b);
EXPORT_ENTRY int multiply(int a, int b);
EXPORT_ENTRY int divide(int a, int b);
DynamicLibrary.cpp
#include "DynamicLibrary.h"
int add(int a, int b)
{
return a + b;
}
int subtract (int a, int b)
{
return a - b;
}
int multiply(int a, int b)
{
return a * b;
}
int divide(int a, int b)
{
return a / b;
}
client 項目下的測試文件文件中
#include <iostream>
using namespace std;
#pragma comment(lib,"../Debug/dynamicLibrary.lib")
/*forward declarations */
//extern "C" int add(int a, int b);
#include "../DynamicLibrary/DynamicLibrary.h"
int main(void)
{
cout << subtract(15, 12) << endl;
return 0;
}
顯示加載
修改源.cpp的代碼
#include <iostream>
#include <windows.h>
using namespace std;
//#pragma comment(lib,"../Debug/dynamicLibrary.lib")
/*forward declarations */
//extern "C" int add(int a, int b);
//#include "../DynamicLibrary/DynamicLibrary.h"
typedef int(*PAdd)(int, int);
int main(void)
{
//cout << subtract(15, 12) << endl;
HMODULE hModule=::LoadLibrary(L"../Debug/dynamicLibrary.dll");
if (hModule == INVALID_HANDLE_VALUE)
return 1;
PAdd add=reinterpret_cast<PAdd>(::GetProcAddress(hModule,"add"));
if (add)
{
cout << (*add)(12, 15) << endl;
}
::FreeLibrary(hModule);
hModule = nullptr;
return 0;
}
導出類 基本沒有這用的
重添加一個項目dynamicLibrarywithObject
Operation.h
#pragma once
#ifdef __DLL_EXPORT_
#define EXPORT_ENTRY __declspec(dllexport)
#else
#define EXPORT_ENTRY __declspec(dllimport)
#endif // __DLL_EXPORT_
class EXPORT_ENTRY Operation
{
public:
Operation();
void add(int a, int b);
void subtract(int a, int b);
void multiply(int a, int b);
void divide(int a, int b);
int result(void)const;
private:
int _result;
};
Operation.cpp
#include "Operation.h"
Operation::Operation():_result(0)
{
}
void Operation::add(int a, int b)
{
_result = a + b;
}
void Operation::subtract(int a, int b)
{
_result = a - b;
}
void Operation::multiply(int a, int b)
{
_result = a * b;
}
void Operation::divide(int a, int b)
{
_result = a / b;
}
int Operation::result(void)const
{
return _result;
}
源.cpp
#include <iostream>
#include <windows.h>
using namespace std;
#pragma comment(lib,"../Debug/dynamicLibrarywithObject.lib")
/*forward declarations */
//extern "C" int add(int a, int b);
#include "../dynamicLibrarywithObject/Operation.h"
//typedef int(*PAdd)(int, int);
int main(void)
{
//cout << subtract(15, 12) << endl;
// HMODULE hModule=::LoadLibrary(L"../Debug/dynamicLibrary.dll");
// if (hModule == INVALID_HANDLE_VALUE)
// return 1;
// PAdd add=reinterpret_cast<PAdd>(::GetProcAddress(hModule,"add"));
// if (add)
// {
// cout << (*add)(12, 15) << endl;
// }
//
// ::FreeLibrary(hModule);
// hModule = nullptr;
Operation operation;
operation.add(12,18);
cout << operation.result() << endl;
return 0;
}
如果你是一箇中間件廠商,你會怎麼封裝你產品的功能,供給其他的客戶使用,而且還不暴露你裏面的內容。下面他的載體就是動態鏈接庫。
看下什麼是接口?
接口一定沒有實現的細節。接口一定是函數抽象的沒有實現,
沒有成員變量,沒有值域。
把withobject改成組件的形式
在該項目中增加一個頭文件 ,寫一個接口文件 IOperation.h
#pragma once
#ifdef __DLL_EXPORT_
#define EXPORT_ENTRY extern "C" __declspec(dllexport)
#else
#define EXPORT_ENTRY extern "C" __declspec(dllimport)
#endif // __DLL_EXPORT_
class IOperation1
{
public:
virtual void add(int a, int b)=0;
virtual void subtract(int a, int b)=0;
virtual int result(void)const=0;
};
class IOperation2
{
public:
virtual void multiply(int a, int b) = 0;
virtual void divide(int a, int b) = 0;
virtual int result(void)const = 0;
};
EXPORT_ENTRY IOperation1* getOperation1(void);
EXPORT_ENTRY IOperation2* getOperation2(void);
EXPORT_ENTRY void shutdownOper(void);
Operation.h 修改爲
#pragma once
#include "IOperation.h"
class Operation:public IOperation1,public IOperation2
{
public:
Operation();
void add(int a, int b);
void subtract(int a, int b);
void multiply(int a, int b);
void divide(int a, int b);
int result(void)const;
private:
int _result;
};
Operation.cpp修改爲
#include "Operation.h"
Operation* oper = nullptr;
Operation::Operation():_result(0)
{
}
void Operation::add(int a, int b)
{
_result = a + b;
}
void Operation::subtract(int a, int b)
{
_result = a - b;
}
void Operation::multiply(int a, int b)
{
_result = a * b;
}
void Operation::divide(int a, int b)
{
_result = a / b;
}
int Operation::result(void)const
{
return _result;
}
IOperation1* getOperation1(void)
{
if (!oper)//兩個接口用同一個類實現的 必須同時沒有
oper = new Operation;
return oper;
}
IOperation2* getOperation2(void)
{
if (!oper)//兩個接口用同一個類實現的 必須同時沒有
oper = new Operation;
return oper;
}
void shutdownOper(void)
{
if (oper)
{
delete oper;
oper = nullptr;
}
}
源.cpp修改爲
#include <iostream>
#include <Windows.h>
using namespace std;
#pragma comment(lib,"../Debug/dynamicLibrarywithObject.lib")
#include "../dynamicLibrarywithObject/IOperation.h"
int main(void)
{
IOperation2* oper2 = getOperation2();
oper2->divide(10, 2);
cout << oper2->result() << endl;
IOperation1* oper1 = getOperation1();
oper1->add(1, 2);
cout << oper1->result() << endl;
shutdownOper();
return 0;
}
組件開發,讓用戶瞭解的越少越好,不讓他看見代碼,只讓他知道這個功能怎麼使,然後所有的實現都讓另外一個廠商寫,另外一個廠商想怎麼改就怎麼改。只要這個接口不變,用戶一直用這個接口,拿來就可以使,而且沒有dll地域的東西,就是dll版本不對,造成的改名機制不匹配,最後用不了,但是我們的這個都是純虛的,沒有這一說,這個就是所謂的組件開發的基礎。
什麼是動態鏈接庫
A程序和B程序都訪問一動態鏈接庫DLL,動態鏈接庫裏面存的都是代碼,A調用可能執行的函數是一樣的,但是數據可能不一樣,B也是,就是把代碼映射到自己進程的地址空間中,紅色區域是完全相同的部分,哪裏不同的?比如A代碼運行出來的數據,得到的數是不同的,藍色和綠色部分是數據部分,各自獨有的。代碼就是一分,但是數據有多份。
靜態庫就是代碼和數據 都是各自有一份的。共享性不是那麼特別好。
所以我們比較習慣於使用動態鏈接庫,他也是組件開發的載體。
下篇講解微軟的組件是真正怎麼做的。。。按照組件開發的的理念想。
軟件架構裏面有一個插件式開發,都是一系列的動態鏈接庫,軟件更新就是更新DLL。