很久以前看到有人問“如何在C++中實(shí)現(xiàn)動(dòng)態(tài)加載類”時(shí),簡(jiǎn)單地做了一個(gè)。
不過當(dāng)時(shí)沒有去考慮動(dòng)態(tài)加載DLL的情況。
今天在
cpp@codingnow.com中也有人問到這個(gè)問題,就把它給做完了。
當(dāng)然只是簡(jiǎn)單地做到了“從全局類型庫中,根據(jù)類名創(chuàng)建實(shí)例,支持動(dòng)態(tài)DLL加載”,說得更明白點(diǎn):
在應(yīng)用程序App1中,向全局類型庫中注冊(cè)一個(gè)類型"Test",在另一個(gè)隱式鏈接的DLL中(即App1一啟動(dòng)就加載的DLL),向全局類型庫中注冊(cè)另外幾個(gè)類型。這時(shí)可以在App1中通過類型的名字生成實(shí)例。
在另一個(gè)顯式加載的DLL中(即調(diào)用LoadLibrary加載),向全局類型庫中注冊(cè)其它幾個(gè)類型。這時(shí)通過LoadLibrary加載這個(gè)DLL,就可以生成這幾個(gè)類型的實(shí)例了。
這地方不能上傳文件,就把代碼貼一點(diǎn)吧:
typelib.h文件:
#ifndef __TYPE_LIB_H__
#define __TYPE_LIB_H__
typedef void*(*CREATE_FUNC)();
typedef void(*RELEASE_FUNC)(void*);
void regtype (const char* name, CREATE_FUNC cfunc, RELEASE_FUNC rfunc);
void* createObject (const char* name);
void releaseObject (const char* name, void* p);
struct ITestInterface
{
virtual ~ITestInterface () {}
virtual void print () const = 0;
};
template <class T>
void* create ()
{
return new T;
}
template <class T>
void release (void* p)
{
delete (T*)p;
}
#endif // __TYPE_LIB_H__
typelib.cpp文件:
#include "typelib.h"
#include <string>
#include <map>
using namespace std;
namespace TypeRegistry
{
static map < string, pair<CREATE_FUNC, RELEASE_FUNC> > types_info;
template <class T>
void regType (const string& name)
{
types_info.insert (make_pair(name, make_pair(create<T>, release<T>)));
}
}
void regtype (const char* name, CREATE_FUNC cfunc, RELEASE_FUNC rfunc)
{
TypeRegistry::types_info.insert (make_pair(name, make_pair(cfunc, rfunc)));
}
void* createObject (const char* name)
{
map < string, pair<CREATE_FUNC, RELEASE_FUNC> >::const_iterator iter;
iter = TypeRegistry::types_info.find (name);
if (iter != TypeRegistry::types_info.end ())
return (*iter->second.first)();
return NULL;
}
void releaseObject (const char* name, void* p)
{
map < string, pair<CREATE_FUNC, RELEASE_FUNC> >::const_iterator iter;
iter = TypeRegistry::types_info.find (name);
if (iter != TypeRegistry::types_info.end ())
(*iter->second.second)(p);
}
把它編譯成靜態(tài)lib或DLL,就可以使用了。
在那2個(gè)為我們提供類型的DLL中,DllMain函數(shù)中加入下面的代碼:
// FirstTest和SecondTest是2個(gè)類名
regtype("FirstTest", create<FirstTest>, release<FirstTest>);
regtype("FirstTest", create<SecondTest>, release<SecondTest>);
就可以向全局類型庫中注冊(cè)類型。注意在類型庫中是沒有保存類信息的,所以最好是使用單根類庫來做。
下面是一點(diǎn)測(cè)試代碼:
int main()
{
// 程序啟動(dòng)時(shí)注冊(cè)類型。
// 實(shí)際上啟動(dòng)時(shí)就加載了另一個(gè)動(dòng)態(tài)鏈接庫,那里面有3個(gè)類型,所以現(xiàn)在有4個(gè)類型
regtype ("MyTest", create<MyTest>, release<MyTest>);
while (1)
{
string class_name;
cin >> class_name;
if (class_name == "q")
break;
// 當(dāng)輸入load時(shí),把另一個(gè)動(dòng)態(tài)鏈接庫加載進(jìn)來,那個(gè)鏈接庫中有2個(gè)類型,現(xiàn)在共有6個(gè)類型可用。
if (class_name == "load")
{
LoadLibrary("typelibdll_test.dll");
continue;
}
ITestInterface* test = (ITestInterface*)createObject (class_name.c_str());
if (!test)
{
cout << "This type not found" << endl;
continue;
}
test->print ();
releaseObject (class_name.c_str(), test);
}
return 0;
}
還有一個(gè)沒考慮的地方,就是沒有給它加鎖,因?yàn)橛锌赡茉谝粋€(gè)線程中加載一個(gè)DLL。
不過我還有些懷疑這東西是否真的有用?