web-dev-qa-db-ja.com

メッセージポンプとは何ですか?

このスレッド (約1年前に投稿)には、非対話型セッションでWordを実行するときに発生する可能性のある問題についての議論があります。そこに与えられた(非常に強い)アドバイスはそうすることではありません。ある投稿では、「Office APIはすべて、デスクトップ、モニター、キーボード、マウス、そして最も重要なことにはメッセージポンプを備えたインタラクティブセッションでOfficeを実行していることを前提としています。」それが何なのか分かりません。 (私はC#で約1年間しかプログラミングしていません。他のプログラミングの経験は、主にColdFusionを使用してきました。)

更新:

私のプログラムは多数のRTF=ファイルを実行して、医療レポート番号の作成に使用される2つの情報を抽出します。RTF仕事、私はちょうどそれらをWordで開き、そこからテキストを引き出すことにしました(実際にGUIを起動することなく)。時折、プログラムは1つのファイルの処理の途中で中断し、接続されたWordスレッドを開いたままにしましたそのドキュメント(私はまだその1つをシャットダウンする方法を把握する必要があります。)プログラムを再実行すると、もちろん、そのファイルを使用しているスレッドがあるという通知を受け取り、読み取り専用を開きたいと思いました。 「はい」と言ったとき、Word GUIが突然どこからともなくポップアップし、ファイルの処理を開始しました。なぜそうなったのかと思いましたが、ダイアログボックスがポップアップすると、メッセージポンプがメインGUIをWindowsにプッシュし始めたようですまあ?

94
Matt Gutting

メッセージループは、ネイティブ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が1つのスレッドから別のスレッドへのインターフェイスメソッド呼び出しをマーシャリングするために使用するためです。 .NETを使用すると、呼び出しのマーシャリングが簡単になります(たとえば、Control.BeginInvokeやDispatcher.BeginInvoke)が、実際には非常に難しい作業です。呼び出しを実行するスレッドは、既知の状態でなければなりません。スレッドをarbitrarily意的に中断してメソッド呼び出しを強制することはできません。これにより、恐ろしい再入可能性の問題が発生します。スレッドは「アイドル」であり、プログラムの状態を変更しているコードの実行でビジーではありません。

おそらく、それがどこにつながるかを見ることができます。はい、プログラムがメッセージループを実行しているとき、それはアイドル状態です。実際のマーシャリングは、COMが作成する隠しウィンドウを介して行われ、PostMessageを使用してそのウィンドウのウィンドウプロシージャにコードを実行させます。 STAスレッド上。メッセージループにより、このコードが実行されます。

170
Hans Passant

「メッセージポンプ」は、ウィンドウメッセージをアプリケーションのさまざまな部分にディスパッチするWindowsプログラムのコア部分です。これがWin32 UIプログラミングの中核です。ユビキタスであるため、多くのアプリケーションはメッセージポンプを使用して異なるモジュール間でメッセージを渡します。そのため、UIなしで実行するとOfficeアプリケーションが破損します。

ウィキペディアには 基本的な説明 があります。

11
JSBձոգչ

Johnは、Windowsシステム(および他のウィンドウベースのシステム- X Window 、元のMac OS ....)がメッセージシステム経由のイベントを使用して非同期ユーザーインターフェイスを実装する方法について話しています。

各アプリケーションの舞台裏では、各ウィンドウが他のウィンドウまたはイベントリスナーにイベントを送信できるメッセージングシステムがあります。これは、メッセージキューにメッセージを追加することで実装されます。このメッセージキューを常に確認してから、メッセージ(またはイベント)をリスナーにディスパッチするメインループがあります。

ウィキペディアの記事Microsoft Windowsのメッセージループは、基本的なWindowsプログラムのサンプルコードを示しています。 Windowsプログラムの最も基本的なレベルは、単なる「メッセージポンプ」です。

それで、それをすべて一緒に引きます。 UIをサポートするように設計されたWindowsプログラムがサービスとして動作できない理由は、UIサポートを有効にするために常に実行されるメッセージループが必要だからです。説明したようにサービスとして実装すると、内部の非同期イベント処理を処理できなくなります。

6
Hogan

[〜#〜] com [〜#〜] では、メッセージポンプはアパートメント間で送信されたメッセージをシリアル化および非シリアル化します。アパートメントは、COMコンポーネントを実行できるミニプロセスです。アパートにはシングルスレッドモードとフリースレッドモードがあります。シングルスレッドアパートメントは、主に、マルチスレッドをサポートしないCOMコンポーネントのアプリケーション用のレガシーシステムです。通常、Visual BASIC(マルチスレッドコードをサポートしていなかったため)およびレガシーアプリケーションで使用されていました。

Word のメッセージポンプの要件は、COM APIまたはスレッドセーフではないアプリケーションの一部に起因していると思います。 。NET スレッド化およびガベージコレクションモデルは、そのままではCOMとうまく連携しないことに注意してください。 COMには、非常に単純化されたガベージコレクションメカニズムとスレッドモデルがあり、COMの方法で行う必要があります。標準の Office PIA を使用するには、引き続きCOMオブジェクト参照を明示的にシャットダウンする必要があるため、作成されたすべてのCOMハンドルを追跡する必要があります。あなたが注意していなければ、PIAは舞台裏の物も作成します。

.NET-COM統合は、それ自体がすべてのトピックであり、このテーマに関する書籍もあります。インタラクティブなデスクトップアプリケーションからOfficeのCOM APIを使用する場合でも、フープをジャンプして、参照が明示的に解放されていることを確認する必要があります。

Officeはスレッドセーフでないと見なすことができるため、Wordの個別のインスタンス Excel またはその他の Office アプリケーションがスレッドごとに必要です。開始オーバーヘッドが発生するか、スレッドプールを維持する必要があります。すべてのCOM参照が正しく解放されたことを確認するには、スレッドプールを入念にテストする必要があります。インスタンスを起動およびシャットダウンする場合でも、すべての参照が正しくリリースされていることを確認する必要があります。ここでiにドットを付けてtを越えないと、大量のデッドCOMオブジェクトや実行中のWordのインスタンス全体がリークされることになります。

ウィキペディアは、プログラムの メインイベントループ を意味することを示唆しています。

2
Vince Bowdren

このチャンネル9のディスカッション には簡潔な説明があります。

このウィンドウ通信プロセスは、いわゆるWindows Message Pumpによって可能になります。メッセージポンプは、アプリケーションウィンドウとデスクトップ間の連携を可能にするエンティティと考えてください。

0
Richard Everett