0

COM自動化用に作成したクラスを使用するWindowsワークフローアプリケーションがあります。COMを使用してクラスからWordとExcelを開いています。

私は現在、COMヘルパーにIDisposableを実装しており、Marshal.ReleaseComObject()を使用しています。ただし、ワークフローが失敗した場合、Dispose()メソッドは呼び出されず、WordまたはExcelのハンドルは開いたままになり、アプリケーションがハングします。

この問題の解決策は非常に簡単ですが、単に解決するのではなく、何かを学び、COMを使用する正しい方法についての洞察を得たいと思います。COMハンドルを所有するクラスのライフサイクルを処理するための「最良の」または最も効率的で安全な方法を探しています。パターン、ベストプラクティス、またはサンプルコードが役立ちます。

4

2 に答える 2

1

Dispose() メソッドを呼び出さない失敗が何なのかわかりません。例外をスローするコード アクティビティのみを含むシーケンシャル ワークフローでテストを行いましたが、ワークフローの Dispose() メソッドが 2 回呼び出されました (これは、標準の WorkflowTerminated イベント ハンドラーが原因です)。次のコードを確認してください。

Program.cs

    class Program
    {
        static void Main(string[] args)
        {
            using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
            {
                AutoResetEvent waitHandle = new AutoResetEvent(false);
                workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) 
                {
                    waitHandle.Set();
                };
                workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
                {
                    Console.WriteLine(e.Exception.Message);
                    waitHandle.Set();
                };

                WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowConsoleApplication1.Workflow1));
                instance.Start();

                waitHandle.WaitOne();
            }
            Console.ReadKey();
        }
    }

Workflow1.cs

    public sealed partial class Workflow1: SequentialWorkflowActivity
    {
        public Workflow1()
        {
            InitializeComponent();
            this.codeActivity1.ExecuteCode += new System.EventHandler(this.codeActivity1_ExecuteCode);
        }

        [DebuggerStepThrough()]
        private void codeActivity1_ExecuteCode(object sender, EventArgs e)
        {
            Console.WriteLine("Throw ApplicationException.");
            throw new ApplicationException();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Here you must free your resources 
                // by calling your COM helper Dispose() method
                Console.WriteLine("Object disposed.");
            }
        }
    }

何か不足していますか?アクティビティ (およびワークフロー) オブジェクトのライフサイクル関連のメソッドについては、この投稿を確認してください:アクティビティの「ライフタイム」メソッド。廃棄に関する一般的な記事だけが必要な場合は、このを確認してください。

于 2008-09-18T20:38:29.263 に答える
0

基本的に、作業の最後にオブジェクトで Dispose() を呼び出すためにハンド コードに頼るべきではありません。あなたはおそらく今このようなものを持っています:

MyComHelper helper = new MyComHelper();
helper.DoStuffWithExcel();
helper.Dispose();
...

代わりに、try ブロックを使用して、トリガーされる可能性のある例外をキャッチし、その時点で dispose を呼び出す必要があります。これは標準的な方法です:

MyComHelper helper = new MyComHelper();
try
{
    helper.DoStuffWithExcel();
}
finally()
{
    helper.Dispose();
}

これは非常に一般的であるため、C# には上記とまったく同じコードを生成する特別な構造があります [注を参照]。これは、ほとんどの場合行うべきことです (上記のような手動パターンを扱いやすくする特別なオブジェクト構築セマンティクスがある場合を除きます)。

using(MyComHelper helper = new MyComHelper())
{
    helper.DoStuffWithExcel();
}

EDIT :
注: 生成される実際のコードは、上記の 2 番目の例よりも少し複雑です。これは、usingブロック後にヘルパー オブジェクトを使用できなくする新しいローカル スコープも導入するためです。2 番目のコード ブロックが { } で囲まれているようなものです。説明を明確にするために省略しました。

于 2008-09-18T21:15:11.797 に答える