在宏/模板的帮助下为任何 dll 生成包装器

问题描述 投票:0回答:1

例如我有

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
.

c++ winapi dll c++17 c++14
1个回答
0
投票

我不认为你可以使用

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()
© www.soinside.com 2019 - 2024. All rights reserved.