VB6: minimiertes Programmfenster wiederherstellen

  • VB6

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von Unknown.

    VB6: minimiertes Programmfenster wiederherstellen

    Hallo,
    ich brauche Hilfe bei einem Programm, an dem ich gerade arbeite. Es geht darum, einen Doppelstart des Programms zu verhindern. Sollte das Programm zum zweiten mal gestartet werden, soll das zuerst gestartete Programm in den Vordergrund geholt werden. Bis dahin funktioniert auch alles einwandfrei. Das Problem ist nur, wenn das Fenster minimiert ist, wird dieses nich wiederhergestellt und auch nicht in den Vordergrund geholt. Nach lagem suchen habe ich festgestellt, dass es zwei Handles beim Start des Programms gibt. Wenn das Fenster nicht minimiert ist, wird das richtige Handle gefunden und somit kann das Fenster wieder aktiviert werden. Ist das Fenster jedoch minimiert, wird das andere Handle zuerst gefunden und das Programm versucht dann natürlich das flasche Handle zu aktivieren. Naja ich hoffe mal dass ich es nicht zu kompliziert erklärt habe. Hier nochmal ein Teil des Quellcodes für das Verständniss:

    Visual Basic-Quellcode

    1. Private Const SW_MAXIMIZE As Long = 3&
    2. Private Const SW_MINIMIZE As Long = 6&
    3. Private Const SW_RESTORE As Long = 9&
    4. Private Const SW_NORMAL = 1
    5. Private Declare Function ShowWindow Lib "user32" (ByVal _
    6. hWnd As Long, ByVal nCmdShow As Long) As Long
    7. Private Declare Function FindWindow Lib "user32" Alias _
    8. "FindWindowA" (ByVal lpClassName As String, ByVal _
    9. lpWindowName As String) As Long
    10. Public Declare Function SetForegroundWindow Lib "User32.Dll" (ByVal hWnd As Long) As Long
    11. Private Sub Form_Load()
    12. Dim MemTitle As String
    13. Dim hWnd As Long
    14. If App.PrevInstance Then
    15. MemTitle = App.Title
    16. App.Title = "%&irgendwas"
    17. Unload frm_IHT
    18. 'Sucht Applikation und stellt sie wieder her
    19. hWnd = FindWindow(vbNullString, MemTitle)
    20. ShowWindow hWnd, SW_NORMAL
    21. SetForegroundWindow hWnd
    22. Exit Sub
    23. End If
    24. End Sub

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Akay“ ()

    FindWindow ermittelt das Fenster, welches auf
    der Z-Ebene an vorderster Stelle steht und
    die angegebenen Kriterien erfüllt. Wenn das
    Fenster minimiert ist, steht es an letzter Stelle
    und somit hinter dem noch nicht sichtbaren,
    im Form_Load-Ereignis erstellten Formular.

    Deshalb musst du die FindWindowEx-Funktion
    benutzen, da du mit ihr die Fensterliste durch-
    gehen kannst:

    Visual Basic-Quellcode

    1. h = FindWindowEx(0, h, vbNullString, "Titel")
    2. While h <> 0
    3. 'Nächstes Fenster, dessen Titelleiste "Titel" lautet.
    4. h = FindWindowEx(0, h, vbNullString, "Titel")
    5. Wend
    Danke schonmal für die Antwor aber irgendwie funktioniert das ganze noch nicht richtig. Jetzt wird das Fenster noch nichtmal in den Vordergrund geholt wenn es nicht minimiert ist. Hab das jetzt folgendermaßen eingebaut:

    Visual Basic-Quellcode

    1. Private Declare Function FindWindowEx Lib "user32.dll" _
    2. Alias "FindWindowExA" ( _
    3. ByVal hwndParent As Long, _
    4. ByVal hwndChildAfter As Long, _
    5. ByVal lpszClass As String, _
    6. ByVal lpszWindow As String) As Long
    7. Private Sub Form_Load()
    8. Dim MemTitle As String
    9. Dim hWnd As Long
    10. Dim h As Long
    11. If App.PrevInstance Then
    12. MemTitle = App.Title
    13. App.Title = "%&irgendwas"
    14. Unload frm_IHT
    15. 'Sucht Applikation und stellt sie wieder her
    16. 'hWnd = FindWindow(vbNullString, MemTitle)
    17. h = FindWindowEx(0, h, vbNullString, MemTitle)
    18. While h <> 0
    19. 'Nächstes Fenster, dessen Titelleiste "Titel" lautet.
    20. hWnd = FindWindowEx(0, h, vbNullString, MemTitle)
    21. Wend
    22. ShowWindow h, SW_NORMAL
    23. SetForegroundWindow h
    24. Exit Sub
    25. End If
    26. End Sub
    Die Schleife war nur ein Hinweis darauf, wie
    Fenster durchlaufen werden können. Das sollte
    kein konkretes Beispiel darstellen, tut mir leid,
    wenn das so rüberkam.

    Probiere folgendes:

    Visual Basic-Quellcode

    1. Private Declare Function FindWindowEx Lib "user32.dll" _
    2. Alias "FindWindowExA" ( _
    3. ByVal hwndParent As Long, _
    4. ByVal hwndChildAfter As Long, _
    5. ByVal lpszClass As String, _
    6. ByVal lpszWindow As String) As Long
    7. Private Declare Function IsIconic Lib "user32.dll" (ByVal hwnd As Long) As Long
    8. Private Sub Form_Load()
    9. Dim MemTitle As String
    10. Dim hwnd As Long
    11. Dim h As Long
    12. If App.PrevInstance Then
    13. MemTitle = App.Title
    14. App.Title = "%&irgendwas"
    15. Unload frm_IHT
    16. 'Sucht Applikation und stellt sie wieder her
    17. 'hWnd = FindWindow(vbNullString, MemTitle)
    18. 'Solange suchen, bis ein minimiertes Fenster
    19. 'mit MemTitle gefunden wird.
    20. h = FindWindowEx(0, h, vbNullString, MemTitle)
    21. While IsIconic(h) = 0 And h <> 0
    22. h = FindWindowEx(0, h, vbNullString, MemTitle)
    23. Wend
    24. 'Wenn kein solch minimiertes Fenster gefunden wird,
    25. 'erstes Fenster mit diesem Titel suchen.
    26. If h = 0 Then
    27. h = FindWindowEx(0, 0, vbNullString, MemTitle)
    28. 'Falls auch diesmal kein Fenster gefunden wird,
    29. 'Fehler ausgeben.
    30. If h = 0 Then
    31. MsgBox "Fenster nicht gefunden!", vbCritical, "Fehler"
    32. Exit Sub
    33. End If
    34. End If
    35. ShowWindow h, SW_NORMAL
    36. SetForegroundWindow h
    37. Exit Sub
    38. End If
    39. End Sub
    Hm. Muss dir leider sagen, dass es immer noch nicht funktioniert. Habe Testweise eine Msgbox in die IsIconic Schleife geschrieben und das Programm geht immer in die Schleife rein, auch wenn das Fenster nicht minimiert ist. Wenn das Fenster jedoch minimiert ist wird immernoch der zweite Handle ausgewählt.
    ______

    Also ich hab jetzt nochmal ein bischen rumprobiert und das Problem ist, dass die Funktion Isiconic garnicht erkannt, dass das Fenster minimiert ist. Sie gibt mir nämlich für beide Handles immer den Wert 0 zurück auch wenn das Fenster minimiert ist.
    ______

    So hab jetzt noch ein bischen rumprobiert und muss sagen, dass ich oben etwas falsches geschrieben habe. Man kann mit beiden Handles das Fenster in den Vordergrund holen und mit keinem der Handles kann man das Fenster wiederherstellen. Was vielleicht noch zu erwähnen ist, ist das der Fenstertitel nicht dem Programmtitel entspricht. Wenn ich nämlich nach dem Fenstertitel suche kann ich dieses wiederherstellen. Mit dem Programmtitel jedoch nicht. Da ich aber mehrere Fenster mit verschiedenen Titeln habe kann ich nicht auschließlich nach den Fenstertiteln suchen. Optimal wär natürlich der Programmtitel aber das funktioniert ja nicht. Hat jemand vielleicht noch eine andere Idee wie ich die minimierten Fenster wiederherstellen kann?

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Akay“ ()

    Nun, mit den neuen Informationen wird die Umsetzung
    ein wenig komplizierter. Wenn der Programmtitel
    nicht dem Fenstertitel entspricht, kann die Schleife
    natürlich nicht funktionieren. Die einzige Möglichkeit
    ist tatsächlich die Fenster zu aktivieren, die zum
    zuvor gestarteten Prozess gehören.

    Ich würde es wie im nachfolgenden Code lösen:

    Visual Basic-Quellcode

    1. Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
    2. Private Declare Function GetWindowThreadProcessId Lib "user32.dll" (ByVal hwnd As Long, ByRef lpdwProcessId As Long) As Long
    3. Private Declare Function ShowWindow Lib "user32.dll" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
    4. Private Declare Function GetModuleBaseName Lib "psapi.dll" Alias "GetModuleBaseNameA" (ByVal hProcess As Long, ByVal hModule As Long, ByVal lpBaseName As String, ByVal nSize As Long) As Long
    5. Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
    6. Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
    7. Private Declare Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
    8. Private Declare Function SetForegroundWindow Lib "user32.dll" (ByVal hwnd As Long) As Long
    9. Private Const PROCESS_QUERY_INFORMATION As Long = (&H400)
    10. Private Const PROCESS_VM_READ As Long = (&H10)
    11. Private Const SW_SHOWNOACTIVATE As Long = 4
    12. Private Const GWL_STYLE As Long = -16
    13. Private Const WS_CAPTION As Long = &HC00000
    14. Function GetProcessModuleName(ByVal procId As Long) As String
    15. Dim szBuffer As String * 261
    16. Dim hProc As Long
    17. 'Prozess öffnen.
    18. hProc = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ, _
    19. 0, _
    20. procId)
    21. If hProc <> 0 Then
    22. 'Dateinamen (ohne Pfad) ermitteln.
    23. GetModuleBaseName hProc, _
    24. 0, _
    25. szBuffer, _
    26. Len(szBuffer) - 1
    27. GetProcessModuleName = Left$(szBuffer, _
    28. InStr(1, szBuffer, vbNullChar) - 1)
    29. CloseHandle hProc
    30. End If
    31. End Function
    32. Sub ActivatePreviousInstance()
    33. Dim szModule As String
    34. Dim hWndCurrent As Long
    35. Dim procId As Long
    36. hWndCurrent = FindWindowEx(0, 0, vbNullString, vbNullString)
    37. While hWndCurrent <> 0
    38. 'Gehört das Fenster zu diesem Prozess ?
    39. If GetWindowThreadProcessId(hWndCurrent, procId) <> App.ThreadID Then
    40. 'Nein, Modulnamen ermitteln.
    41. szModule = GetProcessModuleName(procId)
    42. 'Handelt es sich um die gesuchte Anwendung ?
    43. If LCase$(szModule) = LCase$(App.EXEName & ".exe") Then
    44. 'Ist dies ein für den Benutzer sichtbares Fenster ?
    45. If GetWindowLong(hWndCurrent, GWL_STYLE) And WS_CAPTION Then
    46. 'Ja, gegebenenfalls wiederherstellen
    47. ShowWindow hWndCurrent, SW_SHOWNOACTIVATE
    48. '... und aktivieren.
    49. SetForegroundWindow hWndCurrent
    50. End If
    51. End If
    52. End If
    53. 'Nächstes Fenster holen.
    54. hWndCurrent = FindWindowEx(0, hWndCurrent, vbNullString, vbNullString)
    55. Wend
    56. End Sub


    Beachte, dass hier alle Fenster des vorherigen
    Prozesses wiederhergestellt bzw. in den Vorder-
    grund geholt werden, allerdings nur das erste
    ermittelte Fenster den Fokus erhält, da diesen nur
    diejenige Applikation abgeben kann, die derzeit
    den Fokus besitzt. Falls dieses Verhalten nicht
    gewünscht ist, müssen die Kriterien nach denen
    ein Fenster aktiviert werden soll genauer
    spezifiziert werden (z.B. durch GetWindowText).

    Bedauernswerterweise besitzt dieser Ansatz
    einen Nachteil: Die Funktion GetModuleFileNameEx
    wird nicht auf allen Windows-Versionen von der
    selben Bibliothek zur Verfügung gestellt. Dieses
    Programm würde demnach auf Windows 7/Windows
    Server 2008 R2 und nachfolgenden Versionen wohl
    nicht mehr funktionieren. Für diese Versionen
    ist die Importbibliothek "kernel32", nicht "psapi".