2013-01-11 15 views
4

我已經在C#中編寫了Excel的包裝器,以便允許在批處理過程(在JobScheduler下)中運行Excel工作簿。我的問題是這樣的......運行代碼時退出Interop受控Excel

如果代碼運行時間過長或需要通過作業調度程序終止,則包裝程序需要處理此終止事件。爲此,我添加了

SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true); 

代碼。在ConsoleCtrlCheck方法中,我調用一個通用的退出例程(用於正常或終止環境)。這種路由做以下按MS建議..

關閉並釋放工作簿
關閉並釋放Excel中
垃圾收集

,然後用Excel的方法被調用的返回碼退出(中入口點)。 這個效果很好。

但是,如果VBA代碼仍在運行,則Interop對象不會響應工作簿關閉或應用程序退出調用。這可能是因爲一切都變得緩慢,或者因爲模態對話已經發出。 爲了解決這個我添加了以下這個普通程序開始...

  • 創建新的線程來運行KillExcel方法
  • KillExcel法睡在指定時間內(所以正常退出代碼有一個工作的機會),然後殺死進程
  • 如果正常的代碼工作它調用中止的線程上
private static void Cleanup() 
{ 
    // Give this X seconds then terminate 
    mKillThread = new Thread(KillExcel); 
    mKillThread.IsBackground = false; 
    mKillThread.Start(); 
    ... 
    // close the workbooks and excel application 
    // Marshal.FinalReleaseComObject etc 

    GC.Collect(); 
    GC.WaitForPendingFinalizers(); 

    // Not sure if necessary but makes sure Process gone 
    try 
    { 
     Process p = Process.GetProcessById(mExcelPid); 
     p.WaitForExit(); 
    } 
    catch(ArgumentException) 
    {} 

    mKillThread.Abort(); 
} 

private static void KillExcel() 
{ 
    Thread.Sleep(Settings.Default.KillWaitMilliSeconds); 

    if (mLog.IsInfoEnabled) 
     mLog.Info(string.Format("Waited {0} seconds, killing Excel process [{1}]",Settings.Default.KillWaitMilliSeconds/1000, mExcelPid)); 

    try 
    { 
     Process p = Process.GetProcessById(mExcelPid); 

     if (!p.HasExited) 
      p.Kill(); 
    } 
    catch(ArgumentException) 
    { 
    } 
} 

我的問題是,有沒有要去一個更好的辦法回合或者這是爲了確保在作業終止事件中刪除excel進程的方式?

回答

1

你在做什麼幾乎是完全確保Excel退出的標準方式。考慮到有COM Interop的參與,而且excel有一個令人討厭的留下孤兒實例的習慣,你遵循的方法非常簡單。

但是,如果您有權訪問vba代碼並且可以控制它,那麼您可以做一件基本的事情來確保VBA代碼確實允許其他代碼運行。

DoEvents 

根據我的經驗,在運行繁重的計算前後放置這一行代碼通常允許excel正確處理例行事件。雖然通常將這建議用於與UI相關的操作,但它也適用於讓Worksheet/Application事件正常工作。

希望這會有所幫助。

0

有沒有可能用EPPLUS等第三方庫替換VBA邏輯?這將是更大的幅度....