午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

ウィンドウのタイトルバー情報を取得するWinAPIのGetTitleBarInfoを使ってみた、WPF、C#

ウィンドウのタイトルバー情報を取得

WinAPIのGetTitleBarInfo関数を使う
docs.microsoft.com

BOOL GetTitleBarInfo( HWND hwnd, PTITLEBARINFO pti );


よくわからんけど、取得したいウィンドウのハンドルを渡すとPTITLEBARINFOに情報が入ってくるみたい


TITLEBARINFO構造

docs.microsoft.com

インデックス タイトルバー要素
0 タイトルバー自体。
1 予約済み。
2 最小化ボタン。
3 最大化ボタン。
4 ヘルプボタン。
5 閉じるボタン。

インデックス1番の予約済みってのがわからんけど、それ以外はそのままだねえ、で、それぞれがどんな状態なのかって値の種類は以下

意味
STATE_SYSTEM_FOCUSABLE 0x00100000 要素はフォーカスを受け入れることができます。
STATE_SYSTEM_INVISIBLE 0x00008000 要素は非表示です。
STATE_SYSTEM_OFFSCREEN 0x00010000 要素には表示された表現はありません。
STATE_SYSTEM_UNAVAILABLE 0x00000001 要素は使用できません。
STATE_SYSTEM_PRESSED 0x00000008 エレメントはプレス状態です。

この5種類で、重複もありなので、非表示 + 使用できないって場合は、0x00010001になるはず
ここまで見たけど、実際にC#でどう書けばいいのかわからないので、検索して

GetTitleBarInfo
https://forums.codeguru.com/showthread.php?443988-GetTitleBarInfo

ここを参考にコピペ改変C#で書いたのが

//Rect取得用
public struct RECT
{
    //型はlongじゃなくてintが正解!!!!!!!!!!!!!!
    //longだとおかしな値になる
    public int left;
    public int top;
    public int right;
    public int bottom;
    public override string ToString()
    {
        return $"横:{right - left:0000}, 縦:{bottom - top:0000}  ({left}, {top}, {right}, {bottom})";
    }
}

[DllImport("user32.dll")]
internal static extern bool GetTitleBarInfo(IntPtr hWnd, ref TITLEBARINFO pti);
public struct TITLEBARINFO
{
    public int cbSize;
    public RECT rcTitleBar;
    public TitleBarButtonStates rgState;
}
public enum TitleState
{
    STATE_SYSTEM_UNAVAILABLE = 1,
    STATE_SYSTEM_PRESSED = 8,
    STATE_SYSTEM_INVISIBLE = 32768,
    STATE_SYSTEM_OFFSCREEN = 65536,
    STATE_SYSTEM_FOCUSABLE = 1048576,
    STATE_SYSTEM_INVISIBLE_AND_FOCUSABLE = 0x00108000,
}
public struct TitleBarButtonStates
{
    public TitleState TitleBarState;
    public TitleState Reseved;
    public TitleState MinState;
    public TitleState MaxState;
    public TitleState HelpState;
    public TitleState CloseState;
}


最前面ウィンドウのタイトルバー情報取得の場合は
WinAPIのGetForegroundWindowで取得できるウィンドウハンドルを渡して

var ti = new TITLEBARINFO();
ti.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(ti);
GetTitleBarInfo(GetForegroundWindow(), ref ti);


こう書けば、tiに取得した情報が入る
わかんないのが2行目のti.cbSizeのところ
SizeOfってのがめんどくさい、stringBuiluderとかもそうだけど、めんどくさい
でも、こうしないと全部0になる

TitleStateのそれぞれの値の指定

コピペで書いたから、例えば
STATE_SYSTEM_PRESSEDは0x00000008を STATE_SYSTEM_PRESSED = 8, って書いたけど、どちらでもいいみたい
なので、INVISIBLEとFOCUSABLEの両方の状態のときは
STATE_SYSTEM_INVISIBLE_AND_FOCUSABLE = 0x00108000, って書いてみた

f:id:gogowaten:20210214133251p:plain
電卓
0x00108000は十進数だと1081344だった、どっちでもいいはず

テストアプリのコード

github.com

作成環境



API.cs

using System;
using System.Text;

using System.Runtime.InteropServices;

namespace _20210213_API_タイトルバー情報
{
    static class API
    {
        //Rect取得用
        public struct RECT
        {
            //型はlongじゃなくてintが正解!!!!!!!!!!!!!!
            //longだとおかしな値になる
            public int left;
            public int top;
            public int right;
            public int bottom;
            public override string ToString()
            {
                return $"横:{right - left:0000}, 縦:{bottom - top:0000}  ({left}, {top}, {right}, {bottom})";
            }
        }
        //座標取得用
        public struct POINT
        {
            public int X;
            public int Y;
        }
        //ウィンドウ情報用
        public struct WINDOWINFO
        {
            public int cbSize;
            public RECT rcWindow;
            public RECT rcClient;
            public uint dwStyle;
            public uint dwExStyle;
            public uint dwWindowStatus;
            public uint cxWindowBorders;
            public uint cyWindowBorders;
            public ushort atomWindowType;
            public short wCreatorVersion;
        }


        public enum WINDOW_STYLE : uint
        {
            WS_BORDER = 0x00800000,
            WS_CAPTION = 0x00C00000,
            WS_CHILD = 0x40000000,
            WS_CHILDWINDOW = 0x40000000,
            WS_CLIPCHILDREN = 0x02000000,
            WS_CLIPSIBLINGS = 0x04000000,
            WS_DISABLED = 0x08000000,
            WS_DLGFRAME = 0x00400000,
            WS_GROUP = 0x00020000,
            WS_HSCROLL = 0x00100000,
            WS_ICONIC = 0x20000000,
            WS_MAXIMIZE = 0x01000000,
            WS_MAXIMIZEBOX = 0x00010000,
            WS_MINIMIZE = 0x20000000,
            WS_MINIMIZEBOX = 0x00020000,
            WS_OVERLAPPED = 0x00000000,
            WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
            //The window is an overlapped window.Same as the WS_TILEDWINDOW style.
            WS_POPUP = 0x80000000,
            WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU,
            WS_SIZEBOX = 0x00040000,
            WS_SYSMENU = 0x00080000,
            WS_TABSTOP = 0x00010000,
            WS_THICKFRAME = 0x00040000,
            WS_TILED = 0x00000000,
            WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW,
            //(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
            WS_VISIBLE = 0x10000000,
            WS_VSCROLL = 0x00200000,
        }

        //DWM(Desktop Window Manager)
        //見た目通りのRectを取得できる、引数のdwAttributeにDWMWA_EXTENDED_FRAME_BOUNDSを渡す
        //引数のcbAttributeにはRECTのサイズ、Marshal.SizeOf(typeof(RECT))これを渡す
        //戻り値が0なら成功、0以外ならエラー値
        [DllImport("dwmapi.dll")]
        internal static extern long DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out RECT rect, int cbAttribute);

        //ウィンドウ属性
        //列挙値の開始は0だとずれていたので1からにした
        internal enum DWMWINDOWATTRIBUTE
        {
            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,//見た目通りのウィンドウのRect
            DWMWA_HAS_ICONIC_BITMAP,
            DWMWA_DISALLOW_PEEK,
            DWMWA_EXCLUDED_FROM_PEEK,
            DWMWA_CLOAK,
            DWMWA_CLOAKED,
            DWMWA_FREEZE_REPRESENTATION,
            DWMWA_LAST
        };


        //
        [DllImport("user32.dll")]
        internal static extern IntPtr GetActiveWindow();

        //ウィンドウのRect取得
        [DllImport("user32.dll")]
        internal static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

        //手前にあるウィンドウのハンドル取得
        [DllImport("user32.dll")]
        internal static extern IntPtr GetForegroundWindow();

        //ウィンドウ名取得
        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        internal static extern int GetWindowText(IntPtr hWin, StringBuilder lpString, int nMaxCount);

        //パレントウィンドウ取得
        [DllImport("user32.dll")]
        internal static extern IntPtr GetParent(IntPtr hWnd);

        [DllImport("user32.dll")]
        internal static extern IntPtr GetWindow(IntPtr hWnd, GETWINDOW_CMD uCmd);//本当のuCmdはuint型
        public enum GETWINDOW_CMD
        {
            GW_CHILD = 5,
            //指定されたウィンドウが親ウィンドウである場合、取得されたハンドルは、Zオーダーの最上位にある子ウィンドウを識別します。
            //それ以外の場合、取得されたハンドルはNULLです。この関数は、指定されたウィンドウの子ウィンドウのみを調べます。子孫ウィンドウは調べません。
            GW_ENABLEDPOPUP = 6,
            //取得されたハンドルは、指定されたウィンドウが所有する有効なポップアップウィンドウを識別します
            //(検索では、GW_HWNDNEXTを使用して最初に見つかったそのようなウィンドウが使用されます)。
            //それ以外の場合、有効なポップアップウィンドウがない場合、取得されるハンドルは指定されたウィンドウのハンドルです。
            GW_HWNDFIRST = 0,
            //取得されたハンドルは、Zオーダーで最も高い同じタイプのウィンドウを識別します。
            //指定されたウィンドウが最上位のウィンドウである場合、ハンドルは最上位のウィンドウを識別します。
            //指定されたウィンドウがトップレベルウィンドウである場合、ハンドルはトップレベルウィンドウを識別します。
            //指定されたウィンドウが子ウィンドウの場合、ハンドルは兄弟ウィンドウを識別します。

            GW_HWNDLAST = 1,
            //取得されたハンドルは、Zオーダーで最も低い同じタイプのウィンドウを識別します。
            //指定されたウィンドウが最上位のウィンドウである場合、ハンドルは最上位のウィンドウを識別します。指定されたウィンドウがトップレベルウィンドウである場合、ハンドルはトップレベルウィンドウを識別します。指定されたウィンドウが子ウィンドウの場合、ハンドルは兄弟ウィンドウを識別します。

            GW_HWNDNEXT = 2,
            //取得されたハンドルは、指定されたウィンドウの下のウィンドウをZオーダーで識別します。
            //指定されたウィンドウが最上位のウィンドウである場合、ハンドルは最上位のウィンドウを識別します。
            //指定されたウィンドウがトップレベルウィンドウである場合、ハンドルはトップレベルウィンドウを識別します。
            //指定されたウィンドウが子ウィンドウの場合、ハンドルは兄弟ウィンドウを識別します。

            GW_HWNDPREV = 3,
            //取得されたハンドルは、指定されたウィンドウの上のウィンドウをZオーダーで識別します。
            //指定されたウィンドウが最上位のウィンドウである場合、ハンドルは最上位のウィンドウを識別します。
            //指定されたウィンドウがトップレベルウィンドウである場合、ハンドルはトップレベルウィンドウを識別します。
            //指定されたウィンドウが子ウィンドウの場合、ハンドルは兄弟ウィンドウを識別します。

            GW_OWNER = 4,
            //取得されたハンドルは、指定されたウィンドウの所有者ウィンドウを識別します(存在する場合)。詳細については、「所有するWindows」を参照してください。
        }

        //ウィンドウのクライアント領域のRect取得
        [DllImport("user32.dll")]
        internal static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);

        //クライアント領域の座標を画面全体での座標に変換
        [DllImport("user32.dll")]
        internal static extern bool ClientToScreen(IntPtr hWnd, out POINT lpPoint);


        [DllImport("user32.dll")]
        internal static extern int GetWindowInfo(IntPtr hWnd, ref WINDOWINFO info);

        [DllImport("user32.dll")]
        internal static extern IntPtr GetLastActivePopup(IntPtr hWnd);

        /// <summary>
        /// 指定したWindowの一番上のChildWindowを返す
        /// </summary>
        /// <param name="hWnd">IntPtr.Zeroを指定すると一番上のWindowを返す</param>
        /// <returns>ChildWindowを持たない場合はnullを返す</returns>
        [DllImport("user32.dll")]
        internal static extern IntPtr GetTopWindow(IntPtr hWnd);

        /// <summary>
        /// 指定したWindowのメニューのハンドルを返す
        /// </summary>
        /// <param name="hWnd">Windowのハンドル</param>
        /// <returns>Windowがメニューを持たない場合はnullを返す</returns>
        [DllImport("user32.dll")]
        internal static extern IntPtr GetMenu(IntPtr hWnd);

        /// <summary>
        /// キーボードフォーカスを持つWindowのハンドルを返す
        /// </summary>
        /// <returns></returns>
        [DllImport("user32.dll")]
        internal static extern IntPtr GetFocus();

        [DllImport("user32.dll")]
        internal static extern IntPtr GetMenuBarInfo(IntPtr hWnd, MenuObjectId idObject, long idItem, MENUBARINFO pmbi);

        public struct MENUBARINFO
        {
            public long cbSize;
            public RECT rcBar;
            public IntPtr hMenu;
            public bool fBarFocused;
            public bool fFocused;
        }
        public enum MenuObjectId : long
        {
            OBJID_CLIENT = 0xFFFFFFFC,
            OBJID_MENU = 0xFFFFFFFD,
            OBJID_SYSMENU = 0xFFFFFFFF,
        }


        //        GetTitleBarInfo
        //https://forums.codeguru.com/showthread.php?443988-GetTitleBarInfo

        [DllImport("user32.dll")]
        internal static extern bool GetTitleBarInfo(IntPtr hWnd, ref TITLEBARINFO pti);
        public struct TITLEBARINFO
        {
            public int cbSize;
            public RECT rcTitleBar;
            public TitleBarButtonStates rgState;
        }
        public enum TitleState
        {
            STATE_SYSTEM_UNAVAILABLE = 1,
            STATE_SYSTEM_PRESSED = 8,
            STATE_SYSTEM_INVISIBLE = 32768,
            STATE_SYSTEM_OFFSCREEN = 65536,
            STATE_SYSTEM_FOCUSABLE = 1048576,
            STATE_SYSTEM_INVISIBLE_AND_FOCUSABLE = 0x00108000,
        }
        public struct TitleBarButtonStates
        {
            public TitleState TitleBarState;
            public TitleState Reseved;
            public TitleState MinState;
            public TitleState MaxState;
            public TitleState HelpState;
            public TitleState CloseState;
        }







        [DllImport("user32.dll")]
        internal static extern IntPtr GetMenuItemRect(IntPtr hWnd, IntPtr hMenu, uint uItem, out RECT rect);


        //指定座標にあるウィンドウのハンドル取得
        [DllImport("user32.dll")]
        internal static extern IntPtr WindowFromPoint(POINT pOINT);

        //祖先ウィンドウを取得
        [DllImport("user32.dll")]
        internal static extern IntPtr GetAncestor(IntPtr hWnd, AncestorType type);

        public enum AncestorType
        {
            GA_PARENT = 1,
            GA_ROOT = 2,//Parentを辿ってルートを取得
            GA_ROOTOWNER = 3,//GetParentを使ってルートを取得

        }

        [DllImport("user32.dll")]
        internal static extern IntPtr GetDesktopWindow();


        [DllImport("user32.dll")]
        internal static extern IntPtr GetShellWindow();

        [DllImport("user32.dll")]
        internal static extern IntPtr GetSubMenu(IntPtr hWnd, int nPos);

        [DllImport("user32.dll")]
        internal static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        [DllImport("user32.dll")]
        internal static extern bool IsWindowVisible(IntPtr hWnd);



        //public delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lparam, List<IntPtr> intPtrs);
        //[DllImport("user32.dll")]
        //[return: MarshalAs(UnmanagedType.Bool)]
        //internal static extern bool EnumChildWindows(IntPtr hWnd, EnumWindowsDelegate enumWindows, IntPtr lparam);


        //internal static List<IntPtr> GetChildWindows(IntPtr hWnd)
        //{
        //    List<IntPtr> childList = new();
        //    EnumChildWindows(hWnd, new EnumWindowsDelegate(EnumWindowCallBack), IntPtr.Zero);
        //    return childList;
        //}
        //private static bool EnumWindowCallBack(IntPtr hWnd, IntPtr lparam, List<IntPtr> childList)
        //{
        //    childList.Add(hWnd);
        //    return true;
        //}














        //グローバルホットキー登録用
        internal const int WM_HOTKEY = 0x0312;
        [DllImport("user32.dll")]
        internal static extern int RegisterHotKey(IntPtr hWnd, int id, int modkyey, int vKey);
        [DllImport("user32.dll")]
        internal static extern int UnregisterHotKey(IntPtr hWnd, int id);

        //マウスカーソル座標
        [DllImport("user32.dll")]
        internal static extern bool GetCursorPos(out POINT lpPoint);


        //Bitmap描画関連
        //DC取得
        //nullを渡すと画面全体のDCを取得、ウィンドウハンドルを渡すとそのウィンドウのクライアント領域DC
        //失敗した場合の戻り値はnull
        //使い終わったらReleaseDC
        [DllImport("user32.dll")]
        internal static extern IntPtr GetDC(IntPtr hWnd);

        //渡したDCに互換性のあるDC作成
        //失敗した場合の戻り値はnull
        //使い終わったらDeleteDC
        [DllImport("gdi32.dll")]
        internal static extern IntPtr CreateCompatibleDC(IntPtr hdc);

        //指定されたDCに関連付けられているデバイスと互換性のあるビットマップを作成
        //使い終わったらDeleteObject
        [DllImport("gdi32.dll")]
        internal static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int cx, int cy);

        //DCにオブジェクトを指定する、オブジェクトの種類はbitmap、brush、font、pen、Regionなど
        [DllImport("gdi32.dll")]
        internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr h);

        //画像転送
        [DllImport("gdi32.dll")]
        internal static extern bool BitBlt(IntPtr hdc, int x, int y, int cx, int cy, IntPtr hdcSrc, int x1, int y1, uint rop);
        internal const int SRCCOPY = 0x00cc0020;
        internal const int SRCINVERT = 0x00660046;

        ////
        //[DllImport("user32.dll")]
        //private static extern bool PrintWindow(IntPtr hWnd, IntPtr hDC, uint nFlags);
        //private const uint nFrags_PW_CLIENTONLY = 0x00000001;

        //[DllImport("user32.dll")]
        //private static extern bool DeleteDC(IntPtr hdc);

        [DllImport("user32.dll")]
        internal static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

        [DllImport("gdi32.dll")]
        internal static extern bool DeleteObject(IntPtr ho);


    }
}

前回からのコピペなので長いけど使っているのは一部
書き加えた部分は223行目から251行目
下のMainWindow.xaml.csで使うには、namespaceをMainWindow.xaml.csと同じに書き換える必要がある

MainWindow.xaml

<Window x:Class="_20210213_API_タイトルバー情報.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:_20210213_API_タイトルバー情報"
        mc:Ignorable="d"
        Title="MainWindow" Height="150" Width="200">
    <Grid>

    </Grid>
</Window>



MainWindow.xaml.cs

using System;
using System.Text;
using System.Windows;
using System.Windows.Input;

using System.Windows.Interop;

//GetTitleBarInfo function(winuser.h) -Win32 apps | Microsoft Docs
//https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-gettitlebarinfo
//TITLEBARINFO(winuser.h) - Win32 apps | Microsoft Docs
//https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-titlebarinfo
//        GetTitleBarInfo
//https://forums.codeguru.com/showthread.php?443988-GetTitleBarInfo


namespace _20210213_API_タイトルバー情報
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        //ホットキー
        private const int HOTKEY_ID1 = 0x0001;//ID
        private IntPtr MyWindowHandle;//アプリのハンドル



        public MainWindow()
        {
            InitializeComponent();



            MyInitializeHotKey();

            //ホットキーに修飾キーとPrintScreenキーを登録
            //int mod = GetModifierKeySum();
            //int mod = 2;//ctrl
            //int mod = 1;//alt
            //int mod = 4;//shift
            //int mod = 6;//ctrl + shift
            //int mod = 0;//修飾キーなし
            int mod = 0;
            ChangeHotKey(mod, Key.PrintScreen, HOTKEY_ID1);

            //アプリ終了時にホットキーの解除
            Closing += MainWindow_Closing;
        }

        //ホットキー判定
        private void ComponentDispatcher_ThreadPreprocessMessage(ref MSG msg, ref bool handled)
        {
            if (msg.message != API.WM_HOTKEY) return;

            //ホットキーが押されたら
            else if (msg.wParam.ToInt32() == HOTKEY_ID1)
            {

                MyTitleBarInfoFromCursorUnderWindow();

            }
        }

        private void MyTitleBarInfoFromCursorUnderWindow()
        {
            //マウスカーソル下のウィンドウのタイトルバー情報
            API.GetCursorPos(out API.POINT cp);
            MyWidndowInfo cursor = GetWindowInfo(API.WindowFromPoint(cp));
            var tiカーソル下 = new API.TITLEBARINFO();
            tiカーソル下.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(tiカーソル下);
            API.GetTitleBarInfo(cursor.hWnd, ref tiカーソル下);

            //最前面ウィンドウのタイトルバー情報
            var fore = GetWindowInfo(API.GetForegroundWindow());
            var ti最前面 = new API.TITLEBARINFO();
            ti最前面.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(ti最前面);
            API.GetTitleBarInfo(fore.hWnd, ref ti最前面);

        }


        #region Rect取得


        private Rect MyConverterApiRectToRect(API.RECT rect)
        {
            return new Rect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
        }


        private MyWidndowInfo GetWindowInfo(IntPtr hWnd)
        {
            return new MyWidndowInfo()
            {
                hWnd = hWnd,
                Rect = GetWindowRect(hWnd),
                Text = GetWindowText(hWnd),
                IsVisible = API.IsWindowVisible(hWnd)
            };

        }

        //ウィンドウハンドルからRect取得
        private Rect GetWindowRect(IntPtr hWnd)
        {
            _ = API.GetWindowRect(hWnd, out API.RECT re);
            return MyConverterApiRectToRect(re);
        }
        //ウィンドウハンドルからRECT取得
        private static API.RECT GetWindowAPIRECT(IntPtr hWnd)
        {
            _ = API.GetWindowRect(hWnd, out API.RECT re);
            return re;
        }

        //ウィンドウハンドルからText取得
        private static string GetWindowText(IntPtr hWnd)
        {
            StringBuilder text = new StringBuilder(65535);
            _ = API.GetWindowText(hWnd, text, 65535);
            return text.ToString();
        }

        #endregion Rect取得




        #region ホットキー関連
        //アプリのウィンドウが非アクティブ状態でも任意のキーの入力を感知、WPFでグローバルホットキーの登録
        //https://gogowaten.hatenablog.com/entry/2020/12/11/132125
        private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            //ホットキーの登録解除
            _ = API.UnregisterHotKey(MyWindowHandle, HOTKEY_ID1);
            ComponentDispatcher.ThreadPreprocessMessage -= ComponentDispatcher_ThreadPreprocessMessage;
        }

        private void MyInitializeHotKey()
        {
            MyWindowHandle = new WindowInteropHelper(this).Handle;
            ComponentDispatcher.ThreadPreprocessMessage += ComponentDispatcher_ThreadPreprocessMessage;
        }
        private void ChangeHotKey(int mod, Key Key, int hotkeyId)
        {
            ChangeHotKey(mod, KeyInterop.VirtualKeyFromKey(Key), hotkeyId);
        }
        private void ChangeHotKey(int mod, int vKey, int hotkeyId)
        {
            //上書きはできないので、古いのを削除してから登録
            _ = API.UnregisterHotKey(MyWindowHandle, hotkeyId);

            if (API.RegisterHotKey(MyWindowHandle, hotkeyId, mod, vKey) == 0)
            {
                MessageBox.Show("登録に失敗");
            }
            else
            {
                //MessageBox.Show("登録完了");
            }
        }
        #endregion ホットキー関連



        //ウィンドウハンドルからウィンドウの情報用
        //ウィンドウのハンドル、Rect、Text、IsVisible
        private struct MyWidndowInfo
        {
            public IntPtr hWnd;
            public Rect Rect;
            public bool IsVisible;
            public string Text;

            public override string ToString()
            {
                string visible = IsVisible == true ? "可視" : "不可視";
                //x16は書式で、xが16進数で表示、16が表示桁数
                return $"IntPtr({hWnd.ToString("x16")}), Rect({Rect}), {visible}, Text({Text})";
            }
        }


    }


}



グローバルなホットキーの登録は
gogowaten.hatenablog.com


ウィンドウのタイトルバー情報取得してみる

ホットキーを押したときに最前面ウィンドウとマウスカーソル下のウィンドウのタイトルバー情報を取得
80行目にブレークポイントを設定している
ホットキーはPrintScreenキー

エクセルを最前面にしてマウスカーソルも置いた状態でホットキーを押す

f:id:gogowaten:20210214134855p:plain
エクセルのタイトルバー情報取得

f:id:gogowaten:20210214135047p:plain
一時停止して確認
80行目にブレークポイント

f:id:gogowaten:20210214135332p:plain
エクセルのタイトルバー情報
rgStateの中の6個の値がそれ
HelpStateはINVISIBLEなのでヘルプボタンは非表示ってのがわかる、ResevedもINVISIBLEらしいけど、Reseved自体が何なのかわからん、TitleBarStateはFOCUSABLEは、タイトルバーにフォーカスが可能なんだなってのがわかる
わからんのが0の値をとっているもの3つ、閉じるボタンと最大化、最小化なんだけど、これはタイトルバーに普通に表示されているから、0ってのは表示中とか有効になっているって意味かな


f:id:gogowaten:20210214140514p:plain
エクセルの右クリックメニュー
エクセルの右クリックメニューのタイトルバー情報は
f:id:gogowaten:20210214140603p:plain
エクセルの右クリックメニューウィンドウのタイトルバー情報
0が多い、これ見ると0ってのは表示しているの意味じゃないねえ、なんだろ有効かな
0じゃないのはタイトルバー自体の値で、非表示 + フォーカス可能の値をとっている


f:id:gogowaten:20210214141039p:plain
セルの書式設定ウィンドウ

最小化、最大化ボタンが無い代わりに、ヘルプボタンがある

f:id:gogowaten:20210214141055p:plain

セルの書式設定ウィンドウのタイトルバー情報

最小化、最大化ボタンの値は非表示になっている!


f:id:gogowaten:20210214145713p:plain
メモ帳と右クリックメニュー
メモ帳自体のウィンドウ
f:id:gogowaten:20210214145751p:plain
メモ帳のタイトルバー情報
エクセルのウィンドウと同じ結果


f:id:gogowaten:20210214145805p:plain
メモ帳の右クリックメニューのタイトルバー情報
メモ帳の右クリックメニューもエクセルの右クリックメニューと同じ結果


f:id:gogowaten:20210214153000p:plain
メモ帳のメニュー
カーソル下のメニューウィンドウは

f:id:gogowaten:20210214153032p:plain
メモ帳のメニューウィンドウのタイトルバー情報
右クリックメニューと同じ結果


Visual Studio

f:id:gogowaten:20210214153316p:plain
Visual Studioのメニューウィンドウ
f:id:gogowaten:20210214153335p:plain
Visual Studioのメニューウィンドウのタイトルバー情報
これも同じ結果


f:id:gogowaten:20210214150219p:plain
Pixtack紫陽花のアプリ情報ウィンドウ
閉じるボタンしかないウィンドウの場合は?

f:id:gogowaten:20210214150314p:plain
Pixtack紫陽花のアプリ上のウィンドウのタイトルバー情報
閉じるボタンしかないのに、普通のウィンドウと同じ結果


f:id:gogowaten:20210214150649p:plain
メモ帳のバージョン情報ウィンドウ
これも閉じるボタンしかないウィンドウ

f:id:gogowaten:20210214150719p:plain
メモ帳のバージョン情報ウィンドウのタイトルバー情報
これは最小化、最大化ボタンも非表示の値になっている、微妙に違うんだねえ

ここまでの結果を一覧表にすると

ウィンドウ 閉じる ヘルプ 最大化 最小化 予約済み タイトルバー自体
エクセル 0 Invisible 0 0 Invisible Forcusable
メモ帳 0 Invisible 0 0 Invisible Forcusable
Pixtack紫陽花のアプリ情報 0 Invisible 0 0 Invisible Forcusable
メモ帳のバージョン情報 0 Invisible Invisible Invisible Invisible Forcusable
セルの書式設定 0 0 Invisible Invisible Invisible Forcusable
エクセルの右クリックメニュー 0 0 0 0 0 Invisible and Focusable
メモ帳の右クリックメニュー 0 0 0 0 0 Invisible and Focusable
メモ帳のメニュー 0 0 0 0 0 Invisible and Focusable
Visual Studioのメニュー 0 0 0 0 0 Invisible and Focusable

メニューや右クリックメニューのウィンドウは、タイトルバー自体の値がINVISIBLE + FOCUSABLEってのが特徴
これでメニュー系のウィンドウなのか、それ以外のウィンドウなのかの判定ができそう




関連記事
自家のWPF記事は翌日

gogowaten.hatenablog.com


前回のWPF記事は一昨日

gogowaten.hatenablog.com



3日前
gogowaten.hatenablog.com スクショののキャプチャ範囲の動作でメニュー系のウィンドウかどうかの判定するのに、今回のGetTitleBarInfoが使えそうなんだよねえ