メッセージ ループは、ネイティブ Windows プログラムに存在する小さなコードです。おおよそ次のようになります。
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
GetMessage() Win32 API は、Windows からメッセージを取得します。通常、プログラムは 99.9% の時間をそこで過ごし、Windows が何か興味深いことが起こったことを通知するのを待ちます。TranslateMessage() は、キーボード メッセージを翻訳するヘルパー関数です。DispatchMessage() は、ウィンドウ プロシージャがメッセージと共に呼び出されることを保証します。
すべての GUI 対応 .NET プログラムにはメッセージ ループがあり、Application.Run() によって開始されます。
Office に対するメッセージ ループの関連性は、COM に関連しています。Office プログラムは COM 対応のプログラムであり、Microsoft.Office.Interop クラスはそのように機能します。COM は、COM コクラスに代わってスレッド化を処理し、COM インターフェイスで行われる呼び出しが常に正しいスレッドから行われるようにします。ほとんどの COM クラスには、ThreadingModel を宣言するレジストリ キーがレジストリにあり、最も一般的なもの (Office を含む) は "Apartment" を使用します。つまり、インターフェイス メソッドを呼び出す唯一の安全な方法は、クラス オブジェクトを作成したスレッドと同じスレッドから呼び出すことです。別の言い方をすれば、ほとんどの COM クラスはスレッドセーフではありません。
すべての COM 対応スレッドは、COM アパートメントに属します。シングル スレッド アパートメント (STA) とマルチ スレッド アパートメント (MTA) の 2 種類があります。アパートメント スレッドの COM クラスは、STA スレッドで作成する必要があります。これは .NET プログラムで確認できます。Windows フォームまたは WPF プログラムの UI スレッドのエントリ ポイントには [STAThread] 属性があります。他のスレッドのアパートメント モデルは、Thread.SetApartmentState() メソッドによって設定されます。
UI スレッドが STA でない場合、Windows の配管の大部分は正しく機能しません。特に、ドラッグ アンド ドロップ、クリップボード、OpenFileDialog などの Windows ダイアログ、WebBrowser などのコントロール、スクリーン リーダーなどの UI オートメーション アプリです。また、Office などの多くの COM サーバー。
STA スレッドの厳しい要件は、決してブロックしてはならず、メッセージ ループをポンピングする必要があるということです。メッセージ ループは、あるスレッドから別のスレッドへのインターフェイス メソッド呼び出しをマーシャリングするために COM が使用するものであるため、重要です。.NET では呼び出しのマーシャリングが簡単になりますが (Control.BeginInvoke や Dispatcher.BeginInvoke など)、実際には非常に扱いにくいものです。呼び出しを実行するスレッドは既知の状態である必要があります。スレッドを任意に中断してメソッド呼び出しを強制することはできません。これは恐ろしい再入可能性の問題を引き起こします。スレッドは「アイドル状態」で、プログラムの状態を変化させるコードの実行でビジーではありません。
プログラムがメッセージ ループを実行しているとき、プログラムはアイドル状態です。実際のマーシャリングは、COM が作成する隠しウィンドウを通じて行われ、PostMessage を使用して、そのウィンドウのウィンドウ プロシージャにコードを実行させます。STA スレッドで。メッセージ ループにより、このコードが確実に実行されます。