メッセージポンプとは


102

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

更新:

私のプログラムは、多数のRTFファイルを実行して、医療レポート番号の作成に使用される2つの情報を抽出します。RTFでのフォーマットの指示がどのように機能するかを理解するのではなく、Wordで開き、そこからテキストを(実際にはGUIを起動せずに)取り出すだけにしました。ときどき、プログラムは1つのファイルの処理中に中断し、そのドキュメントに添付されたWordスレッドを開いたままにしました(まだ、そのファイルをシャットダウンする方法を理解する必要があります)。プログラムを再実行すると、もちろん、そのファイルを使用するスレッドがあるという通知が表示されました。読み取り専用のコピーを開きますか?私が「はい」と言ったとき、Word GUIが突然どこからもポップアップし、ファイルの処理を開始しました。なぜそうなったのかと思っていました。


3
これはなぜwin32とタグ付けされているのですか?-メッセージシステムはWindows V1でした(私が覚えているように8ビットでした)
Hogan

回答:


185

メッセージループは、ネイティブの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を含む)では、「アパートメント」を使用します。つまり、インターフェイスメソッドを呼び出す唯一の安全な方法は、クラスオブジェクトを作成したのと同じスレッドから呼び出すことです。言い換えると、ほとんどの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スレッド上。メッセージループにより、このコードが実行されます。


とても素敵で詳細な答え。追加するだけです-メインSTAと呼ばれる特別なSTAもあります。これは、最初に作成されたSTAです。理想的には、UIスレッドによって作成されたものである必要があります。メインSTAは、スレッドモデル=なしのコンポーネントが作成される場所です。メインSTAがUIスレッドによって作成されたものではない場合、スレッドモデルを持たない古いActiveXコントロールを使用すると、興味深い問題が発生する可能性があります。
quixver 2014

12

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

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


メッセージループなしでWindowsアプリを作成することは不可能だと思います。したがって、すべてのアプリケーションがメッセージポンプを使用します。
ホーガン

2
アプリなしでシンプルなGUIアプリを作成することもできます。たとえば、独自のアプリでアプリ内にメッセージループがなくても、メッセージボックスをポップアップできます。

DialogBoxまたはDialogBoxを介してダイアログを間接的に作成する場合-メッセージループは必要ありません。Windowsから呼び出される関数(dlgproc)を指定するだけです。(そしてメッセージボックスは単なるダイアログです)
quixver '18

6

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

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

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

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


6

ではCOM、メッセージポンプserialisesとデserialisesメッセージがアパートの間で送信されます。アパートメントは、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の実行中のインスタンス全体がリークされます。


1
回答にはいくつかの不正確な点があります。STA(シングルスレッド)、MTA(マルチスレッド)、NTA(ニュートラルスレッド)の3種類のアパートメントがあります。フリースレッドは、フリースレッドマーシャラーを集約するコンポーネントを記述するために使用されます。フリースレッドのアパートなどはありません。COMはメッセージを使用してSTAと通信します。MTA内に存在する(またはフリースレッドマーシャラーを集約する)コンポーネントの場合、メッセージループは必要ありません。AFAIK-lpcは、呼び出し元のスレッドからRPCスレッドプールのスレッドにデータをマーシャリングするために使用されます。RPCスレッドプールは、実際にメソッドを呼び出します。
quixver 2014


0

このChannel 9のディスカッションには、簡潔でわかりやすい説明があると思います。

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


2
うわー...それは恐ろしく誤解を招く引用です。(「エンティティ」?エラー番号。)
ホーガン

4
エンティティ-オブジェクト:単一の個別のオブジェクトとして存在する、または認識されるものencarta.msn.com/dictionary_1861608661/entity.html
マシューホワイト
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.