获取 processId 有点复杂。试试这个...
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Excel = Microsoft.Office.Interop.Excel;
using Word = Microsoft.Office.Interop.Word;
/// <summary>
/// Gets an Interop.Application object and its associated processId
/// </summary>
/// <returns>Excel.Application or Word.Application depending on _isExcel</returns>
private object ApplicationFactory()
{
object application = null;
string processName = (_isExcel) ? "excel" : "winword";
Process[] beforeProcesses = null;
Process[] afterProcesses = null;
int i = 0;
while (i < 3)
{ // ourProcess = afterList - beforeList
beforeProcesses = Process.GetProcessesByName(processName);
application = (_isExcel) ? (object)new Excel.Application() : (object)new Word.Application();
afterProcesses = Process.GetProcessesByName(processName);
if ((afterProcesses.Length - beforeProcesses.Length) == 1)
{ // OK. Just a single new process
break;
}
else
{ // Two or more processes, we cannot get our processId
// therefore quit while we can and try again
if (_isExcel)
((Excel._Application)application).Quit();
else
((Word._Application)application).Quit();
int indexReferences = 1;
do
{
indexReferences = System.Runtime.InteropServices.Marshal.ReleaseComObject(application);
}
while (indexReferences > 0);
application = null;
System.Threading.Thread.Sleep(150);
i++;
}
}
if (application == null)
{
throw new ApplicationException("Unable to create Excel Application and get its processId");
}
List<int> processIdList = new List<int>(afterProcesses.Length);
foreach (Process procDesp in afterProcesses)
{
processIdList.Add(procDesp.Id);
}
foreach (Process proc in beforeProcesses)
{
processIdList.Remove(proc.Id);
}
_processId = processIdList[0];
return application;
}
/// <summary>
/// Kills _processId process if exists
/// </summary>
private void ProcessKill()
{
Process applicationProcess = null;
if (_processId != 0)
{
try
{
applicationProcess = Process.GetProcessById(_processId);
applicationProcess.Kill();
}
catch
{ // no Process with that processId
}
}
}
也就是说,暴力只是最后的资源 ;-) 你需要杀死,因为有一些 COM 对象没有释放。(请参阅
MS 支持:Office 应用程序未关闭)尝试始终引用您的 COM 对象,将它们放入堆栈并在使用后释放它们
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
然后,一个简单application.Quit();application = null
的技巧就可以了。
希望能帮助到你。
编辑: - 总是意味着:“每当你使用两点(_xlApp.Application., _xlWorkbook.Worksheets,...
)
我包括 mi helperStack
using System.Collections.Generic;
namespace OfficeUtils.Stack
{
/// <summary>
/// Stack of COM objects to be released
/// </summary>
public abstract class ComObjectsStack
{
private Stack<object> comObjects = new Stack<object>();
private int mark = 0;
/// <summary>
/// Releases all the remaining COM objects
/// </summary>
~ComObjectsStack()
{
if (comObjects.Count > 0)
ReleaseAll();
comObjects = null;
}
/// <summary>
/// Add a new object to the stack to be released
/// </summary>
/// <param name="obj">Nuevo objeto a liberar</param>
public void Push(object obj)
{
comObjects.Push(obj);
}
/// <summary>
/// Release the last object in the stack
/// </summary>
public void Pop()
{
Release(1);
}
/// <summary>
/// Mark for future use of ReleaseUpToMark
/// </summary>
public void Mark()
{
mark = comObjects.Count;
}
/// <summary>
/// Release up to mark
/// </summary>
/// <returns>Number of released objects</returns>
public int ReleaseUpToMark()
{
int numberObjects = comObjects.Count - mark;
if (numberObjects > 0)
{
Release(numberObjects);
return numberObjects;
}
else
{
return 0;
}
}
/// <summary>
/// Release all the objects in the stack
/// </summary>
public void ReleaseAll()
{
if (comObjects != null)
Release(comObjects.Count);
}
/// <summary>
/// Release the last numberObjects objects in stack
/// </summary>
/// <param name="numberObjects">Number of objects to release</param>
private void Release(int numberObjects)
{
for (int j = 0; j < numberObjects; j++)
{
object obj = comObjects.Pop();
int i = 1;
do
{
i = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
}
while (i > 0);
obj = null;
}
}
}
}