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
トリックを行います。
それが役に立てば幸い。
編集: - 常に意味: 「2 つのポイントを使用するときはいつでも ( _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;
}
}
}
}