20

.NETで(Microsoft.Office.Interop.Wordアセンブリを介して)Word COMオブジェクトを作成するときに、オブジェクトを適切に閉じて解放しても、WinWordプロセスが終了しないという古典的なシナリオに遭遇しています。

Word.Documents.Add()メソッドの使用に絞り込みました。他の方法(ドキュメントを開く、コンテンツを変更するなど)でWordを操作でき、指示するとWinWord.exeが終了します。Add()メソッドを使用すると(テンプレートを追加する場合のみ)、プロセスが実行されたままになります。

問題を再現する簡単な例を次に示します。

Dim word As New Word.Application()
word.Visible = False

Dim documents As Word.Documents = word.Documents
Dim doc As Word.Document = documents.Add(Template:=CObj(templatePath), NewTemplate:=False, DocumentType:=Word.WdNewDocumentType.wdNewBlankDocument, Visible:=False)

'' dispose objects
doc.Close()
While (Marshal.ReleaseComObject(doc) <> 0)
End While
doc = Nothing

While (Marshal.ReleaseComObject(documents) <> 0)
End While
documents = Nothing

word.Quit()
While (Marshal.ReleaseComObject(word) <> 0)
End While
word = Nothing

GC.Collect()

ご覧のとおり、オブジェクトを適切に作成して破棄していますが、適切なコードが返されるまでMarsha.ReleaseComObjectをループするための追加の手順を実行しています。Wordオブジェクトの操作は、他の点では問題ありません。厄介なDocuments.Addが原因で、私は悲しみを覚えています。このプロセスで作成され、参照して破棄する必要のある別のオブジェクトはありますか?従う必要のある別の廃棄手順はありますか?他に何かありますか?あなたの助けは大歓迎です:)

Update:廃棄ステップの最後にGC.Collectを試しましたが、それでもうまくいきませんでした。

Update 2: 問題をカスタムテンプレートの使用に絞り込みました。Documents.Add(...)を呼び出すと、新しいドキュメントのカスタムテンプレートを指定します。これを行わず、代わりにパラメーターなしでAdd()を呼び出すと、問題は発生しません。

4

13 に答える 13

11

(私のアドバイスはすべて、Excel の相互運用に関するこの回答を基にしています。)

ここで重要なことがいくつかあります。

1) 同じ行に 2 つのドットを使用しないでください。インデクサーもドットと見なす

良い

Word.Documents d = wordApp.Documents;
Word.Document aDoc = d.Open(/*...*/);

悪い

Word.Document aDoc = wordApp.Documents.Open(/*...*/);

2) すべてのポインターを解放します。

3)いいえ、戻ってすべてのポインターを解放します。どこかで1つ見逃しています(または、少なくとも私はいつもそうしています)。

これは、多くの嘆きと歯ぎしりの後、最終的に1つのプロジェクトで私のために働いたものの完全な例です:

object m = Missing.Value;
// this must be an object, not a string. if you forget though,
// intellisense will remind you
object oFilename = @"C:\my sheet.doc";

object readOnly = false;
object isVisible = false;

Word.Application wordApp = new Word.ApplicationClass();
wordApp.Visible = false;
// remember: don't use 2 dots on 1 line
Word.Documents d = wordApp.Documents;
Word.Document aDoc = d.Open(ref oFilename, ref m, ref readOnly, ref m,
    ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref isVisible,
    ref m, ref m, ref m, ref m);
aDoc.Activate();

object findText = "my old value";
object replaceText = "new and improved value";

object oTrue = true;
object oFalse = false;
object replace = 2;
object wrap = 1;

Word.Selection s = wordApp.Selection;
Word.Find f = s.Find;
f.Execute(ref findText, ref oTrue,
    ref oTrue, ref oFalse, ref oFalse,
    ref oFalse, ref oTrue, ref wrap, ref oFalse,
    ref replaceText, ref replace, ref oFalse, ref oFalse,
    ref oFalse, ref oFalse);

aDoc.SaveAs(ref oFilename, ref m, ref m, ref m, ref m, ref m, ref m,
    ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref m, ref m);

object doNotSaveChanges = Word.WdSaveOptions.wdDoNotSaveChanges;
// casting here because intellisense complained of ambiguity
(aDoc as Word._Document).Close(ref doNotSaveChanges, ref m, ref m);

// release each in the reverse of the order in which it was first used
// ReleaseComObject might also work as well. I haven't tested yet
Marshal.FinalReleaseComObject(f);
Marshal.FinalReleaseComObject(s);
Marshal.FinalReleaseComObject(aDoc);
Marshal.FinalReleaseComObject(d);

// must quit app before releasing
// again: casting because intellisense complained of ambiguity
(wordApp as Word._Application).Quit(ref m, ref m, ref m);
Marshal.FinalReleaseComObject(wordApp);
于 2010-07-07T19:34:21.773 に答える
4

変えてみましたか

oWord.Visible = False

oWord.Visible = True

?

使用しようとしているこのテンプレートに関連することを Word が要求している可能性があるため、お尋ねします。ダイアログが表示されていると判断した場合、通常はシャットダウンしません。IIRCには、Quitを強制してダイアログを待たないようにQuitする方法があります。でも、お久しぶりです。

于 2010-03-25T16:15:34.790 に答える
4

私はそれをしていたときに同じ問題を抱えていました:

object missing = System.Reflection.Missing.Value;
wordApplication.Quit(ref missing, ref missing, ref missing);

私はこのように解決しました:

object objFalse = false;
wordApplication.Quit(ref objFalse, ref objFalse, ref objFalse);

理由は聞かないでください。オフィスの自動化は冒険です :)

于 2010-04-05T17:38:05.513 に答える
2

私はExcelの自動化を行っただけですが、同様の問題が発生しました。いくつかの古いコードを参照して、閉じる最後のステップには、GC.Collect()という行があります。

この記事もそれについて言及しています: http ://support.microsoft.com/kb/317109

于 2010-03-24T21:35:03.020 に答える
2

カスタム テンプレートを使用する場合の Documents.Add() の使用が原因であることがわかりました。なぜこれが WinWord.exe をハングさせたままにするのか説明できません。ただし、テンプレートからドキュメントを作成する方法は他にもありますが、同じ問題は発生しません。

だから私は置き換えました:

Dim doc As Word.Document = documents.Add(Template:=CObj(templatePath))

と:

Dim doc As Word.Document = documents.Add()  
doc.AttachedTemplate = templatePath  
doc.UpdateStyles()

AttachedTemplate を使用してテンプレートを指定すると、WinWord.exe がハングしたままになることはありません。

(しかし、新たな問題が発生しました... AttachedTemplate/UpdateStyles を使用すると、テンプレートのフッターの画像がドキュメントにコピーされません。それは別の問題として取り上げています。しかし、この方法は元の問題を解決するので、私は'満足しています。回答を提供してくれた皆さんに感謝します!)

于 2010-03-26T18:08:29.233 に答える
2

の代わりに呼び出しGC.WaitForPendingFinalizers()て使用してみてください。これにより、ループする必要がなくなります。Marshal.FinalReleaseComObjectMarshal.ReleaseComObject

コードをこれに更新して試してください(GC呼び出しは意図的に最初にあります):

GC.Collect()
GC.WaitForPendingFinalizers()

oDoc.Close()
Marshal.FinalReleaseComObject(oDoc)

Marshal.FinalReleaseComObject(oDocuments)

oWord.Quit()
Marshal.FinalReleaseComObject(oWord)

Excel の問題について説明しているこの関連する質問も確認してください。

于 2010-03-25T15:54:51.663 に答える
1

テンプレートに関する同様の問題のために、あなたの投稿に出会いました。プログラムで単語を閉じようとすると、.dotm ファイルを保存するように求めるメッセージが表示されます。正確なテンプレート パスがないため、受け入れられた回答を使用できませんでした。プログラムが受け取ったドキュメントを開くだけです。

私が使ったのは

Word.NormalTemplate.Saved = true;

アプリケーションを破棄する前にそのコードを使用すると、テンプレートを保存していないというダイアログが表示されなくなり、不要な「winWord.exe」プロセスを実行したままにすることなく破棄が実行されます。

ここのビジュアルベーシックフォーラムでユーザー「NeedSomeAnswers 」から「NormalTemplate.Saved」のヒントを得ました。彼の言葉によれば、「[それ] は実際には法線に保存されません。法線が既に保存されていることを Word に伝えるだけなので、保存する必要はありません」。

これは同じ問題に対する2番目の答えだと思います。お役に立てば幸いです。

素晴らしい一日をお過ごしください。

-コードが機能する日はいつでも祝うのに良い日です-

于 2015-08-10T17:44:51.140 に答える
0

「oDocuments」には.Dispose()または.Close()メソッドがありますか?あなたは他の2つを処分していますが、これは処分していません。

于 2010-03-24T21:18:00.703 に答える
0

vb.net から Word でドキュメントの作成を自動化しようとしましたが、ドキュメントを閉じた後でも winword.exe が実行されていました。この問題の解決策を見つけました。サブルーチンから独立して寸法を記入するのではなく、文書の編集に使用していたサブルーチン内に単語オブジェクトの薄暗い部分を移動しました (私の最初の方法)。

お役に立てれば。

于 2015-11-07T00:06:27.323 に答える
0

これはC#ですが、多分それはあなたを助けるでしょう. この方法を使用して、複数のドキュメントを 1 つにマージしています。すべてのドキュメントを Arraylist に渡しました。終了すると、Word は適切に閉じているようです。

 public static void documentsMerge(object fileName, ArrayList arrayList) {
        // object fileName = Path.Combine(Environment.CurrentDirectory, @"NewDocument.doc");
        File.Delete(fileName.ToString());
        try {
            wordApplication = new ApplicationClass();
            var doc = wordApplication.Documents.Add(ref missing, ref missing, ref missing, ref missing);
            try {
                doc.Activate();
                int count = 0;
                foreach (var alItem in arrayList) {
                    addDocument(alItem, doc, count == 0);
                    count++;
                }
               // addDocument(@"D:\Projects\WordTests\ConsoleApplication1\Documents\Doc1.doc", doc ) ; //, false);
               // addDocument(@"D:\Projects\WordTests\ConsoleApplication1\Documents\Doc2.doc", doc ) ; //, true);
                doc.SaveAs(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
            } finally {
                doc.Close(ref missing, ref missing, ref missing);
            }
        } finally {
            wordApplication.Quit(ref missing, ref missing, ref missing);
        }
    }

finallyブロックは、cleaning uptry ブロックで割り当てられたリソースや、例外が発生した場合でも実行する必要があるコードの実行に役立ちます。try ブロックの終了方法に関係なく、制御は常に finally ブロックに渡されます。

コードを try / finally ブロックに入れて、どのように動作するかを確認してみてください。

VB.NET の場合

Try
' Statement which can cause an exception.
Catch x As Type
' Statements for handling the exception
Finally
End Try 'Any cleanup code
于 2010-03-24T21:40:13.493 に答える
0
oWord.Visible = True

私の問題を解決しました。根本的な問題は文書の回復でした。次の行があるにもかかわらず、ダイアログが表示されていました。

_wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;

私はここに示されているすべてのトリックを使用しましたが、ドキュメント回復リストがクリアされるまで、アプリケーションが実行されるたびに「ゾンビ」ワード プロセスが取り残されました。

于 2013-03-21T12:30:52.117 に答える
0

これは完璧な解決策です。私は同じ問題を抱えていました。これに従っただけで、完璧に機能しています。

オブジェクト objFalse = false;

wordApplication.Quit(ref objFalse, ref objFalse, ref objFalse);

于 2014-10-03T06:57:43.397 に答える
0

Word.Documents.Add で作成されたドキュメント オブジェクトを破棄しないでください。完了したら、オートメーションから取得したすべての COM オブジェクトで Marshal.ReleaseComObject を保存して呼び出します。つまり、オブジェクトをどこにもキャッシュしない場合です

于 2010-03-25T19:38:53.043 に答える