EnumWindows返回已关闭的Windows应用商店应用程序

时间:2017-05-11 23:31:35

标签: c# winapi

使用此代码:

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应用商店应用?
  4. 编辑:

    1. 通过“过滤器”:仅检索具有可见窗口的应用程序。使用我的用例,只能看到3个窗口。
    2. 我试图让每个窗口的WsStyle和WsEXStyle进行比较,但我找不到任何区别。

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

3 个答案:

答案 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