【问题标题】:EnumWindows returns closed Windows Store applicationsEnumWindows 返回关闭的 Windows 应用商店应用程序
【发布时间】:2017-05-11 23:31:34
【问题描述】:

使用此代码:

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 项目列出了当前页面的标题。因为我最近从崩溃中恢复过来,只加载了那个页面。

我的问题是:

  1. 为什么列出了我的关闭 Windows 应用商店应用程序? (甚至两次)
  2. 为什么会列出我的 Edge 选项卡?
  3. 如何过滤 Edge 选项卡和关闭的 Windows 应用商店应用?

编辑:

  1. 通过“过滤器”:仅检索具有可见窗口的应用程序。在我的用例中,只有 3 个窗口可见。

我试图让每个窗口的 WsStyle 和 WsEXStyle 进行比较,但我找不到任何区别。

IsWindowVisible() 方法无法过滤掉不可见的 Windows 应用商店应用。

【问题讨论】:

标签: c# winapi


【解决方案1】:

为什么列出了我关闭的 Windows 应用商店应用程序?

因为它们实际上并没有关闭。使用任务管理器,进程选项卡易于查看。您会看到拥有这些窗口的进程被暂停。作为 WinRT(又名 UWP,又名 Store,又名 Modern UI,又名 Metro)编程框架方法的一部分,现代机器具有足够的 RAM,即使用户不与它们交互,也可以保持进程运行。让它们再次快速恢复并节省电池寿命。如果其他地方需要 RAM,则操作系统将通过终止此类进程来挽救它。

为什么列出了我的 Edge 选项卡?

因为 Edge 也是一个 WinRT 应用程序。

如何过滤 Edge 选项卡和关闭的 Windows 应用商店应用?

鉴于窗口实际上并未关闭,因此您要过滤哪个属性并不完全清楚。 GetWindowThreadProcessId() 和 IsImmersiveProcess() 可以告诉您您正在处理这样一个进程。考虑 IsWindowVisible()。也许this post 可以提供帮助,还可以告诉您为什么会看到多个窗口。


编辑(尼克·马纳林):

通过检查 Cloacked 属性,可以忽略隐藏/后台商店应用程序:

DwmGetWindowAttribute(handle, (int)DwmWindowAttribute.Cloaked, out bool isCloacked, Marshal.SizeOf(typeof(bool)));

if (isCloacked)
    return true;

编辑 2(Nicke Manarin):

每个 Edge 选项卡的行为都像一个窗口(我相信这与您可以拖动选项卡以创建新窗口有关)。

【讨论】:

  • 1) 是的,但为什么要两次? 2)也许我得到了很多边缘项目,因为每个选项卡都像一个窗口一样,所以它可以被拖动...... 3)我想从我的列表中删除这些条目,我只想得到可见的窗口。如您所见,我已经在使用 IsWindowVisible(),但我正在获取这些应用程序。
  • 隐藏窗口从 IsWindowVisible() 返回 TRUE,但实际上不可见。不幸的是。
【解决方案2】:

我无法在我的 W10 Desktop 中重现该行为。使用您的代码后,还过滤掉 WsEXStyle WS_EX_TOOLWINDOW,显示与 alt+tab 相同的应用程序。我打开并关闭了 Edge 和 Photos,它们在关闭时不再出现。也许是修改了触发该行为的 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();
        }
    }


}

【讨论】:

  • 问题是我也想要工具窗口,而不仅仅是普通窗口。
  • 工具窗口是什么意思,有例子吗?
  • 启用了扩展样式 WS_EX_TOOLWINDOW 的窗口。此设置更改窗口的标题栏 UI。示例:i.stack.imgur.com/TYYek.jpg(背景:普通窗口,前景:工具窗口)
  • 如果我注释掉“if (HasSomeExtendedWindowsStyles(handle)) return true;”这行,包括 WS_EX_TOOLWINDOW ,其他窗口会出现,但我仍然看不到你提到的行为。
  • 现在我也没有。我不确定是什么触发了 Cloaked 行为。但它看起来只有在商店应用程序在后台运行时才会发生。
【解决方案3】:

我制作了简单的窗口过滤器方法,其中包括隐藏的 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-02
    相关资源
    最近更新 更多