例如我有
name1.dll
方法:
void func1(int)
int func2(bool, char)
和
name2.dll
方法:
std::string func1()
bool func2(int, int, int)
为了与它们一起工作,我想使用以下语法分别获取一些生成的类及其对象
DECLARE_WRAPPER(
Wrapper1,
DECLARE_METHOD(func1, void(int))
DECLARE_METHOD(func2, int(bool, char))
)
和
DECLARE_WRAPPER(
Wrapper2,
DECLARE_METHOD(func1, std::string())
DECLARE_METHOD(func2, bool(int, int, int))
)
并像这样使用:
Wrapper1 w1("name1.dll");
w1 func1(6);
w1.func2(false, 'c');
Wrapper w2("name2.dll");
w2.func1();
w2.func2(6, 5, 7)
到目前为止,我的 C++ 代码如下:
#include <iostream>
#include <string>
#include <windows.h>
#define DECLARE_METHOD(name, ret, ...) \
ret name(__VA_ARGS__) { \
FARPROC proc = GetProcAddress(m_hDll, #name); \
if (proc == nullptr) { \
throw std::runtime_error("Function not found"); \
} \
va_list args; \
va_start(args, __VA_ARGS__); \
ret result = reinterpret_cast<ret(__cdecl*)(__VA_ARGS__)>(proc)(__VA_ARGS__); \
va_end(args); \
return result; \
}
#define DECLARE_WRAPPER(wrapperName, ...) \
class wrapperName { \
public: \
wrapperName(const std::string& dllPath) : m_hDll(nullptr) { \
m_hDll = LoadLibraryA(dllPath.c_str()); \
} \
~wrapperName() { \
if (m_hDll) { \
FreeLibrary(m_hDll); \
} \
} \
__VA_ARGS__ \
private: \
HMODULE m_hDll; \
};
DECLARE_WRAPPER(
Wrapper1,
DECLARE_METHOD(func1, void, int)
DECLARE_METHOD(func2, int, bool, char)
);
DECLARE_WRAPPER(
Wrapper2,
DECLARE_METHOD(func1, std::string)
DECLARE_METHOD(func2, bool, int, int, int)
);
int main() {
const std::string dllPath1 = "name1.dll";
const std::string dllPath2 = "name2.dll";
Wrapper1 w1(dllPath1);
w1.func1(6);
int res = w1.func2(false, 'c');
std::cout << "Wrapper1::func2 returned " << res << std::endl;
Wrapper2 w2(dllPath2);
std::string str = w2.func1();
std::cout << "Wrapper2::func1 returned " << str << std::endl;
bool b = w2.func2(6, 5, 7);
std::cout << "Wrapper2::func2 returned " << b << std::endl;
return 0;
}
但是我有错误,我无法让它工作。如何修复此代码?或者,我是否正在尝试实现 C++ 中无法完成的事情?我可以使用的当前版本是
C++17
.
我不认为你可以使用
DECLARE_METHOD()
inside of DECLARE_WRAPPER()
你正在做的事情。您可能必须将 DECLARE_WRAPPER()
分解成单独的宏,这样您就可以在它们之间使用 DECLARE_METHOD()
s。
但是,
DECLARE_METHOD()
本身肯定不会像您编写的那样工作。它不能使用__VA_ARGS__
既声明方法参数又调用加载的proc()
。而且,它根本无法将 __VA_ARGS__
传递给 va_start()
(这并不重要,因为您无论如何都没有使用 args
)。你应该使用 C++ 风格的可变参数模板而不是 C 风格的可变参数宏。
尝试更像这样的东西:
#define DECLARE_METHOD(name, returnType) \
template<typename... Args> \
returnType name(Args&&... args) \
{ \
using procType = returnType (__cdecl *)(Args...); \
procType proc = reinterpret_cast<procType>(GetProcAddress(m_hDll, #name)); \
if (proc == nullptr) { \
throw std::runtime_error("Function not found"); \
} \
return proc(std::forward<Args>(args)...); \
}
#define DECLARE_WRAPPER_BEGIN(wrapperName) \
class wrapperName { \
public: \
wrapperName(const std::string& dllPath) : m_hDll(nullptr) { \
m_hDll = LoadLibraryA(dllPath.c_str()); \
if (m_hDll == nullptr) \
throw std::runtime_error("DLL not found"); \
} \
~wrapperName() { \
FreeLibrary(m_hDll); \
}
#define DECLARE_WRAPPER_END() \
private: \
HMODULE m_hDll; \
};
DECLARE_WRAPPER_BEGIN(Wrapper1)
DECLARE_METHOD(func1, void)
DECLARE_METHOD(func2, int)
DECLARE_WRAPPER_END()
DECLARE_WRAPPER_BEGIN(Wrapper2)
DECLARE_METHOD(func1, std::string)
DECLARE_METHOD(func2, bool)
DECLARE_WRAPPER_END()
附带说明,
Wrapper2::func1()
跨越 DLL 边界传递 std::string
是不安全的。如果 DLL 函数返回一个您想要转换为 char*
的 std::string
,那么您的 DECLARE_METHOD()
宏将必须考虑到这一点,通过使用单独的参数来分别指定两种返回类型。例如:
#define DECLARE_METHOD(name, dllReturnType, methReturnType) \
template<typename... Args> \
methReturnType name(Args&&... args) \
{ \
using procType = dllReturnType (__cdecl *)(Args...); \
procType proc = reinterpret_cast<procType>(GetProcAddress(m_hDll, #name)); \
if (proc == nullptr) { \
throw std::runtime_error("Function not found"); \
} \
return proc(std::forward<Args>(args)...); \
}
}
DECLARE_WRAPPER_BEGIN(Wrapper1)
DECLARE_METHOD(func1, void, void)
DECLARE_METHOD(func2, int, int)
DECLARE_WRAPPER_END()
DECLARE_WRAPPER_BEGIN(Wrapper2)
DECLARE_METHOD(func1, char*, std::string)
DECLARE_METHOD(func2, bool, bool)
DECLARE_WRAPPER_END()