c++ 在宏/模板的帮助下生成任何DLL的 Package 器

7tofc5zh  于 2023-04-01  发布在  其他
关注(0)|答案(2)|浏览(136)

例如,我有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

zxlwwiss

zxlwwiss1#

我不认为你可以像现在这样在DECLARE_WRAPPER()的内部使用DECLARE_METHOD()。你可能需要将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()

Online Demo
顺便说一下,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()
mutmk8jj

mutmk8jj2#

也许这会对某些人有用,所以我正在写我的“最终”表格。是的,有很多事情要做,但这里有一个框架,几乎适合我:

#include <windows.h>
#include <type_traits>
#include <filesystem>

#define DECLARE_METHOD(name, ret, ...)                 \
    private:                                           \
        using MethodType_##name = ret(*)(__VA_ARGS__); \
        MethodType_##name m_##name{ nullptr };         \

#define DEFINE_METHOD(name)                                                                                   \
    public:                                                                                                   \
        template<typename... Args>                                                                            \
        typename std::enable_if<!std::is_void<std::invoke_result_t<decltype(m_##name), Args...>>::value,      \
                                std::invoke_result_t<decltype(m_##name), Args...>>::type                      \
        name(Args&&... args)                                                                                  \
        {                                                                                                     \
            if (!m_##name)                                                                                    \
            {                                                                                                 \
                m_##name = reinterpret_cast<MethodType_##name>(GetProcAddress(m_hDll, #name));                \
            }                                                                                                 \
            if (!m_##name)                                                                                    \
            {                                                                                                 \
                throw std::runtime_error("Function not found");                                               \
            }                                                                                                 \
            return m_##name(std::forward<Args>(args)...);                                                     \
        }                                                                                                     \
                                                                                                              \
        template<typename... Args>                                                                            \
        typename std::enable_if<std::is_void<std::invoke_result_t<decltype(m_##name), Args...>>::value>::type \
        name(Args&&... args)                                                                                  \
        {                                                                                                     \
            if (!m_##name)                                                                                    \
            {                                                                                                 \
                m_##name = reinterpret_cast<MethodType_##name>(GetProcAddress(m_hDll, #name));                \
            }                                                                                                 \
            if (!m_##name)                                                                                    \
            {                                                                                                 \
                throw std::runtime_error("Function not found");                                               \
            }                                                                                                 \
            m_##name(std::forward<Args>(args)...);                                                            \
        }

#define DECLARE_DLL_WRAPPER(WrapperName, ...)                            \
    class WrapperName                                                    \
    {                                                                    \
    public:                                                              \
        explicit WrapperName(const std::filesystem::path& fullPathToDll) \
        {                                                                \
            m_hDll = LoadLibraryA(fullPathToDll.u8string().c_str());     \
            if (!m_hDll)                                                 \
            {                                                            \
                throw std::runtime_error("DLL not found");               \
            }                                                            \
        }                                                                \
        ~WrapperName()                                                   \
        {                                                                \
            FreeLibrary(m_hDll);                                         \
        }                                                                \
        __VA_ARGS__                                                      \
                                                                         \
    private:                                                             \
        HMODULE m_hDll{ nullptr };                                       \
};

#define DECLARE_AND_DEFINE_METHOD(name, ret, ...)   \
    DECLARE_METHOD(name, ret, __VA_ARGS__)          \
    DEFINE_METHOD(name)

// Declaring some dll wrapper type for futher using it
DECLARE_DLL_WRAPPER(Wrapper1,
    DECLARE_AND_DEFINE_METHOD(func1, int, bool bParam, int iParam)
    DECLARE_AND_DEFINE_METHOD(func2, void, float dParam)
)

int main()
{
    Wrapper1 w1("plugin.dll");

    const auto ret = w1.func1(false, 6);
    w1.func2(2.0f);

    return 0;
}

不要严格判断。理想情况下,如果可以突出显示所用方法的所有参数,那将是非常方便和良好的。

相关问题