一度私は以下のクラスを作った。それはしばらく前です、私は最近それを使用していないので、動作しない場合は、私を掛けないでください。気軽に使用、変更、インスピレーション、または無視してください。
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..
}
あなたのプログラムを実行します。レポートをエクスポートした後、何もする必要がありますか?そうでない場合は、Excelをエクスポートし、正式にExcelを閉じてからファイルを起動してください(例:[Link](http://stackoverflow.com/a/1283593/1050927))ので、ユーザーがExcelを閉じるときに気をつけてください。ゾンビプロセスは残っていません。 – Prisoner
残念ながらExcelでよく知られている問題です。私は防弾ソリューションは見つかりませんでしたが、Excel APIから返されたすべてのオブジェクトを使用しなくなったときにnullに設定するのに役立つようです。多分、マーシャリングを通してすべてのExcelプロセスを閉じて、処理されたファイルを引数としてProcess.Start経由で1つのインスタンスを再度開くことができますが、ユーザーによって開かれた他のExcelインスタンスが予期せず閉じられる可能性があります。 –
Alex/Henrik - それは最善の方法のように見えます。データをエクスポートするときに、私は可視に設定されたExcelアプリケーションを作成しました。ユーザーがデータダンプを中断していたことがありました。だから、私はファイルを保存し、Excelのプロセスを終了し、Process.Startを使って再び起動させ、彼らは決して知りませんでした! – John