111

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

アップデート:

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

4

6 に答える 6

204

メッセージ ループは、ネイティブ 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 スレッドで。メッセージ ループにより、このコードが確実に実行されます。

于 2010-02-08T16:54:30.150 に答える
13

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

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

于 2010-02-08T14:59:52.733 に答える
8

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

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

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

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

于 2010-02-08T15:01:27.237 に答える
6

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

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

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

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

于 2011-06-14T09:11:51.293 に答える
2

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

于 2010-02-08T14:58:31.510 に答える
1

この Channel 9 の議論には簡潔な説明があると思います。

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

于 2010-02-08T15:05:21.640 に答える