-1

我创建了一个 excel 助手类,用于交互 excel 互操作服务。但我注意到excel.exe服务器上没有关闭。(windows 2008 64bit Japanese OS 和 office 2007 32bit)。当我使用进程资源管理器检查时,它显示的工具提示如下:

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

关于如何处理这种情况的任何想法?

4

2 回答 2

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 支持:Office 应用程序未关闭)尝试始终引用您的 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;
        }
    }
}

}

于 2012-11-13T10:31:43.430 回答
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;
    }
于 2013-01-24T13:32:42.930 回答