Новости:

Интересные и полезные статьи по работе с Excel и VBA
можно найти в разделе ХИТРОСТИ

Главное меню

Передать ошибку VBA внешнему приложению при обработке ошибок

Автор McConst, 01.02.2024, 09:22:41

« назад - далее »

McConst

Добрый день.
У меня код на VB6 открывает книгу Excel и вызывает в ней серию макросов

Public Sub RecalculateDB()
'Пересчёт цен в базе данных
Dim excel As Object
Dim wb As Object 'Книга Excel

On Error GoTo Recalc_exit
Set excel = CreateObject("Excel.Application")
excel.Visible = True
Set wb = excel.Workbooks.Open(filename:=ExcelDBApp, ReadOnly:=True)
excel.run (wb.name & "!RecalculatePrice") 'Пересчёт локальной базы данных
excel.run (wb.name & "!CreateReserveDB") 'Создание резервной копии пересчитанных данных
excel.run (wb.name & "!UploadCalcFile") 'Переносим файл калькуляции на интернет-сервер

'Сразу после пересчета закидываем обновленнные данные по базе в интернет. True - отправить уведомление в телеграм,
'False - не отображать MsgBox об успешности операции обновления данных в интернете
excel.run wb.name & "!CreateSafetySQLScript", True, False

wb.Close
excel.quit
Exit Sub
Recalc_exit:
'Ошибка пересчёта базы данных
    If Len(AdminTelegramID) > 0 Then
        SendTelegramMessage "Ошибка при пересчёте и обновлении базы данных \n \n" & Err.Description, _
            AdminTelegramID
    End If
End Sub


Иногда на стороне макросов появляются ошибки, связанные с работой сети. Если обработать ошибку в процедуре VBA, то внешнее приложение её не замечает. Если не обрабатывать, то код зависает вместе с выводом Alerta: Debug / End и ждёт действий пользователя. При этом код висит.
Как корректно обработать ошибку в процедуре VBA и вернуть её внешнему приложению, чтобы внешнее приложение приняло сообщение об ошибке и корректно закрыло книгу?

Дмитрий Щербаков(The_Prist)

Здесь вариантов не много - в любом случае надо хранить информацию и имени процедуры и номере(типе) ошибки где-то "извне": либо в отдельном текстовом файле, либо в реестре.
Перед запуском из внешней процедуры очищать эти данные, чтобы не было ошибочных записей.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...

McConst

#2
Цитата: Дмитрий Щербаков(The_Prist) от 01.02.2024, 14:17:53
Здесь вариантов не много - в любом случае надо хранить информацию и имени процедуры и номере(типе) ошибки где-то "извне": либо в отдельном текстовом файле, либо в реестре.
Перед запуском из внешней процедуры очищать эти данные, чтобы не было ошибочных записей.

А если как-нибудь так?
Вызываю код в приложении VB6
Set app_err = excel.run(wb.name & "!test")

Вызываемая функция, возвращающая объект ошибки

Public Function Test() As ErrObject
Dim a
Set Test = Err 'по умолчанию код ошибки 0
On Error GoTo Ext
a = 6 / 0
Exit Function
Ext:
   Set Test = Err
End Function


Можно ли вообще получить  от ActiveX функции ответ? Потестил. VBA ошибку генерирует, ответ в функции в виде объекта ошибки отправляет, а VB6 получает пустой объект с ошибкой ноль

Или есть возможность достучаться до глобальной переменной книги Excel?

McConst

Попробовал такой вариант.
Код во внешнем приложении VB6

Public Sub Test()
'Тестирование получения ошибки от приложения
Dim excel As Object
Dim wb As Object 'Книга Excel
Dim app_err As ErrObject

On Error GoTo Recalc_exit
Set excel = CreateObject("Excel.Application")
excel.Visible = True
Set wb = excel.Workbooks.Open(filename:=ExcelDBApp, ReadOnly:=True)
excel.displayAlerts = False


Call excel.run(wb.name & "!test", app_err)  'Проверка получения кода ошибки по ссылке на объект ошибки
wb.Close savechanges:=False
excel.quit
Exit Sub

Recalc_exit:
wb.Close
excel.quit

'Уведомление об ошибке в телегу
   If Len(AdminTelegramID) > 0 Then
       SendTelegramMessage "Ошибка при пересчёте и обновлении базы данных \n \n" & Err.Description, _
           AdminTelegramID
   End If

End Sub


Код вызываемой процедуры на VBA

Public Sub Test(Optional ByRef err_obj As ErrObject)
Dim a

Set err_obj = Err
On Error GoTo Ext
a = 6 / 0
Exit Sub
Ext:
'Аварийный выход по ошибке

End Sub



Возвращается объект с ошибкой 0.
Возможно ексель её сбрасывае в ноль? Попробовать с полным копированием объекта вернуть?

McConst

Ещё одну странность обнаружил.
Пробовал внутри одного и того же модуля передавать по ссылке переменную, проверить как можно возвращать ошибку
Вот таким кодом


Public Sub Test(ByRef err_obj As String)
Dim a

err_obj = "0"
On Error GoTo Ext
a = 6 / 0
Exit Sub
Ext:
'Аварийный выход по ошибке
   
    err_obj = err.Description

End Sub

Public Sub testStart()
Dim e As String

e = "1"
Test (e)
End Sub


Запускаю testStart
Проверяю как изменится значение переменной е внутри testStart, которая ушла по ссылке в процедуру test. Никак. Осталось точно такое же значение - 1, как и до вызова процедуры.
Почему???

Дмитрий Щербаков(The_Prist)

#5
Цитата: McConst от 01.02.2024, 15:47:38Почему???
Скобки уберите - таким образом Вы передаете не совсем так, как ожидаете. Либо добавьте явный вызов:
либо
Public Sub testStart()  
Dim e As String  
 
e = "1"  
Test e
End Sub

либо
Public Sub testStart()  
Dim e As String  
 
e = "1"  
Call Test(e)
End Sub

если кратко:
Вот эта строка: Test (e)
равносильна вот этой: Test CVar(e)
Т.е. (e) или CVar(e) в данном случае создают вспомогательную(runtime) переменную с типом Variant, которая и передается в функцию Test.

Все остальное комментировать желания нет - VBA(Excel) и VB разные приложения, никак между собой не связанные. Следовательно передавать объект ошибки напрямую нельзя. Можно поиграться с функциями API, конечно - но лично я считаю, что оно того не стоит. Сначала надо будет загнать в память нужный объект, затем его считать. И тут очень важно не "налажать" с типами объектов.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...

Яндекс.Метрика Рейтинг@Mail.ru