退出后,Excel的VBA自动化在内存中留下一个进程

时间:2014-01-22 18:31:37

标签: excel vba

我已经看到了很多关于这个问题的建议,我已经尝试了所有这些,但似乎都没有。 VBA代码位于非Microsoft产品(SAP Business Objects,这可能是问题)。我创建了一个Excel对象:

Set oExcel = CreateObject("Excel.Application")

从特定工作簿中的某个WorkSheets的第1列加载内容,然后关闭Excel。每次都会在内存中留下一个进程,占用5+ mb的内存。

我尝试使oExcel对象可见,这样至少我可以在不使用任务管理器的情况下杀死它,但是当我调用Quit时,UI退出,仍然离开了进程。

每次运行代码时,都会创建一个新进程。所以我尝试通过调用

重用任何现有的Excel进程

Set m_oExcel = GetObject(, "Excel.Application")

并且仅在该调用不返回任何内容时创建它,

这并未扩散流程,但单个流程每次增长5+ mb,因此问题基本相同。

在每种情况下,我都会关闭我打开的工作簿,并在退出前将DisplayAlerts设置为False:

m_oBook.Close SaveChanges:=False
m_oExcel.DisplayAlerts = False
m_oExcel.Quit

这段代码已经使用了至少五年,但是在我们迁移到Windows 7之前,这个问题并没有出现。

如果有帮助,这是完整的代码。请注意,所有Excel对象都是每个建议的模块级变量(“m_”前缀),并且我已根据另一个建议使用了“一点”规则。我也尝试使用通用对象(即后期绑定),但这也没有解决问题:

Private Function GetVariablesFromXLS(ByVal sFile As String) As Boolean
    On Error GoTo SubError

    If Dir(sFile) = "" Then
        MsgBox "File '" & sFile & "' does not exist.  " & _
               "The Agent and Account lists have not been updated."
    Else
        Set m_oExcel = CreateObject("Excel.Application")
        Set m_oBooks = m_oExcel.Workbooks
        Set m_oBook = m_oBooks.Open(sFile)

        ThisDocument.Variables("Agent(s)").Value = DelimitedList("Agents")
        ThisDocument.Variables("Account(s)").Value = DelimitedList("Accounts")
    End If

    GetVariablesFromXLS = True

SubExit:

    On Error GoTo ResumeNext
    m_oBook.Close SaveChanges:=False
    Set m_oBook = Nothing
    Set m_oBooks = Nothing

    m_oExcel.DisplayAlerts = False
    m_oExcel.Quit

    Set m_oExcel = Nothing

    Exit Function

SubError:
    MsgBox Err.Description
    GetVariablesFromXLS = False
    Resume SubExit

ResumeNext:
    MsgBox Err.Description
    GetVariablesFromXLS = False
    Resume Next

End Function

5 个答案:

答案 0 :(得分:2)

大多数情况下会发生这种情况,因为Excel会保持COM加载项打开。尝试使用以下链接获取有关删除COM加载项的帮助。

Add or remove add-ins

我在笔记中找到了特别的安慰:

  

注意这会从内存中删除加载项,但会将其名称保留在可用加载项列表中。它不会从您的计算机中删除加载项。

答案 1 :(得分:2)

根据David Zemens评论添加答案。适合我。

m_oExcel.Quit            '<- Still in Task Manager after this line
Set m_oExcel = Nothing   '<- Gone after this line

答案 2 :(得分:1)

Acantud在回复后续帖子时已经回答了这个问题: https://stackoverflow.com/questions/25147242 完全限定对打开的Excel工作簿中的对象的引用,以避免在任务管理器中创建孤立的进程。在这种情况下,解决方案是在DelimitedList前加m_oBook,例如

ThisDocument.Variables("Agent(s)").Value = m_oBook.DelimitedList("Agents")

答案 3 :(得分:0)

虽然这不应该发生,但你可以向excel发送一个“WindowClose”消息以强行关闭。

您将需要这些API函数

Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

看起来应该是这样的:

// First, get the handle
hWindow = FindWindow(vbNullString, "Excel")
//Get proccess ID
GetWindowThreadProcessId(hWindow, ProcessValueID)
//Kill the process
ProcessValue = OpenProcess(PROCESS_ALL_ACCESS, CLng(0), ProcessValueID)
TerminateProcess(ProcessValue, CLng(0))
CloseHandle ProcessValueID

答案 4 :(得分:-2)

仅需使用:

Private Sub Workbook_BeforeClose(Cancel As Boolean)

    Excel.Application.Quit

End Sub