「[[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。

-[[戻る>Windows]]

* 目次 [#sb75d7ba]
#contents

*概要 [#od51b6e4]
ウィンドウ・システムの詳細を理解して、

>「バックグラウンド・スレッドから上げた~
モーダル・ダイアログがモーダルにならない理由」

などのさまざまな挙動を理解できるようにする。

*テンプレート [#s05a223e]
Windowsプログラムは、

-エントリポイント(プログラムの開始)である(1)WinMainと、
-Windowsから呼び出されて渡されたメッセージを処理する~
(2)ウインドウプロシ-ジャ(通常WinProcと書く)

から成り立つ。

そして(1)WinMainの中は、
-(A)ウインドウクラスの登録
-(B)ウィンドウの作成
-(C)ウインドウの表示
-(D)メッセージループ

の4つのパートから成り立つ。

 //(1)Winmain
  WinMain (
 HINSTANCE hInstance,
 HINSTANCE hPrevInstance,
 LPSTR lpCmdLine,
 int nCmdShow )
 {
   // ウィンドウクラス構造体を設定
 
   //(A) ウインドウクラスの登録
   RegisterClassEx
 
   //(B) ウインドウを作成
   CreateWindow
 
   //(C) ウインドウを表示
   ShowWindow
   UpdateWindow
 
   //(D) メッセージループ
 }
 
 //(2) ウィンドウプロシージャ
 WndProc (
 HWND hWnd,
 UNIT message,
 WPARAM wParam,
 LPARAM lParam )
 {
    ・・・
 }

*Windowsメッセージキューとメッセージループ [#rf68c087]

**Windowsメッセージキュー [#z34491c0]
MSMQではなく、ウィンドウ メッセージ用のキュー。~
ウィンドウ・システム(WindowsのGUI)の根幹をなすメカニズム。

***作成方法 [#da9d8264]
-Windowsメッセージキューは、~
1つのスレッドが1つだけ保持できる。

--ウィンドウを作成したスレッドには、~
Windowsメッセージキューが与えられる。

--スレッドからメッセージ系のAPIを使用した場合も、~
Windowsメッセージキューが与えられる。

-この際、システムは、
--THREADINFO構造体を作成してスレッドに割り当てる。
--THREADINFO構造体はWindowsメッセージキューに関する情報を持っている。

|>|THREADINFO構造体|h
|項目|APIとの関連|h
|ポストメッセージ|PostMessage()で送信されるメッセージ|
|送信メッセージキュー|SendMessage()で送信されるメッセージ、別スレッドの場合|
|応答メッセージキュー|SendMessage()で送信されるメッセージ、別スレッドの場合|
|仮想入力キュー(ハードウェア入力)|-|
|ウェイクフラグ|PostQuitMessage()|
|nExitCode|PostQuitMessage()|
|スレッドローカル・入力状態管理変数|-|

***作成単位 [#bff89f1a]
-Windowsメッセージキューは、複数のウィンドウ間で共有される。

--通常、1つのプロセスは、1つのUIスレッドで、複数(全て)のウィンドウを処理する。~
このため、通常、1プロセス、1UIスレッド、1Windowsメッセージキューになる。

--この理由は、1プロセスで、2つ以上のUIスレッドを持つ場合、~
画面間の通信をスレッドセーフに実装する必要があり実装し難くなる。

***利用方法 [#j7fd3258]
後述のWin32APIを使用する。

-PostMessage()~
メッセージ・ループにキューイングする。
-SendMessage()~
ウィンドウ・プロシージャ(WndProc)を直接呼び出す。

***その他の利用方法 [#j7fd3258]

-プロセス間通信
-スレッド間通信
-COMのSTA(呼び出しの直列化)

などでも利用される。

**メッセージループ [#nca334b2]
GetMessage関数でWindowsメッセージキューから取り出したMSG 構造体を~
DispatchMessage関数でウィンドウ・プロシージャに渡す。

 while (GetMessage (&msg,NULL,0,0)) { /* メッセージループ */
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }

*ウィンドウ的なもの [#ibf9d3ef]

**ウィンドウクラス [#u8d37135]
.NETで言う、FormもControlも全てが~
ウィンドウ(hwnd:ウィンドウハンドルを持つ)。

-用語(7):ウィンドウクラスって?~
http://yonex1.cis.ibaraki.ac.jp/~yonekura/winclass.html
>ウィンドウクラスとは、ウィンドウの雛形(テンプレート)のようなもので、~
対応するウィンドウ関数・アイコン・カーソル・背景色など 基本的な情報が登録されている。

***Form的なもの [#qf9d4920]
自前のウィンドウクラス名を持つウィンドウクラス(.NETで言う、Form的なもの)は、~
WndProcを用意して、WNDCLASS 構造体にまとめて、 RegisterClassExで登録する。~
その時に 自前のウィンドウクラス名 を登録し、CreateWindowEXで、ウィンドウを作る。~

そのイベントは、すべて、 WNDCLASS で登録した WndProc へ来る(これについては後述)。

***Control的なもの [#hb30291b]
あらかじめ登録されている既定のウィンドウクラスとしては
-"BUTTON"
-"COMBOBOX"
-"EDIT"
-"LISTBOX"
-"MDICLIENT"
-"RichEdit"
-"RICHEDIT_CLASS"
-"SCROLLBAR"
-"STATIC"

がある(.NETで言う、Control的なもの)。

これらは登録済みで個別用途のウィンドウクラスであるため~
(例えばボタンウィンドウやエディットボックスなど)、~
下記のRegisterClassEx関数を使用せずに作成可能。

自前のウィンドウクラス(Form的な)の中へ、~
既定のウィンドウクラス(Control的な)を貼り付けたければ、~
自前で CreateWindowす(自前のウィンドウクラス の hwnd,...)する。

**ダイアログ [#u0ed1ff6]
VC++のダイアログエディタで、ダイアログリソースを作ってCreateDialogする。

ダイアログのイベントは、WndProcではなく、DlgProc へ来る(これについては後述)。

*ウィンドウプロシージャ [#ibfcede7]
イベントハンドラみたいなもの。

以下のように、イベントハンドラを実装する。

-Control的なウィンドウクラスの標準WndProcは、~
親ウィンドウクラスに対してSendMessageでWM_Commandを送るようになっている。

-Form的な親ウィンドウのカスタムWndProcに、~
WM_Commandを処理するカバレージをcase WM_COMMAND:等を使用して追加する。

-参考
--子ウインドウ~
http://eternalwindows.jp/control/controlbase/controlbase01.html

**WndProc [#s2b8e69c]
 //(2) ウィンドウプロシージャ
 WndProc (
 HWND hWnd,
 UNIT message,
 WPARAM wParam,
 LPARAM lParam )
 {
    ・・・
 }

**DlgProc [#zb8aba2e]
???

**サブクラス化 [#n23e3ff2]

-GetWindowLong(hwnd, GWL_WNDPROC) を使って、今あるWndProc を取得して、

-SetWindowLong(hwnd, GWL_WNDPROC, 自前WndProc) で置き換えて、

--元あったWndProcを呼ばなければ、そのイベントの処理を置き換え。

--自前WndProc の中で、 CallWndProc(取得したWndProc, pMsg)し、~
元のWndProcを呼ぶことで、WndProcのチェインに割って入る。

この既定のWndProcを置き換えることで、~
イベントの挙動(≠イベント・ハンドラ、ボタン押下時にボタンが凹む等)~
をカスタマイズすることが可能である。

*Win32PI [#m645932a]

**ウィンドウの生成 [#h0121534]
-WNDCLASS structure (Windows)~
http://msdn.microsoft.com/ja-jp/library/windows/desktop/ms633576.aspx
>ウィンドウクラスの属性を表します。

-RegisterClassEx 関数~
http://msdn.microsoft.com/ja-jp/library/cc410996.aspx
>ウィンドウクラスを登録します。

-CreateWindow 関数~
http://msdn.microsoft.com/ja-jp/library/cc410713.aspx
>メモリ上にウィンドウを生成します。

-ShowWindow 関数~
http://msdn.microsoft.com/ja-jp/library/cc411211.aspx
>ウィンドウを表示します。

-UpdateWindow 関数~
http://msdn.microsoft.com/ja-jp/library/cc428780.aspx
>ウィンドウを更新します。

-GetWindowThreadProcessId 関数~
http://msdn.microsoft.com/ja-jp/library/cc364779.aspx
>指定されたウィンドウを作成したスレッドの ID を取得します。

**メッセージの送信 [#w1750e46]
***PostMessage [#p8157cb2]
PostMessageはメッセージ・ループにキューイングする。
 
-PostMessage 関数~
http://msdn.microsoft.com/ja-jp/library/cc410952.aspx
--指定されたウィンドウのメッセージキューに 1 つのメッセージをポストします。
--対応するスレッドがメッセージを処理するのを待たずに制御を返します。

-PostThreadMessage 関数~
http://msdn.microsoft.com/ja-jp/library/cc410979.aspx
--指定されたスレッドのメッセージキューに 1 つのメッセージをポストします。
--この関数は、スレッドがメッセージを処理するのを待たず、即座に制御を返します。

-PostQuitMessage 関数~
http://msdn.microsoft.com/ja-jp/library/cc410954.aspx
>WM_NCLBUTTONDOWN メッセージなどを取得した場合に、~
WM_QUIT メッセージをメッセージキューにポストする。

***SendMessage [#v0311886]
SendMessageはウィンドウ・プロシージャ(WndProc)を直接呼び出す。

-SendMessage 関数~
http://msdn.microsoft.com/ja-jp/library/cc411022.aspx
--1 つまたは複数のウィンドウへ、指定されたメッセージを送信します。
--指定されたウィンドウのウィンドウプロシージャを呼び出します。
--ウィンドウプロシージャがメッセージを処理し終わった後で、制御を返します。

--基本的には、サブルーチン的にイベント実装を処理するためのもの。

--スレッド跨ぎか否かで動作が大きく異なる。
---スレッド跨ぎでない場合、サブルーチン的にイベント実装を処理
---スレッド跨ぎの場合、送信・応答メッセージキューを使用する(同期呼出の実現)。

--なお、処理の優先度は、PostMessageより高い。   

以下は、SendMessageの同期呼出ハングの問題を回避するための関数(送信側)。

-SendMessageTimeout 関数~
http://msdn.microsoft.com/ja-jp/library/cc411010.aspx
--SendMessage のタイムアウト機能付きバージョン。
--同一スレッドからの場合はタイムアウト地を無視する。

-SendMessageCallback 関数~
http://msdn.microsoft.com/ja-jp/library/cc411008.aspx
--SendMessage のCallback機能付き非同期版(即座に制御を返す)
--オーバーラップウィンドウにメッセージをブロードキャストできる。

-SendNotifyMessage 関数~
http://msdn.microsoft.com/ja-jp/library/cc411012.aspx
--PostMessageに近いが、以下の点がPostMessageと異なる。
---PostMessageよりも優先度が高い(先にキューから取り出される)。
---スレッド跨ぎでない場合、SendMessage的に動作する。

以下は、SendMessageの同期呼出ハングの問題を回避するための関数(受信側)。

-ReplyMessage 関数~
http://msdn.microsoft.com/ja-jp/library/cc411016.aspx
--SendMessage送信側の応答メッセージキューに結果をポストし、制御を返す。
--スレッド跨ぎでない場合、何もしない(falseを返す)。

-InSendMessage 関数~
http://msdn.microsoft.com/ja-jp/library/cc364787.aspx
--スレッド跨ぎでない場合、falseを返す。
--スレッド跨ぎの場合、trueを返す。

**メッセージ・ループで使用 [#y87a9a48]
***GetMessage [#q46270fc]
-MSG 構造体~
http://msdn.microsoft.com/ja-jp/library/vstudio/900ks98t.aspx
>メッセージのデータを表します。

-GetMessage 関数~
http://msdn.microsoft.com/ja-jp/library/cc364699.aspx
>Windowsメッセージキューからメッセージを MSG 構造体として取得

-PeekMessage 関数~
http://msdn.microsoft.com/ja-jp/library/cc410948.aspx
>GetMessage 関数とは異なり、~
メッセージキューにメッセージがなかった場合、~
メッセージがポストされるのを待たずに制御を返す。

-TranslateMessage 関数~
http://msdn.microsoft.com/ja-jp/library/cc364841.aspx
>仮想キーメッセージを文字メッセージへ変換(ショートカットの変換)

-DispatchMessage 関数~
http://msdn.microsoft.com/ja-jp/library/cc410766.aspx
>GetMessage関数で取得したMSG 構造体をウィンドウ・プロシージャに渡す。

 while (GetMessage (&msg,NULL,0,0)) { /* メッセージループ */
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }

-GetQueueStatus 関数~
http://msdn.microsoft.com/ja-jp/library/cc364726.aspx
>当該スレッドのWindowsメッセージキューの状態確認

*** [#t7db56f5]

-WaitForMultipleObjects
--
--

-WaitForMultipleObjectsEx
--
--

**ウィンドウプロシージャで使用 [#r203665c]
***WindowProc [#d3583459]
-WindowProc 関数
--http://msdn.microsoft.com/ja-jp/library/cc364868.aspx
--ウィンドウへ送信されたメッセージを処理する、アプリケーション定義のコールバック関数です。

-DefWindowProc 関数
--http://msdn.microsoft.com/ja-jp/library/cc410753.aspx
--既定のウィンドウプロシージャを呼び出して、既定の処理を提供します。
--この関数は、すべてのメッセージが処理されることを保証します。

-WM_DESTROY メッセージ
--ウィンドウプロシージャはその全てのメッセージに対応できなければならないため。

-PostQuitMessage 関数~
http://msdn.microsoft.com/ja-jp/library/cc410954.aspx
--WM_NCLBUTTONDOWN メッセージなどを取得した場合に、~
WM_QUIT メッセージをメッセージキューにポストする。
--終了処理~
http://wisdom.sakura.ne.jp/system/winapi/win32/win11.html

***サブクラス化 [#he020548]

-IsWindowUnicode 関数~
http://msdn.microsoft.com/ja-jp/library/cc410878.aspx
>ウィンドウが Unicode のネイティブウィンドウであるかどうかをチェック

-SetWindowLongPtr 関数~
http://msdn.microsoft.com/ja-jp/library/cc411204.aspx
>WndProcのサブクラス化

-CallWindowProc 関数~
http://msdn.microsoft.com/ja-jp/library/cc410622.aspx
>元WndProcにメッセージを送信

-.etc

*ハードウェア入力モデル [#t3c890e8]

-用語
--SHIQ(system hardware input queue:システムハードウェア入力キー)
--RIT(raw input thread:生入力スレッド)/(SHIQを待機、取出、変換)
--VIQ(virtual input queue:仮想入力キュー)/(THREADINFO構造体内)
 
-RITが接続するVIQのスレッドを識別する
--マウスポインタ:マウスカーソルの下のウィンドウのスレッド
--キーストローク:フォアグラウンド・ウィンドウのスレッド
--その他、Alt+Tabなどの特殊キー・シーケンスを処理する。

-スレッドローカル・入力状態管理変数(THREADINFO構造体内)
--キーボード入力、ウィンドウフォーカス情報
---フォーカス・ウィンドウ
---アクティブ・ウィンドウ
---押下されているキー
---キャレット(入力カーソル)の状態

--マウスカーソル管理情報
---形
---表示/非表示の状態
---キャプチャ

-マウスによる切り替え
--WM_KILLFOCUS

**関連するWin32API [#z42e3ae8]

***フォーカス [#b942a276]

-SetFocus 関数~
http://msdn.microsoft.com/ja-jp/library/cc411074.aspx
--WM_SETFOCUS
--VIQの切り替えはできない。
--通常、RITに接続されているときだけ呼び出す。
  
--スレッド1がRITに接続しているときに~
スレッド2が自身のウィンドにSetFocusを~
呼び出すと2つのフォーカス矩形が現れ問題。~
(RITに接続するVIQは切り替わらないので)

-GetFocus 関数~
http://msdn.microsoft.com/ja-jp/library/cc364641.aspx
>ローカル入力状態からフォーカスを持つウィンドウのHWNDを返す。

***アクティブ化 [#y2b1c07d]

-SetActiveWindow 関数~
http://msdn.microsoft.com/ja-jp/library/cc411014.aspx
--ウィンドウをアクティブにする。~
--RITに接続するVIQの切り替えはできない。
--通常、RITに接続されているときだけ呼び出す。

-GetActiveWindow 関数~
http://msdn.microsoft.com/ja-jp/library/cc410861.aspx
>ローカル入力状態からアクティブなウィンドウのHWNDを返す。

***フォアグラウンド化 [#db2fc325]

-BringWindowToTop 関数~
http://msdn.microsoft.com/ja-jp/library/cc410618.aspx
>HWND_TOPを指定しSetWindowPosを呼び出す(RITに接続するVIQを変更可能)。

-SetWindowPos 関数~
http://msdn.microsoft.com/ja-jp/library/cc411206.aspx
>ウィンドウをアクティブにしてサイズ、位置、Zオーダを変更(RITに接続するVIQを変更可能)。

-GetForgroundWindow 関数~
http://msdn.microsoft.com/ja-jp/library/cc364732.aspx
>フォアグラウンド・ウィンドウのHWNDを返す。

-SetForgroundWindow 関数~
http://msdn.microsoft.com/ja-jp/library/cc411039.aspx
--ウィンドウをフォアグラウンドに移動する(RITに接続するVIQを変更可能)
--このAPIは、プログラマによって乱用されたため、~
MSはRITに接続されているか、RITに接続されている別スレッドが一定時間以上、~
入力を受け取っていない場合にのみ成功するように機能を追加した。
--失敗の際は、タスクバーをフラッシュさせる。

-AllowSetForgroundWindow 関数~
http://msdn.microsoft.com/ja-jp/library/cc430255.aspx
>指定したプロセスのスレッドがSetForgroundWindowを呼び出すことを許可する。

-LockSetForgroundWindow 関数~
http://msdn.microsoft.com/ja-jp/library/cc410898.aspx
>他のSetForgroundWindow呼出をロックする(Windowsスタートメニューなどで使用されている)。

***キー入力状態 [#x7b0f1a6]

-GetKeyState 関数~
http://msdn.microsoft.com/ja-jp/library/cc364676.aspx
--最後のキー入力を返す。
--入力フォーカスを持ったウィンドウを持ってる必要はない。

-GetAsyncKeyState 関数~
http://msdn.microsoft.com/ja-jp/library/cc364583.aspx
--キーが押されているか?前回の呼び出し以降にキーが押されたか?を返す。
--入力フォーカスを持ったウィンドウを持ていること。
  
***カーソル入力状態 [#p8d7129e]

-SetCursor 関数~
http://msdn.microsoft.com/ja-jp/library/cc411027.aspx
>マウス・カーソルのセット(砂時計など)

-ShowCursor 関数~
http://msdn.microsoft.com/ja-jp/library/cc364876.aspx
>マウス・カーソルの表示・非表示

-ClipCursor 関数~
http://msdn.microsoft.com/ja-jp/library/cc410663.aspx
>マウス・カーソルの範囲を指定する(非同期的なアクティブ化イベントで中止)。

-SetCapture 関数~
http://msdn.microsoft.com/ja-jp/library/cc411051.aspx
--マウス・カーソルがウィンドウの範囲内にあるかどうか~
に関わり無く、すべてのマウス入力を受け取る。 
--一度に 1 つのウィンドウだけがマウスをキャプチャできる。
--通常はマウスのボタン押下後に呼び出す。

-ReleaseCapture 関数~
http://msdn.microsoft.com/ja-jp/library/cc410990.aspx
>上記のマウスのキャプチャを停止する。

***VIQの共有 [#ifd6b3ff]
-AttachThreadInput 関数~
http://msdn.microsoft.com/ja-jp/library/cc429027.aspx
>複数のスレッドに複数のVIQとローカル入力状態を共有させる。

--ただし、THREADINFO構造体の、
---ポストメッセージ
---送信メッセージキュー
---応答メッセージキュー
---ウェイクフラグ

>については自分のものを使い続ける。

--このAPIはシステムの強度を損なう可能性がある。

--用途としてはジャーナルの記録・再生フックをインストールした場合。~
---RE#2347:アプリケーションの切替方法について~
http://www.gizcollabo.jp/vbtomo/log/archive/vbqanda_2302_2.html#Num2360-0~
>AttachThreadInput API関数で無理やり現在アクティブなスレッドに自分のスレッドをアタッチして、~
その間にBringWindowToTop API関数で自分のフォームを前面に出します。~
その後もう一度AttachThreadInputAPI関数でデタッチして解除すれば可能です。~
もちろん、Windowsの仕様に反しますが。

*DLL注入とAPIフック [#d5dfeb5c]
UIオートメーションの裏側。

> ちなみに、操作ログの取得って
> GetMessegeのフックと
> AttachThreadInputの
> 2つの方法がありそうですが、
> 現行はどっちを使用しているんでしょうか?

答えは、GetMessegeのフックらしい。

↓↓↓

例えばAttachThreadInputでSetWindowLongPtrを使用して~
別プロセスのウィンドウをサブクラス化できるか?と言うとこれは当然できない。~
これは、呼び出し元のWndProcのアドレスが呼び出し先のプロセスで有効でないから。~

しかし、これを可能にする方法がある。

「[[DLL注入>#qdb30fde]]」と「[[APIフック>#le7d156d]]」である。

**DLL注入 [#qdb30fde]

-AppInit_DLLs による DLL インジェクション~
http://keicode.com/windows/win08.php
>レジストリエントリを使用してDLLを注入する。~
ただし、問題としては汎用性がない点が挙げられる。~
DLLを注入してSetWindowLongPtrを実行する。

**APIフック [#le7d156d]
別プロセスのウィンドウにGetMsgProcフックプロシージャをインストールしてメッセージを監視する。~
GetMsgProcフックプロシージャは、前述のDLL注入のDLL中に実装しておく。

***SetWindowsHookEx 関数 [#f3186672]
http://msdn.microsoft.com/ja-jp/library/cc430103.aspx
-第一引数:インストール対象のフックタイプ
-第二引数:関数ポインタ(フックタイプにより可変)
-第三引数:上記関数を格納するDLLのモジュールハンドル
-第四引数:フックすべきスレッド

-ウィンドウのスレッドを取得するには、~
FindWindow→GetWindowThreadProcessId 関数を使用する。
--FindWindow 関数~
http://msdn.microsoft.com/ja-jp/library/cc364634.aspx
--GetWindowThreadProcessId 関数~
http://msdn.microsoft.com/ja-jp/library/cc364779.aspx

***フックタイプと関数ポインタ [#p8555cb5]

-フックタイプにはWH_GETMESSAGEを指定する。

--メッセージキューへポストされた~
メッセージを監視する1個のフックプロシージャをインストール。 

--フックは、メッセージ系を処理するものが多数である。~
その他、シェル、デバッガ、CBT用途のフックなどがある。

-関数ポインタには、GetMsgProcフックプロシージャを指定する。~
詳細については、GetMsgProcフックプロシージャの説明を参照。 
 
--GetMsgProcフックプロシージャ~
http://msdn.microsoft.com/ja-jp/library/cc429822.aspx~
---システムは、 または関数がアプリケーションのメッセージキューからメッセージを取得するときに、必ずこの関数を呼び出す。
---システムは、取得したメッセージを目的のウィンドウプロシージャへ渡す前に、そのメッセージをこのフックプロシージャに渡す。
---GetMsgProcを実装したDLLは、呼出元プロセスと同じ位置にロードされるよう努力されるが、~
同じ位置でなければ、システムが自動的に呼出先プロセスの関数アドレスを算出する。
---これにより、「呼出先プロセス」でSetWindowLongPtrを実行できる。
---(ただし本来の用途とは異なる。通常は、メッセージを処理する追加処理を実装する)

--Windowsに土足で乱入?! ~ フック関数の使い方~
http://dsas.blog.klab.org/archives/50829204.html~
>・所定のプロセスに対する Windows メッセージの監視・捕捉~
・所定のプロセスでの特定のイベントに呼応する自作コードの注入~
・既存のアプリケーションの所作を変更 .etc~

--また、フックチェーンを実装することもできる。
---フックチェーンを実装(CallNextHookEx)~
http://msdn.microsoft.com/ja-jp/library/cc429591.aspx

*スパイ [#v1243eda]
Spy++やWinspector Spyを使用すると、ウィンドウのメッセージの分析が可能。

-イベントの順番を確認する。
-欲しいイベントのメッセージが来ているか?調べる。
-当該イベントではどのようなメッセージが来るのか?調べる。
-SetCaptureにより別のマウスイベントが来てしまっていないか?確認する。
-SendMessage/PostMessageどちらで送られてきているか?確認する。
-IMEの漢字入力で挙動不振の場合、イベントの順番、WM_CHAR WM_KEYDOWN を調べる。

-当該ウィンドウの
--ウィンドウ名を確認する。
--ウィンドウクラス名を確認する。
--ウィンドウ位置、大きさを確認する。
--WndProc の値が変わっているかを確認する。

**Spy++ [#le2a0891]
-Spy++ ヘルプ~
http://msdn.microsoft.com/ja-jp/library/vstudio/dd460760.aspx

**Winspector Spy [#r034c8c7]
-窓の杜 - 【NEWS】クラス名から~
各種ウィンドウ内のオブジェクトを検索できる「Winspector」が公開~
http://www.forest.impress.co.jp/article/2004/05/18/winspector.html

*別スレッド [#ed1408fa]
**別スレッドでウィンドウが起動する例 [#i6a6c87b]
-スレッドを明示的に起動して、そこからForm等、新規ウィンドウを生成する。

-以下は、暗黙的に、別スレッドからウィンドウを起動する例。
-[[async/await]]を使用する。
-System.Timers.Timerを使用する。
--System.Timers.Timer は制度が高い反面、別スレッドで実行される。
--[参考] C# の Timer 種類別 特徴 と 使い方~
https://garafu.blogspot.jp/2015/01/c-timer.html

**発生する問題の例 [#od2c91ab]
ここまで、色々と説明してきたように、スレッド関係で色々な問題が発生する。

***サーバーの同期呼出でUIがハングする。 [#tfaa56f4]
メッセージループを持つスレッドで同期呼出を行うと、~
同一のスレッド(メッセージループ)を共有する全てのスレッドがハングする。

そのため、サーバー呼出を別スレッドで処理を行うことがあるが、~
以下の様な問題が発生するため、基本的に、[[UI処理はUIスレッドで処理するようにする。>#l3b4d072]]

***モーダル・ダイアログがモーダルにならない。 [#o4165f4d]
バックグラウンド・スレッドから上げたモーダル・ダイアログがモーダルにならない。

これは、UIスレッドと別スレッドのメッセージループが異なるので、~
スレッド間のウィンドウはモーダル・ダイアログ的な動作にならないため。

***IME制御がおかしくなる。 [#p6d8f316]
-IMEはスレッド単位の初期化が必要になる。
-基本的には、[[UI処理は、UIスレッドから処理するようにする>#l3b4d072]]。
-止む無く、別スレッドから処理する場合。
--IMEを制御する方法~
http://www7a.biglobe.ne.jp/~tsuneoka/win32tech/7.html
--他のスレッドのFormを表示した後にSPREADのImeModeを切り替えられなくなることがある~
SPREAD for Windows Forms 5.0J - ナレッジベースの詳細 | GrapeCity Developer Tools~
https://www.grapecity.com/tools/support/technical/knowledge_detail.asp?id=36622

**UI処理をUIスレッドで処理する方法 [#l3b4d072]
非同期処理が必要になっても、UI処理はUIスレッドで処理するようにする。

それには以下の技術を使用できる。

***[[Control.Invoke、.BeginInvoke>非同期処理#x24ad95f]] [#t81ae59e]
***[[async/await>非同期処理#ae25c1af]] [#bb1866c2]

*参考 [#c6769d79]

**書籍 [#x5c74f4e]
-Amazon.co.jp: Advanced Windows 改訂第4版~
ジェフリー リッチャー, Jeffrey Richter, 長尾 高弘, ロングテール~
http://www.amazon.co.jp/Advanced-Windows-%E6%94%B9%E8%A8%82%E7%AC%AC4%E7%89%88-%E3%82%B8%E3%82%A7%E3%83%95%E3%83%AA%E3%83%BC-%E3%83%AA%E3%83%83%E3%83%81%E3%83%A3%E3%83%BC/dp/4756138055
--第6部:ウィンドウシステム

**msdn [#wf269b0d]

-C++ による Windows プログラミングの学習 (Windows)~
http://msdn.microsoft.com/ja-jp/library/ff381399.aspx
--モジュール 1. 初めての Windows プログラム (Windows)~
http://msdn.microsoft.com/ja-jp/library/ff381409.aspx
--Windows プログラミングの学習 サンプル コード (Windows)~
http://msdn.microsoft.com/ja-jp/library/ff485845.aspx

-hilo Windows 7 対応 C++ アプリケーションの開発 (Windows)~
http://msdn.microsoft.com/ja-jp/library/ff708696.aspx

**標準 Windows API [#ide08338]
-http://wisdom.sakura.ne.jp/system/winapi/win32/
--メッセージ~
http://wisdom.sakura.ne.jp/system/winapi/win32/win9.html
--ウィンドウプロシージャ~
http://wisdom.sakura.ne.jp/system/winapi/win32/win10.html
--終了処理~
http://wisdom.sakura.ne.jp/system/winapi/win32/win11.html

**Win32 API 階梯 [#c95b15b1]
-C による GUI アプリケーション開発~
http://www.wgag.net/winapi/index.html
--2. ウィンドウ
---1.ウィンドウの生成~
http://www.wgag.net/winapi/0008.html
---2.メッセージループ~
http://www.wgag.net/winapi/0009.html
---3.ウィンドウプロシージャ~
http://www.wgag.net/winapi/0010.html
---4.メッセージのふるい分け~
http://www.wgag.net/winapi/0011.html
---5.スケルトンプログラム~
http://www.wgag.net/winapi/0012.html

**Windowsプログラムの正しい雛形 [#z9e2b594]
-前編~
http://www.geocities.co.jp/SiliconValley-Bay/7437/cpp/createwindow.html
-中編~
http://www.geocities.co.jp/SiliconValley-Bay/7437/cpp/createwindow2.html

**WindowsAPI Programming [#g5de7233]
-第1章 ~スケルトンプログラム~~
http://yonex1.cis.ibaraki.ac.jp/~yonekura/lecture01/lecture01a.html
-第1章 ~スケルトンプログラム~その2~
http://yonex1.cis.ibaraki.ac.jp/~yonekura/lecture01/lecture01b.html
-第1章 ~スケルトンプログラム~ その3~
http://yonex1.cis.ibaraki.ac.jp/~yonekura/lecture01/lecture01c.html
-第1章 ~スケルトンプログラム~その4~
http://yonex1.cis.ibaraki.ac.jp/~yonekura/lecture01/lecture01d.html

**EternalWindows [#q79b9cca]
http://eternalwindows.jp/index.html

-コントロール基礎
http://eternalwindows.jp/control/controlbase/controlbase00.html
--子ウインドウ~
http://eternalwindows.jp/control/controlbase/controlbase01.html
--サブクラス化~
http://eternalwindows.jp/control/controlbase/controlbase05.html
--新しいサブクラス化~
http://eternalwindows.jp/control/controlbase/controlbase06.html
--オーナードロー~
http://eternalwindows.jp/control/controlbase/controlbase07.html
--カスタムドロー~
http://eternalwindows.jp/control/controlbase/controlbase08.html

----
Tags: [[:Windows]], [[:ウィンドウ・システム]], [[:プログラミング]]

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS