在Windows服务中从C#杀死EXCEL.exe进程

thi*_*ag0 9 excel windows-services office-automation office-interop

我有一个Windows服务,通过Microsoft.Office.Interop.Excel.Application对象打开Excel电子表格.

Application xlApp = new Application();
Workbook workbook = xlApp.Workbooks.Open(fileName, 2, false);
...
...
workbook.Close();
xlApp.Quit();
Run Code Online (Sandbox Code Playgroud)

我想杀死完成工作簿使用后剩余的EXCEL.exe进程.

我试过以下但没有成功......

// This returns a processId of 0
IntPtr processId;
GetWindowThreadProcessId(new IntPtr(xlApp.Hwnd), out processId);
Process p = Process.GetProcessById(processId.ToInt32());   
p.Kill();
Run Code Online (Sandbox Code Playgroud)

任何人都有任何关于如何通过Windows服务这样做的想法?

dot*_*kow 10

正确关闭打开的Excel工作簿并退出应用程序非常困难.如果我能找到我发布的链接,但基本上你必须清理对你创建的任何COM对象的所有引用.这包括ODBCConnections(数据连接),工作表,工作簿和Excel应用程序中的所有内容.我开始工作的组合涉及垃圾收集和System.Runtime.InteropServices.Marshal对象:

// Garbage collecting
GC.Collect();
GC.WaitForPendingFinalizers();
// Clean up references to all COM objects
// As per above, you're just using a Workbook and Excel Application instance, so release them:
workbook.Close(false, Missing.Value, Missing.Value);
xlApp.Quit();
Marshal.FinalReleaseComObject(workbook);
Marshal.FinalReleaseComObject(xlApp);
Run Code Online (Sandbox Code Playgroud)

就像你提到的那样,循环并杀死每个Excel进程通常不是一个好主意,因为如果你将它作为Windows应用程序运行,你可以关闭用户的Excel,或者在服务中关闭正在运行的Excel实例通过其他一些程序.

编辑:有关详细信息,请参阅此问题.


小智 7

您需要检查文件句柄并获取由进程打开然后将其终止的PID.它对我有用.

private void genExcel(
{
   int pid = -1;
   //Get PID
   xlApp = new Excel.Application();
   HandleRef hwnd = new HandleRef(xlApp, (IntPtr)xlApp.Hwnd);
   GetWindowThreadProcessId(hwnd, out pid);
   .
   .
   .
   .
   //Finally
   KillProcess(pid,"EXCEL");
}

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowThreadProcessId(HandleRef handle, out int processId);

private void KillProcess(int pid, string processName)
{
    // to kill current process of excel
    System.Diagnostics.Process[] AllProcesses = System.Diagnostics.Process.GetProcessesByName(processName);
    foreach (System.Diagnostics.Process process in AllProcesses)
    {
       if (process.Id == pid)
       {
         process.Kill();
       }
    }
    AllProcesses = null;
}
Run Code Online (Sandbox Code Playgroud)


thi*_*ag0 6

经过多次阅读和挫折,我找到了解决方案!

所有功劳都归功于dotNetkow,nightcoderMike Rosenblum在这篇文章中的解决方案:如何正确清理Excel互操作对象?

这是我做的...
1.将项目的构建模式更改为"Release"(在DEBUG模式下,COM对象很难处理它们的引用
.2.删除所有双点表达式(所有COM对象都应该绑定)到一个变量,以便它们可以被释放)
3.在finally块中显式调用GC.Collect(),GC.WaitForPendingFinalizers()和Marshal.FinalReleaseComObject()

这是我正在使用的实际代码:

Application xlApp = null;
Workbooks workbooks = null;
Workbook workbook = null;
Worksheet sheet = null;
Range r = null;
object obj = null;

try
{
    xlApp = new Application();
    xlApp.DisplayAlerts = false;
    xlApp.AskToUpdateLinks = false;
    workbooks = xlApp.Workbooks;
    workbook = workbooks.Open(fileName, 2, false);
    sheet = workbook.Worksheets[1];

    r = sheet.get_Range("F19");
    obj = r.get_Value(XlRangeValueDataType.xlRangeValueDefault);
}
finally
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
    if (value != null) Marshal.FinalReleaseComObject(value);
    if (r != null) Marshal.FinalReleaseComObject(r);
    if (sheet != null) Marshal.FinalReleaseComObject(sheet);
    if (workbooks != null) Marshal.FinalReleaseComObject(workbooks);
    if (workbook != null)
    {
        workbook.Close(Type.Missing, Type.Missing, Type.Missing);
        Marshal.FinalReleaseComObject(workbook);
    }
    if (xlApp != null)
    {
        xlApp.Quit();
        Marshal.FinalReleaseComObject(xlApp);
    }
}
Run Code Online (Sandbox Code Playgroud)