查看DLL的導出情況and初識動態鏈接庫

找到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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章