ここから本文です

Windowsの「応答なし」ウィンドウ、実は“別人(ゴースト)”です

@IT 2/23(木) 5:10配信

●「応答なし」ウィンドウはクリックでは復活しません!

 Windows上で実行されるアプリケーションのウィンドウは、応答がない状態になると、ウィンドウタイトルに「(応答なし)」と表示してユーザーに知らせます。

実は「応答なし」ウィンドウは、“別人(ゴースト)”です

 「応答なし」のウィンドウを操作しようと繰り返していると、今度は「<アプリケーション名>は応答していません。プログラムを閉じると、情報が失われる可能性があります」というダイアログボックスが表示され、「プログラムを再起動します」「プログラムを終了します」「プログラムの応答を待ちます」の選択を求められます。

 この選択に答えなくても、アプリケーションが応答するようになれば、ダイアログボックスは勝手に消え、応答するようになったウィンドウに戻ります。

 もう少し詳しく説明すると、“応答がない状態”とは、アプリケーションのプロセスが持つウィンドウオブジェクトが「ウィンドウメッセージ(Window Message)」に5秒(既定)以上、応答しなくなる状態を指します。マウスの左右クリック操作やキー入力操作は、ウィンドウメッセージとしてアプリケーションに送信されます。

 Windowsのこの仕様は(最後の「少し詳しい」の説明を除いて)、経験上、皆さんも何となく分かっていると思います。応答しない状態であっても、クリックしてあげれば「大丈夫ですかぁー」と声を掛けているような気がしませんか。そうしてあげることで、応答が返ってくる“かもしれない”という期待も込めて。でも、その行為は、全く無駄です。症状を起こしているアプリケーションにあなたの声(クリック操作やキー入力)は届いていません。なぜなら、相手は今、そこにはいないのですから。

●実は「応答なし」ウィンドウは“別人(ゴースト)”でした

 マイクロソフトが無料公開しているユーティリティー群「Windows Sysinternals」について、調べものをしているときに、応答なしウィンドウについて説明している公式ブログの古い記事を見つけました。

・Windows Error Reporting(For Hangs)[英語](https://blogs.msdn.microsoft.com/meason/2010/01/04/windows-error-reporting-for-hangs/:Microsoft Developer)

 応答なしウィンドウは「ゴーストウィンドウ(Ghost Window)」と呼ばれるもので、Windows Vistaから実装された機能です。

 Windowsは、ウィンドウの応答なし状態を検出すると、応答なしウィンドウを隠し、同じ場所に新しいウィンドウを作成して表示します。これがゴーストウィンドウであり、もともとのウィンドウの前回正常実行状態(last known good state)のビットマップを描画したものです。ゴーストウィンドウのウィンドウタイトルは、応答なしウィンドウのウィンドウタイトルに「(応答なし)」を追加したものになります。

 そして、このゴーストウィンドウは、もともとのアプリケーションのプロセスのものではなく「デスクトップウィンドウマネージャー(dwm.exe)」の持ち物であり、“応答性がある”(Responsive)ウィンドウだということです。

 Word 2013やWord 2016のウィンドウタイトルには背景があり、ウィンドウタイトルのテキストは中央に表示されますが、応答なしウィンドウのウィンドウタイトルには背景がなく、テキストが左側に表示されるのは、そういう理由です。

 また、応答なしを検出する5秒(既定)までは、ウィンドウは全く反応しませんが、5秒後にウィンドウタイトル「(応答なし)」のゴーストウィンドウに切り替わった瞬間、ウィンドウの移動が可能になります。そして、ウィンドウ内でクリックすると、「再起動」「終了する」「応答を待つ」の選択肢を提供するダイアログボックスが表示されるようになります。つまり、「(応答なし)」のゴーストウィンドウが「応答している」のです。

●PowerShellでゴーストウィンドウを実証してみましょう

 前述した公式ブログの古い記事では、Visual Studioに付属する「Spy++」を利用して、ゴーストウィンドウである証拠を示していますが、筆者はもっと簡単な、別の方法で証拠を示したいと思います。

 以下のように記述したWindows PowerShellスクリプト(.ps1)を実行すれば、応答なしウィンドウを持つプロセスとプロセスIDを識別することができます。もともとのアプリケーションのプロセスではなく、デスクトップウィンドウマネージャー(dwm.exe)のプロセスが示されるはずです。


$psArray = [System.Diagnostics.Process]::GetProcesses()
foreach ($ps in $psArray){
if ($ps.MainWindowTitle -like "*応答なし*") {
"Window Title: " + $ps.MainWindowTitle
"ProcessName(PID): " + $ps.Name + "(" + [string] $ps.Id + ")"
}
}



 このPowerShellスクリプトの「"*応答なし*"」の部分を「"*"」に変えると、さらに興味深い結果が得られます。応答がある状態では、もともとのアプリケーションのプロセスが表示されます。応答なしの状態になると、「ウィンドウタイトル」と「ウィンドウタイトル(応答なし)」の2つのウィンドウが表示され、それぞれアプリケーションのプロセスとデスクトップウィンドウマネージャー(dwm.exe)のプロセスが持つウィンドウであることを示します(画面3)。そして、「ウィンドウタイトル」のウィンドウの方は非表示になっており、ユーザーからは隠されています。

 筆者が利用したアプリケーションは、『Windows Sysinternals Administrator’s Reference』という書籍(この書籍のアップデート版『Troubleshooting with the Windows Sysinternals Tools』が2016年末に出ました。日本語翻訳版も近日中に出版されるそうです)の執筆のために作られた「VirtMemTest.exe」というツールで、応答なしウィンドウを意図的に発生させることができます。このツールは、Microsoft Developerのサイトからダウンロードできます。

・VirtMemTest: a utility to exercise memory and other operations[英語](https://blogs.msdn.microsoft.com/aaron_margosis/2013/06/14/virtmemtest-a-utility-to-exercise-memory-and-other-operations/:Microsoft Developer)

 ちなみに、Windows Sysinternalsの「Process Explorer(Procexp)」を使ってデスクトップウィンドウマネージャー(dwm.exe)のプロセスの詳細を見てみると、「dwmghost.dll」というDLLがロードされていることを確認できます。おそらく、このDLLがゴーストウィンドウを処理しているものと想像します。

 ところで、Windows SysinternalsのProcess Explorer(Procexp)や「Process Monitor」には、アプリケーションのウィンドウを捕まえ、対応するプロセスを素早く識別できる機能があります。この機能は、ゴーストウィンドウへの配慮がきちんとされており、応答なしのウィンドウを捕まえても、デスクトップウィンドウマネージャー(dwm.exe)ではなく、本当に応答しなくなったアプリケーションのプロセスを識別してくれます。

●筆者紹介
山市 良/岩手県花巻市在住。Microsoft MVP:Cloud and Datacenter Management(Oct 2008 - Sep 2016)。SIer、IT出版社、中堅企業のシステム管理者を経て、フリーのテクニカルライターに。マイクロソフト製品、テクノロジーを中心に、IT雑誌、Webサイトへの記事の寄稿、ドキュメント作成、事例取材などを手掛ける。個人ブログは『山市良のえぬなんとかわーるど』。近著は『Windows Server 2016テクノロジ入門-完全版』(日経BP社)。

最終更新:2/23(木) 5:10

@IT

Yahoo!ニュースからのお知らせ