【问题标题】:How to stop office application from C# console [duplicate]如何从 C# 控制台停止办公应用程序 [重复]
【发布时间】:2014-08-05 14:10:32
【问题描述】:

鉴于以下代码(控制台应用程序 C#),Word 应用程序在大约 300-400 毫秒后停止,但 Excel 应用程序继续运行。我找不到阻止它的方法(不终止进程)。

有什么建议吗?

using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Diagnostics;
using Microsoft.Office.Interop.Word;
using Microsoft.Office.Interop.Excel;
using Microsoft.Office.Interop.PowerPoint;
using System.Collections.Generic;

namespace test
{

    class Program
    {

        private static int GetProcessIdByWindowTitle(string AppId) 
        {
            Process[] P_CESSES = Process.GetProcesses();
            for (int p_count = 0; p_count < P_CESSES.Length; p_count++) 
            {
                if (P_CESSES[p_count].MainWindowTitle.IndexOf(AppId) != -1) 
                {
                    return P_CESSES[p_count].Id;
                }
            }
            return Int32.MaxValue;
        }

        static void Excel()
        {

            // create the MS-Excel Application
            Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();

            // Set the appID
            string appID = "zizozazezu";
            excelApp.Application.Caption = appID;
            excelApp.Application.Visible = true;

            // Excel needs a workbook to sete a caption visible...
            Microsoft.Office.Interop.Excel.Workbooks wbs = excelApp.Workbooks;
            Microsoft.Office.Interop.Excel.Workbook wb = wbs.Add();

            // find the 
            int processID = GetProcessIdByWindowTitle(appID);

            // verified this is the pid of MS-Excel
            Console.WriteLine(processID);

            // bailing out, no save
            object saveChanges = false;
            ((Microsoft.Office.Interop.Excel._Workbook)wb).Close(saveChanges);
            ((Microsoft.Office.Interop.Excel._Application)excelApp).Quit();

            System.Runtime.InteropServices.Marshal.ReleaseComObject(wb);
            wb = null;

            System.Runtime.InteropServices.Marshal.ReleaseComObject(wbs);
            wbs = null;

            System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp);
            excelApp = null;

            Console.WriteLine("Excel is done...");

            for (int i=0; i<100; i++)
            {
                // Patience....
                Thread.Sleep(100);

                // still running???
                bool isRunning = false;
                try 
                {
                    Process p = Process.GetProcessById(processID);
                    if (!p.HasExited)
                    {
                        isRunning = true;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("{0} Exception caught.", ex);
                }

                if (isRunning) 
                {
                    Console.Write(".");
                }
                else
                {
                    Console.WriteLine("Excel done at i=" + i.ToString());   
                    return;
                }
            }
            return;
        }

        static void Word()
        {
            // create the MS-Word Application 
            Microsoft.Office.Interop.Word.Application wordApp = new Microsoft.Office.Interop.Word.Application();

            // Set a caption - find the right instance
            string appID = "ladadidada";
            wordApp.Caption = appID;
            wordApp.Visible = true;

            // find the 
            int processID = GetProcessIdByWindowTitle(appID);

            // verified this is the pid of MS-Word
            Console.WriteLine(processID);

            // Stop MS-Word
            object saveChanges = false;
            ((Microsoft.Office.Interop.Word._Application)wordApp).Quit(ref saveChanges);

            for (int i=0; i<100; i++)
            {
                // Patience....
                Thread.Sleep(100);

                // still running???
                bool isRunning = false;
                try 
                {
                    Process p = Process.GetProcessById(processID);
                    if (!p.HasExited)
                    {
                        isRunning = true;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("{0} Exception caught.", ex);
                }

                if (isRunning) 
                {
                    Console.Write(".");
                }
                else
                {
                    Console.WriteLine("Word done at i=" + i.ToString());    
                    return;
                }
            }
            return;
        }

        static int Main(string[] args)
        {

            Word();
            Excel();

            return -1;
        }
    }
}

【问题讨论】:

  • 您是否尝试单步执行代码以查看发生了什么?
  • 是的,我做到了...进程不会终止/从进程列表中消失
  • 我注意到您的代码中有catch {}。这是一个很大的代码气味。您可能会在没有正确处理它们的情况下吞下异常。至少您应该将异常写入控制台。
  • Excel Introp 非常尴尬,如果你不清理使用 Dispose() 或 usings 引用的所有 COM 对象,那么当你告诉它时应用程序不会关闭
  • 做。不是。双倍的。点。您在 excelApp.Workbooks.Add(XlWBATemplate.xlWBATWorksheet) 泄露了工作簿参考。

标签: c# excel ms-word


【解决方案1】:

所以我突然想到了一些事情。

  1. 您不会在 Excel 应用程序本身上调用 quit。这是它关闭的信号。
  2. 您还需要确保在工作簿上调用 Close。
  3. 确保在完成所有对象后将其关闭并设置为 null
  4. 我还发现,对我使用过的所有对象不仅调用 Marshal.ReleaseComObject 还调用 Marshal.FinalReleaseComObject 很有帮助。
  5. 你是双点,这意味着你泄露了一堆引用。不好的做法,会鼓励 Excel 闲逛
  6. 最后,为了真正确定我杀死 Excel,在完成上述所有操作后,我通过窗口句柄杀死进程。

    public static bool TryKillProcessByMainWindowHwnd (int hWnd) {

    uint processID;
    
    GetWindowThreadProcessId((IntPtr)hWnd, out processID);
    
    if (processID == 0) return false;
    
    try
    {
        Process.GetProcessById((int)processID).Kill();
    }
    catch (ArgumentException)
    {
        return false;
    }
    catch (Win32Exception)
    {
        return false;
    }
    catch (NotSupportedException)
    {
        return false;
    }
    catch (InvalidOperationException)
    {
        return false;
    }
    
    return true;
    

    }

为了完成上述工作,您还需要确保包含 Win32 API。

[DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

【讨论】:

    猜你喜欢
    • 2021-05-09
    • 1970-01-01
    • 2019-09-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 2017-12-27
    相关资源
    最近更新 更多