wpf 获取所有打开的窗口
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28178254/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get ALL open windows
提问by Arm0geddon
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.Windowsbut 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?
我正在开发一个 WPF 应用程序,我需要一种方法来获取应用程序中所有打开的窗口,包括从另一个线程打开的窗口。我试过了,Application.Current.Windows但这并没有给我从另一个线程打开的窗口。甚至可以访问由另一个线程打开的窗口吗?不应该所有的窗口都在同一个应用程序域中吗?
Thanks.
谢谢。
回答by Icemanind
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.
现在正如评论者之一提到的,您不应该有多个线程来执行 GUI 工作。一个线程应该进行 GUI 绘图,而其他线程则执行实际的其他工作。
回答by Mike Zboray
The Windowclass checks that the current application's dispatcher is the current thread's dispatcher, if it is then it is added to the Windowscollection. It doesn't look like these other windows are exposed in a public collection but there is an internal property on Application, NonAppWindowsInternalthat has the windows.
本Window类检查当前应用程序的调度是当前线程的调度,如果是则加入到Windows集合。看起来这些其他窗口并未公开在公共集合中,但是 上有一个内部属性Application,NonAppWindowsInternal该属性包含这些窗口。
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.
我总是在单个 UI 线程上创建 UI 对象。如果这样做,您将可以通过Application.Current.Windows.
回答by AzzamAziz
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.
如果这没有帮助,请尝试使用 Process.GetProcessesByName("ApplicationName") 并查看它返回的内容。
It may also help to look at this solutionand the MSDN class pageand the available methods in it.

