我有一个C#应用程序,可以将大量数据导出到Excel。我将Excel应用程序保持打开状态,以便用户可以决定他们想要用它做什么。但是,当Excel关闭时(直接从Excel中),仍然有一个Excel进程,必须手动终止。
我想解决方案是将数据保存在Excel中并使用Marshal从我的代码中关闭它,从而不会留下任何Excel应用程序,但我的用户希望在导出数据时向他们打开文件。
有没有人找到解决僵尸进程的方法?
答案 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..
}