獲取Windows正在執行的視窗程序

2022-08-28 18:01:03

主要是獲取Alt+Tab中展示的視窗

原理主要是獲取視窗的樣式來判斷是否會在Alt+Tab中顯示

具體程式碼如下

/// <summary>
        /// Alt+Tab 應用
        /// </summary>
        /// <param name="hWnd"></param>
        /// <returns></returns>
        public static bool IsAltTabWindow(IntPtr hWnd)
        {
            // The window must be visible
            if (!IsWindowVisible(hWnd))
                return false;

            // The window must be a root owner
            if (GetAncestor(hWnd, GA_ROOTOWNER) != hWnd)
                return false;

            // The window must not be cloaked by the shell
            DwmGetWindowAttribute(hWnd, DwmWindowAttribute.DWMWA_CLOAKED, out int cloaked, sizeof(uint));
            if (cloaked == DWM_CLOAKED_SHELL)
                return false;

            // The window must not have the extended style WS_EX_TOOLWINDOW
            int style = Utils.Win32Api.GetWindowLong(hWnd, GWL_EXSTYLE);
            if ((style & WS_EX_TOOLWINDOW) != 0)
                return false;

            return true;
        }

 [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool IsWindowVisible(IntPtr hWnd);

 [DllImport("user32.dll")]
        public static extern IntPtr GetAncestor(IntPtr hWnd, uint gaFlags);
 [DllImport("dwmapi.dll")]
        public static extern int DwmGetWindowAttribute(IntPtr hwnd, DwmWindowAttribute dwAttribute, out int attrValue, int cbAttribute);

const uint DWM_CLOAKED_SHELL = 0x00000002;
        const uint GA_ROOTOWNER = 3;

        const uint WS_EX_TOPMOST = 0x00000008;


[Flags]
    public enum DwmWindowAttribute : uint
    {
        DWMWA_NCRENDERING_ENABLED = 1,
        DWMWA_NCRENDERING_POLICY,
        DWMWA_TRANSITIONS_FORCEDISABLED,
        DWMWA_ALLOW_NCPAINT,
        DWMWA_CAPTION_BUTTON_BOUNDS,
        DWMWA_NONCLIENT_RTL_LAYOUT,
        DWMWA_FORCE_ICONIC_REPRESENTATION,
        DWMWA_FLIP3D_POLICY,
        DWMWA_EXTENDED_FRAME_BOUNDS,
        DWMWA_HAS_ICONIC_BITMAP,
        DWMWA_DISALLOW_PEEK,
        DWMWA_EXCLUDED_FROM_PEEK,
        DWMWA_CLOAK,
        DWMWA_CLOAKED,
        DWMWA_FREEZE_REPRESENTATION,
        DWMWA_LAST
    }
 /// <summary>
        /// 獲取表單控制程式碼
        /// </summary>
        /// <param name="hwnd"></param>
        /// <param name="nIndex"></param>
        /// <returns></returns>
        [DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]
        public static extern int GetWindowLong(IntPtr hwnd, int nIndex);

const int GWL_EXSTYLE = -20;//得到擴充套件的視窗風格
    public const int WS_EX_TOOLWINDOW = 0x00000080;

  以上方式對於全螢幕的UWP視窗時無法獲取得到的,因此需要引入以下方式獲取全螢幕UWP視窗

/// <summary>
        /// 全螢幕的UWP應用
        /// </summary>
        /// <param name="hWnd"></param>
        /// <returns></returns>
        public  static  bool IsFullScreenUwpWindows(IntPtr hWnd)
        {
            // Get the extended style of the window
            var style = GetWindowLong(hWnd, GWL_EXSTYLE);

            // The window must have the extended style WS_EX_TOPMOST
            if ((style & WS_EX_TOPMOST) == 0)
                return false;

            // The window must not have the extended style WS_EX_NOACTIVATE
            if ((style & WS_EX_NOACTIVATE) != 0)
                return false;

            // The window must not have the extended style WS_EX_TOOLWINDOW
            if ((style & WS_EX_TOOLWINDOW) != 0)
                return false;

            return true;
        }

public const int WS_EX_NOACTIVATE = 0x08000000;

然後通過列舉視窗的方式就可以獲取到所有視窗了

/// <summary>
        /// 列舉表單的回撥
        /// </summary>
        /// <param name="hwnd"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        public delegate bool EnumWindowsCallBack(IntPtr hwnd, IntPtr lParam);
        /// <summary>
        /// 列舉出表單
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        [DllImport("user32")]
        public static extern int EnumWindows(EnumWindowsCallBack x, IntPtr y);

 /// <summary>
        /// 列舉子視窗
        /// </summary>
        /// <param name="hWndParent"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        [DllImport("user32")]
        public static extern int EnumChildWindows(IntPtr hWndParent, EnumWindowsCallBack x, IntPtr y);
 List<KeyValuePair<IntPtr, string>> handles = new List<KeyValuePair<IntPtr, string>>();
            EnumWindows((hWnd, lPam) =>
            {
                if (!IsAltTabWindow(hWnd)) return true;//繼續列舉
                var title = GetWindowTitle(hWnd);
                handles.Add(new KeyValuePair<IntPtr, string>(hWnd, title));
                return true;//繼續列舉
            }, IntPtr.Zero);

            EnumChildWindows(GetDesktopWindow(), (hWnd, lPam) =>
            {
                if (handles.Any(kv => kv.Key == hWnd)||!IsFullScreenUwpWindows(hWnd)) return true;//繼續列舉
                var title = GetWindowTitle(hWnd);
                handles.Add(new KeyValuePair<IntPtr, string>(hWnd, title));
                return true;//繼續列舉
            }, IntPtr.Zero);







[DllImport("user32.dll")]
        public static extern IntPtr GetDesktopWindow();
/// <summary>
        /// 獲取表單的名稱
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="lpString"></param>
        /// <param name="nMaxCount"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern int GetWindowTextW(IntPtr hWnd, IntPtr lpString, int nMaxCount);

/// <summary>
        /// 預設獲取字串的長度
        /// </summary>
        private const int NumChars = 256;
        public static string GetWindowTitle(IntPtr hwnd)
        {
            IntPtr intPtr = Marshal.AllocHGlobal(NumChars);
            Utils.Win32Api.GetWindowTextW(hwnd, intPtr, 100);
            var s = Marshal.PtrToStringUni(intPtr);
            Marshal.FreeHGlobal(intPtr);
            return s;
        }

以上程式碼需要做調整才能執行起來,有空我補上完整程式碼

參考:https://stackoverflow.com/questions/72069771/show-a-list-of-all-alttab-windows-even-full-screen-uwp-windows-and-retrieve