可以办到。这是我测试的示例实现的框架。它是用 Visual C++/VS 2010 构建的。
接口在头文件 Iface.h 中声明:
#pragma once
#include <memory>
#include <string>
#ifdef IFACE_EXPORTS
#define IFACE_API __declspec(dllexport)
#else
#define IFACE_API __declspec(dllimport)
#endif
namespace Generic
{
class Iface
{
public:
virtual void DoSomething(std::string const&) = 0;
virtual ~Iface() {};
};
IFACE_API std::unique_ptr<Iface> GetIface();
typedef std::unique_ptr<Iface> (*GetIfaceType)();
}
几个 Dll 实现了这个接口,而第三个 Dll 称为 Factory,动态加载其中一个。反过来,Factory 导出一个函数供应用程序使用,该函数将隐式链接到它(即通过导出库。)
这是 FactoryIface.h,将包含在客户端应用程序中:
#pragma once
#include <memory>
#include "Iface.h"
#ifdef FACTORY_EXPORTS
#define FACTORY_API __declspec(dllexport)
#else
#define FACTORY_API __declspec(dllimport)
#endif
class FACTORY_API IFaceCustomDeleter
{
void* hMod_;
public:
IFaceCustomDeleter(void* hMod=nullptr);
void operator()(Generic::Iface* ptr);
};
FACTORY_API std::unique_ptr<Generic::Iface, IFaceCustomDeleter> FactoryGetIface();
请注意,必须导出自定义删除器类。那是我忘记做的第一件事。构建客户端应用程序很快就指向了它。下面是关键部分,Factory Dll 中 FactoryGetIface() 的实现:
// A trick to get decorated name of exported function
std::string DecoratedName;
namespace Generic
{
std::unique_ptr<Iface> GetIface()
{
DecoratedName = __FUNCDNAME__;
return std::unique_ptr<Iface>(nullptr);
}
}
using namespace Generic;
// for keeping Iface from dynamically loaded DLL
std::unique_ptr<Iface> ExternalIface;
// Custome deleter implementation
IFaceCustomDeleter::IFaceCustomDeleter(void* hMod)
: hMod_(hMod)
{
}
void IFaceCustomDeleter::operator()(Iface* ptr)
{
ExternalIface.reset(nullptr);
if(hMod_)
::FreeLibrary((HMODULE)hMod_);
}
FACTORY_API std::unique_ptr<Generic::Iface, IFaceCustomDeleter> FactoryGetIface()
{
// determine path of DLL to load for Iface implementation
auto path = L".\\IfaceImplB.dll";
auto hmod = ::LoadLibrary(path);
if(hmod)
{
GetIface(); // get decorated name
GetIfaceType ptrGetIface;
ptrGetIface = (GetIfaceType)::GetProcAddress(hmod, DecoratedName.c_str());
// Alternatively, use full decorated name like below:
//ptrGetIface = (GetIfaceType)::GetProcAddress(hmod,
//"?GetIface@Generic@@YA?AV?$unique_ptr@VIface@Generic@@U?$default_delete@VIface@Generic@@@std@@@std@@XZ");
if(ptrGetIface)
{
ExternalIface = ptrGetIface();
ExternalIface->DoSomething("Hello from Factory");
IFaceCustomDeleter del(hmod);
return std::unique_ptr<Generic::Iface, IFaceCustomDeleter>(ExternalIface.get(), del);
}
}
IFaceCustomDeleter del;
return std::unique_ptr<Generic::Iface, IFaceCustomDeleter>(nullptr, del);
}
请注意,Dll 路径是硬编码的:这只是一个示例,但它可以编译和工作。在实际应用中,可以有,例如。解析一些指定要加载的 Dll 的 xml。
通过 Factory 使用 Iface 的非常基本的控制台应用程序如下所示:
#include "FactoryIface.h"
int _tmain(int argc, _TCHAR* argv[])
{
{
std::unique_ptr<Generic::Iface, IFaceCustomDeleter> iface = FactoryGetIface();
iface->DoSomething("Hello from Factory user");
}
return 0;
}
当我运行它时,我得到如下输出:
In IfaceImplB constructor
Doing something: Hello from Factory
Doing something: Hello from Factory user
In IfaceImplB destructor