获取所有打开的窗口

时间:2015-01-27 19:16:21

标签: c# wpf multithreading

我正在开发一个WPF应用程序,我需要一种方法来获取应用程序中的所有打开的窗口,包括从另一个线程打开的窗口。我试过了Application.Current.Windows,但这并没有给我从另一个线程打开的窗口。甚至可以访问另一个线程打开的窗口?不应该所有窗口都在同一个应用程序域中吗?

感谢。

3 个答案:

答案 0 :(得分:7)

这应该这样做。它将返回给定应用程序名称的每个打开窗口的整数指针列表:

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;
}

现在作为评论者之一,您不应该有多个线程在进行GUI工作。一个线程应该进行GUI绘图,而其他线程执行实际的其他工作。

答案 1 :(得分:3)

Window类检查当前应用程序的调度程序是当前线程的调度程序,如果是,则将其添加到Windows集合中。看起来这些其他窗口在公共集合中不公开,但ApplicationNonAppWindowsInternal上有一个具有窗口的内部属性。

我总是在单个UI线程上创建UI对象。如果这样做,您将可以通过Application.Current.Windows访问所有Window对象。

答案 2 :(得分:1)

我不确定这个解决方案,但我发现它最接近一个。

尝试获取程序:

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);
    }
}

如果这没有帮助,请尝试使用Process.GetProcessesByName(“ApplicationName”)并查看它返回的内容。

查看this solutionMSDN class page以及其中的可用方法也可能有所帮助。