2014-01-22 1 views
7

Я видел много предложений по этой проблеме, и я пробовал их все, но ни один из них не работает. Код VBA находится в продукте, отличном от Microsoft (SAP Business Objects, что может быть проблемой). Я создать объект Excel:Автоматизация VBA Excel оставляет процесс в памяти после выхода

Set oExcel = CreateObject("Excel.Application")

загружать содержимое из колонны 1 одного из листов в конкретной книге, затем закройте Excel. Каждый раз он оставляет процесс в памяти, занимая 5 МБ памяти.

Я попытался сделать объект oExcel видимым, чтобы по крайней мере я мог его убить, не прибегая к диспетчеру задач, но когда я вызываю Quit, пользовательский интерфейс завершает работу и все еще покидает процесс.

Каждый раз, когда я запускаю код, он создает новый процесс. Так что я пытался повторно использовать существующие процессы Excel, вызвав

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

и создаёт его, если этот вызов не возвращает ничего,

Это не пролиферируют процессы, но единый процесс вырос на 5+ мб каждый раз, по сути, та же проблема.

В каждом случае я закрываю книгу, я открыл и поставил DisplayAlerts в Ложные перед выходом:

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 
+0

Я думаю, что диспетчер задач, как известно, ненадежен для такого рода вещей ... Я думаю, что здесь были другие вопросы по аналогичной теме, и консенсус в том, что ТМ неверна. Позвольте мне посмотреть, могу ли я это подтвердить. –

+2

Попытайтесь изменить 'm_oBook.Close SaveChanges: = False' на' m_oBook.Saved = True' –

+2

hmmmm Я играю с этим и 'Set m_oExcel = Nothing 'освобождает его из диспетчера задач * каждый раз *; даже если я не делаю 'm_oExcel.Quit'. На самом деле, даже если я не устанавливаю его в Nothing, диспетчер задач удаляет этот процесс после выполнения. –

ответ

0

Хотя это не должно произойти, вы можете отправить первенствует сообщение «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 
+0

Это тоже не сработало - процесс «EXCEL.EXE * 32» по-прежнему находится в списке процессов после того, как все завершено - в том числе приложение, на котором размещается VBA. Мне пришлось изменить «Public» на FindWindow на «Private», так как VBA жаловался на публичное объявление в модуле, и я изменил PROCESS_ALL_ACCESS на PROCESS_TERMINATE, потому что не смог найти определение для PROCESS_ALL_ACCESS. Поскольку все, что я делаю, заканчивается, я предполагаю, что это не изменит ситуацию. – user3224542

2

В большинстве случаев это происходит потому, что Excel держит COM Add-в открытой. Попробуйте использовать приведенную ниже ссылку для получения справки об удалении надстройки COM.

Add or remove add-ins

Я нахожу особое утешение в примечании:

Примечания Это удаляет надстройку из памяти, но сохраняет свое имя в списке доступных надстроек. Он не удаляет надстройку с вашего компьютера.

+0

Используйте 'oExcel.COMAddIns ([Index]). Connect = False', чтобы отключить любые надстройки COM, которые могут быть активны. Это решило эту проблему для меня. – 110SidedHexagon

1

Этот вопрос уже был дан ответ на Acantud в ответ на последующее сообщение: https://stackoverflow.com/questions/25147242 Полностью квалифицировать ваши ссылки на объекты в рабочей книге Excel, вы открываете, чтобы избежать создания осиротевших процессов в диспетчере задач. В этом случае решение является префиксом DelimitedList с m_oBook, такие, как

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

Необходимость использования только:

Private Sub Workbook_BeforeClose(Cancel As Boolean) 

    Excel.Application.Quit 

End Sub 
+0

К сожалению, это решение не работает. –

0

Добавление ответ, основанный на David Zemens комментарий. Работает на меня.

m_oExcel.Quit   '<- Still in Task Manager after this line 
Set m_oExcel = Nothing '<- Gone after this line 
Смежные вопросы