Ошибка VBA с модулями: «не могу найти модуль» - PullRequest
0 голосов
/ 03 августа 2009

Приведенная ниже процедура в Access 2003 выдает ошибку 7961 - Моя база данных «не может найти модуль». Но это только на некоторых модулях. Согласовано, на каких модулях происходит сбой.
В чем дело?

Private Sub DoReplace()
    Dim obj As AccessObject
    For Each obj In CurrentProject.AllModules
       Debug.Print ModuleType(obj.Name) & "  " & obj.Name
    Next obj
End Sub

Public Function ModuleType(ByVal ModuleName As String) As Variant
On Error GoTo errHandler
    Dim mdl As Module
    Set mdl = Modules(ModuleName)
    ModuleType = mdl.Type
    ModuleType = Switch(ModuleType = 0, "std     ", ModuleType = 1, "class   ")
    Set mdl = Nothing
errExit: Exit Function
errHandler:
        ModuleType = "Err " & Err.Number  '7961
        Resume errExit
End Function

Отладочный вывод:

Err 7961  vba_28_Part_Asterisk
class     cls_22_mas90_Item2
Err 7961  vba_44_Part_WhereUsed2
Err 7961  cls_22_JobOps_BOM_WhereUsed_method2
Err 7961  vba_26_Part_misc
std       vba_44_Part_MRP
std       vba_99_TurnOffSubDataSheets
Err 7961  vba_99_MasteringArraysByScott
Err 7961  vba_44_Part_WhereUsed
Err 7961  cls_22_JobOps_BOM_WhereUsed
Err 7961  cls_22_mas90_Item
class     cls_22_mas90_Order
class     cls_23_HOMER_Item
class     cls_44_mrp_record

Ответы [ 3 ]

5 голосов
/ 10 августа 2009

Я знаю, что вы выяснили проблему, но вы, похоже, не поняли, почему она работает таким образом, и не нашли лучший подход для решения вашей проблемы.

Во всех версиях Access есть несколько коллекций, которые вы используете постоянно:

  • TableDefs
  • QueryDefs
  • Forms
  • Отчеты

и другие, которые используются не так часто:

  • Макросы
  • Модули

Первые две коллекции доступны только как члены базы данных, поэтому вы можете использовать коллекцию TableDefs или QueryDefs только через что-то вроде этого:

  CurrentDB.TableDefs.Count

Это потому, что TableDefs и QueryDefs являются чисто объектами Jet, а не объектами Access.

Другие коллекции являются коллекциями объектов Access, и они включают только объекты OPEN, как вы можете увидеть, если вы сделаете это:

  ?Forms.Count

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

До Access 2000 вам приходилось использовать контейнер Documents, чтобы попасть в список сохраненных объектов Access, которые не были загружены. Это было довольно запутанно, и к различным типам объектов приходилось подходить по-разному. Для модулей вот код:

  Dim db As DAO.Database
  Dim cnt As Container
  Dim doc As Document

  Set db = CurrentDb
  Set cnt = db.Containers!Modules
  For Each doc In cnt.Documents
    Debug.Print doc.Name
  Next doc
  Set doc = Nothing
  Set cnt = Nothing
  Set db = Nothing

И вам также нужно было знать, что макросы хранятся в контейнере под названием «Сценарии». Довольно некрасиво.

В Access 2000 из-за изменения способа хранения проекта Access (как одно поле BLOB в одной записи в системной таблице вместо хранения в нескольких записях, по одной на объект), CurrentProject. Все **** коллекции были представлены. Это были:

  • CurrentProject.AllDataAccessPages
  • CurrentProject.AllForms
  • CurrentProject.AllMacros
  • CurrentProject.AllModules
  • CurrentProject.AllReports

Для ваших целей лучше всего выбрать коллекцию AllModules вместо коллекции Modules, потому что таким образом вам не нужно беспокоиться о том, открыты модули или нет. Конечно, подход Контейнеры / Документы работает, но AllModules требует значительно меньше кода.

EDIT:

Код для использования AllModules:

  Dim i As Integer

  For i = 0 To CurrentProject.AllModules.Count - 1
    Debug.Print CurrentProject.AllModules(i).name
  Next i

OR

  Dim obj As Object

  For Each obj In CurrentProject.AllModules
    Debug.Print obj.name
  Next obj
  Set obj = Nothing

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

Кроме того, имейте в виду, что коллекция модулей (то есть открытые модули) включает в себя модули формы, а также автономные и классовые модули, тогда как AllModules ограничен автономными и классовыми модулями.

0 голосов
/ 10 августа 2009

Решение состоит в том, чтобы передать AccessObject (вместо строки). Итак, из этого:

ModuleType(ByVal ModuleName As String) As Variant

... на это:

ModuleType(ByVal obj As AccessObject) As Variant

Пост Дэвида помог мне пересмотреть код, а также дал хорошие общие знания, и я соответственно голосую за его ответ. Однако моя ошибка была связана с объектами и функциями, а не с тем, как использовать все коллекции.

0 голосов
/ 04 августа 2009
Set mdl = Modules(obj.Name)

Для выполнения вышесказанного объект модуля должен быть загружен. Это проверяется с помощью

obj.IsLoaded

(obj - это AccessObject, mdl - это модуль - см. Выше.)

Моя проблема заключалась в том, что были загружены только некоторые модули. Загрузка модуля может быть выполнена путем открытия его в IDE VBA. Нет больше Ошибка 7961.

Я очень удивлен, насколько сложно было получить этот ответ. Я должен был забить на Google и применить некоторые свои собственные песчинки. Надеюсь, это поможет кому-то еще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...