2012-11-08 171 views
-1

我創建了一個excel幫助程序類,用於與Excel交互服務進行交互。 但我注意到excel.exe沒有在服務器上關閉。 (windows 2008 64bit日語操作系統和office 2007 32bit)。 當我用進程管理器檢查它表明類似工具提示:Microsoft Office Interop Excel未關閉Windows 2008 64位和Office 2007 32位

Path:[Error opening process] 

我做excel.Quit()Marshal.FinalReleaseComObject(_xlApp)但沒有按預期工作,然後試圖通過processID殺的過程中,仍然沒有殺死進程。

uint processID = 0; 
GetWindowThreadProcessId((IntPtr)_hWnd, out processID); 
if (processID != 0) 
{ 
    System.Diagnostics.Process.GetProcessById((int)processID).Kill(); 
} 

然後我嘗試了下面兩種方法,但它關閉了所有手動打開的Excel文檔。

System.Diagnostics.Process[] procs = System.Diagnostics.Process.GetProcessesByName("EXCEL"); 
     foreach (System.Diagnostics.Process p in procs) 
     { 
      int baseAdd = p.MainModule.BaseAddress.ToInt32(); 
      if (baseAdd == _xlApp.Hinstance) 
      { 
       p.Kill(); 
      } 
     } 

System.Diagnostics.Process[] procs = System.Diagnostics.Process.GetProcessesByName("EXCEL"); 
     foreach (System.Diagnostics.Process p in procs) 
     { 
      if (p.MainWindowTitle.Length == 0) 
      { 
       p.Kill(); 
      } 
     } 

有關如何處理這種情況的任何想法?

回答

1

獲得processId有點複雜。 嘗試......

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using Excel = Microsoft.Office.Interop.Excel; 
using Word = Microsoft.Office.Interop.Word; 

    /// <summary> 
    /// Gets an Interop.Application object and its associated processId 
    /// </summary> 
    /// <returns>Excel.Application or Word.Application depending on _isExcel</returns> 
    private object ApplicationFactory() 
    { 
     object application = null; 
     string processName = (_isExcel) ? "excel" : "winword"; 
     Process[] beforeProcesses = null; 
     Process[] afterProcesses = null; 
     int i = 0; 
     while (i < 3) 
     { // ourProcess = afterList - beforeList 
      beforeProcesses = Process.GetProcessesByName(processName); 
      application = (_isExcel) ? (object)new Excel.Application() : (object)new Word.Application(); 
      afterProcesses = Process.GetProcessesByName(processName); 
      if ((afterProcesses.Length - beforeProcesses.Length) == 1) 
      { // OK. Just a single new process 
       break; 
      } 
      else 
      { // Two or more processes, we cannot get our processId 
       // therefore quit while we can and try again 
       if (_isExcel) 
        ((Excel._Application)application).Quit(); 
       else 
        ((Word._Application)application).Quit(); 
       int indexReferences = 1; 
       do 
       { 
        indexReferences = System.Runtime.InteropServices.Marshal.ReleaseComObject(application); 
       } 
       while (indexReferences > 0); 
       application = null; 
       System.Threading.Thread.Sleep(150); 
       i++; 
      } 
     } 
     if (application == null) 
     { 
      throw new ApplicationException("Unable to create Excel Application and get its processId"); 
     } 
     List<int> processIdList = new List<int>(afterProcesses.Length); 
     foreach (Process procDesp in afterProcesses) 
     { 
      processIdList.Add(procDesp.Id); 
     } 
     foreach (Process proc in beforeProcesses) 
     { 
      processIdList.Remove(proc.Id); 
     } 
     _processId = processIdList[0]; 
     return application; 
    } 

    /// <summary> 
    /// Kills _processId process if exists 
    /// </summary> 
    private void ProcessKill() 
    { 
     Process applicationProcess = null; 
     if (_processId != 0) 
     { 
      try 
      { 
       applicationProcess = Process.GetProcessById(_processId); 
       applicationProcess.Kill(); 
      } 
      catch 
      { // no Process with that processId 
      } 
     } 
    } 

也就是說,暴力是剛剛過去的地質礦產;-) 你需要殺死,因爲有一些COM對象不會被釋放。 (見 MS Support: Office application does not close) 嘗試總是引用您的COM對象,把它們放在一個堆棧,並釋放他們使用後

System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) 

那麼,一個簡單的application.Quit();application = null將會使的伎倆。

希望它有幫助。

編輯: - 始終表示:「每當你使用兩個點(_xlApp.Application., _xlWorkbook.Worksheets,...

  • 添加到疊層裝置stack.push(_xlApp.Application)

  • 發佈意味着stack.pop()

我包括MI helperStack

using System.Collections.Generic; 

namespace OfficeUtils.Stack 
{ 
/// <summary> 
/// Stack of COM objects to be released 
/// </summary> 
public abstract class ComObjectsStack 
{ 
    private Stack<object> comObjects = new Stack<object>(); 
    private int mark = 0; 

    /// <summary> 
    /// Releases all the remaining COM objects 
    /// </summary> 
    ~ComObjectsStack() 
    { 
     if (comObjects.Count > 0) 
      ReleaseAll(); 
     comObjects = null; 
    } 

    /// <summary> 
    /// Add a new object to the stack to be released 
    /// </summary> 
    /// <param name="obj">Nuevo objeto a liberar</param> 
    public void Push(object obj) 
    { 
     comObjects.Push(obj); 
    } 

    /// <summary> 
    /// Release the last object in the stack 
    /// </summary> 
    public void Pop() 
    { 
     Release(1); 
    } 

    /// <summary> 
    /// Mark for future use of ReleaseUpToMark 
    /// </summary> 
    public void Mark() 
    { 
     mark = comObjects.Count; 
    } 

    /// <summary> 
    /// Release up to mark 
    /// </summary> 
    /// <returns>Number of released objects</returns> 
    public int ReleaseUpToMark() 
    { 
     int numberObjects = comObjects.Count - mark; 
     if (numberObjects > 0) 
     { 
      Release(numberObjects); 
      return numberObjects; 
     } 
     else 
     { 
      return 0; 
     } 
    } 

    /// <summary> 
    /// Release all the objects in the stack 
    /// </summary> 
    public void ReleaseAll() 
    { 
     if (comObjects != null) 
      Release(comObjects.Count); 
    } 

    /// <summary> 
    /// Release the last numberObjects objects in stack 
    /// </summary> 
    /// <param name="numberObjects">Number of objects to release</param> 
    private void Release(int numberObjects) 
    { 
     for (int j = 0; j < numberObjects; j++) 
     { 
      object obj = comObjects.Pop(); 
      int i = 1; 
      do 
      { 
       i = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); 
      } 
      while (i > 0); 
      obj = null; 
     } 
    } 
} 

}

+0

喜,@raist非​​常感謝您的意見。似乎是一個好方法。讓我試試這個,並且會更新你。 – Ullas

1

我發現用我能夠從任務管理器刪除Excel如下:

using System.Runtime.InteropServices; 
    using Microsoft.Office.Interop.Excel; 

    /// <summary> 
    /// Excel application 
    /// </summary> 
    private ApplicationClass m_xlApp = null; 

    /// <summary> 
    /// Reference to the workbook. 
    /// </summary> 
    private Workbook m_book = null; 

    /// <summary> 
    /// Reference to the worksheet. 
    /// </summary> 
    private Worksheet m_sheet = null; 

    /// <summary> 
    /// Close the workbook. 
    /// </summary> 
    public void Close() 
    { 
     if (m_book != null) 
      m_book.Close(Missing.Value, Missing.Value, Missing.Value); 

     if (m_xlApp != null) 
     { 
      m_xlApp.Workbooks.Close(); 
      m_xlApp.Quit(); 
     } 

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

     // Release the objects 
     Marshal.FinalReleaseComObject(m_sheet); 
     Marshal.FinalReleaseComObject(m_book); 
     Marshal.FinalReleaseComObject(m_xlApp); 

     m_sheet = null; 
     m_book = null; 
     m_xlApp = null; 
    } 
相關問題