如何从创建的"Excel.Application"对象中获取进程ID?

14 浏览
0 Comments

如何从创建的"Excel.Application"对象中获取进程ID?

如何从正在运行的对象中获取进程ID?

Dim xlApp As Object = CreateObject("Excel.Application")

我需要使用后期绑定,因为我无法保证我将得到哪个版本,所以使用Microsoft.Office.Interop.Excel不起作用。

'使用xlApp进行一些工作
xlApp.Quit
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)
xlApp = Nothing

此时,Excel仍在后台运行。我熟悉使用变量并释放它们然后使用System.Runtime.InteropServices.Marshal.ReleaseComObject(o)的所有建议。这种方法不可靠。我所做的工作非常复杂。我使用多个文件进行循环等操作。不可能释放Excel中的所有资源。我需要更好的选择。

我想在Excel上使用Process.Kill,但我不知道如何从xlApp对象中获取进程。我不想杀死所有Excel进程,因为用户可能打开了一个工作簿。

我尝试使用Dim xProc As Process = Process.Start(ExcelPath),然后使用xProc.Kill()。有时这样可以工作,除非在用户已经打开Excel窗口的情况下,使用XLApp = GetObject("Book1").ApplicationXLApp = GetObject("", "Excel.Application")来获取正确的Excel对象有点棘手。我需要更好的选择。

我无法使用GetActiveObjectBindToMoniker来获取Excel对象,因为它们仅在使用早期绑定时起作用。例如Microsoft.Office.Interop.Excel

如何从正在运行的对象中获取进程ID?

编辑:实际上,我对如何使Excel优雅退出并不感兴趣。其他问题已经解决了这个问题。 herehere我只想杀死它;干净,准确和直接。我想杀死我启动的确切进程,而不是其他进程。

0
0 Comments

问题的出现原因是想要从一个已创建的"Excel.Application"对象中获取进程ID,并且使用该进程ID来终止该进程。

解决方法是使用Windows API函数"GetWindowThreadProcessId"来获取指定窗口的进程ID,并将其传递给"KillProcess"函数来终止该进程。

以下是完整的

在编程过程中,有时候我们需要获取已创建的应用程序的进程ID,以便进行一些操作。在这个问题中,我们想要从一个已创建的"Excel.Application"对象中获取进程ID,并使用该进程ID来终止该进程。

为了实现这个目标,我们可以使用Windows API函数"GetWindowThreadProcessId"来获取指定窗口的进程ID。以下是具体的代码实现:

Public Declare Function GetWindowThreadProcessId Lib "user32" _
  (ByVal hwnd As Long, _
   ByRef lpdwProcessId As Long) As Long
Function KillProcess(hwnd As Long)
  Dim CurrentForegroundThreadID As Long
  Dim strComputer As String
  Dim objWMIService
  Dim colProcessList
  Dim objProcess
  Dim ProcIdXL As Long
  
  ProcIdXL = 0
  CurrentForegroundThreadID = GetWindowThreadProcessId(hwnd, ProcIdXL)
  
  strComputer = "."
  Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
  Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process Where ProcessID =" & ProcIdXL)
  
  For Each objProcess In colProcessList
    objProcess.Terminate
  Next
End Function
KillProcess (ExcelApplication.hwnd)

在上述代码中,我们首先声明了"GetWindowThreadProcessId"函数,它是一个Windows API函数,用于获取指定窗口的线程ID和进程ID。然后,我们定义了"KillProcess"函数,它接收一个窗口句柄作为参数,并使用"GetWindowThreadProcessId"函数来获取该窗口对应的进程ID。接下来,我们使用WMI(WIndows Management Instrumentation)来获取指定进程ID对应的进程对象,并调用"Terminate"方法来终止该进程。

最后,我们调用"KillProcess"函数,并传递"ExcelApplication.hwnd"作为参数来获取并终止"Excel.Application"对象的进程。

通过以上的代码,我们可以方便地从一个已创建的"Excel.Application"对象中获取进程ID,并使用该进程ID来终止该进程。这样,我们就能够在编程过程中更好地控制和管理应用程序的进程。

0
0 Comments

在创建"Excel.Application"对象后,如何获取进程ID的问题出现的原因是,使用Marshal.ReleaseComObject()或杀死Excel.exe进程是丑陋、容易出错和不必要的应急措施。而且从长远来看,这对性能有很大的负面影响,这个问题展示了可能发生的情况。正确的方法是调用GC.Collect(),但是调试程序时,这个方法往往不起作用,可以阅读这个答案以了解原因。

解决方法很简单,只需要确保在一个不同的方法中调用GC.Collect(),这样可以确保你的Excel对象引用不再在作用域内。因此,一个正确处理的程序的大致概述如下:

Sub Main()

DoOfficeStuff()

GC.Collect()

GC.WaitForPendingFinalizers()

'' Excel.exe现在会消失

'' 继续工作

''...

End Sub

Sub DoOfficeStuff()

Dim xlApp As Object = CreateObject("Excel.Application")

'' 其他操作...

End Sub

个人而言,除非EPPlus不能以某些特殊的仅限于Excel的方式操作电子表格,否则我不会费心使用Office Interop。

Passant: GC最终会垃圾回收Excel吗(尽管它会按照自己的方式进行)?在这种情况下,使用GC.Collect强制回收有什么用处吗?下面的说法正确吗:如果"调用COM对象的至少一个成员而没有将其分配给一个变量",Excel不会被释放。请参考stackoverflow.com/questions/158706/....

它肯定会回收。长期以来的问题是程序员实际上并不喜欢垃圾回收器的工作方式。他们会做一些不明智的事情,比如停止分配内存,却仍然期望GC来回收垃圾。

我理解你的观点,只是我自己关于如何终止Excel的答案并不容易出错;它的工作非常干净。所以我不认为它是丑陋、容易出错或不必要的应急措施。在我看来,它实际上是美丽的,精确的,并解决了Excel不退出的问题。

无论如何,这个答案甚至没有回答问题;它只是尝试提供另一种强制Excel退出的方法。我实际上提出的问题是:如何从创建的"Excel.Application"对象中获取进程ID?

对不起,但是指出程序员正在使用错误的解决方案来解决问题被认为是一个合理的回答。更重要的是,解决方案不仅仅适用于提问者,任何通过谷歌搜索这个问题的人可能更愿意不故意杀死一个进程。他们当然应该这样做。你能理解其中的道理吧?你可以投票反对一个答案,这样你会觉得好受一些。

这里有一个关于是否应该使用GC.Collect的问题。stackoverflow.com/questions/118633/...

0
0 Comments

如何从创建的“Excel.Application”对象中获取进程ID?

实际上,不用管了;我找到了解决方法。这是一个非常干净、精确定位的解决方案,可以终止启动的确切进程。它不会干扰用户可能打开的任何其他进程或文件。根据我的经验,在关闭文件和退出Excel之后终止进程是处理Excel最快、最简单的方法。这是一个描述问题和Microsoft推荐解决方案的知识库文章。

请注意,这个解决方案并不终止Excel应用程序。它只会在未正确释放指针的情况下终止空的进程外壳。当我们调用xlApp.quit()时,Excel本身确实会退出。这可以通过尝试附加运行中的Excel应用程序来确认,该操作将失败,因为根本没有运行Excel。

很多人不建议终止进程;请参阅

《如何正确清理Excel interop对象》

和《理解.NET垃圾回收》

另一方面,很多人不建议使用GC.Collect。请参阅《使用GC.Collect()有什么问题?》

一定要关闭任何打开的工作簿、退出应用程序、释放xlApp对象。最后检查进程是否仍然存活,如果是,则终止它。

Private Declare Auto Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As IntPtr, _
              ByRef lpdwProcessId As Integer) As Integer
Sub testKill()
    'start the application
    Dim xlApp As Object = CreateObject("Excel.Application")
    'do some work with Excel
    'close any open files
    'get the window handle
    Dim xlHWND As Integer = xlApp.hwnd
    'this will have the process ID after call to GetWindowThreadProcessId
    Dim ProcIdXL As Integer = 0
    'get the process ID
    GetWindowThreadProcessId(xlHWND, ProcIdXL)
    'get the process
    Dim xproc As Process = Process.GetProcessById(ProcIdXL)
    'Quit Excel
    xlApp.quit()
    'Release
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)
    'set to nothing
    xlApp = Nothing
    'kill it with glee
    If Not xproc.HasExited Then
        xproc.Kill()
    End If
End Sub

一旦我意识到我可以从Excel获取窗口句柄,然后我只需要从窗口句柄获取进程ID的函数。因此,GetWindowThreadProcessId如果有人知道一个vb.net的方法来获取它,我将不胜感激。

这完全是错误的解决问题的方式。请阅读这个答案以了解发生了什么。

非常有趣的一篇文章。它阐明了GC垃圾回收的原理。但很多人说,使用GC.Collect(); GC.WaitForPendingFinalizers();实际上是一个昂贵的操作。我不确定为什么在关闭文件和退出应用程序之后终止Excel进程比GC.Collect更糟糕。希望能得到一个答案。

感谢您对此的参与。我编辑了我的答案,包含了一些处理Excel的推荐方法的链接。

stackoverflow.com/questions/21310221/…

0