Excel fährt Access mit Hammer herunter
#1
Hallo zusammen

Folgenden Code-Schnipsel, welcher im Access läuft, möchte ich gerne in Excel haben. Dabei soll nach diversen Rcordsets, Close usw. das Access heruntergefallen werden, wenn es "hängen" geblieben ist. Da untenstehender Code (64 bit) nur im Access selber läuft, hoffe ich, dass ihr mit 64 bit auch eine Möglichkeit kennt, wo vom Excel-VBA aus eine bekannte (Laufwerk und Name) Access-DB heruntergefahren werden kann, wenn sie trotz .Close nicht vollständig heruntergeladen werden könnte. Es gibt Beispiele im Internet, jedoch nur ohne PtrSafe. 
Vielen Dank für Eure Unterstützung.

Gruss
Stefan

Code:
Option Explicit

Private Const PROCESS_TERMINATE As Long = &H1
Private Declare PtrSafe Function GetCurrentProcess Lib "kernel32" () As LongPtr
Private Declare PtrSafe Function GetCurrentProcessId Lib "kernel32" () As Long
Private Declare PtrSafe Function OpenProcess Lib "kernel32" _
        (ByVal dwDesireAccess As Long, _
         byVal bInDecitHandle As Boolean, _
         ByVal dwProcessId As Long) As LongPtr
Private Declare PtrSafe Function TerminateProcess Lib "kernel32" _
        (byVal hProcess AS LongPtr, ByVal uExitCode AS Long) As Boolean
Private Declare PtrSafe Function CloseHandle Lib "kernel32" (ByVal hObject As longPtr) AS Boolean

Private Sub TestClose()
Dim processId As Long
Dim processHandle As LongPtr
    processId = GetCurrentProcessID
    processHandle = OpenProcess(PROCESS_TERMINATE, False, processID)
    TerminateProcess processHandle, 0
    CloseHandle processHandle
End Sub
Antworten Top
#2
Zitat:Dabei soll nach diversen Rcordsets, Close usw. das Access heruntergefallen werden, wenn es "hängen" geblieben ist. 92

Der VBA-Code ist nicht Access spezifisch und kann eigentlich jeden Prozess terminieren, wenn man dazu die Berechtigung hat und die richtig ProezessID hat. Allerdings sollte man wissen, was man da macht, ansonsten kann eine Datenbank auch mal schnell beschädigt werden, wenn man den Access-Prozess einfach mal terminiert.

Am einfachsten ist es, das mit dem Taskmanager zu machen oder man verwendet dafür die Kommandozeile im Admin-Modus:
https://dashdot.de/2018/12/21/prozess-pe...en-killen/

Dafür in Excel ein Makro zu erstellen, halte ich nicht für sinnvoll.
Antworten Top
#3
Auf jeden Fall schließe ich mit VBA die Recordset (SELECT ...)-Anweisung aus Excel auf dem ordentlichen Weg mit RS.Close und DB.Close sowie Set RS = Nothing und DB = Nothing. Doch Leider kommt es immer wieder mal vor, dass sich trotz sorgfältigem Schliessen der Access-Datenbank von Excel aus trotzdem nicht herunterfahren und nur in diesem Fall würde ich es gerne via dem Prozess Handle diese Access-Datenbank schliessen können. Also so sauber als möglich mit dem Risiko das erwähnt wurde. Zu diesem Zweck müsste ich allerdings die Handle-ID kennen, doch wie komme ich VBA-mäßig daran?
Antworten Top
#4
(04.11.2024, 19:13)Stefan1 schrieb: ... in diesem Fall würde ich es gerne via dem Prozess Handle diese Access-Datenbank schliessen können. Also so sauber als möglich mit dem Risiko das erwähnt wurde. Zu diesem Zweck müsste ich allerdings die Handle-ID kennen, doch wie komme ich VBA-mäßig daran?

Code:
Option Explicit

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 GetWindowThreadProcessId Lib "user32" _
    (ByVal hWnd As LongPtr, lpdwProcessId As Long) As Long
Private Declare PtrSafe Function EnumWindows Lib "user32" _
    (ByVal lpEnumFunc As LongPtr, ByVal lParam As LongPtr) As Long

' Globale Variable für den Datenbanknamen und die Prozess-ID
Private gDatabaseFileName As String
Private gFoundProcessId As Long

Public Function GetAccessProcessIdByTitle(databaseFileName As String) As Long
    ' Setzt den Dateinamen und initialisiert die Prozess-ID
    gDatabaseFileName = databaseFileName
    gFoundProcessId = 0
   
    ' Startet die Fenstertitel-Suche
    EnumWindows AddressOf EnumWindowsProc, 0
   
    ' Gibt die gefundene Prozess-ID zurück (0, falls keine gefunden wurde)
    GetAccessProcessIdByTitle = gFoundProcessId
End Function

Private Function EnumWindowsProc(ByVal hWnd As LongPtr, ByVal lParam As LongPtr) As Long
    Dim processId As Long
    Dim windowTitle As String * 255
    Dim titleLength As Long
   
    ' Holt den Fenstertitel
    titleLength = GetWindowText(hWnd, windowTitle, Len(windowTitle))
    windowTitle = Left(windowTitle, titleLength)

    ' Überprüft, ob der Datenbankname im Fenstertitel enthalten ist
    If InStr(1, windowTitle, gDatabaseFileName, vbTextCompare) > 0 Then
        ' Holt die Prozess-ID des Fensters
        GetWindowThreadProcessId hWnd, processId
        If processId > 0 Then
            gFoundProcessId = processId
            EnumWindowsProc = 0 ' Beendet die Schleife, da die Prozess-ID gefunden wurde
            Exit Function
        End If
    End If
    EnumWindowsProc = 1 ' Fortsetzen der EnumWindows-Schleife
End Function

Sub TestGetAccessProcessId()
    Dim processId As Long
    processId = GetAccessProcessIdByTitle("<full database file name>")
   
    If processId > 0 Then
        MsgBox "Die Prozess-ID des Access-Prozesses ist: " & processId
    Else
        MsgBox "Kein Access-Prozess mit dieser Datenbank gefunden."
    End If
End Sub
[-] Folgende(r) 1 Nutzer sagt Danke an Warkings für diesen Beitrag:
  • Stefan1
Antworten Top
#5
Guten Tag Warkings
Perfekt. Vielen Dank. Habe den Code etwas modifiziert und er funktioniert einwandfrei, wenn sie die Datenbank einfach nicht ordentlich schliessen lässt. 
19
Nochmals vielen Dank, einfach Super.
Gruss
Stefan1
Antworten Top
#6
Hallo Stefan,

Zitat:Doch Leider kommt es immer wieder mal vor, dass sich trotz sorgfältigem Schliessen der Access-Datenbank von Excel aus trotzdem nicht herunterfahren ...
Also wenn das der Fall ist, ist in deinem Code auf jeden Fall ein Fehler und den solltest du beheben, anstatt im Nebel rumzustochern; alles andere kann deine DB zerstören und inkonsistent machen !!!

Zitat:... in diesem Fall würde ich es gerne via dem Prozess Handle diese Access-Datenbank schliessen können.
Wenn du per DAO auf die Datenbank-Datei zugreifst, gibt es keine Access-Anwendung, die du terminieren könntest. So etwas kann nur vorkommen, wenn du per Automation auf Access zugreifst. DAO läuft außerdem, anders als ADO, InProzess, womit du die Excel-Anwendung abschießt. Wer macht den sowas?  42

Bring deinen Code i.O. und gut ist.

Tip:  immer alle Fehler abfangen und im Fehlerfall auch das DAO.Error Objekt auswerten.

Gruß
Knobbi38
[-] Folgende(r) 1 Nutzer sagt Danke an knobbi38 für diesen Beitrag:
  • Stefan1
Antworten Top
#7
Guten Tag miteinander

Es läuft jetzt einwandfrei und sehr selten. Es handelt sich um einen bekannten Fehler von Access, den man nicht beheben kann. Mit Unterstützung konnte ich jetzt die Lösung in seltenen Fällen (ich protokollere es) nun implementieren. Normalerweise reicht auch mit DAO das problemlose Schliessen von der Access-Datenbank. Jedoch in selten Fällen, die nicht kontrolliert werden können, muss der Anwender dann den Prozess forciert beenden, wenn er sich daran stösst, dass Access im Hintergrund offen bleibt. Selbst wenn der Anwendung den PC herunterfährt, kommt es letztendlich zu dieser Hammermethode. Und ja, die Datenbank kann korrupt gehen. 
Code:
Sub TerminateAccessProcess()
Dim processId As Long
Dim processHandle As LongPtr
    processId = GetAccessProcessIdByTitle(CON_DATA_02_A_COCKPIT)
    If processId > 0 Then
        'MsgBox "Die Prozess-ID des Access-Prozesses ist: " & processId
        processHandle = OpenProcess(PROCESS_TERMINATE, False, processId)
        TerminateProcess processHandle, 0
        CloseHandle processHandle
        Call FehlerLog("TerminateAccessProcess")
    Else
        'MsgBox "Kein Access-Prozess mit dieser Datenbank gefunden."
    End If
End Sub
Antworten Top
#8
Zitat:Es handelt sich um einen bekannten Fehler von Access

Hast du für diese Behauptung eine verlässliche Quelle, oder woher beziehst du dein Wissen?

Zitat:Jedoch in selten Fällen, die nicht kontrolliert werden können, muss der Anwender dann den Prozess forciert beenden, wenn er sich daran stösst, dass Access im Hintergrund offen bleibt.

Nochmal: 
Einen separaten Prozess "Access" gibt es bei DAO nicht! Es gibt nur einen separaten Access-Prozess, wenn du per Automation auf Access zugreifst, was aber für einen reinen Datenzugriff aus Excel heraus nicht notwendig ist - und ja, bei Automation muß man sehr vorsichtig sein, wenn man das stabil hinbekommen möchte. Da muß jedes Objekt in der richtigen Reihenfolge beendet und freigegeben werden, sonst kommt es zu dem von dir beschrieben Effekt. Also nicht einfach diese Dinge durcheinander bringen und vermischen. Die haben miteinander nichts, aber auch gar nichts zu tun.

Zitat:Selbst wenn der Anwendung den PC herunterfährt, kommt es letztendlich zu dieser Hammermethode.
 
Aber dann wirst du darauf auch hingewiesen, daß da noch ein Prozess aktiv ist.

PC herunterfahren um Fehlersymptome zu beheben, sollte in der heutigen Zeit nicht mehr notwendig sein, das sind eher Relikte von früher.

Gruß
Knobbi38
Antworten Top
#9
Guten Tag knobbi38

Ich habe hier zwei Beispiele eingestellt (es gibt noch mehr):

Prüfen, ob ein Task noch läuft und ggf. beenden
https://www.vbarchiv.net/tipps/tipp_475-...enden.html

Windows API in VBA – Terminate Process – Workaround für Access Hängt beim Beenden (von  Better VBA 0 - Einleitung)
https://www.youtube.com/watch?v=nlux9J8nWxk

Selbstverständlich sollte die verwendete Programmierung so optimal wie möglich sein, doch es lässt sich nicht immer vermeiden, dass nicht nur Access quasi "hängen" bleibt. Selbst wenn Access oder auch Excel geöffnet wird und kaum VBA angewendet wird. Microsoft Office-Programme sind von Natur aus nicht immer stabil, dazu kommen Netzwerkinstabilitäten usw. Eine "abgestürzte" MS Office-Anwendung lässt sich manchmal nur noch mit dem Task-Manager beenden, da hilft einfach nichts mehr. Seit meinem Einbau dieser "Hammer"-Methode hatte ich noch kein protokollierter Fall, obwohl Excel hier sehr häufig pro Tag gebraucht wird. Ich bin also optimistisch, dass es sehr selten vorkommt. Die Access-Datenbank lässt sich einfach wiederherstellen, falls schwer beschädigt. Hoffen wir das es nie wird der Fall sein. 16
Danke für Unterstützung.
Gruss
Stefan1
Antworten Top
#10
Hallo Stefan,

Zitat:Microsoft Office-Programme sind von Natur aus nicht immer stabil, dazu kommen Netzwerkinstabilitäten usw.
Das ist doch MS Bashing, entbehrt jeder Grundlage und damit FAKE!

Deine Quelle belegen keines Falls deine Behauptung, sondern du vergleichst hier Äpfel mit Birnen -  InProzess-Zugriff mit DAO und eine Access-Anwendung. Im Übrigen ist der beschriebene Fehler aus dem 2.Link ein nachvollziehbares Verhalten unter sehr konkreten Umständen, die i.d.R. nur sehr  selten eintreten. Hierbei wird der Fehler durch die Anwendung MS-Access verursacht und nicht durch einen Datenzugriff auf eine Datenbank - Datei.

Bevor du so einen Workaround in deine Anwendung einbaust, solltest du dir mal alle Informationen zu dem Problem ansehen und vor allem erstmal verstehen, was da programmiert wird, wie der genaue Ablauf dabei ist und welche Auswirkungen das hat. Einfach nur einen Prozess zu terminieren, reicht hier übrigens nicht. Die entsprechenden Lockdateien müssen u.U. ebenfalls entfernt werden!

Das Alles trifft in deinem Fall überhaupt nicht zu.

Du kannst ja machen, was dir gefällt und das bleibt dir überlassen, aber als Admin oder IT-Verantworlicher würde wahrscheinlich so eine VBA-Programmierung bei einer QS-Prüfung/Audit niemals zur Installation freigegeben werden.

Gruß
Knobbi38
Antworten Top


Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste