Собственно суть темы отражена в названии. Как при выполнении кода из VBA узнать перед обращением к книге открыта она или нет? Ведь если книга закрыта, то обращение к ней вызовет ошибку, а если открывать без проверки - то это может повлечь за собой утерю данных, если предварительно эта книга не была сохранена. Ни один ни второй вариант, естественно, не устраивают. Я покажу два способа проверки через функции. Если функция вернет True - книга открыта, если False - закрыта. Для проверки функций используем проверочную процедуру Check_Open_Book:
Sub Check_Open_Book() If IsBookOpen("Книга1.xls") Then MsgBox "Книга открыта", vbInformation, "Сообщение" Else MsgBox "Книга закрыта", vbInformation, "Сообщение" 'открываем книгу Workbooks.Open "C:\Книга1.xls" End If End Sub |
Данная процедура вызывает функцию IsBookOpen, передавая ей в качестве параметра имя книги, "открытость" которой мы хотим проверить. Я приведу несколько вариантов самой функции IsBookOpen. Во всех вариантах действует один и тот же принцип: код любого из вариантов функции IsBookOpen необходимо скопировать и вставить в стандартный модуль. Модуль должен быть внутри той книги, в кодах которой планируется проверять открыта ли книга. Только тогда IsBookOpen будет доступна для вызова из любого кода этой же книги.
Если вдруг в момент выполнения на строке
Function IsBookOpen(wbName As String) As Boolean Dim wbBook As Workbook For Each wbBook In Workbooks If wbBook.Name <> ThisWorkbook.Name Then If Windows(wbBook.Name).Visible Then If wbBook.Name = wbName Then IsBookOpen = True: Exit For End If End If Next wbBook End Function |
Функция просматривает все открытые книги и если находит среди них книгу с указанным именем, то функция возвращает True. Есть небольшая особенность - функция исключает скрытые книги(это либо надстройки, либо PERSONAL.XLS). Так же из просмотра исключена та книга, в которой расположен сам код. Если Вам нужно проверить наличие книги независимо от её видимости, то необходимо просто заменить блок
If Windows(wbBook.Name).Visible Then If wbBook.Name = wbName Then IsBookOpen = True: Exit For End If |
на одну строку(просто убрать лишнее условие проверки)
If wbBook.Name = wbName Then IsBookOpen = True: Exit For |
Либо можно использовать
Function IsBookOpen(wbName As String) As Boolean Dim wbBook As Workbook: On Error Resume Next Set wbBook = Workbooks(wbName) IsBookOpen = Not wbBook Is Nothing End Function |
Данный способ обращается к любой открытой книге, даже если она скрыта как PERSONAL.XLS или надстройка. Однако у данной функции есть недостаток - используется оператор On Error и если в настройках VBA(Tools -Options -вкладка General) установлено Break on All Errors - то этот код не сработает, если книга не открыта - получим ошибку. В то время как Вариант1 с циклом по всем открытым книгам сработает без ошибок.
По просьбам читателей решил добавить код, который проверяет открыта ли книга независимо от её месторасположения и используемого приложения Excel. Книга может быть открыта другим пользователем (если книга на сервере), в другом экземпляре Excel или в этом же экземпляре Excel.
Function IsBookOpen(wbFullName As String) As Boolean Dim iFF As Integer, retval As Boolean iFF = FreeFile On Error Resume Next Open wbFullName For Random Access Read Write Lock Read Write As #iFF retval = (Err.Number <> 0) Close #iFF IsBookOpen = retval End Function |
Функция несколько отличается от приведенных выше - передается в неё не только имя книги, а полный путь к книге, включая имя и расширение:
Sub Test() MsgBox "Файл 'Книга1'" & IIf(IsBookOpen("C:\Книга1.xls"), " уже открыт", " не занят") End Sub |
Или более близкий к жизненной ситуации вариант: надо открыть книгу, внести в книгу изменения, сохранить и закрыть. Если книга кем-то уже открыта - получим ошибку на этапе сохранения или запрос на этапе открытия. Поэтому сначала проверяем доступность книги и если она доступна - вносим изменения и сохраняем.
Sub Test() Dim sWBFullName As String Dim wb As Workbook 'полный путь к проверяемой книге sWBFullName = "C:\Documents\Книга1.xls" 'если книга кем-то открыта - пропускаем обработку этой книги 'книга закрыта - вносим изменения, сохраняем, закрываем If IsBookOpen(sWBFullName) = False Then Set wb = Application.Workbooks.Open(sWBFullName) 'изменяем значение ячейки "A1" на первом листе книги wb.Sheets(1).Range("A1").Value = "www.excel-vba.ru" ws.Close True End If End Sub |
При использовании функции
Также см.:
Как получить данные из закрытой книги?
Как узнать существует ли лист в книге?
Как узнать существует ли модуль в книге
У меня немного другая проблема, мой файл может быть открыт либо на чтение либо полный доступ, при этом вставлен макрос который закрывает файл автоматически по истечении заданного времени допустим по истечении 5 мин если никаких действий не производится. Вопрос, как должен быть написан код чтобы, если файл был открыт только на чтение происходило просто закрытие файла без сохранения, а если и на запись то сначала сохранял файл , а затем закрывал его.
прошу извинить, не уточнил. Код должен определить "каким способом (меня) книгу открыли" и выбрать вариант закрытия.
Алексей, имеет смысл сначала хоть что-то поискать среди свойств и методов книги :) Как правило много чего можно найти
здравствуйте
в варианте №3 ошибочка:
retval Ss Boolean
следует заменить на:
retval As Boolean
Вариант 3
строка Dim iFF As Integer, retval Ss Boolean
содержит маленькую ошибку "Ss" -> "As"
Вадим, спасибо. Исправил.