0

前にここで説明したように、C++ テンプレートを使用するスタティック ライブラリをビルドし、ソースをヘッダーから分離して、コードを他のプロジェクトからプライベートに保つときに発生する LNK2019 問題の回避策を見つけようとしています。私は(私の特定の状況では)ほぼ結論に達したと信じていますが、これが正しい/最善の方法であるかどうかは完全にはわかりません.追加?

目標は、型チェックを行って、テンプレートの署名がターゲット プロトタイプ関数の署名と一致するかどうかを確認し、プライベートな処理を行い、それが成功したかどうかを返すことです。上記のリンクのソリューションの以前のバージョンからを削除し、すべてを と にマージして、少し明確にするために静的クラスに戻したことに注意しSdkHookMgr.hSdkHookMgr.cppSdkLib.hてくださいSdkLib.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");
    }
};

(これは、このアプローチの 1 つの欠点を示していることに注意してください。関数シグネチャごとに 1 つのフックしか持てません。完全を期すためにこれについて言及しますが、これは問題であることが証明されていないと仮定します。)

(アサートがある場合は、コンパイル時のアサートに置き換えたいと思うかもしれません。)

ValidateHook は、strcmpどのフックがフックされているかを把握するために使用します。それがどのフックであるかを把握したらuintptr_t、適切な関数ポインター型にキャストします。C++ のオーバーロード メカニズムを使用してすべてを実行しているため、ポインタが元々そのフックの正しい型であったことがわかります。(または、文字列を渡すのではなく、たとえば、すべてのフックの種類に対して列挙型を使用することもできます。それはあなた次第です。重要な部分は、渡される値を完全に制御できることです。コードは間違いなく一致する値を使用しています。)

このコードを生成するのは少し面倒ですが、typedef 名のリストが既にある場合は、選択したエディターで正規表現の検索と置換、またはキーボード マクロを使用して、対応するコードを作成できます。または、いわゆる「X-Macro」のようなものを使用して、すべての生成を自動化することもできます。

于 2012-11-09T19:55:47.703 に答える