Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get ALL open windows

I am working on a WPF application and I need a way to get all the open windows within the application, including the ones that have been opened from another thread. I tried Application.Current.Windows but this does not give me the windows that have been opened from another thread. Is it even possible to access the windows opened by another thread? Shouldn't all the windows be in the same Application Domain?

Thanks.

like image 700
Arm0geddon Avatar asked Dec 14 '22 17:12

Arm0geddon


1 Answers

This should do it. It will return a list of integer pointers to each open window of the given application name:

public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);

[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);

static void Main(string[] args)
{
    Process[] processes = Process.GetProcessesByName("MyApp");

    var windows = new List<IntPtr>();

    foreach (Process p in processes)
    {
        IEnumerable<IntPtr> w = GetRootWindowsOfProcess(p.Id);
        windows.AddRange(w);
    }
}

private static IEnumerable<IntPtr> GetRootWindowsOfProcess(int pid)
{
    IEnumerable<IntPtr> rootWindows = GetChildWindows(IntPtr.Zero);
    var dsProcRootWindows = new List<IntPtr>();
    foreach (IntPtr hWnd in rootWindows)
    {
        uint lpdwProcessId;
        GetWindowThreadProcessId(hWnd, out lpdwProcessId);
        if (lpdwProcessId == pid)
            dsProcRootWindows.Add(hWnd);
    }
    return dsProcRootWindows;
}

private static IEnumerable<IntPtr> GetChildWindows(IntPtr parent)
{
    var result = new List<IntPtr>();
    GCHandle listHandle = GCHandle.Alloc(result);
    try
    {
        var childProc = new Win32Callback(EnumWindow);
        EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
    }
    finally
    {
        if (listHandle.IsAllocated)
            listHandle.Free();
    }
    return result;
}

private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
    GCHandle gch = GCHandle.FromIntPtr(pointer);
    var list = gch.Target as List<IntPtr>;
    if (list == null)
    {
        throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
    }
    list.Add(handle);
    //  You can modify this to check to see if you want to cancel the operation, then return a null here
    return true;
}

Now as one of the commenter's mentioned, you shouldn't have multiple threads doing GUI work. One thread should be doing the GUI drawing while other threads do the actual other work.

like image 196
Icemanind Avatar answered Jan 06 '23 12:01

Icemanind