使用此代码:
internal static List<DetectedWindow> EnumerateWindows()
{
var shellWindow = GetShellWindow();
var windows = new List<DetectedWindow>();
EnumWindows(delegate (IntPtr handle, int lParam)
{
if (handle == shellWindow)
return true;
if (!IsWindowVisible(handle))
return true;
if (IsIconic(handle))
return true;
var length = GetWindowTextLength(handle);
if (length == 0)
return true;
var builder = new StringBuilder(length);
GetWindowText(handle, builder, length + 1);
GetWindowRect(handle, out Rect rect);
windows.Add(new DetectedWindow(handle, rect.ToRect(), builder.ToString()));
return true;
}, IntPtr.Zero);
return windows;
}
熟悉的课程:
public class DetectedWindow
{
public IntPtr Handle { get; private set; }
public Rect Bounds { get; private set; }
public string Name { get; private set; }
public DetectedWindow(IntPtr handle, Rect bounds, string name)
{
Handle = handle;
Bounds = bounds;
Name = name;
}
}
我正在获取此应用程序列表(窗口文本 - Rect
边界):
Microsoft Visual Studio - -8;-8;1936;1056
Microsoft Edge - 0;77;1920;963
EnumWindows - Stack Overflow and 7 more pages - Microsoft Edge - -8;-8;1936;1056
Microsoft Edge - 0;77;1920;963
Microsoft Edge - 0;77;1920;963
Microsoft Edge - 0;0;1920;1080
Microsoft Edge - 0;0;1920;1080
Microsoft Edge - 0;8;1920;1040
Microsoft Edge - 0;85;1920;963
Microsoft Edge - 150;79;1532;42
Microsoft Edge - 0;85;1920;963
Microsoft Edge - 0;77;1920;963
Microsoft Edge - 0;85;1920;963
Microsoft Edge - 0;213;1920;964
Microsoft Edge - 0;0;1920;1080
Microsoft Edge - 484;208;952;174
Microsoft Edge - 0;84;1920;964
Microsoft Edge - 0;84;1920;964
Microsoft Edge - 0;84;1920;964
Microsoft Edge - 0;0;1920;1080
Mail - 0;32;1356;693
Mail - 278;252;1372;733
OneNote - 0;8;1920;1040
My notes - OneNote - -8;-8;1936;1056
Photos - 0;32;1920;1008
Photos - -8;-8;1936;1056
Skype - 0;40;1920;1008
Skype - -8;-8;1936;1056
Store - 0;40;1920;1008
Store - -8;-8;1936;1056
Movies & TV - 0;0;1920;1080
Movies & TV - -8;-8;1936;1056
Groove Music - 0;32;1466;712
Groove Music - -7;3;1372;733
Settings - 0;40;1920;1008
Settings - -8;-8;1936;1056
Windows Shell Experience Host - 0;0;1920;1080
我当前的不最小化窗口是 Visual Studio和两个Edge窗口(每个窗口都有几个标签)。我可以理解只有一个Edge项目列出了当前页面的标题。因为我最近从崩溃中恢复过来,只加载了该页面。
我的问题是:
编辑:
我试图让每个窗口的WsStyle和WsEXStyle进行比较,但我找不到任何区别。
方法IsWindowVisible()
无法过滤掉不可见的Windows应用商店应用。
答案 0 :(得分:10)
为什么我的已关闭的Windows应用商店应用会被列出?
因为它们实际上并未关闭。使用任务管理器,进程选项卡轻松查看。您将看到拥有这些窗口的进程已暂停。作为WinRT(又名UWP,又称Store,又名现代UI,又名Metro)编程框架方法的一部分,现代机器具有足够的RAM,使得即使用户不与它们交互也能保持进程运行。再次快速将它们带回来并节省电池寿命。如果在其他地方需要RAM,那么操作系统将通过杀死这样一个过程来挽救它。
为什么要列出我的Edge标签?
因为Edge也是一个WinRT应用程序。
如何过滤Edge标签和已关闭的Windows应用商店应用?
由于窗口实际上未关闭,因此您想要过滤哪个属性并不完全清楚。 GetWindowThreadProcessId()和IsImmersiveProcess()可以告诉您正在处理这样的过程。考虑IsWindowVisible()。也许this post可以提供帮助,也会告诉您为什么会看到多个窗口。
编辑(Nicke Manarin):
通过检查Cloacked属性,可以忽略隐藏/后台Store应用程序:
DwmGetWindowAttribute(handle, (int)DwmWindowAttribute.Cloaked, out bool isCloacked, Marshal.SizeOf(typeof(bool)));
if (isCloacked)
return true;
编辑2(Nicke Manarin):
每个Edge选项卡的行为都像一个窗口(我相信它与您可以拖动选项卡以创建新窗口这一事实有关。)
答案 1 :(得分:3)
我无法重现W10桌面中的行为。使用您的代码后,同样过滤掉WsEXStyle WS_EX_TOOLWINDOW,显示的应用程序与alt + tab相同。我打开并关闭了边缘和照片,它们在关闭时没有出现。也许正在修补P / Invoke触发了这种行为。重启后是否继续使用以下代码?。
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApp1
{
public class EnumerateWindowsTest
{
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, out Rect lpRect);
[DllImport("user32.dll")]
static extern IntPtr GetShellWindow();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
public delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.dll")]
static extern int EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern System.UInt32 GetWindowLong(IntPtr hWnd, int nIndex);
internal static List<DetectedWindow> EnumerateWindows()
{
var shellWindow = GetShellWindow();
var windows = new List<DetectedWindow>();
EnumWindows(delegate (IntPtr handle, IntPtr lParam)
{
if (handle == shellWindow)
return true;
if (!IsWindowVisible(handle))
return true;
if (IsIconic(handle))
return true;
if (HasSomeExtendedWindowsStyles(handle))
return true;
var length = GetWindowTextLength(handle);
if (length == 0)
return true;
var builder = new StringBuilder(length);
GetWindowText(handle, builder, length + 1);
GetWindowRect(handle, out Rect rect);
windows.Add(new DetectedWindow(handle, rect, builder.ToString()));
return true;
}, IntPtr.Zero);
return windows;
}
static bool HasSomeExtendedWindowsStyles(IntPtr hwnd)
{
const int GWL_EXSTYLE = -20;
const uint WS_EX_TOOLWINDOW = 0x00000080U;
uint i = GetWindowLong(hwnd, GWL_EXSTYLE);
if ((i & (WS_EX_TOOLWINDOW)) != 0)
{
return true;
}
return false;
}
}
public class DetectedWindow
{
public IntPtr Handle { get; private set; }
public EnumerateWindowsTest.Rect Bounds { get; private set; }
public string Name { get; private set; }
public DetectedWindow(IntPtr handle, EnumerateWindowsTest.Rect bounds, string name)
{
Handle = handle;
Bounds = bounds;
Name = name;
}
}
class Program
{
static void DetectWindows()
{
foreach (DetectedWindow w in EnumerateWindowsTest.EnumerateWindows())
{
Console.WriteLine("{0} - {1};{2};{3};{4}",w.Name,w.Bounds.Left,w.Bounds.Top,w.Bounds.Right,w.Bounds.Bottom);
}
}
static void Main(string[] args)
{
DetectWindows();
Console.ReadLine();
}
}
}
答案 2 :(得分:0)
我制作了简单的窗口过滤器方法,其中包括隐藏的 Microsoft 商店应用程序。它们也由类名 ApplicationFrameWindow 和 Windows.UI.Core.CoreWindow 标识
public static class WindowFilter
{
public static bool NormalWindow(IWindow window)
{
if (IsHiddenWindowStoreApp(window, window.ClassName)) return false;
return !window.Styles.IsToolWindow && window.IsVisible;
}
private static bool IsHiddenWindowStoreApp(IWindow window, string className)
=> (className == "ApplicationFrameWindow" || className == "Windows.UI.Core.CoreWindow") && window.IsCloaked;
}
上面的例子是github的一个项目的一部分,你可以看到其余的代码。 https://github.com/mortenbrudvik/WindowExplorer