0

如前所述我正在尝试为 LNK2019 问题找到一种解决方法,该问题在构建使用 C++ 模板的静态库时出现,并将源代码与标头分离以使代码对其他项目保持私有。我相信我几乎已经得出了一个可行的结论(针对我的特殊情况),但我不完全确定这是否是正确/最佳的解决方法,并且想知道是否有人有任何建议、改进/评论添加?

目标是做一些类型检查,看看模板的签名是否与目标原型函数的签名匹配,做一些私有处理,并返回它是否成功。请注意,我已从上述链接中的解决方案的先前版本中删除SdkHookMgr.handSdkHookMgr.cpp ,并将所有内容重新合并到SdkLib.handSdkLib.cpp中,以保持清晰。

SDKLib.h:

#include <typeinfo>
#ifdef MY_EXPORTS
#   define MYDECL __declspec(dllexport)
#else
#   define MYDECL
#endif

// Prototypes
typedef HMODULE (WINAPI *HookLoadLibraryA)( LPCSTR lpFileName );
//...

class CHook;
class CHookManager;


MYDECL BOOL WINAPI ValidateHook( CHook *hook );

class CHook
{
public:
    CHook() : m_type(NULL), m_target(NULL), m_result(FALSE) {};
    CHook( const char *type, PVOID target ) : m_type(type), m_target(target) {
        m_result = ValidateHook(this);
    };
    const char *m_type;
    PVOID m_target;
    BOOL m_result;
};

class CHookManager
{
public:
    template <typename HookFunction> static BOOL Hook(HookFunction target)
    {
        const type_info& type = typeid(HookFunction);
        CHook *hook = new CHook( type.name(), target );
        return hook->m_result;
    }
};

SdkLib.cpp:

#include <SdkLib.h>
IDXDECL BOOL WINAPI ValidateHook( CHook *hook )
{
    // Do type checking, private processing, etc here...
    return TRUE;
}

演示DLL.cpp:

#include <SdkLib.h>
HMODULE WINAPI Hooked_LoadLibraryA( LPCSTR lpFileName )
{
    DebugBreak();
}

// The function that starts the rollercoaster.
// - Syntax: Hook< prototype >( target )
if!(CHookManager::Hook<HookLoadLibraryA>(Hooked_LoadLibraryA))
    cout << "Failed to create hook for LoadLibraryA!" << endl;
4

1 回答 1

0

您可能会发现typeidDLL 和主程序的结果不一致。(例如,参见不同 dll 的 typeid 结果。)

由于您可能的钩子列表是有限的,我觉得重载函数将是比模板更好的选择。这样您就没有 DLL 问题,并且每个钩子的有效性将在编译时检查。这是我正在考虑的事情的一个例子;显然,在实践中,您会将其拆分为单独的定义和声明,这些定义位于 DLL 中,因此它们都被干净地分开了。

class CHookManager {
public:
    BOOL Hook(HookLoadLibraryA hook) {
        assert(sizeof hook<=sizeof(uintptr_t));
        return ValidateHook((uintptr_t)hook,"LoadLibraryA");
    }

    BOOL Hook(HookLoadLibraryW hook) {
        assert(sizeof hook<=sizeof(uintptr_t));
        return ValidateHook((uintptr_t)hook,"LoadLibraryW");
    }
};

(请注意,这显示了这种方法的一个缺点——每个函数签名只能有一个钩子。为了完整起见,我提到了这一点,但我假设这没有被证明是一个问题。)

(如果有的话,您可能想用编译时断言替换断言。)

ValidateHook 将strcmp用来确定哪个钩子被钩住了。一旦确定了它是哪个钩子,它就会将其uintptr_t转换为适当的函数指针类型。它知道指针最初是该钩子的正确类型,因为您使用 C++ 重载机制来完成这一切。(或者你可以为所有钩子类型设置一个枚举,而不是传入一个字符串——这取决于你。关键部分是你可以完全控制传递的值,以便 DLL 和调用代码肯定使用匹配值。)

生成此代码会有些麻烦,但如果您已经有了 typedef 名称列表,那么您可以在您选择的编辑器中使用正则表达式搜索和替换或键盘宏来创建相应的代码。或者您可以使用所谓的“X-Macro”之类的东西来自动生成整个事物。

于 2012-11-09T19:55:47.703 回答