1

我的目标是使用 C# 控制第 3 方应用程序。第三方应用程序可以由 COM 引用控制。

我在我的简单控制台应用程序中添加了引用,我可以看到类和方法没有问题。

以下行触发第 3 方应用程序启动。它确实如此。您可以在 Taskmanager/Processes (mfl32.exe) 中愉快地看到它:

MFL32.Application mfl = new MFL32.Application();

当我的控制台应用程序退出时,mfl32.exe 仍在进程列表中 - 这是可以预料的,因为我没有调用关闭它。然后我添加了这一行:

mfl.Quit();

现在,当我的控制台应用程序运行时,它会触发 mfl32.exe 启动,当我的控制台应用程序关闭时,它会终止 mfl32.exe 进程。

出现的问题是我的代码需要在单独的线程中调用此应用程序。mfl32.exe 进程不会在线程结束时终止,只会在我的控制台应用程序关闭时自行删除。当前代码如下所示:

namespace lt
{

class threadtest
{
    public void LaserTest()
    {

        Console.WriteLine("Worker thread started...");
        MFL32.Application mfl = new MFL32.Application();
        int i = 0;
        while (i < 50000)
        {
            i++;
        }
        mfl.Quit();
        Console.WriteLine("Worker thread now finished!");
    }

    void laser_AppQuit() // Quit event handler triggered
    {
        Console.WriteLine("The QUIT method has been caught. It should kill the lfm32.exe process");
    }
}



class Program
{
    static void Main(string[] args)
    {
        threadtest workerObject = new threadtest();
        Thread workerThread = new Thread(workerObject.LaserTest);
        workerThread.Start();
        Console.WriteLine("End of main thread reached");
        Console.ReadKey();
    }
}

}

关于为什么触发的 exe 仅在主控制台应用程序终止而不是在到达单独线程的末尾时终止的任何想法?

4

2 回答 2

1

即使在调用mfl.Quit(). 这有点奇怪,因为“Quit()”方法的正常语义是强制进程退出(有序)并使任何 COM 引用无效。

按照设计,当保存引用的变量(好的,保存对RCW 的引用或保存对应用程序的 COM 引用的 Runtime-Callable Wrapper 对象的引用的变量)熄灭时,.Net 不会在 COM 对象上调用 Release()范围,因为 .Net 是垃圾收集的。

Release()只有当您的进程(技术上是 AppDomain)结束时,或者当垃圾收集器决定收集您的 RCW 对象时,才会在 COM 对象上调用,这在短暂的控制台应用程序上是“从不”。

我本来希望 RCW 对象Dispose()能够,但事实并非如此。也许有技术原因,也许直到在.Net 1.0的开发过程中为时已晚才引入dispose模式来改变RCW的行为。

在任何情况下,要强制 RCW 调用Release()其 COM 引用,请调用:

  Marshal.ReleaseComObject(mfl);

调用该Quit()方法后尝试一下,看看它是否会改变第三方程序的行为。

于 2013-05-31T13:13:49.593 回答
0

我会假设在 COM dll 中没有正确发布某些内容。我会尝试在单独的应用程序域中运行 LaserTest。在 .NET 中加载程序集后,它会一直加载,除非应用程序域被破坏。或者,您可以创建单独的“启动器”程序集,在您的线程中运行启动程序程序集并在启动程序程序集中强制退出,一旦它完成了 COM 的东西。至于在单独的应用程序域中运行:

  var domain = AppDomain.CreateDomain("LaserDomain");
  domain.DoCallBack(() => {
      // dummy wait - run laser test here
      Thread.Sleep(5000);
      AppDomain.Unload(AppDomain.CurrentDomain);
  });
于 2013-05-31T12:46:53.783 回答