Ordner öffnen (Process.Start) --> mainWindowhandle herrausfinden

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von Mokki.

    Ordner öffnen (Process.Start) --> mainWindowhandle herrausfinden

    Hi,
    Ich möchte in meinem Programm einen Ordner öffnen und dann auf das geöffnete Fenster zugreifen. Dafür benutz ich folgendes:

    C#-Quellcode

    1. processOrdner = new Process();
    2. processOrdner.StartInfo = new ProcessStartInfo("explorer.exe")
    3. {
    4. FileName = path,
    5. UseShellExecute = true,
    6. Verb = "open"
    7. };
    8. processOrdner.EnableRaisingEvents = true;
    9. processOrdner.Start();
    10. foreach (ProcessListDemo.Window w in win.lstWindows)
    11. {
    12. if (w.winHandle == processOrdner.MainWindowHandle)
    13. {
    14. o.WindowSettings = w;
    15. }
    16. }


    Wenn ich allerdings au den MainWindowhandle zugreifen will kommt folgende Fehlermeldung:

    Ein Ausnahmefehler des Typs "System.InvalidOperationException" ist in System.dll aufgetreten.
    Zusätzliche Informationen: Diesem Objekt ist kein Prozess zugeordnet.

    Kann mir jemand sagen wie ich den MainWindowHandle des Explorerfensteres bekomme?

    Danke schon mal

    LG Wolf

    Rote Farbe entfernt. ~Trade

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

    @Wolf066 Wenn Du uns noch mitteilst, was win und o ist, können wir Dein Problem sogar nachvollziehen. ;)
    =======
    Es ist so:
    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!

    Wolf066 schrieb:

    Ich möchte in meinem Programm einen Ordner öffnen und dann auf das geöffnete Fenster zugreifen


    Dafuer musst du nicht extra einen Explorer starten, schau mal im taskmanager was passiert, starte 20 mal den explorer. Wenn man einen Ordner oeffnen lassen moechte, reicht der Ordnerpfad als parameter bei Process.Start() aus. Ich habe im Beispiel unten bewusst einen Process deklariert anstatt Process.Start(), denn scheinbar ist mit Process.Start() das Fenster noch nicht da.

    C#-Quellcode

    1. class X_Files
    2. {
    3. [DllImport("user32.dll")]
    4. private static extern int GetWindowText(IntPtr hwnd, System.Text.StringBuilder lpString, int cch);
    5. [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    6. private static extern int GetWindowTextLength(IntPtr hwnd);
    7. [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    8. private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    9. [DllImport("User32.dll")]
    10. private static extern bool EnumChildWindows(IntPtr WindowHandle, EnumWindowProcess Callback, IntPtr lParam);
    11. private delegate bool EnumWindowProcess(IntPtr Handle, IntPtr Parameter);
    12. private static IntPtr[] GetChildWindows(IntPtr ParentHandle)
    13. {
    14. List<IntPtr> ChildrenList = new List<IntPtr>();
    15. GCHandle ListHandle = GCHandle.Alloc(ChildrenList);
    16. try
    17. {
    18. EnumChildWindows(ParentHandle, EnumWindow, GCHandle.ToIntPtr(ListHandle));
    19. }
    20. finally
    21. {
    22. if (ListHandle.IsAllocated)
    23. {
    24. ListHandle.Free();
    25. }
    26. }
    27. return ChildrenList.ToArray();
    28. }
    29. private static bool EnumWindow(IntPtr Handle, IntPtr Parameter)
    30. {
    31. List<IntPtr> ChildrenList = (global::System.Collections.Generic.List<global::System.IntPtr>)GCHandle.FromIntPtr(Parameter).Target;
    32. if (ChildrenList == null)
    33. {
    34. throw new Exception("GCHandle Target could not be cast as List(Of IntPtr)");
    35. }
    36. ChildrenList.Add(Handle);
    37. return true;
    38. }
    39. private static string GetText(IntPtr hWnd)
    40. {
    41. int length = 0;
    42. if (hWnd == IntPtr.Zero)
    43. {
    44. return null;
    45. }
    46. length = GetWindowTextLength(hWnd);
    47. if (length == 0)
    48. {
    49. return null;
    50. }
    51. System.Text.StringBuilder sb = new System.Text.StringBuilder("", length);
    52. GetWindowText(hWnd, sb, sb.Capacity + 1);
    53. return sb.ToString();
    54. }
    55. public static IntPtr OpenExplorerAndGetHandle(string folder)
    56. {
    57. folder = folder.Replace("/", "\\");
    58. if (!folder.EndsWith("\\"))
    59. {
    60. folder += "\\";
    61. }
    62. using (Process p = new Process())
    63. {
    64. p.StartInfo.FileName = folder;
    65. p.Start();
    66. }
    67. string folderName = new System.IO.DirectoryInfo(folder).Name;
    68. IntPtr hwnd = FindWindow("CabinetWClass", folderName);
    69. if (hwnd == IntPtr.Zero)
    70. {
    71. return IntPtr.Zero;
    72. }
    73. IntPtr[] hwnds = GetChildWindows(hwnd);
    74. foreach (IntPtr handle in hwnds)
    75. {
    76. string windowText = GetText(handle);
    77. if ((windowText != null))
    78. {
    79. string tmpFolderPath = folder.Substring(0, folder.Length - 1).ToLower();
    80. if (windowText.ToLower().Contains(tmpFolderPath))
    81. {
    82. return handle;
    83. }
    84. }
    85. }
    86. return IntPtr.Zero;
    87. }
    88. }

    And i think to myself... what a wonderfuL World!
    Ein Hinweis:

    VB.NET-Quellcode

    1. Dim P As New Process
    2. P.StartInfo.FileName = "notepad.exe"
    3. P.Start()
    4. 'Zu diesem Zeitpunkt muss das Fenster noch nicht geöffnet sein!
    5. P.WaitForInputIdle() 'Wartet, bis der Prozess die Nachrichtenschleife ausführt.
    6. 'Sobald diese Stelle erreicht wurde hat der notepad-Prozess das Fenster geöffnet (und wartet auf Benutzereingaben). Ab jetzt sollte P.MainWindowHandle funktionieren.


    Beim Explorer ist das etwas schwieriger. Da hat man nicht unbedingt einen Prozess pro offenem Fenster (das kann man in den Ordneroptionen einstellen) und deshalb funktioniert MainWindowHandle auch nicht unbedingt wie erwartet.
    Was genau möchtest Du denn im Explorer machen?
    Wenn Du nur eine Datei markieren willst, geht das auch, indem man explorer.exe /select "C:\Foo\Bar.txt" ausführt.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Ich denke mal das es hier

    C#-Quellcode

    1. folder = folder.Replace("/", "\\");
    2. if (!folder.EndsWith("\\"))
    3. {
    4. folder += "\\";
    5. }

    oder hier klemmt

    C#-Quellcode

    1. string tmpFolderPath = folder.Substring(0, folder.Length - 1).ToLower();


    Ich hatte das mit VB, hab es mit einem Converter in C# uebersetzt. Ueberpuefe ob der Pfads auch gueltig ist u.U. auch noch mal mit Spy++ nachschauen.
    And i think to myself... what a wonderfuL World!
    Ich habe auch noch mal mit Spy++ geschaut, das Problem tritt bei mir nur auf, wenn ich ein Root-Directory angebe, bei allen anderen Ordner gehts.

    C#-Quellcode

    1. string folderName = new System.IO.DirectoryInfo(folder).Name;

    Hier bekommen wir wenn wir C:\ als Parameter mitgeben auch C:\ heraus, in Spy++ konnte ich sehen das der WindowText aber(bei mir) Sys (C:) ist, also das VolumeLabel steht mit drin, das must du noch ausbessern. Einfach mal Step by Step debuggen.
    Bilder
    • Unbenannt.png

      4,05 kB, 296×117, 141 mal angesehen
    And i think to myself... what a wonderfuL World!
    @Eddy Hättest Du mal probieren sollen.
    Bei W10 passiert da nix:
    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 hab dir zwar ev ne Erklärung aber keine Lösung (sry): Der Explorerprozess läuft auch wenn du garkein Fenster offen hast(wegen dem Desktop, Windowsapps usw.), deshalb hat er kein Fenster.


    Lg Mokki
    ​Smartnotr - ein intelligentes Notizprogramm
    zum Thread

    OK... Also ich hab jetzt die Lösung die für Fast alles funktioniert bis auf die Ordner die nicht den gleichen Namen als Fenster titel haben. Also z.B. Dokumente: Dokumente ist der Fenstertitel... Documents steht im Pfad.

    C#-Quellcode

    1. ​ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    2. private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    3. /// <summary>
    4. /// Öffnet einen Ordner und gibt den Window-Handle zurück
    5. /// </summary>
    6. /// <param name="path"></param>
    7. /// <returns></returns>
    8. public IntPtr OpenFolderGetHandle(string path)
    9. {
    10. path = path.Replace("/", "\\");
    11. if (!path.EndsWith("\\"))
    12. {
    13. path += "\\";
    14. }
    15. using (Process p = new Process())
    16. {
    17. p.StartInfo.FileName = path;
    18. p.Start();
    19. }
    20. Thread.Sleep(150);
    21. IntPtr handle = getFolderHandle(path);
    22. return handle;
    23. }
    24. /// <summary>
    25. /// Gibt den Window-Handle eines Ordners zurück --> wenn Ordner geöffnet
    26. /// </summary>
    27. /// <param name="path"></param>
    28. /// <returns></returns>
    29. public IntPtr getFolderHandle(string path)
    30. {
    31. path = path.Replace("/", "\\");
    32. if (path.EndsWith("\\"))
    33. {
    34. path = path.Substring(0, path.Length - 1);
    35. }
    36. IntPtr handle = new IntPtr();
    37. string folderName = System.IO.Path.GetFileNameWithoutExtension(path) + System.IO.Path.GetExtension(path);
    38. handle = FindWindow(null, folderName);
    39. return handle;
    40. }


    Hat jemand ne Idee wie ich diese Ordner herrausfinde und dann den Pfad anpasse?

    Danke schonmal für alle bisherigen Antworten...

    LG Wolf