396 Aufrufe
Gefragt in Tabellenkalkulation von heiko1985 Mitglied (127 Punkte)

Hallo zusammen

Ich suche nach einer Möglichkeit, eine Aktion auszuführen, wenn eine UserForm oder das Excel-Fenster in den Vordergrund geholt wird.

Hier im Detail:

  • Ich habe eine Excel-Datei mit geöffneter UserForm.
  • Ich aktiviere ein anderes Fenster, zum Beispiel Word.
  • Das Excel-Fenster ist dadurch nicht mehr im Vordergrund bzw. nicht mehr aktiviert.
  • Ich wechsele zurück zum Excel-Fenster, zum Beispiel über die Taskleiste oder über strg+Tab.
  • Jetzt soll eine Aktion ausgeführt werden.

Also so ähnlich wie "Private Sub Worksheet_Activate()", aber eben mit dem Excel-Fenster oder der UserForm.

Könnt ihr mir da helfen?

Danke und Gruß

Heiko1985

2 Antworten

0 Punkte
Beantwortet von xlking Experte (1.5k Punkte)

Hallo Heiko,

hab schon ewig nicht mehr in diesem Forum vorbeigeschaut. Da ich mein Passwort vergessen hatte und mir vermutlich auch das neue jetzt nicht wirklich merken kann (viel zu lang und zu kompliziert, was SN hier als sicher einstuft) ist es mir nur begrenzt möglich, hier zu antworten. Hab deine Frage daher erst jetzt gesehen.

Falls du hier nochmal reinschauen solltest, hier ein Ansatz für dein Problem:

Es gibt jede Menge Window-Events die ein Fenster bei bestimmten Ereignissen sendet. Um z.B. das Window_Activate-Ereignis abzufangen musst du einen sog. Hook setzen. Wie das in VB geht, steht z.B. hier.

Der Code ist natürlich etwas veraltet und auch nicht direkt für VBA. Hab daher das Grundgerüst genommen und für dich ein wenig angepasst. Hoffe das stimmt so. Da ich selbst noch kein VBA7 habe, musst du das Testen leider selbst übernehmen und ggf. Kleinigkeiten anpassen. Mit meinem VBA6 funktioniert es jedenfalls ganz gut.

Hier der Code für das Userform:

#If VBA7 Then
 Public hwnd As LongPtr
 Private Declare PtrSafe Function FindWindow Lib "user32.dll" _
  Alias "FindWindowA" ( _
  ByVal lpClassName As String, _
  ByVal lpWindowName As String) As LongPtr
#Else
 Public hwnd As Long
 Private Declare Function FindWindow Lib "user32.dll" _
  Alias "FindWindowA" ( _
  ByVal lpClassName As String, _
  ByVal lpWindowName As String) As Long
#End If

Private Sub UserForm_Initialize()
  hwnd = FindWindow("ThunderDFrame", Me.Caption)
  HookForm hwnd
End Sub

Private Sub UserForm_Terminate()
  UnHookForm hwnd
End Sub

und hier der Code für ein allgemeines Modul (z.B. Modul1)

Option Explicit
 
'code von hier: https://www.vbarchiv.net/tipps/details.php?id=1065
'leicht abgewandelt

'Liste aller Windows-Messages u.a. hier: https://wiki.winehq.org/List_Of_Windows_Messages
 
#If VBA7 Then
 Declare PtrSafe Function SetWindowLong Lib "user32" _
  Alias "SetWindowLongA" ( _
  ByVal hwnd As LongPtr, _
  ByVal nIndex As LongPtr, _
  ByVal dwNewLong As LongPtr) As LongPtr
 
 Declare PtrSafe Function CallWindowProc Lib "user32" _
  Alias "CallWindowProcA" ( _
  ByVal lpPrevWndFunc As LongPtr, _
  ByVal hwnd As LongPtr, _
  ByVal Msg As LongPtr, _
  ByVal wParam As LongPtr, _
  ByVal lParam As LongPtr) As LongPtr
 
 Dim PrevProc As LongPtr
#Else
 Declare Function SetWindowLong Lib "user32" _
  Alias "SetWindowLongA" ( _
  ByVal hwnd As Long, _
  ByVal nIndex As Long, _
  ByVal dwNewLong As Long) As Long
 
 Declare Function CallWindowProc Lib "user32" _
  Alias "CallWindowProcA" ( _
  ByVal lpPrevWndFunc As Long, _
  ByVal hwnd As Long, _
  ByVal Msg As Long, _
  ByVal wParam As Long, _
  ByVal lParam As Long) As Long
 
 Dim PrevProc As Long
#End If
 
Private Const GWL_WNDPROC = (-4)
Private Const WM_ACTIVATE = &H6
 
#If VBA7 Then
 Public Sub HookForm(nHwnd As LongPtr)
#Else
 Public Sub HookForm(nHwnd As Long)
#End If
  PrevProc = SetWindowLong(nHwnd, GWL_WNDPROC, _
    AddressOf WindowProc)
End Sub
 
#If VBA7 Then
 Public Sub UnHookForm(nHwnd As LongPtr)
#Else
 Public Sub UnHookForm(nHwnd As Long)
#End If
  SetWindowLong nHwnd, GWL_WNDPROC, PrevProc
End Sub

#If VBA7 Then
 Public Function WindowProc(ByVal hwnd As LongPtr, ByVal uMsg As Long, _
  ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
#Else
 Public Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, _
  ByVal wParam As Long, ByVal lParam As Long) As Long
#End If

  On Error Resume Next
  WindowProc = CallWindowProc(PrevProc, hwnd, uMsg, wParam, lParam)
  
  If uMsg = WM_ACTIVATE Then
    If wParam <> 0 Then
      Debug.Print "Window wurde aktiviert"
    Else
      Debug.Print "Window wurde deaktiviert"
    End If
  End If
  
End Function

Du solltest dich natürlich ein wenig mit API-Programmierung auskennen wenn du weitere Schritte unternehmen willst. Sonst kann es u.U. zu Abstürzen kommen. Wichtig: Benutze keine MsgBox innerhalb dieses Activate-Events, da dadurch das userform vorübergehend deaktiviert und wieder aktiviert wird, was die Msgbox erneut aufrufen würde. (Dauerschleife!)

Wenn du weitere Fragen hast, einfach melden.

Gruß Mr. K.

0 Punkte
Beantwortet von heiko1985 Mitglied (127 Punkte)

Hallo Mr. K.

Danke für deine Antwort und deine Arbeit! Und bitte entschuldige meine seeehr späte Antwort. Irgendwie ist das Thema bei mir in Vergessenheit geraden.

Du solltest dich natürlich ein wenig mit API-Programmierung auskennen

Das tue ich leider nicht ...

Ich werde mir den Code speichern und hoffentlich ausprobieren. Aber ich befürchte, dass das eine Nummer zu hoch für mich ist.

...