こんにちは教えてください。

MessageBoxをフックするプログラムについて教えてください。以下はネットから探したサンプルの抜粋です。
PROCとは何でしょうか?また、=::はどんなものなのでしょうか?

教えてください。

PROC pfnOrig;
pfnOrig = ::GetProcAddress(
GetModuleHandleA("user32.dll"), "MessageBoxA");

回答の条件
  • 1人5回まで
  • 13歳以上
  • 登録:2012/03/17 15:57:30
  • 終了:2012/03/17 20:41:17

ベストアンサー

id:cx20 No.2

cx20回答回数607ベストアンサー獲得回数1082012/03/17 19:40:03

ポイント100pt
PROC pfnOrig;

PROC は関数ポインタ型を表します。
宣言は WinDef.h にありますが「戻り値が『int』で引数が『無い』関数」の型を表します。
(Visual Studio であれば「PROC」をマウス右クリックし「宣言に移動」を選択すると表示できます。)

typedef int (WINAPI *PROC)();

関数ポインタとは、関数へのポインタを代入できる変数のことです。
以下は関数ポインタのサンプルコードです。

// File : FuncPtrTest.c
#include <stdio.h>

int func()
{
    printf( "Hello, World!\n" );
    return 0;
}

int main( int argc, char* argv[] )
{
    int (*pfunc)() = func;  // 「pfunc」変数(関数ポインタ)に「func」関数を代入。
    
    pfunc(); // 「pfunc」変数(関数ポインタ)により「func」を呼び出すことが可能。
    
    return 0;
}

ただ、関数ポインタの宣言として「int (*pfunc)()」を記述するのは、分かりづらい為、typedef で以下のように型宣言することが多いです。

// File : FuncPtrTest2.c
#include <stdio.h>

int func()
{
    printf( "Hello, World!\n" );
    return 0;
}

typedef int (*FUNC)();  // 「int (*)()」の型を「FUNC」として型宣言する。

int main( int argc, char* argv[] )
{
    //int (*pfunc)() = func;
    FUNC pfunc = func; // 「pfunc」変数(FUNC 型)に「func」関数を代入。
    
    pfunc(); // 「pfunc」変数(関数ポインタ)により「func」を呼び出すことが可能。
    
    return 0;
}

PROC 型は、上記コードの「FUNC」型(戻り値が『int』で引数が『無い』関数)に相当します。
MessageBox 関数は、実際には「戻り値が『int』で『4つの引数』を持つ」関数ですので、
呼出し時に適宜、正しい型に変換してあげる必要があります。

また、「::」は、スコープ解決演算子( :: )を表します。
MFC 等のクラスライブラリ等を使用していると、Win32 API と同名のメンバ関数が存在したりする為、意図的に Win32 API 等のグローバルな API を呼び出す場合に「::」を使用することがあります。
今回のコードであれば「::」は無くても動作するかと思います。

<参考情報>
■ Windows API [ 0からのゲームプログラミング ]
http://www.plustarnet.com/aspil/Programming/api00.htm


なお、ネットで探されたサンプルは、

■ Windows API Hooking Tutorial
http://ruffnex.oc.to/kenji/text/api_hook/
http://ruffnex.oc.to/kenji/text/api_hook/ex2.cpp

のコードかと思いますが、一部、誤りがある(UNICODE ビルドに対応していない)ので、修正が必要そうです。

// フックする関数のプロトタイプを定義
typedef int (WINAPI *PFNMESSAGEBOXA)(HWND, LPCSTR, LPCSTR, UINT);   // PCSTR → LPCSTR
typedef int (WINAPI *PFNMESSAGEBOXW)(HWND, LPCWSTR, LPCWSTR, UINT); // PCSTR → LPCWSTR

int WINAPI Hook_MessageBoxA(
                            HWND hWnd, 
                            LPCSTR pszText,      /* PCSTR → LPCSTR */
                            LPCSTR pszCaption,   /* PCSTR → LPCSTR */
                            UINT uType)
{
    // オリジナルMessageBoxAを呼び出す
    PROC pfnOrig = GetProcAddress(
        GetModuleHandleA("user32.dll"), "MessageBoxA");
    int nResult = ((PFNMESSAGEBOXA) pfnOrig)
        (hWnd, pszText, "I am Hook_MessageBoxA", uType); // _T() は不要
    return nResult;
}

int WINAPI Hook_MessageBoxW(
                            HWND hWnd, 
                            LPCWSTR pszText,    /* PCSTR → LPCWSTR */
                            LPCWSTR pszCaption, /* PCSTR → LPCWSTR */
                            UINT uType)
{
    // オリジナルMessageBoxWを呼び出す
    PROC pfnOrig = GetProcAddress(
        GetModuleHandleA("user32.dll"), "MessageBoxW");
    int nResult = ((PFNMESSAGEBOXW) pfnOrig)   // PFNMESSAGEBOXA → PFNMESSAGEBOXW
        (hWnd, pszText, L"I am Hook_MessageBoxW", uType); // _T("") → L"" に変更
    return nResult;
}
id:mai_mai_mail

a-kuma3さんの回答で満足していたのですが、期待を超えた回答をcx20さんからいただきました。ありがとうございます。unicodeビルドに対応していないところはどうなおしていいのかわからずマルチバイトでコンパイルしていましたが、正しくunicodeで出来るようになり他のAPIのフックも正しく動くのではないかと期待しています。本当にありがとうございました。

2012/03/17 20:40:47

その他の回答(1件)

id:a-kuma3 No.1

a-kuma3回答回数4594ベストアンサー獲得回数19332012/03/17 17:35:31

ポイント100pt

PROCとは何でしょうか?

http://msdn.microsoft.com/ja-jp/library/cc429133.aspx
↑では FARPROC となっていますが、GetProcAddress は関数のポインタを返します。
PROC は、こんな感じの型になります。

int (WINAPI * PROC) ()

windows.h とかを include していれば、どんな型かを気にする必要はありません。

また、=::はどんなものなのでしょうか?

= と :: に分けて考えます。

= は普通の代入で、GetProcAddress 関数の戻り値を、変数 pfnOrig に代入しているだけです。

:: は、GetProcAddress を修飾しています。
::GetProcAddress で、「無名の名前空間に属している GetProcAddress だ」ということを表します。

ネットで探したサンプルでは、何かの名前空間に属しているようなコードになっているんじゃないでしょうか。

id:mai_mai_mail

すぐに回答頂きありがとうございます。親切な回答でよくわかりました。

2012/03/17 20:38:18
id:cx20 No.2

cx20回答回数607ベストアンサー獲得回数1082012/03/17 19:40:03ここでベストアンサー

ポイント100pt
PROC pfnOrig;

PROC は関数ポインタ型を表します。
宣言は WinDef.h にありますが「戻り値が『int』で引数が『無い』関数」の型を表します。
(Visual Studio であれば「PROC」をマウス右クリックし「宣言に移動」を選択すると表示できます。)

typedef int (WINAPI *PROC)();

関数ポインタとは、関数へのポインタを代入できる変数のことです。
以下は関数ポインタのサンプルコードです。

// File : FuncPtrTest.c
#include <stdio.h>

int func()
{
    printf( "Hello, World!\n" );
    return 0;
}

int main( int argc, char* argv[] )
{
    int (*pfunc)() = func;  // 「pfunc」変数(関数ポインタ)に「func」関数を代入。
    
    pfunc(); // 「pfunc」変数(関数ポインタ)により「func」を呼び出すことが可能。
    
    return 0;
}

ただ、関数ポインタの宣言として「int (*pfunc)()」を記述するのは、分かりづらい為、typedef で以下のように型宣言することが多いです。

// File : FuncPtrTest2.c
#include <stdio.h>

int func()
{
    printf( "Hello, World!\n" );
    return 0;
}

typedef int (*FUNC)();  // 「int (*)()」の型を「FUNC」として型宣言する。

int main( int argc, char* argv[] )
{
    //int (*pfunc)() = func;
    FUNC pfunc = func; // 「pfunc」変数(FUNC 型)に「func」関数を代入。
    
    pfunc(); // 「pfunc」変数(関数ポインタ)により「func」を呼び出すことが可能。
    
    return 0;
}

PROC 型は、上記コードの「FUNC」型(戻り値が『int』で引数が『無い』関数)に相当します。
MessageBox 関数は、実際には「戻り値が『int』で『4つの引数』を持つ」関数ですので、
呼出し時に適宜、正しい型に変換してあげる必要があります。

また、「::」は、スコープ解決演算子( :: )を表します。
MFC 等のクラスライブラリ等を使用していると、Win32 API と同名のメンバ関数が存在したりする為、意図的に Win32 API 等のグローバルな API を呼び出す場合に「::」を使用することがあります。
今回のコードであれば「::」は無くても動作するかと思います。

<参考情報>
■ Windows API [ 0からのゲームプログラミング ]
http://www.plustarnet.com/aspil/Programming/api00.htm


なお、ネットで探されたサンプルは、

■ Windows API Hooking Tutorial
http://ruffnex.oc.to/kenji/text/api_hook/
http://ruffnex.oc.to/kenji/text/api_hook/ex2.cpp

のコードかと思いますが、一部、誤りがある(UNICODE ビルドに対応していない)ので、修正が必要そうです。

// フックする関数のプロトタイプを定義
typedef int (WINAPI *PFNMESSAGEBOXA)(HWND, LPCSTR, LPCSTR, UINT);   // PCSTR → LPCSTR
typedef int (WINAPI *PFNMESSAGEBOXW)(HWND, LPCWSTR, LPCWSTR, UINT); // PCSTR → LPCWSTR

int WINAPI Hook_MessageBoxA(
                            HWND hWnd, 
                            LPCSTR pszText,      /* PCSTR → LPCSTR */
                            LPCSTR pszCaption,   /* PCSTR → LPCSTR */
                            UINT uType)
{
    // オリジナルMessageBoxAを呼び出す
    PROC pfnOrig = GetProcAddress(
        GetModuleHandleA("user32.dll"), "MessageBoxA");
    int nResult = ((PFNMESSAGEBOXA) pfnOrig)
        (hWnd, pszText, "I am Hook_MessageBoxA", uType); // _T() は不要
    return nResult;
}

int WINAPI Hook_MessageBoxW(
                            HWND hWnd, 
                            LPCWSTR pszText,    /* PCSTR → LPCWSTR */
                            LPCWSTR pszCaption, /* PCSTR → LPCWSTR */
                            UINT uType)
{
    // オリジナルMessageBoxWを呼び出す
    PROC pfnOrig = GetProcAddress(
        GetModuleHandleA("user32.dll"), "MessageBoxW");
    int nResult = ((PFNMESSAGEBOXW) pfnOrig)   // PFNMESSAGEBOXA → PFNMESSAGEBOXW
        (hWnd, pszText, L"I am Hook_MessageBoxW", uType); // _T("") → L"" に変更
    return nResult;
}
id:mai_mai_mail

a-kuma3さんの回答で満足していたのですが、期待を超えた回答をcx20さんからいただきました。ありがとうございます。unicodeビルドに対応していないところはどうなおしていいのかわからずマルチバイトでコンパイルしていましたが、正しくunicodeで出来るようになり他のAPIのフックも正しく動くのではないかと期待しています。本当にありがとうございました。

2012/03/17 20:40:47

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません