はじめに
ウィンドウメッセージについて理解するために、実際にプログラムを動かして確認してみました。なお、C言語やC言語を使用したWindowsプログラミングのことは詳しくないため、間違っている点があるかもしれません。
メッセージについて
Windowsアプリケーションはイベントドリブンであり、システムがメッセージを渡すのを待ちます。
ウィンドウメッセージ一覧
システム定義メッセージの表の一番下のWM
の箇所
メッセージの流れ
Windowsアプリケーションに送られたメッセージは最終的にウィンドウプロシージャに送られて処理されますが、そこに行くまでの経路にはメッセージキューを経由するものとそうでないものの2つがあります。
- メッセージのルーティング/ キーボード入力モデル
- メッセージ処理 / メッセージ ループ / 文字メッセージ
- ウィンドウを閉じる - Win32 apps | Microsoft Learn
- メッセージの投稿と送信
メッセージの値
ウィンドウ メッセージ (Win32 と C++ の概要) - Win32 apps | Microsoft Learn
メッセージは、特定のイベントを指定する単なる数値コードです。
例えば、マウスの左ボタンが押された場合は0x0201
という値が送られてきます。winuser.h
にはこの値に対応した記号定数が#defineされています。0x0201
であればWM_LBUTTONDOWN
になります。
...
#define WM_MOUSEMOVE 0x0200
#define WM_LBUTTONDOWN 0x0201
#define WM_LBUTTONUP 0x0202
...
値の範囲
メッセージにはWM_LBUTTONDOWN
(0x0201
)のようにシステムで定義されているものだけでなく、アプリケーションが独自に使うためにアプリケーションによって作成されるものもあります。メッセージの値は以下のように用途によって使用できる範囲が定められています。
アプリケーション定義のメッセージ / WM_USER / WM_APP
メッセージの共有 / RegisterWindowMessage関数
実際に確認する
開発環境は以下と同じです。
MinGW+C言語でWindows用Dllを作成する #Windows - Qiita
- 確認用のプレーンコードは最小限のwindowsプログラムを参照。
- ソースコードのファイル名は
winlog.cpp
とし、コンパイルはg++ winlog.cpp -mwindows -o winlog.exe
全てのメッセージを確認する
Windows 10で始めるC言語開発(31) WindowsでC言語開発! メッセージループを追っていく | TECH+(テックプラス)
確認用のプレーンコードに対して、ログをファイルに出力するように変更しています。全コードについては、全てのメッセージを出力するプログラムを参照願います。
ファイル名 | 出力する内容 |
---|---|
AllLog.txt |
ウィンドウプロシージャが受け取ったメッセージ 及び、Win32API関数名(関数を呼ぶ前に出力) |
MessageLoopLog.txt |
メッセージループで受け取ったメッセージ |
実際にコンパイルして動作させると、例えば以下のように出力されます。
//AllLog.txt
Before RegisterClass
Before CreateWindowEx
[#0000] message: 0x0024
[#0001] message: 0x0081
[#0002] message: 0x0083
[#0003] message: 0x0001
Before ShowWindow
...
//MessageLoopLog.txt
...
[#0059] message: 0x0200
[#0062] message: 0x0200
[#0065] message: 0x0200
...
数値では分かりにくいのでメッセージの数値を文字列に変換します。
//AllLog_fix.txt
Before RegisterClass
Before CreateWindowEx
[#0000] message: WM_GETMINMAXINFO
[#0001] message: WM_NCCREATE
[#0002] message: WM_NCCALCSIZE
[#0003] message: WM_CREATE
Before ShowWindow
...
//MessageLoopLog_fix.txt
...
[#0059] message: WM_MOUSEMOVE
[#0062] message: WM_MOUSEMOVE
[#0065] message: WM_MOUSEMOVE
...
CreateWindowExW
を呼び出すと、WM_CREATE
などのメッセージが送信されていることが分かります。また、WM_CREATE
に記載の通り、CreateWindow
関数が戻る前に、WM_CREATE
が送信されていることも分かります。
WinMerge等でAllLog_fix.txt
とMessageLoopLog_fix.txt
を比較すると、基本的に「ウィンドウプロシージャの受け取ったメッセージ」=「メッセージループで受け取ったメッセージ」+αでしたが、そうでないものもありました。また、0xC***
というアプリケーション間通信用のメッセージもありました。やはり実際に確認してみると理解が深まると思います。
GetMessageの挙動を確認する
ウィンドウ メッセージ (Win32 と C++ の概要) - Win32 apps | Microsoft Learn
キューが空の場合、関数は別のメッセージがキューに登録されるまでブロックします。
と記載されているので、実際にGetMessage
の挙動を確認してみます。確認用のプレーンコードを変更し、メッセージループに入った回数をアプリケーションウィンドウのタイトルに表示するようにしています。全コードについては、メッセージループ突入回数を表示するプログラムを参照願います。
アプリケーションを起動して、マウスカーソルを動かすと回数がアップしていることが分かります。但し、何もしないと回数は変わりません。
TranslateMessageの挙動を確認する
キーボード入力 (はじめに Win32 および C++ を使用) - Win32 apps | Microsoft Learn
キーボード入力について考える場合は、キー ストロークが文字と同じではないことに注意することが重要です。 たとえば、A キーを押すと、次のいずれかの文字が発生する可能性があります。
a A á
キー ストロークは、... TranslateMessage 関数によって文字に変換されます。 この関数は、キーダウン メッセージを調べて、それらを文字に変換します。
TranslateMessage
によって、例えばShiftを押しながらAを押すと文字"A"のWM_CHAR
メッセージが生成され、Shiftを押さずにAを押すと文字"a"のWM_CHAR
メッセージが生成されるとのことなので、実際にTranslateMessage
の挙動とTranslateMessage
があるときとないときのメッセージを比較してみます。
確認用のプレーンコードを変更し、
- キー入力にかかわるメッセージのみを出力するようにしています。
-
WM_KEYDOWN
メッセージに付加されて送られてくる仮想キーコードの情報や、WM_CHAR
メッセージに付加されて送られてくる文字コードの情報も併せて出力するようにしています。 - ANSI版も作成できるように文字列の定義を変更しています。詳細は文字列の操作を参照。
全コードについては、TranslateMessageの挙動を確認するプログラムを参照願います。
実際にコンパイルして動作させ、メッセージの数値を文字列に変換すると、
//a
message: WM_KEYDOWN 0x41 //Aキーダウン
message: WM_CHAR 0x61 //"a"文字メッセージ
message: WM_KEYUP 0x41 //Aキーアップ
//A
message: WM_KEYDOWN 0x10 //Shiftダウン
message: WM_KEYDOWN 0x41 //Aキーダウン
message: WM_CHAR 0x41 //"A"文字メッセージ
message: WM_KEYUP 0x41 //Aキーアップ
message: WM_KEYUP 0x10 //Shiftアップ
//か
message: WM_KEYDOWN 0xE5 //IME PROCESS キー
message: WM_KEYUP 0x4B //Kキーアップ
message: WM_KEYDOWN 0xE5 //IME PROCESS キー
message: WM_KEYUP 0x41 //Aキーアップ
message: WM_KEYDOWN 0xE5 //IME PROCESS キー
message: WM_CHAR 0x304B //"か"文字メッセージ
文字メッセージが生成されているのが分かります。このプログラムはUNICODE
をdefine
しており、RegisterClassW
でウィンドウクラス登録されるためUnicodeで文字を受け取ります。IMEオンでK
A
と入力するとUnicodeの「か」である304B
を受け取っていることが分かります。なおUNICODE
をdefine
せず、
#ifdef UNICODE
#undef UNICODE
#endif
とすると文字メッセージはShift-JISの「か」である82A9
になっていました。
//Shift-JISの「か」
message: WM_CHAR 0x82
message: WM_CHAR 0xA9
TranslateMessage(&msg);
を削除した場合は、
//a
message: WM_KEYDOWN 0x41 //Aキーダウン
message: WM_KEYUP 0x41 //Aキーアップ
文字メッセージWM_CHAR
が生成されていないことが分かります。
参考URL
用語説明
イベント駆動
メッセージとメッセージ キューについて - Win32 apps | Microsoft Learn
イベント駆動型プログラミング - Wikipedia
例えば、Windowsアプリケーション上でキーが押された場合、システム(Windows)はアプリケーションに対し「キーが押された」というメッセージを渡します。Windowsアプリケーションはこのメッセージを受け取ることでキーが押されたことを認識し、押されたときの処理を行います。
このように何かの事象、動作が起こったことをトリガーとして処理を実行する場合、「イベントドリブン(イベント駆動)です」と表現します。Windowsアプリケーションはイベントドリブンです。システムがメッセージを渡すのを待ちます。
ウィンドウプロシージャ
ウィンドウ プロシージャについて - Win32 apps | Microsoft Learn
Windowsアプリケーションを作成する場合、「ウィンドウプロシージャ」と呼ばれるアプリケーション※に送られてきたすべてのメッセージを処理する関数を実装します。システム(Windows)はアプリケーションに対するメッセージがある場合、この関数を呼びます。
Windowsアプリケーションでは、「マウスがクリックされた場合はこのような処理をする」といったコードをこの関数内に記述することでマウスクリックに応答する動作を実現できます。
上記で「Windowsアプリケーションはメッセージを受け取ることでキーが押されたことを認識し」と記載しましたが、実際にアプリケーション作成時にすることはメッセージに応答する処理を関数内に記載するだけです。関数の呼び出しはシステム(Windows)が行います。
※より丁寧に言うとアプリケーションローカルクラス、つまり実行可能ファイルが通常1つ持つウィンドウクラスに紐づくウィンドウ
ウィンドウクラス
ウィンドウ クラスについて - Win32 apps | Microsoft Learn
ウィンドウの作成 - Win32 apps | Microsoft Learn
ウィンドウクラスという名前ですが、C++でいうクラスではありません。ウィンドウクラスという概念は分かりにくいですが、アプリケーションウィンドウであれ、ボタンウィンドウであれウィンドウを作成するには、何はともあれ先立ってウィンドウクラスが必要です。ウィンドウクラスを登録するにはRegisterClass
を使用します。
間違った理解にはなりますが、メッセージに関して理解するだけであれば、
- ウィンドウクラス :町
- ウィンドウプロシージャ:町に唯一ある郵便局
- ウィンドウ:住人
- メッセージ:郵便物
くらいの捉え方でよいと思います。住人宛ての郵便物を処理するためには受け取って処理する郵便局が必要ですが、そのためには郵便局を持つ町を作って町に住む必要があります。ウィンドウを作成する場合、まずはウィンドウプロシージャを持つウィンドウクラスを登録します。その後、それに紐づかせる形でウィンドウを作成します。ウィンドウクラスの持つウィンドウプロシージャはそのクラスに紐づくウィンドウに対する全てのメッセージを処理します。
実際は現実のように郵便局(ウィンドウプロシージャ)が受け取った郵便物(メッセージ)がその後住人(ウィンドウ)のもとに行くわけではないですし、ウィンドウクラスを登録するときに使う「ウィンドウクラスの属性を格納するWNDCLASS構造体」にはウィンドウプロシージャ以外の様々な設定が必要であるため、「ウィンドウクラスとはそれに紐づくウィンドウが共通で持つ仕様を定義しているもの」というような理解のほうが、より正しい理解になるとは思います。
参考URL
ウィンドウ
ウィンドウとは - Win32 apps | Microsoft Learn
一般的にウィンドウといえば、例えばメモ帳を起動したときなどに表示されるウィンドウのことを想像します。実際にこれはアプリケーションウィンドウと呼ばれるウィンドウですが、Windowsプログラミングの場合はボタンなどのコントロールもウィンドウです。
メッセージループ
ウィンドウ メッセージ (Win32 と C++ の概要) - Win32 apps | Microsoft Learn
Windows Messaging Architecture | Xavier's space
キーボードやマウスなどのユーザー操作によって発生するメッセージはメッセージキューに投稿(POST)されます。このメッセージキューにメッセージがあれば取得し、それをウィンドウプロシージャに送ることを繰り返すのがメッセージループです。具体的にはGetMessage
でメッセージキューからメッセージを取得し、DispatchMessage
でメッセージをウィンドウプロシージャに送ります。
例えばC#ではApplication.Run
メソッドによってメッセージループを開始させます。
参考URL
ソースコード
最小限のWindowsプログラム
確認用プログラムのひな型となる最小限のWindowsアプリケーション用コードです。
モジュール 1 初めての Windows プログラム - Win32 apps | Microsoft Learn
-
アプリケーションウィンドウを作成する前に、まずは
RegisterClass
を使用してウィンドウクラスを登録します。- まずは
RegisterClass
の引数であるWNDCLASSW構造体を作成します。 - WNDCLASSEX 構造体の未使用のメンバーは、0 または NULL に初期化する必要があるため初期化子で初期化します。
- クラス名、ウィンドウプロシージャ、インスタンスのみが必須設定項目であるためこの3つを設定します。
- 必須項目の設定だけでも問題ありませんが、マウスカーソルは通常の矢印カーソルとしたいため、カーソルについては
LoadCursor
を使用して矢印カーソルに設定します。
- まずは
-
CreateWindowEx
を使用してウィンドウを作成します。 -
ShowWindow
とUpdateWindow
を使用してウィンドウを表示します。ShowWindow
の引数にはWinMainアプリケーションのエントリポイントの引数であるnCmdShow
を指定します。 -
メッセージループを作成します。Windowsアプリケーションも例えばコンソールアプリケーションである、
#include <stdio.h> int main(void) { printf("Hello World"); return 0; }
と同じで、最後まで行くとプログラムが終了しますが、メッセージループがあることでこのループを抜けない限りプログラムは終了しません。メッセージループでは、
while (GetMessage(&msg, NULL, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); }
-
GetMessage
でメッセージキューからメッセージを取得 -
TranslateMessage
で文字メッセージを生成 -
ウィンドウプロシージャにメッセージを送るように
DispatchMessage
でシステムに指示
を繰り返します。
GetMessage
の戻り値は、のため、
WM_QUIT
以外のメッセージを受け取っている限り(>0
の場合)ループを繰り返します。 -
-
ウィンドウプロシージャを記載します。基本的に
DefWindowProc
を使用して、処理しないメッセージには既定の処理を実施します。ウィンドウが破棄されると、WM_DESTROYメッセージを受け取るので、PostQuitMessage
を使ってWM_QUIT
メッセージをメッセージキューに投稿(POST)します。
/*
winlog.cpp
g++ winlog.cpp -mwindows -o winlog.exe
*/
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow)
{
// 1.ウィンドウクラスの登録
const wchar_t CLASS_NAME[] = L"ClassName";
WNDCLASS wc = {}; // メンバの初期化
wc.lpszClassName = CLASS_NAME; // クラス名
wc.lpfnWndProc = WindowProc; // ウィンドウ プロシージャ のアドレス
wc.hInstance = hInstance; // インスタンス ハンドル
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // カーソル
RegisterClass(&wc);
// 2.ウィンドウの作成
HWND hwnd = CreateWindowEx(
0, // 拡張ウィンドウ スタイル
CLASS_NAME, L"WindowName", // クラス名、ウィンドウ名
WS_OVERLAPPEDWINDOW, // ウィンドウスタイル
CW_USEDEFAULT, CW_USEDEFAULT, // ウィンドウの表示位置(x,y)
CW_USEDEFAULT, CW_USEDEFAULT, // ウィンドウの幅と高さ
NULL, // 親ウィンドウのハンドル
NULL, // メニューのハンドル
hInstance, // インスタンスハンドル
NULL); // 追加のデータ
if (hwnd == NULL)
{
return 0;
}
// 3.ウィンドウの表示
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// 4.メッセージループ
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// 5.ウィンドウプロシージャ
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
全てのメッセージを出力するプログラム
/*
winlog.cpp
g++ winlog.cpp -mwindows -o winlog.exe
*/
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void LogMessage(LPCWSTR fPath, UINT uMsg);
void LogString(LPCWSTR fPath, LPCWSTR str);
int counter = 0;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow)
{
// 1.ウィンドウクラスの登録
const wchar_t CLASS_NAME[] = L"ClassName";
WNDCLASS wc = {}; // メンバのゼロ初期化
wc.lpszClassName = CLASS_NAME; // クラス名
wc.lpfnWndProc = WindowProc; // ウィンドウ プロシージャ のアドレス
wc.hInstance = hInstance; // インスタンス ハンドル
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // カーソル
LogString(L"AllLog.txt", L"Before RegisterClass\n");
RegisterClass(&wc);
// 2.ウィンドウの作成
LogString(L"AllLog.txt", L"Before CreateWindowEx\n");
HWND hwnd = CreateWindowEx(
0, // 拡張ウィンドウ スタイル
CLASS_NAME, L"WindowName", // クラス名、ウィンドウ名
WS_OVERLAPPEDWINDOW, // ウィンドウスタイル
CW_USEDEFAULT, CW_USEDEFAULT, // ウィンドウの表示位置(x,y)
CW_USEDEFAULT, CW_USEDEFAULT, // ウィンドウの幅と高さ
NULL, // 親ウィンドウのハンドル
NULL, // メニューのハンドル
hInstance, // インスタンスハンドル
NULL); // 追加のデータ
if (hwnd == NULL)
{
return 0;
}
// 3.ウィンドウの表示
LogString(L"AllLog.txt", L"Before ShowWindow\n");
ShowWindow(hwnd, nCmdShow);
LogString(L"AllLog.txt", L"Before UpdateWindow\n");
UpdateWindow(hwnd);
// 4.メッセージループ
LogString(L"AllLog.txt", L"Before Message Loop\n");
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
LogMessage(L"MessageLoopLog.txt", msg.message);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// 5.ウィンドウプロシージャ
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LogMessage(L"AllLog.txt", uMsg);
counter++;
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
// ファイルにログを出力(メッセージ出力用)
void LogMessage(LPCWSTR fPath, UINT uMsg)
{
FILE *fp;
if (_wfopen_s(&fp, fPath, L"a, ccs=UTF-8") == 0)
{
fwprintf_s(fp, L"[#%04d] message: 0x%04X\n", counter, uMsg);
fclose(fp);
}
}
// ファイルにログを出力(Win32API関数名出力用)
void LogString(LPCWSTR fPath, LPCWSTR str)
{
FILE *fp;
if (_wfopen_s(&fp, fPath, L"a, ccs=UTF-8") == 0)
{
fwprintf_s(fp, str);
fclose(fp);
}
}
メッセージループ突入回数を表示するプログラム
/*
winlog.cpp
g++ winlog.cpp -mwindows -o winlog.exe
*/
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow)
{
// 1.ウィンドウクラスの登録
const wchar_t CLASS_NAME[] = L"ClassName";
WNDCLASS wc = {}; // メンバの初期化
wc.lpszClassName = CLASS_NAME; // クラス名
wc.lpfnWndProc = WindowProc; // ウィンドウ プロシージャ のアドレス
wc.hInstance = hInstance; // インスタンス ハンドル
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // カーソル
RegisterClass(&wc);
// 2.ウィンドウの作成
HWND hwnd = CreateWindowEx(
0, // 拡張ウィンドウ スタイル
CLASS_NAME, L"WindowName", // クラス名、ウィンドウ名
WS_OVERLAPPEDWINDOW, // ウィンドウスタイル
CW_USEDEFAULT, CW_USEDEFAULT, // ウィンドウの表示位置(x,y)
CW_USEDEFAULT, CW_USEDEFAULT, // ウィンドウの幅と高さ
NULL, // 親ウィンドウのハンドル
NULL, // メニューのハンドル
hInstance, // インスタンスハンドル
NULL); // 追加のデータ
if (hwnd == NULL)
{
return 0;
}
// 3.ウィンドウの表示
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// 4.メッセージループ
MSG msg = {};
int counter = 0;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
// メッセージループ突入回数を表示
if (counter <= 10000)
{
counter++;
}
wchar_t str_counter[256];
swprintf_s(str_counter, L"%d", counter);
SetWindowTextW(hwnd, str_counter);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// 5.ウィンドウプロシージャ
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
TranslateMessageの挙動を確認するプログラム
/*
winlog.cpp
g++ winlog.cpp -mwindows -o winlog.exe
*/
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
#include <intsafe.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void LogMessage(LPCWSTR fPath, UINT uMsg, WPARAM wParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow)
{
// 1.ウィンドウクラスの登録
const TCHAR CLASS_NAME[] = TEXT("ClassName");
WNDCLASS wc = {}; // メンバの初期化
wc.lpszClassName = CLASS_NAME; // クラス名
wc.lpfnWndProc = WindowProc; // ウィンドウ プロシージャ のアドレス
wc.hInstance = hInstance; // インスタンス ハンドル
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // カーソル
RegisterClass(&wc);
// 2.ウィンドウの作成
HWND hwnd = CreateWindowEx(
0, // 拡張ウィンドウ スタイル
CLASS_NAME, TEXT("WindowName"), // クラス名、ウィンドウ名
WS_OVERLAPPEDWINDOW, // ウィンドウスタイル
CW_USEDEFAULT, CW_USEDEFAULT, // ウィンドウの表示位置(x,y)
CW_USEDEFAULT, CW_USEDEFAULT, // ウィンドウの幅と高さ
NULL, // 親ウィンドウのハンドル
NULL, // メニューのハンドル
hInstance, // インスタンスハンドル
NULL); // 追加のデータ
if (hwnd == NULL)
{
return 0;
}
// 3.ウィンドウの表示
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// 4.メッセージループ
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
if (WM_KEYFIRST <= msg.message && msg.message <= WM_KEYLAST)
{
LogMessage(L"KeyMessage.txt", msg.message, msg.wParam);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// 5.ウィンドウプロシージャ
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
// ファイルにログを出力(メッセージ出力用)
void LogMessage(LPCWSTR fPath, UINT uMsg, WPARAM wParam)
{
FILE *fp;
if (_wfopen_s(&fp, fPath, L"a, ccs=UTF-8") == 0)
{
INT16 key = 0;
if (wParam)
{
UIntPtrToInt16(wParam, &key);
}
fwprintf_s(fp, L"message: 0x%04X 0x%02X\n", uMsg, key);
fclose(fp);
}
}
メッセージの数値を文字列に変換
hex2string.cs
というファイル名で保存して、コマンドライン上で
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe hex2string.cs
でコンパイルします。hex2string.exe
にテキストファイルをドロップすると0x0200
などの数値をWM_MOUSEMOVE
に置き換えます。
/*
hex2string.cs
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe hex2string.cs
*/
using System.Text;
using System.IO;
namespace hex2string
{
internal class Program
{
static void Main(string[] args)
{
foreach (string arg in args)
{
string filepath = arg;
string text = File.ReadAllText(filepath, new UTF8Encoding(false));
text = text.Replace("0x0000", "WM_NULL");
text = text.Replace("0x0001", "WM_CREATE");
text = text.Replace("0x0002", "WM_DESTROY");
text = text.Replace("0x0003", "WM_MOVE");
text = text.Replace("0x0005", "WM_SIZE");
text = text.Replace("0x0006", "WM_ACTIVATE");
text = text.Replace("0x0007", "WM_SETFOCUS");
text = text.Replace("0x0008", "WM_KILLFOCUS");
text = text.Replace("0x000A", "WM_ENABLE");
text = text.Replace("0x000B", "WM_SETREDRAW");
text = text.Replace("0x000C", "WM_SETTEXT");
text = text.Replace("0x000D", "WM_GETTEXT");
text = text.Replace("0x000E", "WM_GETTEXTLENGTH");
text = text.Replace("0x000F", "WM_PAINT");
text = text.Replace("0x0010", "WM_CLOSE");
text = text.Replace("0x0011", "WM_QUERYENDSESSION");
text = text.Replace("0x0012", "WM_QUIT");
text = text.Replace("0x0013", "WM_QUERYOPEN");
text = text.Replace("0x0014", "WM_ERASEBKGND");
text = text.Replace("0x0015", "WM_SYSCOLORCHANGE");
text = text.Replace("0x0016", "WM_ENDSESSION");
text = text.Replace("0x0018", "WM_SHOWWINDOW");
text = text.Replace("0x001A", "WM_WININICHANGE");
text = text.Replace("0x001B", "WM_DEVMODECHANGE");
text = text.Replace("0x001C", "WM_ACTIVATEAPP");
text = text.Replace("0x001D", "WM_FONTCHANGE");
text = text.Replace("0x001E", "WM_TIMECHANGE");
text = text.Replace("0x001F", "WM_CANCELMODE");
text = text.Replace("0x0020", "WM_SETCURSOR");
text = text.Replace("0x0021", "WM_MOUSEACTIVATE");
text = text.Replace("0x0022", "WM_CHILDACTIVATE");
text = text.Replace("0x0023", "WM_QUEUESYNC");
text = text.Replace("0x0024", "WM_GETMINMAXINFO");
text = text.Replace("0x0026", "WM_PAINTICON");
text = text.Replace("0x0027", "WM_ICONERASEBKGND");
text = text.Replace("0x0028", "WM_NEXTDLGCTL");
text = text.Replace("0x002A", "WM_SPOOLERSTATUS");
text = text.Replace("0x002B", "WM_DRAWITEM");
text = text.Replace("0x002C", "WM_MEASUREITEM");
text = text.Replace("0x002D", "WM_DELETEITEM");
text = text.Replace("0x002E", "WM_VKEYTOITEM");
text = text.Replace("0x002F", "WM_CHARTOITEM");
text = text.Replace("0x0030", "WM_SETFONT");
text = text.Replace("0x0031", "WM_GETFONT");
text = text.Replace("0x0032", "WM_SETHOTKEY");
text = text.Replace("0x0033", "WM_GETHOTKEY");
text = text.Replace("0x0037", "WM_QUERYDRAGICON");
text = text.Replace("0x0039", "WM_COMPAREITEM");
text = text.Replace("0x003D", "WM_GETOBJECT");
text = text.Replace("0x0041", "WM_COMPACTING");
text = text.Replace("0x0044", "WM_COMMNOTIFY");
text = text.Replace("0x0046", "WM_WINDOWPOSCHANGING");
text = text.Replace("0x0047", "WM_WINDOWPOSCHANGED");
text = text.Replace("0x0048", "WM_POWER");
text = text.Replace("0x004A", "WM_COPYDATA");
text = text.Replace("0x004B", "WM_CANCELJOURNAL");
text = text.Replace("0x004E", "WM_NOTIFY");
text = text.Replace("0x0050", "WM_INPUTLANGCHANGEREQUEST");
text = text.Replace("0x0051", "WM_INPUTLANGCHANGE");
text = text.Replace("0x0052", "WM_TCARD");
text = text.Replace("0x0053", "WM_HELP");
text = text.Replace("0x0054", "WM_USERCHANGED");
text = text.Replace("0x0055", "WM_NOTIFYFORMAT");
text = text.Replace("0x007B", "WM_CONTEXTMENU");
text = text.Replace("0x007C", "WM_STYLECHANGING");
text = text.Replace("0x007D", "WM_STYLECHANGED");
text = text.Replace("0x007E", "WM_DISPLAYCHANGE");
text = text.Replace("0x007F", "WM_GETICON");
text = text.Replace("0x0080", "WM_SETICON");
text = text.Replace("0x0081", "WM_NCCREATE");
text = text.Replace("0x0082", "WM_NCDESTROY");
text = text.Replace("0x0083", "WM_NCCALCSIZE");
text = text.Replace("0x0084", "WM_NCHITTEST");
text = text.Replace("0x0085", "WM_NCPAINT");
text = text.Replace("0x0086", "WM_NCACTIVATE");
text = text.Replace("0x0087", "WM_GETDLGCODE");
text = text.Replace("0x0088", "WM_SYNCPAINT");
text = text.Replace("0x00A0", "WM_NCMOUSEMOVE");
text = text.Replace("0x00A1", "WM_NCLBUTTONDOWN");
text = text.Replace("0x00A2", "WM_NCLBUTTONUP");
text = text.Replace("0x00A3", "WM_NCLBUTTONDBLCLK");
text = text.Replace("0x00A4", "WM_NCRBUTTONDOWN");
text = text.Replace("0x00A5", "WM_NCRBUTTONUP");
text = text.Replace("0x00A6", "WM_NCRBUTTONDBLCLK");
text = text.Replace("0x00A7", "WM_NCMBUTTONDOWN");
text = text.Replace("0x00A8", "WM_NCMBUTTONUP");
text = text.Replace("0x00A9", "WM_NCMBUTTONDBLCLK");
text = text.Replace("0x00AB", "WM_NCXBUTTONDOWN");
text = text.Replace("0x00AC", "WM_NCXBUTTONUP");
text = text.Replace("0x00AD", "WM_NCXBUTTONDBLCLK");
text = text.Replace("0x00FE", "WM_INPUT_DEVICE_CHANGE");
text = text.Replace("0x00FF", "WM_INPUT");
text = text.Replace("0x0100", "WM_KEYDOWN");
text = text.Replace("0x0101", "WM_KEYUP");
text = text.Replace("0x0102", "WM_CHAR");
text = text.Replace("0x0103", "WM_DEADCHAR");
text = text.Replace("0x0104", "WM_SYSKEYDOWN");
text = text.Replace("0x0105", "WM_SYSKEYUP");
text = text.Replace("0x0106", "WM_SYSCHAR");
text = text.Replace("0x0107", "WM_SYSDEADCHAR");
text = text.Replace("0x0108", "WM_KEYLAST");
text = text.Replace("0x0109", "WM_UNICHAR");
text = text.Replace("0x010D", "WM_IME_STARTCOMPOSITION");
text = text.Replace("0x010E", "WM_IME_ENDCOMPOSITION");
text = text.Replace("0x010F", "WM_IME_COMPOSITION");
text = text.Replace("0x0110", "WM_INITDIALOG");
text = text.Replace("0x0111", "WM_COMMAND");
text = text.Replace("0x0112", "WM_SYSCOMMAND");
text = text.Replace("0x0113", "WM_TIMER");
text = text.Replace("0x0114", "WM_HSCROLL");
text = text.Replace("0x0115", "WM_VSCROLL");
text = text.Replace("0x0116", "WM_INITMENU");
text = text.Replace("0x0117", "WM_INITMENUPOPUP");
text = text.Replace("0x0119", "WM_GESTURE");
text = text.Replace("0x011A", "WM_GESTURENOTIFY");
text = text.Replace("0x011F", "WM_MENUSELECT");
text = text.Replace("0x0120", "WM_MENUCHAR");
text = text.Replace("0x0121", "WM_ENTERIDLE");
text = text.Replace("0x0122", "WM_MENURBUTTONUP");
text = text.Replace("0x0123", "WM_MENUDRAG");
text = text.Replace("0x0124", "WM_MENUGETOBJECT");
text = text.Replace("0x0125", "WM_UNINITMENUPOPUP");
text = text.Replace("0x0126", "WM_MENUCOMMAND");
text = text.Replace("0x0127", "WM_CHANGEUISTATE");
text = text.Replace("0x0128", "WM_UPDATEUISTATE");
text = text.Replace("0x0129", "WM_QUERYUISTATE");
text = text.Replace("0x0132", "WM_CTLCOLORMSGBOX");
text = text.Replace("0x0133", "WM_CTLCOLOREDIT");
text = text.Replace("0x0134", "WM_CTLCOLORLISTBOX");
text = text.Replace("0x0135", "WM_CTLCOLORBTN");
text = text.Replace("0x0136", "WM_CTLCOLORDLG");
text = text.Replace("0x0137", "WM_CTLCOLORSCROLLBAR");
text = text.Replace("0x0138", "WM_CTLCOLORSTATIC");
text = text.Replace("0x0200", "WM_MOUSEMOVE");
text = text.Replace("0x0201", "WM_LBUTTONDOWN");
text = text.Replace("0x0202", "WM_LBUTTONUP");
text = text.Replace("0x0203", "WM_LBUTTONDBLCLK");
text = text.Replace("0x0204", "WM_RBUTTONDOWN");
text = text.Replace("0x0205", "WM_RBUTTONUP");
text = text.Replace("0x0206", "WM_RBUTTONDBLCLK");
text = text.Replace("0x0207", "WM_MBUTTONDOWN");
text = text.Replace("0x0208", "WM_MBUTTONUP");
text = text.Replace("0x0209", "WM_MBUTTONDBLCLK");
text = text.Replace("0x020A", "WM_MOUSEWHEEL");
text = text.Replace("0x020B", "WM_XBUTTONDOWN");
text = text.Replace("0x020C", "WM_XBUTTONUP");
text = text.Replace("0x020D", "WM_XBUTTONDBLCLK");
text = text.Replace("0x020E", "WM_MOUSEHWHEEL");
text = text.Replace("0x0210", "WM_PARENTNOTIFY");
text = text.Replace("0x0211", "WM_ENTERMENULOOP");
text = text.Replace("0x0212", "WM_EXITMENULOOP");
text = text.Replace("0x0213", "WM_NEXTMENU");
text = text.Replace("0x0214", "WM_SIZING");
text = text.Replace("0x0215", "WM_CAPTURECHANGED");
text = text.Replace("0x0216", "WM_MOVING");
text = text.Replace("0x0218", "WM_POWERBROADCAST");
text = text.Replace("0x0219", "WM_DEVICECHANGE");
text = text.Replace("0x0220", "WM_MDICREATE");
text = text.Replace("0x0221", "WM_MDIDESTROY");
text = text.Replace("0x0222", "WM_MDIACTIVATE");
text = text.Replace("0x0223", "WM_MDIRESTORE");
text = text.Replace("0x0224", "WM_MDINEXT");
text = text.Replace("0x0225", "WM_MDIMAXIMIZE");
text = text.Replace("0x0226", "WM_MDITILE");
text = text.Replace("0x0227", "WM_MDICASCADE");
text = text.Replace("0x0228", "WM_MDIICONARRANGE");
text = text.Replace("0x0229", "WM_MDIGETACTIVE");
text = text.Replace("0x0230", "WM_MDISETMENU");
text = text.Replace("0x0231", "WM_ENTERSIZEMOVE");
text = text.Replace("0x0232", "WM_EXITSIZEMOVE");
text = text.Replace("0x0233", "WM_DROPFILES");
text = text.Replace("0x0234", "WM_MDIREFRESHMENU");
text = text.Replace("0x0238", "WM_POINTERDEVICECHANGE");
text = text.Replace("0x0239", "WM_POINTERDEVICEINRANGE");
text = text.Replace("0x023A", "WM_POINTERDEVICEOUTOFRANGE");
text = text.Replace("0x0240", "WM_TOUCH");
text = text.Replace("0x0241", "WM_NCPOINTERUPDATE");
text = text.Replace("0x0242", "WM_NCPOINTERDOWN");
text = text.Replace("0x0243", "WM_NCPOINTERUP");
text = text.Replace("0x0245", "WM_POINTERUPDATE");
text = text.Replace("0x0246", "WM_POINTERDOWN");
text = text.Replace("0x0247", "WM_POINTERUP");
text = text.Replace("0x0249", "WM_POINTERENTER");
text = text.Replace("0x024A", "WM_POINTERLEAVE");
text = text.Replace("0x024B", "WM_POINTERACTIVATE");
text = text.Replace("0x024C", "WM_POINTERCAPTURECHANGED");
text = text.Replace("0x024D", "WM_TOUCHHITTESTING");
text = text.Replace("0x024E", "WM_POINTERWHEEL");
text = text.Replace("0x024F", "WM_POINTERHWHEEL");
text = text.Replace("0x0251", "WM_POINTERROUTEDTO");
text = text.Replace("0x0252", "WM_POINTERROUTEDAWAY");
text = text.Replace("0x0253", "WM_POINTERROUTEDRELEASED");
text = text.Replace("0x0281", "WM_IME_SETCONTEXT");
text = text.Replace("0x0282", "WM_IME_NOTIFY");
text = text.Replace("0x0283", "WM_IME_CONTROL");
text = text.Replace("0x0284", "WM_IME_COMPOSITIONFULL");
text = text.Replace("0x0285", "WM_IME_SELECT");
text = text.Replace("0x0286", "WM_IME_CHAR");
text = text.Replace("0x0288", "WM_IME_REQUEST");
text = text.Replace("0x0290", "WM_IME_KEYDOWN");
text = text.Replace("0x0291", "WM_IME_KEYUP");
text = text.Replace("0x02A0", "WM_NCMOUSEHOVER");
text = text.Replace("0x02A1", "WM_MOUSEHOVER");
text = text.Replace("0x02A2", "WM_NCMOUSELEAVE");
text = text.Replace("0x02A3", "WM_MOUSELEAVE");
text = text.Replace("0x02B1", "WM_WTSSESSION_CHANGE");
text = text.Replace("0x02E0", "WM_DPICHANGED");
text = text.Replace("0x02E2", "WM_DPICHANGED_BEFOREPARENT");
text = text.Replace("0x02E3", "WM_DPICHANGED_AFTERPARENT");
text = text.Replace("0x02E4", "WM_GETDPISCALEDSIZE");
text = text.Replace("0x0300", "WM_CUT");
text = text.Replace("0x0301", "WM_COPY");
text = text.Replace("0x0302", "WM_PASTE");
text = text.Replace("0x0303", "WM_CLEAR");
text = text.Replace("0x0304", "WM_UNDO");
text = text.Replace("0x0305", "WM_RENDERFORMAT");
text = text.Replace("0x0306", "WM_RENDERALLFORMATS");
text = text.Replace("0x0307", "WM_DESTROYCLIPBOARD");
text = text.Replace("0x0308", "WM_DRAWCLIPBOARD");
text = text.Replace("0x0309", "WM_PAINTCLIPBOARD");
text = text.Replace("0x030A", "WM_VSCROLLCLIPBOARD");
text = text.Replace("0x030B", "WM_SIZECLIPBOARD");
text = text.Replace("0x030C", "WM_ASKCBFORMATNAME");
text = text.Replace("0x030D", "WM_CHANGECBCHAIN");
text = text.Replace("0x030E", "WM_HSCROLLCLIPBOARD");
text = text.Replace("0x030F", "WM_QUERYNEWPALETTE");
text = text.Replace("0x0310", "WM_PALETTEISCHANGING");
text = text.Replace("0x0311", "WM_PALETTECHANGED");
text = text.Replace("0x0312", "WM_HOTKEY");
text = text.Replace("0x0317", "WM_PRINT");
text = text.Replace("0x0318", "WM_PRINTCLIENT");
text = text.Replace("0x0319", "WM_APPCOMMAND");
text = text.Replace("0x031A", "WM_THEMECHANGED");
text = text.Replace("0x031D", "WM_CLIPBOARDUPDATE");
text = text.Replace("0x031E", "WM_DWMCOMPOSITIONCHANGED");
text = text.Replace("0x031F", "WM_DWMNCRENDERINGCHANGED");
text = text.Replace("0x0320", "WM_DWMCOLORIZATIONCOLORCHANGED");
text = text.Replace("0x0321", "WM_DWMWINDOWMAXIMIZEDCHANGE");
text = text.Replace("0x0323", "WM_DWMSENDICONICTHUMBNAIL");
text = text.Replace("0x0326", "WM_DWMSENDICONICLIVEPREVIEWBITMAP");
text = text.Replace("0x033F", "WM_GETTITLEBARINFOEX");
text = text.Replace("0x0345", "WM_TOOLTIPDISMISS");
string dir = Path.GetDirectoryName(filepath);
string filename = Path.GetFileNameWithoutExtension(filepath);
File.WriteAllText(dir + @"\" + filename + "_fix.txt", text, new UTF8Encoding(false));
}
}
}
}
その他参考URL
メッセージについて
- メッセージとメッセージ キューについて - Win32 apps | Microsoft Learn
- C言語 #defineとは? 記号定数 | プログラミングランド
- 定数
- 記号定数 | Programming Place Plus 用語集
- Named Constants
HTMLテーブル作成
- レスポンシブも対応!綺麗で見やすい表のデザイン11個[HTML&CSS] | SEO対策なら株式会社ペコプラ
- CSSで下線を引く方法とは?二重線・破線・波線・蛍光線など徹底解説! | 侍エンジニアブログ
ログ出力用