Czasami projekt bazy danych wymaga, (z takich, czy innych względów), by użytkownik nie mógł otworzyć drugiej instancji bieżącej bazy danych. Sposobów zabezpieczenia się (a raczej pseudozabezpieczenia) przed otwarciem drugiej instancji bieżącej bazy jest kilka, jeśli nie kilkanaście. Generalnie wszystkie metody będą działały w oparciu o opcje startowe MS Access:
- • Akcja makro Autoexec
- Makro jest uruchamiane automatycznie podczas startu MS Access. Za pomocą funkcji uruchamianej przez to makro dokonujemy "pseudozabezpieczeń". Możemy również otworzyć jakiś formularz (może być ukryty), który będzie ... patrz punkt niżej:
- Właściwość: StartupForm
- Podczas startu MS Access automatycznie otwierany jest formularz startowy: StartupForm = „Nazwa formularza startowego” w którym np. w zdarzeniu OnLoad uruchamiamy funkcję, która tworzy "pseudozabezpieczenie"
Obie te opcje startowe można pominąć, otwierając bazę danych trzymając wciśnięty klawisz „Shift”. Ale z pomocą przychodzi
właściwość AllowBypassKey, za pomocą której możemy uniemożliwić używanie
klawisza SHIFT dla opcji startowych.
Tak przy okazji, w celu dodatkowego zabezpieczeni możemy skorzystać z właściwości AllowSpecialKeys
za pomocą której możemy uniemożliwić korzystanie użytkownikowi ze specjalnych klawiszy programu MS Access
Sekwencja klawiszy | Skutek |
---|---|
F11 | Wyświetlenie okna bazy danych na wierzchu |
CTRL+G | Wyświetlenie okna analizy programu |
ALT+F11 | Wyświetlenie okna edytora VBA | CTRL+F11 | Przełączanie pomiędzy niestandardowym paskiem menu i wbudowanym paskiem menu |
CTRL+BREAK | Wprowadzenie trybu przerwania i wyświetlenie bieżącego modułu w oknie modułu |
SHIFT | Wciśnięcie podczas startu bazy umożliwia pominięcie opcji startowych tzn. makro Autoexec i formularz startowy nie są uruchamiane. |
• Pseudozapezpieczenia
• Zapis pliku na dysku
Pierwszym, narzucającym się rozwiązaniem jest zapisanie „gdzieś” na dysku, podczas startu bazy, małego pliku tekstowego,
takie niby „cookies”, który będzie usuwany przy zamknięciu bazy danych. Podczas startu bazy danych,
z poziomu makra Autoexec lub formularza startowego, uruchomiana będzie „Jakas_Funkcja”
sprawdzającej obecność pliku. Jak plik istnieje, to zostanie wywołana metoda Application.Quit
dla nowo otwieranej instancji bazy.
' przykładowy kod
If Len(Dir("Sciezka_MojPlik")) > 0 Then
' plik istnieje, zamknij otwieraną bazę
MsgBox "Nie możesz uruchomić następnej bazy danych"
Application.Quit
End If
No niby tak, ale jeżeli zawiesi się System (baza), wtedy plik "Sciezka_MojPlik" nie zostanie usunięty z dysku, i przy następnym uruchomieniu naszej bazy możemy mieć poważne kłopoty. Plik istnieje (i będzie istniał, aż do jego usunięcia), więc może się zdarzyć tak, że zawsze będzie QUIT.
• Tylko jedna instancja MS Access
Innym sposobem jest sprawdzenie podczas uruchomienia bazy danych, czy inna instancja MS Access jest otwarta. W tym celu możemy skorzystać z funkcji własnej CountAccessInstances(...) przedstawionej w art. • Funkcje API - ile uruchomiono instancji MS Access •. Jeżeli funkcja zwróci wartość > 1, wtedy nie pozwalamy na uruchomienie bazy.
' przykładowy kod
If CountAccessInstances > 1 Then
MsgBox "Nie możesz uruchomić następnej bazy danych"
' zamknij otwieraną bazę
Application.Quit
End If
Niestety, to rozwiązanie ma jeden wielki minus. W ten sposób uniemożliwimy użytkownikowi otwarcie jakiejkolwiek innej bazy danych, gdy otwarta jest „ta nasza jedyna baza”.
• Tylko jedna instancja bieżącej bazy MS Access
Aby umożliwić użytkownikowi otwarcie innych baz, z wyłączeniem drugiej instancji bieżącej bazy danych, musimy podczas uruchamiania bazy sprawdzić, czy nie została wcześniej otwarta pierwsza instancja bazy. W tym celu skorzystamy z funkcji własnej GetTextWindow(...) przedstawionej w art. • Funkcje API - jak pobrać tytuł (tekst) okna • w celu pobrania tytułu (tekstu) okna MS Access otwieranej bazy danych oraz (tak jak w poprzednim przykładzie), z funkcji własnej CountAccessInstances(...) przedstawionej w art. • Funkcje API - ile uruchomiono instancji MS Access • w celu pobrania ilości okien MS Access o tytule (tekście) zwróconym przez funkcję własną GetTextWindow(...).
' przykładowy kod
Dim sCurrDbTitle As String
' pobierz tytuł okna MS Access bieżącej bazy
sCurrDbTitle = GetTextWindow(Application.hWndAccessApp)
' pobierz ilość otwartych instancji MS Access o tytule okna sCurrDbTitle
If CountAccessInstances(sCurrDbTitle) > 1 Then
MsgBox "Nie możesz uruchomić drugiej instancji bieżącej bazy danych!"
' zamknij otwieraną bazę
Application.Quit
End If
Niestety, to rozwiązanie też ma swoje wady. Jeżeli baza danych nie ma ustawionej właściwości
CurrentDb.Properties("AppTitle"), którą to właściwość można ustawić za pomocą:
Menu Plik/Opcje/Bieżąca baza danych/Opcje aplikacji/Tytuł Aplikacji, to tytuł okna MS Access zmienia się,
wraz ze zmianą wersji MS Access.
Przykładowo dla bazy testowej: C:\tmp\dbTest.accdb
MS Access 2016 - "Access — dbTest : Baza danych- C:\tmp\dbTest.accdb (format pliku programu Access 2007–2016)"
MS Access 2010 - "Microsoft Access — dbTest : Baza danych (Access 2007 - 2010)"
MS Access 2007 - "Microsoft Access — dbTest : Baza danych (Access 2007)"
Jeżeli wymogiem dla prawidłowego działania kodu jest konieczność ustawienia właściwości CurrentDb.Properties("AppTitle")
to nie musimy korzystać z funkcji własnej GetTextWindow(...), tytuł okna MS Access pobierzemy dzięki właściwości CurrentDb.Properties("AppTitle").
' przykładowy kod
Dim sCurrDbTitle As String
' pobierz tytuł okna MS Access bieżącej bazy
sCurrDbTitle = CurrentDb.Properties("AppTitle")
' pobierz ilość otwartych instancji MS Access o tytule okna sCurrDbTitle
If CountAccessInstances(sCurrDbTitle) > 1 Then
MsgBox "Nie możesz uruchomić drugiej instancji bieżącej bazy danych!"
' zamknij otwieraną bazę
Application.Quit
End If
• Inne rozwiązania
Innym rozwiązaniem jest uruchomienie „jakieś funkcji”, która będzie pilnowała, by otwarta
była jedna instancja bieżącej bazy danych. Innymi słowy „Jakaś funkcja” musi być uruchomiona podczas
startu bazy danych i przez cały czas działania bazy musi sprawdzać, czy nie została otwarta druga instancja bieżącej bazy danych.
Najprostszym rozwiązaniem jest otwarcie ukrytego formularza startowego z włączonym Timerem,
w którym to w pewnych odstępach czasu (patrz. właściwość Form.TimerInterval), będzie sprawdzała, czy nie jest otwarta druga instancja
bazy (druga instancja MS Access)
Oczywistym rozwiązaniem powinno być wykorzystanie systemowych mechanizmów służących do synchronizacji wątków, czyli algorytmów wzajemnego wykluczania (w skrócie mutex, z ang. mutual exclusion) Jak wykorzystać mutex w celu uniemożliwienia otwarcia drugiej instancji bazy danych MS Access opisałem w artykule • Funkcje API - Mutex, jedna instancja bazy MS Access •
Brak komentarzy:
Prześlij komentarz