[英]How to dinamically define member functions in C++
我有这个对象只是Windows中外部DLL的包装器。 在创建对象时,构造函数在注册表中查询键,然后使用dll查询该键的文件夹值,然后加载dll,获取此dll初始化器的ProcAddress,并初始化它。
然后,我想向其他客户端提供这个dll的所有功能,所以我的类包装器提供了成员函数,它将检查我们是否有GetProcAddress ',如果没有那么我们这样做,得到指向这个函数的指针,并调用它。
我不想在构造函数时执行所有GetProcAddress',因为有数百个函数,并且很可能给定的客户端只需要一小部分函数,因此GetProcAddress的所有内容都是浪费。
但现在,我需要定义这些功能,感觉就像一个巨大的复制和粘贴的东西。 所有成员函数都完全相同,类似于
ResultType Wrapper::pertainingMemberFunction(...)
{
if (this->pointerToPertainingDLLFunction == nullptr) {
this->pointerToPertainingDLLFunction =
reinterpret_cast<pertainingType>(GetProcAddress(HMODULEDLL, "pertainingName"));
}
return this->pointerToPertainingDLLFunction (...);
}
这真的感觉像是一种非常不理想的解决方案。 我觉得必须有一些方法来模板化所有这些代码在编译时正确生成。 或许最初的方法不是最好的开始,我不确定。
将逻辑分解为函数模板非常简单:
template <class Function, class... Args>
decltype(auto) getProcAddressAndCall(
Function *&function,
char const *name,
Args &&... args
) {
if(!function)
function = reinterpret_cast<Function *>(GetProcAddress(HMODULEDLL, name));
return function(std::forward<Args>(args)...);
}
...然后你可以打电话给:
ResultType Wrapper::pertainingMemberFunction(...)
{
return getProcAddressAndCall(pointerToPertainingDLLFunction, "pertainingName", ...);
}
其他解决方案都是合理的,但相当复杂。
事实证明,您可以从Visual Studio获得更多帮助。 原因是您的行为与Visual Studio功能,延迟加载的DLL紧密对齐。 Visual Studio通过为DLL的所有函数生成GetProcAddress
调用来实现延迟加载的DLL,这正是您所需要的。
现在看来,您的特定功能是读取注册表项以查找特定的DLL。 碰巧,延迟加载机制有一个钩子机制。 如果定义__pfnDliNotifyHook2
,则会在调用LoadLibrary
之前调用通知dliNotePreLoadLibrary
。
您的钩子函数可以替换其自己的LoadLibrary
函数,并从所需位置加载DLL。 只需返回HMODULE
,Visual Studio将使用它来生成GetProcAddress
调用。
因此,您得到的解决方案如下所示:
ResultType Wrapper::DllFunction(...)
{
return DLLFunction (...);
}
简单,不是吗? Visual Studio将注意到DllFunction
来自延迟加载的DLL并使用__pfnDliNotifyHook2
的HMODULE
插入GetProcAddress
调用。
假设函数声明可用,则可以将包含方法指针的类字段公开为可调用对象:
extern "C"
{
void pertainingName(void);
}
class Wrapper
{
::HMODULE const m_h_library{};
public:
#define WRAPPED_METHOD(method_name) \
decltype(&::method_name) const method_name \
{ \
reinterpret_cast<decltype(&::method_name)> \
( \
::GetProcAddress(m_h_library, #method_name) \
) \
} \
WRAPPED_METHOD(pertainingName);
explicit Wrapper(::LPCWSTR const psz_library_path):
m_h_library{::LoadLibraryW(psz_library_path)}
{}
};
int main()
{
Wrapper wrap{L"foo.dll"};
wrap.pertainingName(); // invoking imported function just as it was a member function
return 0;
}
更复杂的方法可能包括使用专用的可调用模板类而不是原始指针。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.