4

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.

Arm0geddon
  • 466
  • 11
  • 30

3 Answers3

8

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.

Icemanind
  • 47,519
  • 50
  • 171
  • 296
3

The Window class checks that the current application's dispatcher is the current thread's dispatcher, if it is then it is added to the Windows collection. It doesn't look like these other windows are exposed in a public collection but there is an internal property on Application, NonAppWindowsInternal that has the windows.

I would always create UI objects on a single UI thread. If you do so, you will have access to all the Window objects via Application.Current.Windows.

Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
  • @user1274820 Windows and Controls do not have `Invoke` in WPF. You would want to do something like `Application.Current.Dispatcher.Invoke` or `this.Dispatcher.Invoke`. – Mike Zboray Jan 27 '15 at 19:41
1

I'm unsure of this solution but it is what I found to be the closest to one.

Try getting the proceses:

using System.Diagnostics;

Process[] processlist = Process.GetProcesses();

foreach (Process process in processlist)
{
    if (!String.IsNullOrEmpty(process.MainWindowTitle))
    {
        Console.WriteLine("Process: {0} ID: {1} Window title: {2}", process.ProcessName, process.Id, process.MainWindowTitle);
    }
}

If this doesn't help, try using Process.GetProcessesByName("ApplicationName") and see what it returns.

It may also help to look at this solution and the MSDN class page and the available methods in it.

Community
  • 1
  • 1
AzzamAziz
  • 2,144
  • 1
  • 24
  • 34