Solo permita que se ejecute una instancia de una base de datos a la vez
¿Alguna vez ha tenido uno de esos usuarios que abren la base de datos, hace otras cosas, regresa y abre otra instancia … y así va.
Tal vez es hora de minimizar los problemas que esto puede causar al limitar a un usuario solo poder lanzar una sola instancia de una base de datos determinada.
Usando su script de lanzamiento
Si ha configurado correctamente a sus usuarios y tienen su propia copia privada de la base de datos front-end, entonces la técnica más fácil para evitar que inicie múltiples instancias de su base de datos tal vez sea a través del script de lanzamiento.
Un VBScript simple para iniciar una base de datos de Microsoft Access puede verse algo así como:
Option Explicit Dim oAccess ' Create Access Application object Set oAccess = CreateObject("Access.Application") ' Make Access visible oAccess.Visible = True oAccess.UserControl = True ' Open the database oAccess.OpenCurrentDatabase "C:\Databases\Demos\OnlyLaunchOnce.accdb" ' Cleanup Set oAccess = Nothing
Ahora, si quisiéramos evitar que se inicie otra instancia de esa base de datos, la solución más simple sería verificar primero la existencia de un archivo de bloqueo de acceso (LDB, LACCDB) y modificaría lo anterior para ser más como:
Option Explicit Dim oFSO, oAccess, dbPath, laccdbPath ' Set the path to your Access database file dbPath = "C:\Databases\Demos\OnlyLaunchOnce.accdb" ' Construct the path for the .laccdb lock file laccdbPath = Replace(dbPath, ".accdb", ".laccdb") ' Create FileSystemObject Set oFSO= CreateObject("Scripting.FileSystemObject") ' Check if .laccdb file exists If oFSO.FileExists(laccdbPath) Then WScript.Echo "The database is already runnings." Else ' Create Access Application object Set oAccess = CreateObject("Access.Application") ' Make Access visible oAccess.Visible = True oAccess.UserControl = True ' Open the database oAccess.OpenCurrentDatabase dbPath End If ' Cleanup Set oFSO = Nothing Set oAccess = Nothing
Uso del código desde su base de datos
Otra forma de manejar esto podría ser validar que cuando se lance el mismo título de la ventana se encuentra en la lista de ventanas de aplicaciones abiertas. Para esto, debemos girar hacia el uso de un par de API de Windows y haríamos algo como:
Private Declare PtrSafe Function EnumWindows Lib "user32" (ByVal lpEnumFunc As LongPtr, ByVal lParam As LongPtr) As Long Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr Private Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As Long Private Declare PtrSafe Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hWnd As LongPtr) As Long Private Declare PtrSafe Function IsWindowVisible Lib "user32" (ByVal hWnd As LongPtr) As Boolean Private colWindowTexts As Collection Function GetCurrentWindowTitle() As String Dim lHWnd As LongPtr Dim lWindowTextLength As Long Dim sWindowText As String lHWnd = GetActiveWindow() lWindowTextLength = GetWindowTextLength(lHWnd) sWindowText = Space$(lWindowTextLength + 1) GetWindowText lHWnd, sWindowText, lWindowTextLength + 1 GetCurrentWindowTitle = Left$(sWindowText, lWindowTextLength) End Function Private Function EnumWindowsCallback(ByVal lHWnd As LongPtr, _ ByVal lParam As LongPtr) As Long Dim sWindowText As String * 255 Dim lWindowTextLength As Long lWindowTextLength = GetWindowText(lHWnd, sWindowText, Len(sWindowText)) If lWindowTextLength > 0 And IsWindowVisible(lHWnd) Then sWindowText = Left(sWindowText, lWindowTextLength) colWindowTexts.Add Trim(sWindowText) End If EnumWindowsCallback = 1 End Function Function CountWindowsWithTitle(sTitle As String) As Long Dim sWindowText As Variant Set colWindowTexts = New Collection EnumWindows AddressOf EnumWindowsCallback, 0 For Each sWindowText In colWindowTexts 'Debug.Print Trim(sWindowText) 'For debugging purposed If Trim(sWindowText) = sTitle Then CountWindowsWithTitle = CountWindowsWithTitle + 1 End If Next sWindowText Set colWindowTexts = Nothing End Function
Luego, utilizando un formulario de inicio o una macro AutoExec, simplemente realizaríamos la verificación haciendo:
If CountWindowsWithTitle(GetCurrentWindowTitle()) > 1 Then ' Already an instance running MsgBox "The database is already open.", vbInformation, "Database Already Running" Application.Quit acQuitSaveNone End If
Conclusión
Entonces, arriba he proporcionado 2 posibles formas de evitar que los usuarios abran múltiples instancias de la misma base de datos, la elección es suya.
Al tomar tales pasos, en última instancia, está reduciendo la posibilidad de que ocurran confusión y errores, ayudando con el consumo general de recursos, lo que puede afectar el rendimiento general de la base de datos y las PC e incluso evitar problemas de integridad de datos que surgen de los conflictos de datos y la posible pérdida de cambios de tener los mismos cambios de tener los mismos cambios en tener los mismos cambios. Los registros se abren en diferentes casos de Databaase.