Не закрывается excel vba

When Application.Quit is encountered in a subroutine,
it will only stay in memory and continue to run lines under it
and will actually quit until it encounters a «Exit Sub».
When the normal «End Sub» at the primary level is encountered,
it will then also close Excel. But say if the workbook is somehow
closed before reaching the «Exit Sub», «End» or «End Sub» line, then
Excel will not close.

Solution is to create a Public variable called ToQuitNow
with initial False value
and change it to True where you want Excel to quit.
and test right after to see if it is true, then return to previous Sub level
by «Exit Sub» or «End» to quit right away,
and do the same at every subrountine level where
it is expected to return from the deeper subroutine.
When it gets back to the primary level,
then a final «Exit Sub» will actually terminates Excel.
If you do not want Excel to ask for saving changes made,
add line «ThisWorkbook.Saved = True» right after Application.Quit,
or before the final «Exit Sub» at the Primary level
and Excel will quit without saving.

Try the following test below, just run «Test»

Public ToQuitNow As Boolean

Sub Test()

ToQuitNow = False ' initialize with False value
Call SecondSub
MsgBox ("Primary level here. Back from SecondSub")
If ToQuitNow = True Then
    Exit Sub 'will actually quit Excel now if True
End If
MsgBox ("This line will not run if ToQuitNow is True")
End Sub

Sub SecondSub()

MsgBox ("SecondSub here")
Call ThirdSub
MsgBox ("SecondSub here. Back from ThirdSub")
If ToQuitNow = True Then
    Exit Sub ' will return to Main level if True
End If
MsgBox ("This line from SecondSub will not run if ToQuitNow is True")
End Sub

Sub ThirdSub()

MsgBox ("ThirdSub here")
Call FourthSub
MsgBox ("ThirdSub here. Back from FourthSub")
If ToQuitNow = True Then
    Exit Sub ' will return to SecondSub if True
End If
MsgBox ("This line from ThirdSub will not run if ToQuitNow is True")
End Sub

Sub FourthSub()

MsgBox ("FourthSub here")
Application.Quit
ThisWorkbook.Saved = True ' Excel will think changes already saved _
and will quit without saving
ToQuitNow = True ' activate Quit
If ToQuitNow = True Then
    MsgBox ("Quit command executed in FourthSub")
    Exit Sub ' will return to ThirdSub if True
    'Can also put in End in above line to quit right away

End If
MsgBox ("This line from FourthSub will not run if ToQuitNow is True.")
End Sub

Эксель не закрывается с кодом Application.Quit

Sobirjon

Дата: Понедельник, 09.03.2020, 14:56 |
Сообщение № 1

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 151


Репутация:

2

±

Замечаний:
0% ±


2016

Доброго времени суток, уважаемые формучане!
Собственно проблема отражена в названии темы, файл примера прицепил.
Буду признателен за помощь

К сообщению приложен файл:

8801346.xlsb
(13.1 Kb)

 

Ответить

Roman777

Дата: Понедельник, 09.03.2020, 16:24 |
Сообщение № 2

Группа: Проверенные

Ранг: Ветеран

Сообщений: 980


Репутация:

127

±

Замечаний:
0% ±


Excel 2007, Excel 2013

Sobirjon, Добрый день! рекомендую Вам поставить бейкпойнт и проверить чему у вас равно кол-во книг в момент закрытия. У меня число книг всегда больше 1, поскольку есть книга личных макросов.
Ещё мне странным кажется, что код работает нормально при вашей записи, но я бы, всё-таки, сначала закрывал книгу и только потом бы закрывал приложение, а не наоборот.


Много чего не знаю!!!!

Сообщение отредактировал Roman777Понедельник, 09.03.2020, 16:25

 

Ответить

Sobirjon

Дата: Вторник, 10.03.2020, 04:09 |
Сообщение № 3

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 151


Репутация:

2

±

Замечаний:
0% ±


2016

чему у вас равно кол-во книг

Задача выйти полностью из эксель, если нет больше открытых книг.
Перед обращением естественно смотрел в отладчике по шагово.
Условие выполняется, макрос заходит, только по не понятным мне причинам эксель не выходит :help:

сначала закрывал книгу и только потом бы закрывал приложение

Этого не пробовал. Сейчас проверил, не помог

 

Ответить

K-SerJC

Дата: Вторник, 10.03.2020, 09:27 |
Сообщение № 4

Группа: Проверенные

Ранг: Обитатель

Сообщений: 487


Репутация:

86

±

Замечаний:
0% ±


Excel 2013

Доброго дня!
у меня работает так:


Благими намерениями выстелена дорога в АД.

 

Ответить

Sobirjon

Дата: Вторник, 10.03.2020, 14:21 |
Сообщение № 5

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 151


Репутация:

2

±

Замечаний:
0% ±


2016

K-SerJC
[vba][/vba]завершает макрос, но приложение остается по прежнему.

Протестировал вот так:
[vba]

Код

Private Sub Workbook_BeforeClose(Cancel As Boolean)
    With Application
        .DisplayFullScreen = False
        .DisplayFormulaBar = True
        .DisplayAlerts = False
    End With

    ‘    ActiveWorkbook.Close True
‘    Application.Quit
End Sub

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
    Application.DisplayAlerts = False
    Cancel = True
End Sub

Private Sub Workbook_Open()
    Application.DisplayFullScreen = True
End Sub

[/vba]
Приложение закрывается и книга не сохранятся (как и планировался) если больше открытых книг нет.
Если открыто еще книги, тогда на сообщению которые вылетает с запросом о сохранении книги нажать «сохранить», то запрос занового повторяется пока не нажать «не сохранить».
почему-то [vba]

Код

Application.DisplayAlerts = False

[/vba] игнорируется

Сообщение отредактировал SobirjonВторник, 10.03.2020, 14:22

 

Ответить

K-SerJC

Дата: Среда, 11.03.2020, 12:59 |
Сообщение № 6

Группа: Проверенные

Ранг: Обитатель

Сообщений: 487


Репутация:

86

±

Замечаний:
0% ±


Excel 2013

а так?

событие Workbook_BeforeClose запускается когда вы уже закрываете эту книгу
еще раз в нем вызывать закрытие книги не требуется
это будет выполнено по завершению этой процедуры.

переменная trt чтобы повторно событие не запустилось.


Благими намерениями выстелена дорога в АД.

Сообщение отредактировал K-SerJCСреда, 11.03.2020, 13:04

 

Ответить

Sobirjon

Дата: Четверг, 12.03.2020, 07:02 |
Сообщение № 7

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 151


Репутация:

2

±

Замечаний:
0% ±


2016


Огонь respect
Только не могу понять почему при
[vba]

Код

ThisWorkbook.Saved = True

[/vba]
Книга не сохраняется, в чем магия?

Сообщение отредактировал SobirjonЧетверг, 12.03.2020, 07:09

 

Ответить

Sobirjon

Дата: Четверг, 12.03.2020, 11:35 |
Сообщение № 8

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 151


Репутация:

2

±

Замечаний:
0% ±


2016

Книга не сохраняется, в чем магия?

Нашел в справке deal
Этот как раз то что было мне нужно hands Спасибо, еще раз

 

Ответить

Когда Application.Quit встречается в подпрограмме, он остается только в памяти и продолжает выполнять строки под ним и фактически завершает работу до тех пор, пока не встретит «Exit Sub». Когда встречается обычный «End Sub» на основном уровне, он также закрывает Excel. Но скажем, если рабочая книга каким-то образом закрывается до достижения строки «Exit Sub», «End» или «End Sub», Excel не закроется.

Решение состоит в том, чтобы создать общедоступную переменную с именем ToQuitNow с начальным значением False и изменить ее на True там, где вы хотите закрыть Excel. и проверьте сразу после этого, чтобы убедиться, что это правда, затем вернитесь на предыдущий подуровень с помощью «Exit Sub» или «End», чтобы выйти сразу, и сделайте то же самое на каждом уровне подпрограммы, где ожидается возврат из более глубокой подпрограммы. Когда он вернется на основной уровень, последний «Exit Sub» фактически закроет Excel. Если вы не хотите, чтобы Excel запрашивал сохранение внесенных изменений, добавьте строку «ThisWorkbook.Saved = True» сразу после Application.Quit или перед последним «Exit Sub» на начальном уровне, и Excel завершит работу без сохранения.

Попробуйте следующий тест ниже, просто запустите «Тест»

      Public ToQuitNow As Boolean

Sub Test()

ToQuitNow = False ' initialize with False value
Call SecondSub
MsgBox ("Primary level here. Back from SecondSub")
If ToQuitNow = True Then
    Exit Sub 'will actually quit Excel now if True
End If
MsgBox ("This line will not run if ToQuitNow is True")
End Sub

Sub SecondSub()

MsgBox ("SecondSub here")
Call ThirdSub
MsgBox ("SecondSub here. Back from ThirdSub")
If ToQuitNow = True Then
    Exit Sub ' will return to Main level if True
End If
MsgBox ("This line from SecondSub will not run if ToQuitNow is True")
End Sub

Sub ThirdSub()

MsgBox ("ThirdSub here")
Call FourthSub
MsgBox ("ThirdSub here. Back from FourthSub")
If ToQuitNow = True Then
    Exit Sub ' will return to SecondSub if True
End If
MsgBox ("This line from ThirdSub will not run if ToQuitNow is True")
End Sub

Sub FourthSub()

MsgBox ("FourthSub here")
Application.Quit
ThisWorkbook.Saved = True ' Excel will think changes already saved _
and will quit without saving
ToQuitNow = True ' activate Quit
If ToQuitNow = True Then
    MsgBox ("Quit command executed in FourthSub")
    Exit Sub ' will return to ThirdSub if True
    'Can also put in End in above line to quit right away

End If
MsgBox ("This line from FourthSub will not run if ToQuitNow is True.")
End Sub

Okay, this seems long winded… but here goes.

The problem you are seeing is because there can be more than one instance of the Excel Application on a machine at a given time.

When you are manually running the file, you are likely using the default behavior, which is that when you open a workbook directly it opens in your already loaded Excel Application.

This means that when you use:

Set xlApp = GetObject(, "excel.application")

It is actually returning the current Excel.Application.
However, when you load it via the scheduled task, it generates a new Excel.Application in order to handle your task. When it calls the code I quoted it ends up referencing the Excel.Application you already had open (probably).

Since your scheduled workbook is running in a different instance of Excel.Application, when you run xlApp.Quit it only quits that other Excel and not the one actually running the code.

If you want to also close your automated Excel, you will need to add Application.Quit to the end of your sub. Yes, I do mean use both xlApp.Quit AND Application.Quit.

Now technically, you could have more than one Excel Applications open when you load the new one. If you want to close all instances of Excel, the simplest way I know would be to kill all of them via a vbscript call to a program like this which terminates all processes named excel.exe. Note I did not test this on Win 7:

Dim objWMIService, objProcess, colProcess
Dim strComputer, strProcessKill, strFilePath
strComputer = "."
strProcessKill = "'excel.exe'" 

Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\" _
& strComputer & "rootcimv2")

Set colProcess = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = " & strProcessKill)
For Each objProcess In colProcess
        objProcess.Terminate
Next
WScript.Quit

Edit: I just wanted to add that you can replicate the behavior of the scheduled task manually by doing the following:

  1. Have Excel already open.
  2. Navigate through your start menu and open Excel.
  3. From the new instance of Excel, open your workbook.

OR

  1. Have Excel already open.
  2. Run the following Excel.exe [path of workbook in quotes]

Edit 2:
Due to your request, I’ve written this short vbscript file that will close all open Excel Applications without upsetting auto-recover. If you also want to avoid any, «Do you want to save …» alerts uncomment the commented section.

On Error Resume Next
Dim xlApp
Set xlApp = GetObject(, "Excel.Application")
Do While Err.Number <> 429
    'For each wb in xlApp.Workbooks
    '    wb.saved = true
    'next
    xlApp.Quit
    Set xlApp = Nothing
    Set xlApp = GetObject(, "Excel.Application")
Loop
Wscript.quit

To run it, just include the following at the end of your Excel VBA.

Shell "wscript.exe [path of .vbs file]"

 

Badamyan

Пользователь

Сообщений: 72
Регистрация: 21.07.2016

#1

21.07.2016 14:40:19

Код
Sub All_in_one()
    
For Each x In Application.GetOpenFilename(filefilter:="all excel files, *.xl*", Title:="select files to open", MultiSelect:=True)
Workbooks.Open x     
        For Each c In Sheets
            y = Workbooks("All.xlsm").Sheets.Count
               If c.Name <> "MS-Excel" Then
               c.Copy after:=Workbooks("All.xlsm").Sheets(y)
            End If            
        Next c
Workbooks.Close x
Next x

End Sub

Изменено: Badamyan21.07.2016 15:08:59

 

Badamyan,
И о чём говорит название темы? Нормальное название предложите.

И в чём, собственно, вопрос?

Изменено: РОБОТ_РОБИН21.07.2016 14:45:58

 

Badamyan

Пользователь

Сообщений: 72
Регистрация: 21.07.2016

простите я впервые в этом форуме
VBA, с помощью цикла открываю несколько файлов, но потом не могу их закрыть, что пишу не так
Workbooks.Close x  вот это строка не работает, как написать

 

Ts.Soft

Пользователь

Сообщений: 576
Регистрация: 13.04.2016

#4

21.07.2016 14:56:54

Попробуйте так:

Код
Workbooks(x).Close

Не стреляйте в тапера — он играет как может.

 

Юрий М

Модератор

Сообщений: 60585
Регистрация: 14.09.2012

Контакты см. в профиле

#5

21.07.2016 14:59:25

Цитата
Badamyan написал:
простите я впервые в этом форуме

Ну а нормальное название сформулировать это разве мешает? VBA — и что?
Название исправил, а в следующий раз сами думайте над формулировками.
Ещё момент: код следует оформлять соответствующим тегом. Ищите такую кнопку и исправьте своё сообщение.
И не нужно столько пустых строк.
Спасибо!

Прикрепленные файлы

  • Тег VBA.jpg (19.2 КБ)

 

Badamyan

Пользователь

Сообщений: 72
Регистрация: 21.07.2016

#6

21.07.2016 15:02:15

окей Юрий, спасибо
так тоже пробовал, не работает

Код
Workbooks(x).Close 

Изменено: Badamyan21.07.2016 15:04:53

 

Юрий М

Модератор

Сообщений: 60585
Регистрация: 14.09.2012

Контакты см. в профиле

#7

21.07.2016 15:08:00

Не исправили стартовое сообщение…
В общем случае можно так:

Код
ActiveWorkbook.Close
 

Badamyan

Пользователь

Сообщений: 72
Регистрация: 21.07.2016

Юрий так тоже не будет работать, активным считаеться тот файл в котором работает макрос, при таком коде он и будет закрываться

Изменено: Badamyan21.07.2016 15:12:25

 

Hugo

Пользователь

Сообщений: 23253
Регистрация: 22.12.2012

#9

21.07.2016 15:18:55

Цитата
Badamyan написал:
тот файл в котором работает макрос

это вообще может быть любой файл…
А сразу после открытия файл активен — вот тут его сразу можно… и закрыть :)
Вообще удобнее делать так:

Код
set wb=workbooks.open(x)

Тогда всегда с этим wb можно делать что угодно.

 

Ts.Soft

Пользователь

Сообщений: 576
Регистрация: 13.04.2016

#10

21.07.2016 15:19:28

Цитата
Badamyan написал:
активным считаеться тот файл в котором работает макрос

Нет, активным считается именно активный файл, а тот в котором работает макрос называется ThisWorkbook

Не стреляйте в тапера — он играет как может.

 

Юрий М

Модератор

Сообщений: 60585
Регистрация: 14.09.2012

Контакты см. в профиле

#11

21.07.2016 15:19:34

Цитата
Badamyan написал:
активным считаеться тот файл в котором работает макрос

Проверяли?

 

Badamyan

Пользователь

Сообщений: 72
Регистрация: 21.07.2016

Hugo,Огромное спасибо ) сработал  

 

Hugo

Пользователь

Сообщений: 23253
Регистрация: 22.12.2012

Тот в котором содержится макрос называется ThisWorkbook.
А работать он может в любой другой книге, ну смотря что понимать над «работать» — я понимаю как «делать работу».

 

Badamyan

Пользователь

Сообщений: 72
Регистрация: 21.07.2016

Юрий М,да, но не сработал, закрывает тот файл в котором макрос

 

Юрий М

Модератор

Сообщений: 60585
Регистрация: 14.09.2012

Контакты см. в профиле

У меня сработал.
И обратите внимание на #10 и #13 — там пишут то же самое: что является ActiveWorkbook

 

Ts.Soft

Пользователь

Сообщений: 576
Регистрация: 13.04.2016

#16

21.07.2016 15:34:21

Сейчас проверил код:

Код
Sub nnn()
    x = "Книга2.xlsx"
    Workbooks.Open x
    Workbooks(x).Close
End Sub

работает
а код

Код
Sub nnn1()
    For Each x In Application.GetOpenFilename(filefilter:="all excel files, *.xl*", Title:="select files to open", MultiSelect:=True)
        Workbooks.Open x
        Workbooks(x).Close
    Next x
End Sub

даёт ошибку Subscript out of range. Получается, что x не является объектом Workbook?

Не стреляйте в тапера — он играет как может.

 

The_Prist

Пользователь

Сообщений: 14182
Регистрация: 15.09.2012

Профессиональная разработка приложений для MS Office

#17

21.07.2016 15:35:38

Цитата
Ts.Soft написал:
Получается, что x не является объектом Workbook?

нет. Получается что в x содержится полный путь до книги, а не только её имя, как того требует коллекция Workbooks.

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

 

Ts.Soft

Пользователь

Сообщений: 576
Регистрация: 13.04.2016

The_Prist, спасибо. Учту на будущее.

Не стреляйте в тапера — он играет как может.

 

Badamyan

Пользователь

Сообщений: 72
Регистрация: 21.07.2016

Юрий М, получился и по вашему, наверника запустил макрос не с правильного файла
Всем огромное спасибо

 

Badamyan

Пользователь

Сообщений: 72
Регистрация: 21.07.2016

The_Prist,а как получить только имя ?
может с right ? взять символы до последнего

 

Ts.Soft

Пользователь

Сообщений: 576
Регистрация: 13.04.2016

#21

21.07.2016 15:51:24

Цитата
Badamyan написал:
как получить только имя ?

можно так

Код
Workbooks(Mid(x, InStrRev(x, "") + 1)).Close

Проверил — работает

Изменено: Ts.Soft21.07.2016 15:53:53

Не стреляйте в тапера — он играет как может.

 

Badamyan

Пользователь

Сообщений: 72
Регистрация: 21.07.2016

Ts.Soft,а что делает InStrRev ? находит в X ? ведь в нем несколько -ов
простите я новичок, может задам уж слишком примитивные вопросы, да еще и не Русский, прощу прощение за свой Русский

Изменено: Badamyan21.07.2016 15:55:16

 

Мотя

Пользователь

Сообщений: 3218
Регистрация: 25.12.2012

#23

21.07.2016 15:57:17

Код
Sub xxx()  ' всегда работает безотказно
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim Katal As Variant

Katal = GetFolderPath("Укажите каталог с файлами", ThisWorkbook.Path)

If Katal <> "" Then

Dim FS, KATALOG, FILE, MASSIV As Object
Set FS = CreateObject("Scripting.FileSystemObject")
Set KATALOG = FS.GetFolder(Katal)
Set MASSIV = KATALOG.Files

For Each FILE In MASSIV
    Workbooks.Open Filename:=FILE

'например, всяческие действия в основной книге

    Windows(Dir(FILE)).Activate
    ActiveWindow.Close
Next

    MsgBox "ГОТОВО"
Else
    MsgBox "Каталог не выбран"
End If
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
Function GetFolderPath(Optional ByVal Title As String = "Выберите папку", _
                       Optional ByVal InitialPath As String = "c:") As String
    Dim PS As String: PS = Application.PathSeparator
    With Application.FileDialog(msoFileDialogFolderPicker)
        If Not Right$(InitialPath, 1) = PS Then InitialPath = InitialPath & PS
        .ButtonName = "Выбрать": .Title = Title: .InitialFileName = InitialPath
        If .Show <> -1 Then Exit Function
        GetFolderPath = .SelectedItems(1)
        If Not Right$(GetFolderPath, 1) = PS Then GetFolderPath = GetFolderPath & PS
    End With
End Function

Изменено: Мотя21.07.2016 16:03:02

 

The_Prist

Пользователь

Сообщений: 14182
Регистрация: 15.09.2012

Профессиональная разработка приложений для MS Office

#24

21.07.2016 15:57:22

Цитата
Badamyan написал:
как получить только имя ?
Код
workbooks(Dir(x,16)).close 0

но лучше использовать метод Hugo — надежнее.

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

 

Ts.Soft

Пользователь

Сообщений: 576
Регистрация: 13.04.2016

Badamyan, InStrRev ищет заданный символ с конца строки, но возвращает порядковый номер от начала, т.е. в данном случае находит последний «», к его номеру добавляется единица и с этой позиции до конца выделяется подстрока

Не стреляйте в тапера — он играет как может.

 

Юрий М

Модератор

Сообщений: 60585
Регистрация: 14.09.2012

Контакты см. в профиле

#26

21.07.2016 17:57:31

Цитата
Badamyan написал:
как получить только имя ?

Вариант:

Код
        Next c
        n = Split(x, "")(UBound(Split(x, "")))
        Workbooks(n).Close
 

Hugo

Пользователь

Сообщений: 23253
Регистрация: 22.12.2012

#27

21.07.2016 19:26:56

Зачем всё усложнять?
Попробуйте:

Код
Sub All_in_one()
    Dim x, wb As Workbook, c As Worksheet

    Application.ScreenUpdating = False

    For Each x In Application.GetOpenFilename(filefilter:="all excel files, *.xl*", Title:="select files to open", MultiSelect:=True)
        Set wb = Workbooks.Open(x)
        For Each c In wb.Worksheets
            If c.Name <> "MS-Excel" Then
                With Workbooks("All.xlsm")
                    c.Copy after:=.Sheets(.Sheets.Count)
                End With
            End If
        Next c
        wb.Close 0
    Next x

    Application.ScreenUpdating = True

End Sub

Понравилась статья? Поделить с друзьями:
  • Не закрашивает столбец в excel
  • Не задается область печати в excel
  • Не движется лист в excel
  • Не загружаются файлы в word
  • Не движется курсор в excel это