C#Excel过程持久化

时间:2016-10-28 06:14:59

标签: c# excel

我有一个C#应用程序,可以将大量数据导出到Excel。我将Excel应用程序保持打开状态,以便用户可以决定他们想要用它做什么。但是,当Excel关闭时(直接从Excel中),仍然有一个Excel进程,必须手动终止。

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

有没有人找到解决僵尸进程的方法?

1 个答案:

答案 0 :(得分:1)

我下面的课程。不久之前,我最近没有使用它,所以如果它不起作用,不要挂我。随意使用,改变,启发或忽视它。

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..
  }