パソコンでプログラミングしよう ウィンドウズC++プログラミング環境の構築
1.6.3.6(15)
ソースコード(wxWidgetsのメッセージハンドラ実装)

wxWidgetsライブラリウィンドウズメッセージハンドラをどのように実装するかをソースコードで確認する。

ダウンロードリンク

最新版は以下からダウンロードできる。ただし本項目調査はバージョン3.1.0ソースコードを用いた。

ソースコード

wxWidgetsを利用するソースコード例として動作確認(1)のDesktop1プロジェクトを用いる。メインウィンドウクラスDesktop1FrameはDesktop1Frame.hに定義され、継承はDesktop1Frame->wxFrame->wxFrameBase->wxTopLevelWindow->wxTopLevelWindowNative->wxTopLevelWindowBase->wxNonOwnedWindow->wxNonOwnedWindowBase->wxWindowである。wxWidgetsのウィンドウズ実装でwxTopLevelWindowNativeはwxTopLevelWindowMSW(include\wx\toplevel.h:329)に#defineされ、wxWindowはwxWindowMSW(include\wx\window.h:1932)に#defineされる。ソースコードでwxWindowMSWとされているものはクライアントコードから通常はwxWindowで参照される。

Desktop1Frameは基底クラスのwxFrameを2ステップ構築するためDesktop1Frame.cppのコンストラクタ内でwxFrame::Createをコールする。

Desktop1Frame::Desktop1Frame(wxWindow* parent,wxWindowID id)
{
//(*Initialize(Desktop1Frame)
...
Create(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, _T("id"));
...
//*)
...
}

wxFrameの構築

wxWindowを継承するウィンドウ(コントロールを含む)はウィンドウズAPIが定義するウィンドウハンドルを内部データとして持ち、そのメッセージハンドラとなるウィンドウプロシージャを定義する。ほどんどのwxWindow派生クラスは引数を持つコンストラクタによる1ステップ構築と、引数を持たないデフォルトコンストラクタとCreateメンバ関数による2ステップ構築を用意する。1ステップ構築もコンストラクタ内でCreateをコールする。wxFrame(include\wx\msw\frame.h:18)の場合を示す。

class WXDLLIMPEXP_CORE wxFrame : public wxFrameBase
{
public:
wxFrame() { Init(); }
wxFrame(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_FRAME_STYLE,
const wxString& name = wxFrameNameStr)
{
Init();
Create(parent, id, title, pos, size, style, name);
}
bool Create(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_FRAME_STYLE,
const wxString& name = wxFrameNameStr);
virtual ~wxFrame();
...
};

wxFrame::Create(src\msw\frame.cpp:117)はwxTopLevelWindowMSW::Create(src\msw\toplevel.cpp:414)をコールする。Desktop1プロジェクトはフレームベースなのでCreateはwxTopLevelWindowMSW::CreateFrame(src\msw\toplevel.cpp:398)をコールする。CreateFrameはさらにwxWindowMSW::MSWCreateをコールする。MSWCreate(src\msw\window.cpp:3630)がウィンドウハンドルを生成しウィンドウプロシージャを定義する。

bool wxTopLevelWindowMSW::Create(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
{
...
if ( GetExtraStyle() & wxTOPLEVEL_EX_DIALOG ) // ダイアログベース
{
static const int dlgsize = sizeof(DLGTEMPLATE) + (sizeof(WORD) * 3);
DLGTEMPLATE *dlgTemplate = (DLGTEMPLATE *)malloc(dlgsize);
memset(dlgTemplate, 0, dlgsize);
... // ダイアログの構築
ret = CreateDialog(dlgTemplate, title, pos, sizeReal);
free(dlgTemplate);
}
else // フレームベース
{
ret = CreateFrame(title, pos, sizeReal);
}
...
return ret;
}
...
bool wxTopLevelWindowMSW::CreateFrame(const wxString& title,
const wxPoint& pos,
const wxSize& size)
{
...
return MSWCreate(MSWGetRegisteredClassName(),
title.t_str(), pos, sz, flags, exflags);
}

メインウィンドウがダイアログベースの場合はwxTopLevelWindowMSW::CreateDialog(src\msw\toplevel.cpp:326)をコールする。CreateDialogはMSWCreateをコールせず自らウィンドウハンドルを作成しウィンドウプロシージャを定義する。

bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate,
const wxString& title,
const wxPoint& pos,
const wxSize& size)
{
wxWindow * const
parent = static_cast<wxDialog *>(this)->GetParentForModalDialog();
m_hWnd = (WXHWND)::CreateDialogIndirect
(
wxGetInstance(),
(DLGTEMPLATE*)dlgTemplate,
parent ? GetHwndOf(parent) : NULL,
(DLGPROC)wxDlgProc
);
if ( !m_hWnd )
{
return false;
}
...
SubclassWin(m_hWnd);
...
return true;
}

コントロール(wxControl派生クラス)の場合はケースバイケースとなるが、普通は自らのCreate関数からウィンドウクラス名を指定してwxWindowMSW::MSWCreateControl(src\msw\control.cpp:102)をコールし、MSWCreateControlがウィンドウハンドルを作成しウィンドウプロシージャを定義する。標準コントロール(例えばwxButton)ならウィンドウクラス名に標準名(Button)を指定してウィンドウズが事前定義するコントロールのウィンドウハンドルを作成する。自らのCreate関数を持たない場合はwxWindowMSW::Create(src\msw\window.cpp:478)がwxTopLevelWindowMSW::CreateFrameと同様にMSWCreateをコールし、wxFrameと同じウィンドウクラスとなってしまう。

まとめればwxWindow派生クラスは構築時にMSWCreate、CreateDialog、MSWCreateControlのいずれかでウィンドウハンドルを作成しウィンドウプロシージャを定義する。

ウィンドウハンドルの作成

ウィンドウハンドルの作成についてまとめる。wxFrameのウィンドウクラス名(wxWindowあるいはwxWindowNR)はwxWidgets定義で、そのウィンドウクラスはwxWindowMSW::MSWGetRegisteredClassNameが作成する。wxDialogの奇妙なウィンドウクラス名はウィンドウズ標準ダイアログのウィンドウクラス名である。

基底クラス クラス wxWidgets関数 ウィンドウズAPI ウィンドウクラス名
wxTopLevelWindow wxFrame wxWindowMSW::MSWCreate CreateWindowEx wxWindowNR
wxDialog wxTopLevelWindowMSW::CreateDialog CreateDialogIndirect #32770
wxControl 標準(例えばwxButton) wxWindowMSW::MSWCreateControl CreateWindowEx 標準(例えばButton)
カスタム(Create関数定義) wxWindowMSW::MSWCreateControl CreateWindowEx カスタム

wxWindowMSW::MSWGetRegisteredClassName(src\msw\window.cpp:472)は"wxWindow"を実引数に与えてwxApp::GetRegisteredClassName(src\msw\app.cpp:614)をコールする。GetRegisteredClassNameは与えられた名前(例えばwxWindow)を持つウィンドウクラスが存在しない場合、リサイズ時に再描画するウィンドウクラス(wxWindow)と再描画しないウィンドウクラス(wxWindowNR)をウィンドウズAPIのRegisterClassで作成する。関数はリサイズ再描画する方のウィンドウクラス名(wxWindow)を返す。

const wxChar *wxWindowMSW::MSWGetRegisteredClassName()
{
return wxApp::GetRegisteredClassName(wxT("wxWindow"), COLOR_BTNFACE);
}
const wxChar *wxApp::GetRegisteredClassName(const wxChar *name,
int bgBrushCol,
int extraStyles)
{
... // ウィンドウクラス名が定義済みならそのままリターン
WNDCLASS wndclass;
wxZeroMemory(wndclass);
wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
wndclass.hInstance = wxGetInstance();
wndclass.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)wxUIntToPtr(bgBrushCol + 1);
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | extraStyles;
ClassRegInfo regClass(name);
wndclass.lpszClassName = regClass.regname.t_str();
if ( !::RegisterClass(&wndclass) ) // リサイズ時再描画するウィンドウ
{ // ウィンドウクラス名は例えば"wxWindow"
return NULL;
}
wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW);
wndclass.lpszClassName = regClass.regnameNR.t_str();
if ( !::RegisterClass(&wndclass) ) // リサイズ時再描画しないウィンドウ
{ // ウィンドウクラス名は例えば"wxWindowNR"
::UnregisterClass(regClass.regname.c_str(), wxGetInstance());
return NULL;
}
... // ウィンドウクラス名を登録
return gs_regClassesInfo.back().regname.t_str();
}

MSWCreate、MSWCreateControl、CreateDialogはCreateWindowExあるいはCreateDialogIndirectでウィンドウハンドルを作成した後に、共通のwxWindowMSW::SubclassWinをコールしてウィンドウプロシージャを定義する。wxWindowMSW::MSWCreateの場合を示す。

bool wxWindowMSW::MSWCreate(const wxChar *wclass,
const wxChar *title,
const wxPoint& pos,
const wxSize& size,
WXDWORD style,
WXDWORD extendedStyle)
{
...
wxString className(wclass);
if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) ) // リサイズ時再描画しないウィンドウ
{
className += wxApp::GetNoRedrawClassSuffix(); //ウィンドウクラス名に"NR"を追加
}
...
m_hWnd = (WXHWND)::CreateWindowEx
(
extendedStyle,
className.t_str(),
title ? title : m_windowName.t_str(),
style,
x, y, w, h,
(HWND)MSWGetParent(),
(HMENU)wxUIntToPtr(controlId),
wxGetInstance(),
NULL
);
if ( !m_hWnd )
{
return false;
}
SubclassWin(m_hWnd);
return true;
}

ウィンドウプロシージャの定義

全てのwxWindow派生クラスはwxWindowMSW::SubclassWin(src\msw\window.cpp:1092)をコールして同じwxWndProcをウィンドウプロシージャに定義する。wxFrameのようにウィンドウクラスをwxApp::GetRegisteredClassNameで作成した場合はwxWndProcが既に定義されていて冗長だが、SubclassWinが正しく対応する。wxSetWindowProc(include\wx\msw\private.h:1125/1149)とwxGetWindowProc(include\wx\msw\private.h:1115/1139)は32ビット/64ビットに従いウィンドウズAPIのSetWindowLong/SetWindowLongPtrとGetWindowLong/GetWindowLongPtrで指定されたウィンドウハンドルのウィンドウプロシージャを定義あるいは取得する。

void wxWindowMSW::SubclassWin(WXHWND hWnd)
{
...
HWND hwnd = (HWND)hWnd;
SetHWND(hWnd);
wxAssociateWinWithHandle(hwnd, this); // thisとウィンドウハンドルを関連付け
...
m_oldWndProc = (WXFARPROC)wxGetWindowProc((HWND)hWnd); // 古いウィンドウプロシージャを記憶
if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) ) // 古いウィンドウプロシージャがwxWndProcでない
{
wxSetWindowProc(hwnd, wxWndProc); // ウィンドウプロシージャをwxWndProcに設定
...
}
else // 古いウィンドウプロシージャがwxWndProc(例えばwxFrameの場合)
{
m_oldWndProc = NULL; // 記憶値を消去
}
...
}
#ifdef __WIN64__
inline void *wxGetWindowProc(HWND hwnd)
{
return (void *)::GetWindowLongPtr(hwnd, GWLP_WNDPROC);
}
inline WNDPROC wxSetWindowProc(HWND hwnd, WNDPROC func)
{
return (WNDPROC)::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)func);
}
#else // __WIN32__
inline WNDPROC wxGetWindowProc(HWND hwnd)
{
return (WNDPROC)(LONG_PTR)::GetWindowLong(hwnd, GWL_WNDPROC);
}
inline WNDPROC wxSetWindowProc(HWND hwnd, WNDPROC func)
{
return (WNDPROC)(LONG_PTR)::SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR)func);
}
#endif // __WIN64__/__WIN32__
覚え書き
32ビットではSetWindowLongPtrとGetWindowLongPtrをSetWindowLongとGetWindowLongに#defineし、かつGWLP_XXXとGWL_XXXは等しい。従ってSetWindowLongPtrとGetWindowLongPtrだけを用いれば32ビット/64ビットを切り替える#ifdefは不要である。

wxWndProc(src\msw\window.cpp:2632)はウィンドウハンドルからwxWindowポインタを取得し、派生クラスがオーバーライドするMSWWindowProc仮想メンバ関数をコールする。このMSWWindowProcはマニュアルに記載されていない。wxWindowポインタを取得できない(wxWidgets管理ウィンドウでない)場合、あるいはwxGUIEventLoop::AllowProcessing(include\wx\msw\evtloop.h:48)がfalse(クラッシュレポートなどのクリティカルウィンドウがメッセージ処理抑制)の場合はウィンドウズAPIのDefWindowProcデフォルトウィンドウプロシージャをコールする。

LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
wxWindowMSW *wnd = wxFindWinFromHandle(hWnd); // 関連付けからwxWindowポインタ取得
if ( !wnd && gs_winBeingCreated ) // 関連付けが無いwxWidgets管理ウィンドウ
{
... // SubclassWinが必ず関連付けるのでここの処理が実行される事はない
}
LRESULT rc;
wxSEH_TRY // 例外処理が必要(https://msdn.microsoft.com/en-us/library/ms633573.aspx)
{
if ( wnd && wxGUIEventLoop::AllowProcessing(wnd) )
rc = wnd->MSWWindowProc(message, wParam, lParam);
else // wxWidgets管理ウィンドウでない、あるいはメッセージ処理抑制
rc = ::DefWindowProc(hWnd, message, wParam, lParam);
}
wxSEH_HANDLE(0)
return rc;
}

wxWindow派生クラスはwxWindowMSW::MSWWindowProc(src\msw\window.cpp:3251)のオーバーライドでウィンドウズメッセージ処理を任意に変更できる。ソースコードコメントはMSWWindowProcオーバーライドではなくコールするwxWindowMSW::MSWHandleMessage(src\msw\window.cpp:2676)オーバーライドを推奨している。MSWWindowProcはMSWHandleMessageがメッセージ処理を行わない場合はwxWindowMSW::MSWDefWindowProcをコールする。MSWHandleMessage、MSWDefWindowProc共にMSWWindowProcと同じくマニュアルに記載されていない。

WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
{
WXLRESULT result;
if ( !MSWHandleMessage(&result, message, wParam, lParam) )
{
result = MSWDefWindowProc(message, wParam, lParam);
}
return result;
}
...
bool
wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
WXUINT message,
WXWPARAM wParam,
WXLPARAM lParam)
{
bool processed = false;
union
{
bool allow;
WXLRESULT result;
WXHBRUSH hBrush;
} rc;
rc.result = 0;
switch ( message )
{
... // 多数のウィンドウズメッセージ処理(case WM_XXX: ... break;)
default: // カスタムメッセージ処理
const MSWMessageHandlers::const_iterator
i = gs_messageHandlers.find(message);
if ( i != gs_messageHandlers.end() )
{
processed = (*i->second)(this, message, wParam, lParam);
}
}
if ( !processed )
return false;
*result = rc.result;
return true;
}
覚え書き
wxWidgetsが処理しないウィンドウズメッセージ(カスタムメッセージ)処理はMSWWindowProcあるいはMSWHandleMessageのオーバーライドでも実施できるが、MSWHandleMessageのswitch節デフォルトが示すようにgs_messageHandlersに登録すればオーバーライドは必要ない。登録関数はwxWindowMSW::MSWRegisterMessageHandler(src\msw\window.cpp:5912)、解除関数はwxWindowMSW::MSWUnregisterMessageHandler(src\msw\window.cpp:5922)で、どちらもスタティックメンバ関数でマニュアルには記載されていない。ライブラリはこのカスタムメッセージ登録をただ一箇所(wxFindReplaceDialogImpl::wxFindReplaceDialogImpl(src\msw\fdrepdlg.cpp:117))で利用する。

wxWindowMSW::MSWDefWindowProc(src\msw\window.cpp:2205)仮想メンバ関数はSubclassWinで記憶した古いウィンドウプロシージャをコールし、そのようなウィンドウプロシージャが無い場合(例えばwxFrameの場合)はDefWindowProcをコールする。

WXLRESULT wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
WXLRESULT rc;
if ( m_oldWndProc )
rc = ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
else
rc = ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
... // wxTextEntryオートコンプレッションハック
return rc;
}

wxFrameのウィンドウプロシージャ

wxFrame::MSWWindowProc(src\msw\frame.cpp:825)を示す。

WXLRESULT wxFrame::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
{
WXLRESULT rc = 0;
bool processed = false;
switch ( message )
{
case WM_CLOSE:
processed = !Close();
break;
case WM_SIZE:
processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam);
break;
case WM_COMMAND:
{
WORD id, cmd;
WXHWND hwnd;
UnpackCommand((WXWPARAM)wParam, (WXLPARAM)lParam,
&id, &hwnd, &cmd);
HandleCommand(id, cmd, (WXHWND)hwnd);
processed = true; // HandleCommandが基底コールするので必ずtrue
}
break;
case WM_INITMENUPOPUP:
case WM_UNINITMENUPOPUP:
if ( wxMenuBar* mbar = GetMenuBar() )
{
const int pos = mbar->MSWGetTopMenuPos((WXHMENU)wParam);
if ( pos != wxNOT_FOUND && !mbar->IsEnabledTop(pos) )
{ // 無効なメニューバーからのメッセージは無視する
return MSWDefWindowProc(message, wParam, lParam);
}
}
break;
case WM_QUERYDRAGICON:
{
const wxIcon& icon = GetIcon();
HICON hIcon = icon.IsOk() ? GetHiconOf(icon)
: (HICON)GetDefaultIcon();
rc = (WXLRESULT)hIcon;
processed = rc != 0;
}
break;
}
#if wxUSE_TASKBARBUTTON
...
#endif
if ( !processed )
rc = wxFrameBase::MSWWindowProc(message, wParam, lParam);
return rc;
}

ここで処理されないメッセージはwxTopLevelWindowMSW::MSWWindowProc(src\msw\toplevel.cpp:258)とwxWindowMSW::MSWWindowProcがコールするwxWindowMSW::MSWHandleMessageで処理される。以下がウィンドウズメッセージ処理のほぼ完全なリストである。processedは処理完了フラグで多くは処理結果が代入されるが、いくつかの場合でtrueまたはfalseに固定される。processedがfalseの場合は基底クラスが引き続き処理を実行する。処理関数のうちHandleXXXとDoXXXは各クラスの仮想でないメンバ関数で、MSWOnXXXはマニュアルに記載されない仮想メンバ関数である。HandleXXXの多くはwxWidgetsイベントを生成してイベントハンドラに処理を委ねる。HandleNotifyはMSWOnNotify仮想メンバ関数をコールする。通常のカスタマイズはwxWidgetsイベントハンドラ、あるいは派生クラスにおけるMSWOnXXXを含む仮想メンバ関数オーバーライドで実施する。ウィンドウズメッセージ処理を直接カスタマイズするにはMSWWindowProcかMSWHandleMessageをオーバーライドするが、ほとんどのメッセージはMSWHandleMessageでオーバーライドできる。いくつかのメッセージ(例えばWM_SIZE)はMSWWindowProcが処理するためこちらをオーバーライドする事になるが、これらはwxWidgetsイベント(wxEVT_SIZE)処理でカスタマイズできるため必要性は少ない。

関数 ウィンドウズメッセージ 処理 processed 備考
wxFrame::MSWWindowProc WM_CLOSE !Close(...) -
WM_SIZE HandleSize(...) -
WM_COMMAND HandleCommand(...) true -
WM_QUERYDRAGICON ドラッグアイコン取得 -
wxTopLevelWindowMSW::MSWWindowProc WM_SYSCOMMAND SC_MINIMIZE DoSaveLastFocus(...) false -
SC_RESTORE DoRestoreLastFocus(...) true 先に基底MSWWindowProcをコール
SC_SIZE未満 m_menuSystem->MSWCommand(0,id) true システムメニューカスタマイズ
wxWindowMSW::MSWHandleMessage WM_CREATE HandleCreate(...) -
WM_DESTROY HandleDestroy(...) false -
WM_SIZE HandleSize(...) -
WM_MOVE HandleMove(...) -
WM_MOVING HandleMoving(...) -
WM_ENTERSIZEMOVE HandleEnterSizeMove(...) -
WM_EXITSIZEMOVE HandleExitSizeMove(...) -
WM_SIZING HandleSizing(...) -
WM_ACTIVATEAPP wxTheApp->SetActive(...) false -
WM_ACTIVATE HandleActivate(...) -
WM_SETFOCUS HandleSetFocus(...) -
WM_KILLFOCUS HandleKillFocus(...) -
WM_PRINTCLIENT HandlePrintClient(...) -
WM_PAINT HandlePaint(...) -
WM_CLOSE - true rc.result=true、~wxWindowに任せる
WM_SHOWWINDOW HandleShow(...) -
WM_MOUSEMOVE HandleMouseMove(...) -
WM_MOUSELEAVE 過剰イベントのフィルター false (理解困難)
WM_MOUSEWHEEL など HandleMouseWheel(...) -
WM_LBUTTONDOWN など HandleMouseEvent(...) -
MM_JOY1MOVE など HandleJoystickEvent(...) -
WM_COMMAND HandleCommand(...) -
WM_NOTIFY HandleNotify(...) MSWOnNotifyをコール
WM_DRAWITEM MSWOnDrawItem(...) trueならrc.result=true
WM_MEASUREITEM MSWOnMeasureItem(...) trueならrc.result=true
WM_GETDLGCODE キー入力設定をrc.resultに代入 備考 標準コントロール以外でwxWANTS_CHARS
WM_KEYDOWN など HandleKeyDown(...) 特殊キーならwxEVT_CHARを明示生成
WM_KEYUP など HandleKeyUp(...) -
WM_CHAR など HandleChar(...) WM_KEYDOWN処理があれば何もしない
WM_IME_STARTCOMPOSITION gs_modalEntryWindowCount++ false IMEポップアップのカウントアップ
WM_IME_ENDCOMPOSITION gs_modalEntryWindowCount-- false IMEポップアップのカウントダウン
WM_HOTKEY HandleHotKey(...) -
WM_CUT など HandleClipboardEvent(...) -
WM_HSCROLL など MSWOnScroll(...) -
WM_CTLCOLORMSGBOX など HandleCtlColor(...) -
WM_SYSCOLORCHANGE HandleSysColorChange(...) -
WM_DISPLAYCHANGE HandleDisplayChange(...) -
WM_PALETTECHANGED HandlePaletteChanged(...) -
WM_CAPTURECHANGED HandleCaptureChanged(...) -
WM_SETTINGCHANGE HandleSettingChange(...) -
WM_QUERYNEWPALETTE HandleQueryNewPalette(...) -
WM_ERASEBKGND it->second->MSWEraseBgHook(...) (理解困難)、trueならrc.result=true
WM_DROPFILES HandleDropFiles(...) -
WM_INITDIALOG HandleInitDialog(...) trueならrc.result=false
WM_QUERYENDSESSION HandleQueryEndSession(...) -
WM_SETCURSOR HandleSetCursor(...) trueならrc.result=true
WM_GETOBJECT GetOrCreateAccessible(...) trueならrc.result=オブジェクト参照
WM_HELP ヘルプイベント生成 true
WM_CONTEXTMENU コンテキストメニューイベント true (理解困難)
WM_MENUCHAR HandleMenuChar(...)!=wxNOT_FOUND ポップアップ、rc.result=アイテム
WM_INITMENUPOPUP など HandleMenuPopup(...) -
WM_MENUSELECT HandleMenuSelect(...) -
WM_POWERBROADCAST HandlePower(...) trueで拒絶なければrc.result=true
WM_NCCALCSIZE NC領域サイズを計算 true 先にMSWDefWindowProcをコール
WM_NCPAINT NC領域を描画 true 先にMSWDefWindowProcをコール