Как узнать, в каком модуле выполняется мой код?

В течение очень долгого времени, когда у меня есть обработчик ошибок, я заставляю его сообщать, в каком проекте, модуле и процедуре возникла ошибка. Я всегда добивался этого, просто сохраняя их имена через константы. Я знаю, что в классе вы получаете имя программно с помощью TypeName(Me), но, очевидно, это дает мне только одну из трех частей информации и только тогда, когда я не в «Стандартном» модуле.

У меня нет действительно большой проблемы с использованием констант, просто люди не всегда поддерживают их в актуальном состоянии или, что еще хуже, они копируют и вставляют, а затем вы сообщаете неправильное имя и т. д. Так что я хотел бы нужно найти способ избавиться от констант, показанных в примере, без потери информации.

Option Compare Binary
Option Explicit
Option Base 0
Option Private Module

Private Const m_strModuleName_c As String = "MyModule"

Private Sub Example()
    Const strProcedureName_c As String = "Example"
    On Error GoTo Err_Hnd
Exit_Proc:
    On Error Resume Next
    Exit Sub
Err_Hnd:
    ErrorHandler.FormattedErrorMessage strProcedureName_c, m_strModuleName_c, _
        Err.Description, Err.Source, Err.Number, Erl
    Resume Exit_Proc
End Sub

Кто-нибудь знает способы, чтобы код сказал, где он находится? Если вы можете убедительно показать, что это невозможно сделать, это тоже ответ :)

Редактировать:
Мне также известно, что имя проекта находится в Err.Source. Я надеялся, что смогу получить его без исключения для других целей. Если вы хорошо знаете, если нет, мы можем определить, что это выходит за рамки вопроса.
Я также знаю, как получить строку с ошибкой, но эта информация, конечно, лишь в некоторой степени полезна без знания Module.Procedure.


person Oorang    schedule 26.06.2009    source источник
comment
Все ответы в этой теме были хорошими и исследовали действительные методы, хотя ни один из них не привел меня туда, куда я пытался пойти. Я принял тот, который сделал, потому что он ближе всего подходил к тому, что я пытался сделать, и кто-то должен был получить баллы.   -  person Oorang    schedule 06.10.2009


Ответы (4)


Что касается имени проекта, единственный способ, который я могу придумать, — это преднамеренно выдать ошибку где-нибудь в Sub Main() и в коде обработки ошибок сохранить полученный Err.Source в глобальную переменную g_sProjectName. В противном случае, я, кажется, помню, что была бесплатная сторонняя DLL под названием TLBINF32.DLL, которая выполняла COM-отражение, но это кажется слишком большим для того, что вы хотите сделать, и в любом случае, вероятно, есть разница между общедоступным и частным классы. И, наконец, вы можете использовать двоичный редактор для поиска строки имени проекта в вашем EXE-файле, а затем попытаться прочитать строку с позиции. Хотя это расстраивает, что имена каждого проекта и модуля кода встроены в EXE, похоже, нет предсказуемого способа сделать это, поэтому это НЕ рекомендуется.

person Mark Bertenshaw    schedule 26.06.2009
comment
Хм, похоже, что этот поставляется с Visual Studio 6. Но он не поддерживается для Vista и Windows 7. Если возможно, я бы хотел решение, которое можно было бы использовать, не полагаясь на библиотеки DLL, не являющиеся частью стандартной установки. Тем не менее, хорошая информация. +1 - person Oorang; 27.06.2009

Здесь есть несколько вопросов.

Вы можете получить имя проекта, вызвав App.Name. Вы не можете получить имя метода, в котором вы находитесь. Я рекомендую использовать шаблоны автоматизированных процедур из MZ Tools, который автоматически вставит все нужные вам константы, и с вашей головной болью покончено.

Последняя часть, возможно, должна знать имя EXE (или библиотеки), которая вызвала вашу ActiveX DLL. Чтобы выяснить это, попробуйте следующее:

'API Declarations'
Private Declare Function GetModuleFileName Lib _
    "kernel32" Alias "GetModuleFileNameA" (ByVal _
    hModule As Long, ByVal lpFileName As String, _
    ByVal nSize As Long) As Long

Private Function WhosYourDaddy() As String
    Dim AppPath As String
    Const MAX_PATH = 260

    On Error Resume Next

    'allocate space for the string'
    AppPath = Space$(MAX_PATH)

    If GetModuleFileName(0, AppPath, Len(AppPath)) Then
        'Remove NULLs from the result'
        AppPath = Left$(AppPath, InStr(AppPath, vbNullChar) - 1)
        WhosYourDaddy = AppPath
    Else
        WhosYourDaddy = "Not Found"
    End If
End Function
person AngryHacker    schedule 26.06.2009
comment
Так случилось, что я использую инструменты MZ :) На самом деле не получает название модуля, но все же очень полезно. +1 - person Oorang; 27.06.2009
comment
+1. Кстати, подсветка синтаксиса работает лучше, если вы добавляете одинарную кавычку в конце каждой строки комментария. В противном случае он считает, что комментарий занимает несколько строк. - person MarkJ; 27.06.2009
comment
Я пробовал - вроде не работает. Не стесняйтесь редактировать мой ответ. Похоже, у вас есть право сейчас, когда у вас более 2000 повторений. - person AngryHacker; 28.06.2009
comment
Хорошо, я буду! Я думаю, вы просто пропустили один из комментариев. Я должен использовать эту силу только во благо! :) - person MarkJ; 28.06.2009

К сожалению, вам понадобятся отдельные операторы On Error GoTo X для отдельных модулей и процедур. Проект всегда хранится в Err.Source. Обработка ошибок VBA не так уж и хороша в этой области - в конце концов, насколько хорошо имя проекта как источник ошибки, в отличие от процедуры/модуля, не так ли?

Если вы вручную или программно нумеруете свои строки (например, в старой школе BASIC), вы можете использовать ERL для вывода номера строки, в которой произошла ошибка. Имейте в виду, однако, что ошибка, возникающая в строке без числа, заставит ERL выдать свою собственную ошибку, а не вернуть ноль. Дополнительную информацию можно найти в этом блоге. сообщение.

Если вы используете Access 2007 (не уверены в других приложениях/версиях Office), попробуйте этот фрагмент кода, извлеченный из справочной документации:

Sub PrintOpenModuleNames()
    Dim i As Integer
    Dim modOpenModules As Modules

    Set modOpenModules = Application.Modules

    For i = 0 To modOpenModules.Count - 1

        Debug.Print modOpenModules(i).Name

    Next
End Sub

И Microsoft включает эти замечания:

  • Все открытые модули включаются в коллекцию Modules независимо от того, не скомпилированы ли они, скомпилированы, находятся в режиме приостановки или содержат исполняемый код.
  • Чтобы определить, представляет ли отдельный объект Module стандартный модуль или модуль класса, проверьте свойство Type объекта Module.
  • Коллекция модулей принадлежит объекту приложения Microsoft Access.
  • Отдельные объекты Module в коллекции Modules индексируются, начиная с нуля.

До сих пор я не смог найти ничего о ссылке на текущий проект или процедуру. но это должно указать вам в правильном направлении.

person Andrew Scagnelli    schedule 26.06.2009
comment
Здравствуйте, я извиняюсь, я должен был быть более конкретным в том, что я спрашивал. Я отредактировал основной вопрос, чтобы попытаться немного сузить область. +1 за старание :) - person Oorang; 26.06.2009
comment
Добавленная информация должна помочь, даже если она дает детализацию только на основе модуля. - person Andrew Scagnelli; 26.06.2009
comment
На Access и VBIDE и тому подобное... Это хорошая мысль, но она не говорит вам, где вы находитесь в коде :) Также VBIDE поставляется с багажом AV. - person Oorang; 27.06.2009

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

Есть и другие очень приятные функции — поиск в файлах, который превосходит все, что я видел до ReSharper, дизайнер табуляции и многое другое.

У моего предыдущего работодателя мы использовали этот инструмент много лет, начиная с версии 2005 года. Как только вы привыкнете к нему, без него действительно трудно обойтись.

person Tom Bushell    schedule 02.07.2009