Windows Explorer schließen

    • VB.NET
    • .NET (FX) 4.5–4.8

    Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von Bob_Der_Bert.

      Windows Explorer schließen

      Weil hier diese beiden Threads offensichtlich nicht zum Ziel geführt haben:
      Ordner Schließen
      Geöffnetes Windows-Explorer-Fenster schließen
      habe ich eine hier gefundene VB6-Lösung nach VB.NET portiert und lauffähig gemacht.
      Diese Lösung funktioniert mit anderen Fenstern ebenfalls, dazu erfolgt eine MessageBox-Abfrage, ob automatisch ein Explorer gestartet werden soll. Alternativ kann selbst ein Notepad oder auch ein Explorer oder nix gestartet werden, im letzteren Fall erfolgt ein TimeOut.
      Das Prinzip ist folgendes:
      Vor dem Start eines Programmes werden alle Top-Level-Fenster ermittelt, danach ebenfalls.
      Von der Differenzmenge wird das Fenster mit dem Index 0 per SendMessage() geschlossen. Feddich.
      Interessant ist, dass ein Explorer 5 Fenster nach sich zieht, das Notepad lediglich eines.
      -----
      Getestet unter W7-64
      -----
      Version 2: Explorer-Handling-Klasse gekapselt, Test mit 2 Instanzen
      Dateien
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „RodFromGermany“ ()

      Von @Rebecca82 kam die Anregung, mehrere Explorer-Fenster behandeln zu können.
      Dies ist Version 2 der Solution.
      Die (hier beiden) Fenster müssen in derselben Reihenfolge geschlossen werden, wie sie geöffnet wurden, sonst geht es (noch) nicht.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Ich habe noch eine etwas andere Herangehensweise, welche zu 99,9% funktioniert und nur eine einzige Zeile zum Killen des Prozesses braucht:

      VB.NET-Quellcode

      1. 'Startmethode
      2. Process.Start(New ProcessStartInfo("explorer.exe", "C:\\"))
      3. Dim startTime As DateTime = DateTime.Now
      4. 'Methode zum Beenden
      5. Process.GetProcessesByName("explorer").OrderBy(Function(p) Math.Abs((p.StartTime - startTime).TotalMilliseconds)).First().CloseMainWindow()

      Die Abweichung von der gemessenen Startzeit zur Startzeit des Prozesses ist (bei mir) ca. 14 Millisekunden - man kann also locker das richtige finden.


      Alternativ könnte man auch die Microsoft Internet Controls nutzen - wenn man dort alle InternetExplorer in den ShellWindows enumeriert und die explorer.exe-Prozesse nimmt, kriegt man LocationUrl den Pfad des Fensters, wodurch man viel einfacher bestimmen kann, ob das Fenster auf den gleichen Pfad zeigt.
      @nafets Jou, das funktioniert schon mal. :thumbup:
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Hallo,

      ich wollte das Ganze mal nach dem LIFO-Prinzip umsetzen. Dank dem Quellcode von @RodFromGermany ist es mir auch soweit gelungen. Daher wollte ich mal meinen Quellcode hier posten, für all diejenigen die es interessiert. Wahrscheinlich kann man an meinem Code noch einiges verbessern. Falls ja nur zu. :)
      Die Form hat zwei Buttons - einen um mehrere Explorer-Fenster nacheinander zu öffnen und einen um die geöffneten Explorer-Fenster nacheinander wieder zu schließen.



      Hier der (verbesserte) Quellcode:
      NativeMethoden.vb:

      VB.NET-Quellcode

      1. Imports System.Runtime.InteropServices
      2. ''' <summary>
      3. ''' Die verwendeten API-Funktionen
      4. ''' </summary>
      5. Public Class NativeMethoden
      6. Public Const WM_SYSCOMMAND As Integer = &H112
      7. Public Const GW_HWNDNEXT As Integer = &H2
      8. Public Const SC_CLOSE As Integer = &HF060
      9. 'FindWindow
      10. <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
      11. Public Shared Function FindWindow( _
      12. ByVal lpClassName As IntPtr, _
      13. ByVal lpWindowName As IntPtr) As IntPtr
      14. End Function
      15. 'GetWindow
      16. <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
      17. Public Shared Function GetWindow(ByVal hWnd As IntPtr, ByVal uCmd As UInt32) As IntPtr
      18. End Function
      19. 'GetParent
      20. <DllImport("user32.dll", ExactSpelling:=True, CharSet:=CharSet.Auto)> _
      21. Public Shared Function GetParent(ByVal hWnd As IntPtr) As IntPtr
      22. End Function
      23. 'SendMessage
      24. <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
      25. Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As IntPtr
      26. End Function
      27. End Class

      EinExplorer.vb:

      VB.NET-Quellcode

      1. Public Class EinExplorer
      2. 'Liste der offenen Fenster vor dem Explorer-Start
      3. Private VorherGeoeffneteFenster As List(Of IntPtr)
      4. 'Liste der offenen Fenster nach dem Explorer-Start
      5. Private NachherGeoeffneteFenster As List(Of IntPtr)
      6. 'Die Differenz davon
      7. Private ExplorerWindowHandle() As IntPtr
      8. 'Konstruktor
      9. Public Sub New()
      10. End Sub
      11. 'Explorer-Starten
      12. Public Sub StartExplorer(Path As String)
      13. Dim Proc = New Process
      14. Proc.StartInfo.FileName = "explorer"
      15. Proc.StartInfo.Arguments = Path
      16. Proc.StartInfo.WorkingDirectory = Path
      17. Proc.Start()
      18. 'Kleine Pause, WaitForInputIdle funktioniert nicht beim Explorer
      19. System.Threading.Thread.Sleep(1000)
      20. End Sub
      21. 'Explorer-Schließen
      22. Public Sub Close()
      23. NativeMethoden.SendMessage(ExplorerWindowHandle(0),
      24. NativeMethoden.WM_SYSCOMMAND,
      25. NativeMethoden.SC_CLOSE,
      26. Nothing)
      27. End Sub
      28. 'Nachher-Liste
      29. Public Sub NachherListe()
      30. Do
      31. NachherGeoeffneteFenster = GetWindowList()
      32. Loop Until (NachherGeoeffneteFenster.Count > VorherGeoeffneteFenster.Count)
      33. ExplorerWindowHandle = Delta(NachherGeoeffneteFenster, VorherGeoeffneteFenster)
      34. End Sub
      35. 'Liste der vorher geöffneten Fenster
      36. Public Sub VorherListe()
      37. VorherGeoeffneteFenster = GetWindowList()
      38. End Sub
      39. ''' <summary>
      40. ''' ermittelt die Liste aller Top-Level-Fenster,
      41. ''' das sind Fenster, die kein Parent-Fenster haben
      42. ''' </summary>
      43. ''' <returns>Liste aller Top-Level-Fenster</returns>
      44. Private Function GetWindowList() As List(Of IntPtr)
      45. Dim Handle = New List(Of IntPtr)
      46. Dim Window = NativeMethoden.FindWindow(IntPtr.Zero, IntPtr.Zero)
      47. Do While Window <> IntPtr.Zero
      48. If NativeMethoden.GetParent(Window) = IntPtr.Zero Then
      49. Handle.Add(Window)
      50. End If
      51. Window = NativeMethoden.GetWindow(Window, NativeMethoden.GW_HWNDNEXT)
      52. Loop
      53. Return Handle
      54. End Function
      55. ''' <summary>
      56. ''' Bestimmen der Fenster, die beim Explorer-Start hinzugekommen sind
      57. ''' </summary>
      58. ''' <param name="nachher">Liste der Fenster nach dem Start</param>
      59. ''' <param name="vorher">Liste der Fenster vor dem Start</param>
      60. ''' <returns>Liste der Fenster, die in nachher, nicht aber in vorher vorkommen</returns>
      61. Private Function Delta(Nachher As List(Of IntPtr), Vorher As List(Of IntPtr)) As IntPtr()
      62. Dim Explorer() As IntPtr
      63. Explorer = (From Damals As IntPtr
      64. In Nachher
      65. Where (Not Vorher.Contains(Damals))
      66. Select Damals).ToArray()
      67. Return Explorer
      68. End Function
      69. 'VorherGeoeffneteFenster-ReadOnlyEigenschaft
      70. Public ReadOnly Property AnzahlFensterVorher As Integer
      71. Get
      72. If VorherGeoeffneteFenster Is Nothing Then
      73. Return -1
      74. End If
      75. Return VorherGeoeffneteFenster.Count
      76. End Get
      77. End Property
      78. 'NachherGeoeffneteFenster-ReadOnlyEigenschaft
      79. Public ReadOnly Property AnzahlFensterNachher As Integer
      80. Get
      81. If VorherGeoeffneteFenster Is Nothing Then
      82. Return -1
      83. End If
      84. Return NachherGeoeffneteFenster.Count
      85. End Get
      86. End Property
      87. End Class

      Form1.vb:

      VB.NET-Quellcode

      1. Public Class Form1
      2. Private ExplorerList As New List(Of EinExplorer)
      3. Private CurrentExplorer As EinExplorer
      4. Private EmptyList As Boolean = True
      5. 'Explorer-Fenster öffnen
      6. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
      7. EmptyList = False
      8. ExplorerList.Add(New EinExplorer)
      9. Label2.Text = ExplorerList.Count
      10. CurrentExplorer = ExplorerList(ExplorerList.Count - 1)
      11. CurrentExplorer.VorherListe()
      12. CurrentExplorer.StartExplorer(Application.StartupPath)
      13. CurrentExplorer.NachherListe()
      14. End Sub
      15. 'Explorer-Fenster schließen
      16. Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
      17. If EmptyList = False Then
      18. CurrentExplorer.Close()
      19. ExplorerList.RemoveAt(ExplorerList.Count - 1)
      20. Label2.Text = ExplorerList.Count
      21. If ExplorerList.Count = 0 Then
      22. EmptyList = True
      23. Exit Sub
      24. End If
      25. CurrentExplorer = ExplorerList(ExplorerList.Count - 1)
      26. Else
      27. MessageBox.Show("Keine Explorer-Fenster geöffnet!!!", "Info")
      28. End If
      29. End Sub
      30. End Class

      Würde mich über Verbesserungsvorschläge und Feedback allgemein sehr freuen. :)
      Daher hänge ich das Projekt mal zum Download an. ;)
      @nafets: Dein Beispiel funktioniert sehr gut. Denn bei dir kann man im geöffneten Windows-Explorer wirklich überall hin navigieren, egal wohin und wie lang. Das Explorer-Fenster lässt sich grundsätzlich immer per Klick am Button schließen. Vielen Dank auch für dein Beispiel.

      @RodFromGermany: Bei deinem Beispiel funktioniert das leider nicht immer. Nur dann wenn man das geöffnete Verzeichnis nicht verlassen hat. Dann lässt es sich zu 100% immer schließen. Doch manchmal, wenn man andere Verzeichnisse angeklickt hat usw., lässt es sich nicht mehr per Button schließen. Wie könnte man das noch optimieren, damit es auch da grundsätzlich immer schließt, nachdem man vorher wild drauf los navigiert ist im Explorer-Fenster? Ansonsten aber wirklich super. Deswegen vielen vielen Dank. :)
      Dateien

      Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Rebecca82“ ()

      hier meine Überarbeitung. Ist rein formal, also Funktionalität sollte unverändert sein:

      VB.NET-Quellcode

      1. Public Class Form1
      2. Private _Explorers As New List(Of EinExplorer)
      3. Private _IsCurrentClosed As Boolean = True
      4. Private _CurrentIndex As Integer
      5. Private Sub btOpenExplorer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btOpenExplorer.Click
      6. _IsCurrentClosed = False
      7. _Explorers.Add(New EinExplorer)
      8. Label2.Text = _Explorers.Count.ToString
      9. _CurrentIndex = _Explorers.Count - 1
      10. Dim expl = _Explorers(_CurrentIndex)
      11. expl.HoleVorherListe()
      12. expl.StartExplorer(Application.StartupPath)
      13. expl.NachherListeHolen() 'irgendeine Daten-Initialisierung innerhalb von von expl
      14. End Sub
      15. Private Sub btCloseExplorer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btCloseExplorer.Click
      16. If _IsCurrentClosed Then
      17. MessageBox.Show("Keine Explorer-Fenster geöffnet!!!", "Fehler")
      18. Else
      19. Dim expl = _Explorers(_CurrentIndex)
      20. expl.Close()
      21. _Explorers.RemoveAt(_CurrentIndex)
      22. Label2.Text = _Explorers.Count.ToString
      23. If _Explorers.Count = 0 Then
      24. _IsCurrentClosed = True
      25. Exit Sub
      26. End If
      27. _CurrentIndex = _Explorers.Count - 1
      28. End If
      29. End Sub
      30. End Class
      Es gibt weniger Klassenvariablen, und die Benennung macht fast alle Kommentare überflüssig.
      Ein einziger Kommentar bleibt, und ist wohl der entscheidende.
      Vorher stand da: 'Liste aller hinterher geöffneten Fenster holen, was offensichtlich falsch war, denn dort findet ja keine Zuweisung statt, wie man erwarten würde, wenn etwas "geholt" wird.
      Empfehlenswert, auch diese Methode besser zu benennen - ich hab den Namen so gelassen, weil ich in deren Innereien nicht durchlicke

      Möglicherweise kann man auch _CurrentIndex streichen - es scheint ja immer der Index des letzten elements zu sein. Naja - den Index kann man auch von der List(Of T) - Klasse direkt abrufen - braucht man sich nicht klassenweit zu merken, da ja die Liste selbst klassenweit gemerkt ist.

      edit: nicht möglicherweise, sondern ganz bestimmt.

      edit edit: Also nach meinem Verständnis vonne Funktionalität wäre effektiver einen Stack zu verwenden, dann kann noch viel mehr Brimborium raus:

      VB.NET-Quellcode

      1. Public Class Form1
      2. Private _Explorers As New Stack(Of EinExplorer)
      3. Private Sub btOpenExplorer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btOpenExplorer.Click
      4. Dim expl = New EinExplorer
      5. _Explorers.Push(expl)
      6. Label2.Text = _Explorers.Count.ToString
      7. expl.HoleVorherListe() 'irgendeine Daten-Initialisierung innerhalb von von expl
      8. expl.StartExplorer(Application.StartupPath)
      9. expl.NachherListeHolen() 'irgendeine Daten-Initialisierung innerhalb von von expl
      10. End Sub
      11. Private Sub btCloseExplorer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btCloseExplorer.Click
      12. If _Explorers.Count = 0 Then
      13. MessageBox.Show("Keine Explorer-Fenster geöffnet!!!", "Fehler")
      14. Else
      15. _Explorers.Pop().Close()
      16. Label2.Text = _Explorers.Count.ToString
      17. End If
      18. End Sub
      19. End Class

      Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „ErfinderDesRades“ ()

      @ErfinderDesRades: Vielen Dank für die Verbesserungsvorschläge. :thumbsup:

      Edit:
      ------
      Nochmals vielen Dank an @RodFromGermany, @nafets und an @ErfinderDesRades - dank Euch hier die endgültige Version :D
      EinExplorer.vb

      VB.NET-Quellcode

      1. Public Class EinExplorer
      2. 'Für die Startzeit des Explorers
      3. Private StartTime As DateTime
      4. 'Konstruktor
      5. Public Sub New()
      6. End Sub
      7. 'Explorer-Starten
      8. Public Sub StartExplorer(Path As String)
      9. Process.Start(New ProcessStartInfo("explorer.exe", Path))
      10. StartTime = DateTime.Now
      11. End Sub
      12. 'Explorer-Schließen
      13. Public Sub Close()
      14. Process.GetProcessesByName("explorer").OrderBy(Function(p) Math.Abs((p.StartTime - StartTime).TotalMilliseconds)).First().CloseMainWindow()
      15. End Sub
      16. End Class

      Form1.vb

      VB.NET-Quellcode

      1. Public Class Form1
      2. Private ExplorerList As New Stack(Of EinExplorer)
      3. 'Explorer-Fenster öffnen
      4. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
      5. Dim Explorer = New EinExplorer
      6. ExplorerList.Push(Explorer)
      7. Label2.Text = ExplorerList.Count.ToString()
      8. Explorer.StartExplorer(Application.StartupPath)
      9. End Sub
      10. 'Explorer-Fenster schließen
      11. Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
      12. If ExplorerList.Count = 0 Then
      13. MessageBox.Show("Keine Explorer-Fenster geöffnet!!!", "Info")
      14. Else
      15. ExplorerList.Pop().Close()
      16. Label2.Text = ExplorerList.Count.ToString()
      17. End If
      18. End Sub
      19. End Class


      Diese Version funktioniert perfekt. :)

      Grüße Rebecca
      Dateien

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

      Hallo,

      ich habe aber das Problem, die geöffneten Windows-Explorer Fenster wurden nicht von VB gestartet, sonder vom Desktop.
      Daher habe ich nur eine Explorer.exe.

      Ich würde diese gerne alle geöffneten Explorer-Fenster mit Pfadangaben speichern, dann schliessen.
      Jetzt kommt mein Programmcode.
      Wenn dieser durchgelaufen ist sollten die ursprünglich geöffneten Explorer wieder geöffnet werden.

      P.S. Mein Problem: Ich muss einen Ordner, samt Inhalt löschen.
      My.Computer.FileSystem.DeleteDirectory("C:\OldDirectory",FileIO.DeleteDirectoryOption.DeleteAllContents)
      bzw. Directory.Delete(topPath, True) funktioniert nur solange der Explorer den Pfad zu einem der zu löschenden Ordner nicht offen hat. Er muss noch nicht einmal auf einem der betroffenen Ordner stehen. Fehler: "Verzeichnis ist nicht leer", was so nicht richtig ist. Wenn der Pfad komplett geschlossen ist funktioniert es.

      Besten Dank für Hilfe
      Gruß Bob
      Hallo @Bob_Der_Bert

      Verweis auf die Microsoft Internet Controls setzten.

      VB.NET-Quellcode

      1. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
      2. Dim shellWindows As New SHDocVw.ShellWindows
      3. Dim filename As String
      4. Dim selected As List(Of String) = New List(Of String)
      5. 'Alle Explorer-Fenster durchgehen
      6. For Each ie As SHDocVw.ShellBrowserWindow In shellWindows
      7. filename = IO.Path.GetFileNameWithoutExtension(ie.FullName).ToLower()
      8. If filename.Equals("explorer") Then
      9. 'augewählter Ordnerpfad auslesen
      10. If ie.LocationURL = "" Then
      11. selected.Add(" ")
      12. Else
      13. selected.Add(New Uri(ie.LocationURL).LocalPath)
      14. End If
      15. ie.Quit()
      16. End If
      17. Next
      18. 'hier dein Code
      19. 'Explorer-Fenster wieder öffnen
      20. For Each path As String In selected
      21. Process.Start(New ProcessStartInfo("explorer.exe", Path))
      22. Next
      23. End Sub
      Servus HenryV,

      funktioniert schon mal nicht schlecht, aber bei mehreren geöffneten Explorer-Fenstern ist irgendwie noch ein Fehler drin.
      Trotzdem BESTEN Dank, endlich ein Ansatz :)

      Gruß
      Bob

      @HenryV, Sonderlob für Formatierung + Verweis auf Microsoft Internet Controls. Solche Beiträge sind sehr hilfreich, und ohne Probleme umzusetzten. DANKE.

      Beiträge zusammengefügt. ~Trade

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

      Bob_Der_Bert schrieb:

      Sonderlob
      Dafür gibt es hier den Hilfreich-Button. ;)
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!