【问题标题】:Microsoft Office Interop Excel is not closing on windows 2008 64bit and office 2007 32bitMicrosoft Office Interop Excel 未在 windows 2008 64 位和 office 2007 32 位上关闭
【发布时间】:2012-11-08 05:44:31
【问题描述】:

我创建了一个 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();
             }
         }

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

【问题讨论】:

    标签: c# asp.net memory-management excel-interop


    【解决方案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;
            }
        }
    }
    

    }

    【讨论】:

    • 嗨,@raist 非常感谢您的 cmets。似乎是一个很好的方法。让我试试这个,会更新你。
    【解决方案2】:

    我发现通过使用以下方法可以从任务管理器中删除 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;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多