Microsoft Access: Приложения и утилиты

Автор Allen Browne, февраль 2009 г.  Последнее обновление: апрель 2010 г.

Оригинал http://allenbrowne.com/AppLogDocUse.html

Перевел с английского Александр Артамонов


Лог использования форм и отчетов

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

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

Чтобы использовать лог в своей базе данных:

  1. Скачайте образец базы данных (В сжатом виде 21 Кб для Аксесс 2000 и более поздних версий.)
  2. Откройте вашу базу данных и импортируйте таблицу (tblLogDoc) и модуль (ajbLogDoc.)
    В Аксессе 2007 или 2010, нажмите иконку Access на группе Импорт ленты Внешние данные.
    В более ранних версиях выберите Внешние данные из меню Файл.
  3. Установите свойства Открытие и Закрытие каждой формы или отчета в вашей базе данных таким образом:
    Свойство Для формы Для отчета
    Открытие =LogDocOpen([Form]) =LogDocOpen([Report])
    Закрытие =LogDocClose([Form]) =LogDocClose([Report])
    (Примечание: на заменяйте на имена вашей формы/отчета; пишите для форм и отчетов буквально, как показано.)

Если эти свойства уже установлены на [Обработка событий], нажмите кнопку построителя (...) возле свойства. Аксесс откроет окно кода. Вставьте код в процедуру обработки события таким образом:
    Call LogDocOpen(Me)
и для события Закрытие:
    Call LogDocClose(Me)

Чтобы временно отключить логирование для всех форм/отчетов в базе данных, измените True на False в этой строке (ближе к верху модуля):
    Private Const mbLogDox As Boolean = False

Можно посмотреть код для этой утилиты в отдельном окне.

Что находится в логе?

Поля в таблице лога:

Поле Данные Комментарий
LogDocID Autonumber Первичный ключ
OpenDateTime Когда документ был открыт Пусто, если событие Close не может найти соответствующее событие Open
CloseDateTime Когда документ был закрыт Пусто, если не отмечен, как закрытый (например, при аварийном завершении)
DocTypeID 2 = форма, 3 = отчет (константы acForm и acReport) Формы/отчеты могут иметь одинаковое имя
DocName Название формы/отчета  
DocHWnd Идентификатор окна Windows, содержащего форму/отчет операционной системы. Чтобы отличить друг от друга экземпляры одной формы
ComputerName Рабочая станция, в которая открыла/закрыла документ Помогает идентифицировать сбойный компьютер, вызвавший аварийное завершение
WinUser Текущий пользователь в Windows Помогает идентифицировать пользователя, не закрывшего документ должным образом
JetUser Пользователь, определенный движком JET Будет 'Admin', если только не включена !безопасность! JET
CurView Текущий вид (У отчетов есть "режим отчета" в Аксессе 2007 и более поздних.) Полезно для отчетов в новых версиях

Обрабатываются ли все случаи?

Каждый раз, когда вы открываете форму/отчет, вызывается LogDocOpen() чтобы записать событие. Когда закрываете документ снова, LogdocClose() находит соответствующую запись и записывает время закрытия.

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

Случай Комментарий
1. Форма и отчет могут иметь одинаковое имя. Поле DocTypeID покажет разницу.
2. Можно открыть несколько экземпляров одной формы (используя ключевое слово New.) Идентификатор окна hWnd определяет уникальным образом каждый экземпляр.
3. Можно открыть несколько экземпляров базы данных на одном компьютере. Идентификатор hWnd уникален в любой момент времени, даже при разных экземпляров запущенного Аксесса.
4. Вы можете войти в базу данных с нескольких компьютеров. ComputerName покажет разницу.
5. Пользователи на разных компьютерах могут (теоретически) получить одинаковый hWnd ComputerName + WinUser + hWnd будет уникально в любой момент времени.
6. Используется OpenForm, когда форма уже открыта. Нет проблемы: Событие Open не срабатывает повторно.
7. Событие отчета NoData может быть отменено. Нет проблемы: Аксесс запускает событие Close.
8. Событие Open event может быть отменено программно. Сделайте запись в лог последним действием в событии Log as the last thing in the Open event, only if Cancel has not been set.
9. Системная дата на компьютере меняется между событиями открытия и закрытия формы. При закрытии есть вероятность неправильной записи в лог.

Случай 8 важен. Если событие Open формы или отчета отменено в коде или макросом, форма/отчет не откроются и событие Close не сработает. Поэтому вы должны вызывать команду записи лога, только если событие Open не отменено. Вот таким образом:

Private Sub Form_Open(Cancel As Integer)
'Проведите тесты и отмените Open при необходимости.
If MsgBox("Really open?", vbOKCancel) = vbCancel Then
Cancel = True
End If
'Тогда закончите процедуру так:
If Not Cancel Then
Call LogDocOpen(Me)
End If
End Sub

Вы не можете избежать ситуации, описанной выше, используя событие формы Load вместо Open. Есть случаи, когда Аксесс запускает событие Load, даже когда событие Open отменено, т.е. если вы включаете такую строку в Form_Open:
    RunCommand acCmdRecordsGoToNew

Случай 9 также может быть проблемой. Код записи в лог предполагает ,что вы закроете форму после того, как открыли ее. Такое предположение может быть не выполнено, если системная дата изменилась (вами или скриптом синхронизации) после открытия формы. Если дата была передвинута вперед после открытия формы, код не найдет правильной записи для обновления. В этом случае будет создана новая запись, у которой OpenDateTime будет null. И наоборот, если вы открыли эту форму вчера и было аварийное завершение без закрытия формы, у вас будет запись, датированная вчерашним днем, где CloseDateTime содержит null. Теперь, если системная дата была установлена назад на вчерашний день, и вы случайно получили такой же идентификатор hWnd, как для этой формы вчера, логирующая процедура обновит неправильную запись.

Случае, иные, чем описаны выше, не должны вызывать проблем. Переключение в или с режима конструктора записывается в лог корректно. Закрытие формы в режиме "Фильтр-по-форме" все равно запускает Form_Close. Некоторые события не действуют для отчетов в Аксессе 2007 и более поздних (события разделов в новых режимах Отчет или Макет), но события отчетов Open и Close все еще срабатывают. Если вы знаете о неучтенном случае, свяжитесь с нами.

Интерпретация лога

Лог может обеспечить информацию для диагностирования проблем:

Проблема Что проверять
Не было создано записи для формы/отчета Установлены ли свойства Открытие и Закрытие?
Убедитесь, что обработчик ошибок выдает сообщения, или закомментируйте обработчик в начале каждой процедуры с помощью одиночной кавычки в строке:
    'On Error GoTo Err_Handler
OpenDateTime пусто в нескольких записях лога. Смотрите комментарий выше по поводу Случая 9.
CloseDateTime пусто в нескольких записях лога. Компьютер мог быть выключен аварийно без корректного завершения Аксесса. Изучите поля ComputerName и WinUser, чтобы определить, проблема ли это железа (сбой сети, перегрев компьютера и т.д.) или проблема, вызванная пользователем (закрытие Аксесса с помощью Ctrl+Alt+Del или выключение без корректного выхода из системы.)
CurView пусто в нескольких записях лога. Версии, более старые, чем 2007 не обеспечивают "режим отчета" для отчетов.
JetUser всегда 'Admin' Это нормально для баз данных, не обеспеченных защитой с помощью рабочих групп, у которых не требуется имя пользователя/пароль для открытия базы данных.

Расширение программы

Вы вероятно захотите создать отчеты для показа записей, у которых пустые OpenDateTime или CloseDateTime.

После проверки того, что это все работает, вам, вероятно, захочется подавить все сообщения об ошибках записи в лог, чтобы для пользователя запись в лог проходила незаметно. Удалите одиночный апостроф в строках с If и End If в функции LogError(). Еще лучше, замените ее настоящей процедурой логирования ошибок

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


Примечание переводчика. Обсуждение решения автора по логированию использования форм и отчетов можно посмотреть на форуме сайта www.sql.ru начиная с этого поста http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&msg=11586642

Конструктор сайтов - uCoz