windows_同一プロセス内のメッセージボックスを変更してみる

windowsの環境でsetWindowHookExを使って同一プロセス内のメッセージボックス表示の処理をhookし内容を変更できるようにしたいと思います。別のソフトでのメッセージボックス表示内容を変更できるようになったら面白そうですが、まずは同一プロセス内のメッセージボックスに対して変更できるようになりたいと思います。

プロジェクトはvisual c++で作成します。
MsgBoxをhookする部分のファイルはいかのようになりました。

MsgBoxHook.cpp

#include "stdafx.h"
#include "MsgBoxHook.h"

HHOOK hMsgBoxHook;

LRESULT CALLBACK MsgBoxHookProc(int nCode, WPARAM wp, LPARAM lp)
{
    if (nCode >= 0)
    {
        if (nCode == HCBT_ACTIVATE)
        {
            // テキストラベルの内容を書き換える
            HWND label = ::GetDlgItem((HWND)wp, 0xFFFF);
            SetWindowText(label, "Hook");

            // OK(IDOK)の内容を書き換える
            CHAR okLabel[51] = { 0 };
            GetDlgItemText((HWND)wp, IDOK, okLabel, sizeof(okLabel) - 1);
            SetDlgItemText((HWND)wp, IDOK, strcat(okLabel, "(HOOK)"));

            // キャンセルボタン(IDCANCEL)の内容を書き換える
            CHAR cancelLabel[51] = { 0 };
            GetDlgItemText((HWND)wp, IDCANCEL, cancelLabel, sizeof(cancelLabel) - 1);
            SetDlgItemText((HWND)wp, IDCANCEL, strcat(cancelLabel, "(HOOK)"));
        }
    }
    return CallNextHookEx(hMsgBoxHook, nCode, wp, lp);
}


bool MsgBoxHookStart(HWND hWnd)
{
    HINSTANCE hInst;

    hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);
    hMsgBoxHook = SetWindowsHookEx(WH_CBT, //フック関数のタイプ
        (HOOKPROC)MsgBoxHookProc, //フックプロシージャのアドレス
        hInst, //フックプロシージャが入っているインスタンスハンドル
        GetCurrentThreadId()); //フックされるスレッド 0ならすべてのスレッド
    if (hMsgBoxHook == NULL) {
        MessageBox(hWnd, "フック開始に失敗", "Error", MB_OK);
        return false;
    }
    else {
        return true;
    }
}

bool MsgBoxHookEnd(HWND hWnd)
{
    if (UnhookWindowsHookEx(hMsgBoxHook) != 0) {
        return true;
    }
    else {
        MessageBox(hWnd, "フック解除に失敗", "Error", MB_OK);
        return false;
    }
}

SetWindowsHookExはMsgBoxHookStart関数内で呼び出しています。フックする関数のタイプとしてWH_CBTを指定していますが、これはウィンドウの生成などに対応しているらしいです。今回は実行するソフト内のみで有効なので、フックされるスレッドとしてGetCurrentThreadId()を指定しています。ここですべてのスレッドを指定しようとして0を渡してもhookには失敗するかと思います。

hookを終了するUnhookWindowsHookExはMsgBoxHookEnd関数内で呼び出しています。

メッセージボックスをフックする関数はMsgBoxHookProcで定義しており、メッセージボックスのテキスト、ok、キャンセルボタンの内容を変更するようにしています。 これのヘッダファイルは以下のようになりました。

MsgBoxHook.h

#pragma once
#include<Windows.h>

bool MsgBoxHookStart(HWND hWnd);
bool MsgBoxHookEnd(HWND hWnd);

それからhookの開始、終了、それから今回はメッセージボックスを表示する必要があるので、以下のようなフォームを作成して動かせば確認できるかと思います。

Form1.h

#pragma once
#include "MsgBoxHook.h"
#pragma comment(lib, "User32.lib")

namespace CppCLR_WinformsProjekt {

    using namespace System;
    using namespace System::ComponentModel;a
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;

    /// <summary>
    /// Zusammenfassung f・ Form1
    /// </summary>
    public ref class Form1 : public System::Windows::Forms::Form
    {
    public:
        Form1(void)
        {
            InitializeComponent();
            //
            //TODO: Konstruktorcode hier hinzuf・en.
            //
        }

    protected:
        /// <summary>
        /// Verwendete Ressourcen bereinigen.
        /// </summary>
        ~Form1()
        {
            if (components)
            {
                delete components;
            }
        }
    private: System::Windows::Forms::Button^  button1;
    private: System::Windows::Forms::Button^  button2;
    private: System::Windows::Forms::Label^  label1;
    private: System::Windows::Forms::Button^  button3;


    protected:

    private:
        /// <summary>
        /// Erforderliche Designervariable.
        /// </summary>
        System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
        /// <summary>
        /// Erforderliche Methode f・ die Designerunterst・zung.
        /// Der Inhalt der Methode darf nicht mit dem Code-Editor ge舅dert werden.
        /// </summary>
        void InitializeComponent(void)
        {
            this->button1 = (gcnew System::Windows::Forms::Button());
            this->button2 = (gcnew System::Windows::Forms::Button());
            this->label1 = (gcnew System::Windows::Forms::Label());
            this->button3 = (gcnew System::Windows::Forms::Button());
            this->SuspendLayout();
            //
            // button1
            //
            this->button1->Location = System::Drawing::Point(33, 53);
            this->button1->Name = L"button1";
            this->button1->Size = System::Drawing::Size(101, 40);
            this->button1->TabIndex = 0;
            this->button1->Text = L"start";
            this->button1->UseVisualStyleBackColor = true;
            this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
            //
            // button2
            //
            this->button2->Location = System::Drawing::Point(152, 53);
            this->button2->Name = L"button2";
            this->button2->Size = System::Drawing::Size(101, 40);
            this->button2->TabIndex = 1;
            this->button2->Text = L"stop";
            this->button2->UseVisualStyleBackColor = true;
            this->button2->Click += gcnew System::EventHandler(this, &Form1::button2_Click);
            //
            // label1
            //
            this->label1->AutoSize = true;
            this->label1->Font = (gcnew System::Drawing::Font(L"MS UI Gothic", 22));
            this->label1->Location = System::Drawing::Point(37, 9);
            this->label1->Name = L"label1";
            this->label1->Size = System::Drawing::Size(156, 30);
            this->label1->TabIndex = 2;
            this->label1->Text = L"HOOK OFF";
            this->label1->Click += gcnew System::EventHandler(this, &Form1::label1_Click);
            //
            // button3
            //
            this->button3->Location = System::Drawing::Point(33, 100);
            this->button3->Name = L"button3";
            this->button3->Size = System::Drawing::Size(220, 48);
            this->button3->TabIndex = 3;
            this->button3->Text = L"click";
            this->button3->UseVisualStyleBackColor = true;
            this->button3->Click += gcnew System::EventHandler(this, &Form1::button3_Click_1);
            //
            // Form1
            //
            this->AutoScaleDimensions = System::Drawing::SizeF(6, 12);
            this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
            this->ClientSize = System::Drawing::Size(283, 160);
            this->Controls->Add(this->button3);
            this->Controls->Add(this->label1);
            this->Controls->Add(this->button2);
            this->Controls->Add(this->button1);
            this->Name = L"Form1";
            this->Text = L"Form1";
            this->ResumeLayout(false);
            this->PerformLayout();

        }
#pragma endregion
    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
        HWND hWnd = static_cast<HWND>(this->Handle.ToPointer());
        if( MsgBoxHookStart(hWnd)) {
            this->label1->Text = L"HOOK ON";
        }
    }
    private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {
        HWND hWnd = static_cast<HWND>(this->Handle.ToPointer());
        if (MsgBoxHookEnd(hWnd)) {
            this->label1->Text = L"HOOK OFF";
        }
    }
    private: System::Void richTextBox1_TextChanged(System::Object^  sender, System::EventArgs^  e) {
    }
private: System::Void label1_Click(System::Object^  sender, System::EventArgs^  e) {
}
private: System::Void button3_Click_1(System::Object^  sender, System::EventArgs^  e) {
    MessageBox::Show("not hook",
        "not hook", MessageBoxButtons::OKCancel,
        MessageBoxIcon::Asterisk);
}
};
}