web-dev-qa-db-fra.com

Comment puis-je obtenir les fenêtres enfants d'une fenêtre étant donné son HWND?

J'ai la poignée pour une fenêtre donnée. Comment puis-je énumérer ses fenêtres enfants?

26
Yuriy Faktorovich

J'ai trouvé que la meilleure solution était WindowsAPI managé . Il avait un contrôle CrossHair qui pouvait être utilisé pour sélectionner une fenêtre (ne faisant pas partie de la question) et une méthode AllChildWindows pour obtenir toutes les fenêtres enfants qui enveloppaient probablement la fonction EnumChildWindows. Mieux vaut ne pas réinventer la roue.

7
Yuriy Faktorovich

Ici vous avez une solution de travail:

public class WindowHandleInfo
{
    private delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam);

    [DllImport("user32")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam);

    private IntPtr _MainHandle;

    public WindowHandleInfo(IntPtr handle)
    {
        this._MainHandle = handle;
    }

    public List<IntPtr> GetAllChildHandles()
    {
        List<IntPtr> childHandles = new List<IntPtr>();

        GCHandle gcChildhandlesList = GCHandle.Alloc(childHandles);
        IntPtr pointerChildHandlesList = GCHandle.ToIntPtr(gcChildhandlesList);

        try
        {
            EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
            EnumChildWindows(this._MainHandle, childProc, pointerChildHandlesList);
        }
        finally
        {
            gcChildhandlesList.Free();
        }

        return childHandles;
    }

    private bool EnumWindow(IntPtr hWnd, IntPtr lParam)
    {
        GCHandle gcChildhandlesList = GCHandle.FromIntPtr(lParam);

        if (gcChildhandlesList == null || gcChildhandlesList.Target == null)
        {
            return false;
        }

        List<IntPtr> childHandles = gcChildhandlesList.Target as List<IntPtr>;
        childHandles.Add(hWnd);

        return true;
    }
}

Comment le consommer:

class Program
{
    [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
    public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

    static void Main(string[] args)
    {
        Process[] anotherApps = Process.GetProcessesByName("AnotherApp");
        if (anotherApps.Length == 0) return;
        if (anotherApps[0] != null)
        {
            var allChildWindows = new WindowHandleInfo(anotherApps[0].MainWindowHandle).GetAllChildHandles();
        }
    }
}
22
Caffé

En utilisant:

internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);

[DllImport("user32.dll")]
internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);

vous obtiendrez des rappels sur la fonction que vous transmettez.

11
Grzenio

Utilisez EnumChildWindows, avec p/invoke. Voici un lien intéressant sur certains de ses comportements: https://blogs.msdn.Microsoft.com/oldnewthing/20070116-04/?p=2839

Si vous ne connaissez pas le handle de la fenêtre, mais seulement son titre, vous devrez utiliser EnumWindows. http://pinvoke.net/default.aspx/user32/EnumWindows.html

6
John Fisher

Voici une alternative gérée à EnumWindows, mais vous devrez toujours utiliser EnumChildWindows pour trouver le handle de la fenêtre enfant.

foreach (Process process in Process.GetProcesses())
{
   if (process.MainWindowTitle == "Title to find")
   {
      IntPtr handle = process.MainWindowHandle;

      // Use EnumChildWindows on handle ...
   }
}
3
Special Touch