2013-05-31 34 views
1

我的目標是使用C#控制第三方應用程序。第三方應用程序可以通過COM參考進行控制。由C#啓動的應用程序保持爲運行過程直到主線程關閉

我在我的簡單控制檯應用程序中添加了參考,我可以看到類和方法沒有問題。

以下行觸發第三方應用程序啓動。它做什麼。你可以看到它在任務管理器/進程(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只有終止?

回答

1

雖然有,傑出的COM引用它甚至稱mfl.Quit()後,第三方程序可能保持活着。這有點奇怪,因爲「Quit()」方法的正常語義是強制進程退出(有序)並使任何COM引用無效。

通過設計,.Net不會調用COM對象上的Release(),當持有引用的變量(Ok,變量持有對應用程序的COM引用的對象RCW or Runtime-Callable Wrapper的引用)超出範圍,因爲.Net是垃圾收集的。

Release()只有當你的進程(技術上是AppDomain)結束時,或者當垃圾收集器決定收集你的RCW對象時,它纔會在COM對象上被調用,而這些對象在短暫的控制檯應用程序上是'從不'的。

我本來預計RCW對象的能力是Dispose(),但他們不是。也許有技術上的原因,也許直到在.Net 1.0的開發過程中爲了改變RCW的行爲已經太晚,纔會引入配置模式。

在任何情況下,強制RCW調用Release()其COM參考,請致電:

Marshal.ReleaseComObject(mfl); 

嘗試在調用Quit()方法後,看看它是否改變了第三方程序的行爲。

+0

這很好。比捕獲退出事件更友好,然後嘗試手動終止該過程!非常感謝你。 – tripbrock

0

我會假設COM DLL中沒有正確釋放某些東西。我會嘗試在單獨的應用程序域中運行LaserTest。一旦在.NET中加載程序集,它將保持加載狀態,除非應用程序域被破壞。或者,您可以創建單獨的「啓動器」程序集,在您的線程中運行啓動程序集並在啓動程序集完成後強制退出。至於在單獨的應用程序域中運行:

var domain = AppDomain.CreateDomain("LaserDomain"); 
    domain.DoCallBack(() => { 
     // dummy wait - run laser test here 
     Thread.Sleep(5000); 
     AppDomain.Unload(AppDomain.CurrentDomain); 
    }); 
相關問題