參考:
從自動導出動態連接庫接口看C++的缺點
更新內容:
1.封裝了gDllImportList變量,刪除了DllImportAttribute.cpp文件。
2.封裝了User32類的全局變量,刪除了User32.cpp文件。
更新後的框架只須要一個 DllImportAttribute.h文件,導出函數的文件也只須要一個,減小了文件數量。
#pragma once
#include <Windows.h>
#include <list>
using namespace std;
/*
* DllImportAttribute
* 定義加載和卸載動態連接庫的接口
*/
class DllImportAttribute
{
public:
// 加載動態連接庫
virtual BOOL Init() = 0;
// 卸載動態連接庫
virtual BOOL Uninit() = 0;
};
/*
* DllImportList
* 封裝gDllImportList(全局)變量,避免使用cpp文件
*/
class DllImportList
{
protected:
static DllImportList* m_pInstance;
public:
static DllImportList* CreateInstance()
{
if (m_pInstance == NULL)
{
m_pInstance = new DllImportList();
}
return m_pInstance;
}
static void DeleteInstance()
{
if (m_pInstance != NULL)
{
delete m_pInstance;
m_pInstance = NULL;
}
}
list<DllImportAttribute*> gDllImportList;
};
DllImportList* DllImportList::m_pInstance = NULL;
// 加載全部庫,用在程序初始化的地方
inline BOOL DllImportInit()
{
BOOL bSuccess = TRUE;
auto& list = DllImportList::CreateInstance()->gDllImportList;
for (auto iter = list.begin(); iter != list.end(); iter++)
{
bSuccess &= (*iter)->Init();
}
return bSuccess;
}
// 卸載全部庫,用在程序退出釋放資源的地方
inline BOOL DllImportUninit()
{
BOOL bSuccess = TRUE;
auto& list = DllImportList::CreateInstance()->gDllImportList;
for (auto iter = list.begin(); iter != list.end(); iter++)
{
bSuccess &= (*iter)->Uninit();
}
// 別放了刪除DllImportList實例
DllImportList::DeleteInstance();
return bSuccess;
}
/*
* DLLIMPORTCLASSBEGIN
* 定義CLASS##Dll類的前半部分,主要是庫加載、卸載以及封裝自身實例(避免使用Cpp文件)
* m_nOffPtr :指示變量的位置
*/
#define DLLIMPORTCLASSBEGIN(CLASS, DLLPATH) class CLASS##Dll : public DllImportAttribute \
{ \
protected: \
HMODULE m_hModule; \
public: \
CLASS##Dll() : m_hModule(NULL) { \
DllImportList::CreateInstance()->gDllImportList.push_back(this); \
} \
virtual BOOL Init() { \
m_hModule = LoadLibraryA(DLLPATH); \
return (m_hModule != NULL); \
} \
virtual BOOL Uninit() { \
BOOL bFreeSuccess = FreeLibrary(m_hModule); \
CLASS##Dll::DeleteInstance(); \
return bFreeSuccess; \
} \
protected: \
static CLASS##Dll* m_pInstance; \
public: \
static CLASS##Dll* CreateInstance() \
{ \
if (m_pInstance == NULL) \
{ \
m_pInstance = new CLASS##Dll(); \
memset((BYTE*)m_pInstance + offsetof(CLASS##Dll, m_nOffPtr), 0, \
sizeof(CLASS##Dll) - offsetof(CLASS##Dll, m_nOffPtr)); \
} \
return m_pInstance; \
} \
static void DeleteInstance() \
{ \
if (m_pInstance != NULL) \
{ \
delete m_pInstance; \
m_pInstance = NULL; \
} \
} \
protected: \
int m_nOffPtr; \
/*
* FUNCTIONENTRY
*/
#define FUNCTIONENTRY(ENTRYTYPE, ENTRYPOINT) protected: \
typedef ENTRYTYPE; \
ENTRYPOINT ENTRYPOINT##Ptr; \
public: \
ENTRYPOINT ENTRYPOINT##Func() \
{ \
if (ENTRYPOINT##Ptr == NULL) \
{ \
ENTRYPOINT##Ptr = (ENTRYPOINT)GetProcAddress(m_hModule, #ENTRYPOINT); \
} \
return ENTRYPOINT##Ptr; \
} \
/*
* DLLIMPORTCLASSEND
*/
#define DLLIMPORTCLASSEND(CLASS) }; \
CLASS##Dll* CLASS##Dll::m_pInstance = CLASS##Dll::CreateInstance(); \
/*
* DLLIMPORTCALL
*/
#define DLLIMPORTCALL(CLASS, ENTRYPOINT) CLASS##Dll::CreateInstance()->ENTRYPOINT##Func()
#pragma once
#include "DllImportAttribute.h"
DLLIMPORTCLASSBEGIN(User32, "User32.dll")
FUNCTIONENTRY(int(WINAPI *MessageBoxA)(HWND, LPCSTR, LPCSTR, UINT), MessageBoxA)
DLLIMPORTCLASSEND(User32)
DllImportInit();
DLLIMPORTCALL(User32, MessageBoxA)(NULL, "ad", "ad", MB_OK);
DllImportUninit();