c# Excel进程持久化



我有一个c#应用程序,它将大量数据导出到Excel。我让Excel应用打开,这样用户可以决定他们想用它做什么。然而,当Excel关闭时(直接从Excel中关闭),仍然有一个Excel进程挂在周围,必须手动杀死。

我想一个解决方案是将数据保存在Excel中,并在我的代码中使用Marshal关闭它,从而留下没有Excel应用程序挂在周围,但我的用户希望在导出数据时向他们打开文件。

有没有人找到一种绕过僵尸进程的方法?

有一次我制作了下面的类。这是一段时间以前的事了,我最近没有使用它,所以如果它不起作用,不要绞死我。只要你觉得合适,你可以随意使用、改变、受到启发或忽略它。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Excel = Microsoft.Office.Interop.Excel;
namespace ExcelHandlingTest
{
  public class ExcelManager : IDisposable
  {
    Excel.Application m_excelApp = null;
    Process m_excelProcess = null;
    bool m_closeOnDispose = false;
    bool m_allowKillAll = false;
    public ExcelManager(bool useExistingInstance, bool closeOnDispose, bool visible, bool allowKillAll = false)
    {
      m_closeOnDispose = closeOnDispose;
      m_allowKillAll = allowKillAll;
      if (useExistingInstance)
      {
        try
        {
          m_excelApp = Marshal.GetActiveObject("Excel.Application") as Excel.Application;
        }
        catch (COMException ex)
        {
          m_excelApp = new Excel.Application();
        }
      }
      else
      {
        m_excelApp = new Excel.Application();
      }
      if (m_excelApp == null)
        throw new Exception("Excel may not be present on this machine");
      m_excelApp.Visible = visible;
      SetExcelProcess();
    }
    public Excel.Application Excel
    {
      get
      {
        return m_excelApp;
      }
    }
    [DllImport("User32.dll")]
    private static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint lpdwProcessId);
    private void SetExcelProcess()
    {
      uint processId = 0;
      GetWindowThreadProcessId((IntPtr)m_excelApp.Hwnd, out processId);
      m_excelProcess = Process.GetProcessById((int)processId);
    }
    private static List<int> GetExcelProcessIds()
    {
      return GetAllExcelProcesses().Select(p => p.Id).ToList();
    }
    public static void KillAllExcelProcesses()
    {
      foreach (Process p in GetAllExcelProcesses())
      {
        p.Kill();
      }
    }
    public static List<Process> GetAllExcelProcesses()
    {
      return (from p in Process.GetProcessesByName("Excel")
              where Path.GetFileName(p.MainModule.FileName).Equals("Excel.exe", StringComparison.InvariantCultureIgnoreCase) &&
              p.MainModule.FileVersionInfo.CompanyName.Equals("Microsoft Corporation", StringComparison.InvariantCultureIgnoreCase)
              select p).ToList();
    }
    public event ExitStatusEventHandler ExitStatus;
    private void OnExitStatus(string status)
    {
      if (ExitStatus != null)
        ExitStatus(this, status);
    }
    public void Dispose()
    {
      if (m_excelProcess != null)
        OnExitStatus(string.Format("Process ID: {0}", m_excelProcess.Id));
      if (m_closeOnDispose)
      {
        if (m_excelApp != null)
          m_excelApp.Quit();
        m_excelApp = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Thread.Sleep(50);
        if (m_excelProcess != null)
        {
          List<Process> excelProcs = GetAllExcelProcesses();
          foreach (Process ep in excelProcs)
          {
            if (ep.MainWindowHandle == m_excelProcess.MainWindowHandle)
            {
              ep.Kill();
              ep.WaitForExit();
              OnExitStatus("Exit by Kill");
              m_excelProcess = null;
              return;
            }
          }
        }
        if (m_allowKillAll)
        {
          List<Process> excelProcs = GetAllExcelProcesses();
          if (excelProcs != null && excelProcs.Count > 0)
          {
            KillAllExcelProcesses();
            OnExitStatus("Exit by Kill All");
            m_excelProcess = null;
            return;
          }
        }
        OnExitStatus("Exit by Quit");
        m_excelProcess = null;
      }
    }
  }
  public delegate void ExitStatusEventHandler(ExcelManager sender, string status);
}
用例:

  using (ExcelManager man = new ExcelManager(true, true, true))
  {
    var excel = man.Excel;
    // do stuff..
  }

最新更新