0

我有一个 Windows 工作流应用程序,它使用我为 COM 自动化编写的类。我正在使用 COM 从我的课程中打开 Word 和 Excel。

我目前正在我的 COM 助手中实现 IDisposable 并使用 Marshal.ReleaseComObject()。但是,如果我的工作流程失败,则不会调用 Dispose() 方法,并且 Word 或 Excel 句柄保持打开状态并且我的应用程序挂起。

这个问题的解决方案非常简单,但不仅仅是解决它,我想学习一些东西并深入了解使用 COM 的正确方法。我正在寻找“最佳”或最有效和最安全的方式来处理拥有 COM 句柄的类的生命周期。模式、最佳实践或示例代码会有所帮助。

4

2 回答 2

1

我看不出你有什么不调用 Dispose() 方法的失败。我使用仅包含仅引发异常的代码活动的顺序工作流进行了测试,并且我的工作流的 Dispose() 方法被调用了两次(这是因为标准的 WorkflowTerminated 事件处理程序)。检查以下代码:

程序.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();
        }
    }

工作流1.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();
}

编辑
注意:生成的实际代码比上面的第二个示例稍微复杂一点,因为它还引入了一个新的本地范围,使辅助对象在using块之后不可用。就像第二个代码块被 {}'s 包围一样。为了解释清楚而省略了。

于 2008-09-18T21:15:11.797 回答