WPF、他のアプリの右クリックメニューのウィンドウハンドル取得方法がわからん
目的は右クリックメニューのRectか画像としての取得で、ウィンドウハンドルさえ取得できればいいんだけどねえ、少し試したけどわからんかったって話
結果から言うと、できることはできたけど、マウスカーソルが右クリックメニューの上にあるっていう条件付き
API.GetCursorPos(out API.POINT cP);
IntPtr hWnd = API.WindowFromPoint(cP);
GetCursorPos()でマウスカーソル座標取得して、それをWindowFromPoint()に渡せば取得できた
でも、これだとどのアプリの右クリックメニューなのかわからないから、違うんだよなあ
実行環境
- Visual Studio Community 2019
- Windows 10 Home
- WPF
- .NET Core 5
- C#
API.sc
using System; using System.Text; using System.Runtime.InteropServices;//dllインポート用 namespace _20210129_最前面アプリの右クリックメニュー取得 { 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, } [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); //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); } }
WinAPI用、今回使っていないメソッドがたくさんあるのはコピペだから
MainWindow.xaml.cs
using System; using System.Collections.Generic; using System.Text; using System.Windows; using System.Windows.Input; using System.Windows.Interop; //最前面(アクティブ)アプリの右クリックメニューの、ウィンドウハンドルを取得したい //唯一できた方法はカーソル下のウィンドウハンドルを取得する方法 //でもこれじゃ右クリックメニューって判定しているわけじゃないから、これじゃない感じ namespace _20210129_最前面アプリの右クリックメニュー取得 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { //ホットキー private const int HOTKEY_ID1 = 0x0001;//ID private IntPtr MyWindowHandle;//アプリのハンドル //ウィンドウ探査loopの回数上限値 private const int LOOP_LIMIT = 3; public MainWindow() { InitializeComponent(); MyInitializeHotKey(); //ホットキーにPrintScreenキーを登録 ChangeHotKey(Key.PrintScreen, HOTKEY_ID1); //アプリ終了時にホットキーの解除 Closing += MainWindow_Closing; } #region ホットキー関連 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(Key Key, int hotkeyId) { ChangeHotKey(KeyInterop.VirtualKeyFromKey(Key), hotkeyId); } private void ChangeHotKey(int vKey, int hotkeyId) { //上書きはできないので、古いのを削除してから登録 _ = API.UnregisterHotKey(MyWindowHandle, hotkeyId); //int mod = GetModifierKeySum(); //int mod = 2;//ctrl //int mod = 1;//alt int mod = 0;//修飾キーなし if (API.RegisterHotKey(MyWindowHandle, hotkeyId, mod, vKey) == 0) { MessageBox.Show("登録に失敗"); } else { //MessageBox.Show("登録完了"); } } #endregion ホットキー関連 //ホットキー判定 private void ComponentDispatcher_ThreadPreprocessMessage(ref MSG msg, ref bool handled) { if (msg.message != API.WM_HOTKEY) return; //ホットキー(今回はPrintScreen)が押されたら else if (msg.wParam.ToInt32() == HOTKEY_ID1) { var foreInfo = GetWindowRectAndText(API.GetForegroundWindow());//メモ帳のウィンドウ var focusInfo = GetWindowRectAndText(API.GetFocus());//なし var shellInfo = GetWindowRectAndText(API.GetShellWindow());//program manager var activeInfo = GetWindowRectAndText(API.GetActiveWindow()); //Foregroundwindowから取得できるウィンドウ IntPtr foreW = API.GetForegroundWindow(); var ancesParent = GetWindowRectAndText(API.GetAncestor(foreW, API.AncestorType.GA_PARENT));//Textなしの全画面サイズ var ancesRoot = GetWindowRectAndText(API.GetAncestor(foreW, API.AncestorType.GA_ROOT));//メモ帳のウィンドウ var ancesRootOwner = GetWindowRectAndText(API.GetAncestor(foreW, API.AncestorType.GA_ROOTOWNER));//メモ帳のウィンドウ var lastPop = GetWindowRectAndText(API.GetLastActivePopup(foreW));//メモ帳のウィンドウ var menu = GetWindowRectAndText(API.GetMenu(foreW));//none var parent = GetWindowRectAndText(API.GetParent(foreW));//none var topChild = GetWindowRectAndText(API.GetTopWindow(foreW));//Textなし、メモ帳のウィンドウのクライアント //Foregroundwindowのcmd各種 var childs = GetWindowRectAndTexts(GetCmdWindows(foreW, API.GETWINDOW_CMD.GW_CHILD, LOOP_LIMIT));//メモ帳のウィンドウのクライアント、その後はnone var popups = GetWindowRectAndTexts(GetCmdWindows(foreW, API.GETWINDOW_CMD.GW_ENABLEDPOPUP, LOOP_LIMIT));//none var first = GetWindowRectAndTexts(GetCmdWindows(foreW, API.GETWINDOW_CMD.GW_HWNDFIRST, LOOP_LIMIT));//TextはすべてDefault IME var last = GetWindowRectAndTexts(GetCmdWindows(foreW, API.GETWINDOW_CMD.GW_HWNDLAST, LOOP_LIMIT));//TextはすべてProgram Manager var nexts = GetWindowRectAndTexts(GetCmdWindows(foreW, API.GETWINDOW_CMD.GW_HWNDNEXT, LOOP_LIMIT));//全て関係ないアプリ var prevs = GetWindowRectAndTexts(GetCmdWindows(foreW, API.GETWINDOW_CMD.GW_HWNDPREV, LOOP_LIMIT));//すべて関係ないアプリ var owners = GetWindowRectAndTexts(GetCmdWindows(foreW, API.GETWINDOW_CMD.GW_OWNER, LOOP_LIMIT));//none //カーソルの下のウィンドウハンドル API.GetCursorPos(out API.POINT cP); IntPtr hWnd = API.WindowFromPoint(cP); var CursorW = GetWindowRectAndText(hWnd);//右クリックメニュー var AncesParent = GetWindowRectAndText(API.GetAncestor(hWnd, API.AncestorType.GA_PARENT));//Textなしの全画面サイズ var AncesRoot = GetWindowRectAndText(API.GetAncestor(hWnd, API.AncestorType.GA_ROOT));//右クリックメニュー var AncesRootOwner = GetWindowRectAndText(API.GetAncestor(hWnd, API.AncestorType.GA_ROOTOWNER));//右クリックメニュー var LastPop = GetWindowRectAndText(API.GetLastActivePopup(hWnd));//右クリックメニュー var Menu = GetWindowRectAndText(API.GetMenu(hWnd));//none var Parent = GetWindowRectAndText(API.GetParent(hWnd));//none var TopChild = GetWindowRectAndText(API.GetTopWindow(hWnd));//none var Childs = GetWindowRectAndTexts(GetCmdWindows(hWnd, API.GETWINDOW_CMD.GW_CHILD, LOOP_LIMIT));//すべてnone var Popups = GetWindowRectAndTexts(GetCmdWindows(hWnd, API.GETWINDOW_CMD.GW_ENABLEDPOPUP, LOOP_LIMIT));//none var First = GetWindowRectAndTexts(GetCmdWindows(hWnd, API.GETWINDOW_CMD.GW_HWNDFIRST, LOOP_LIMIT));//TextはすべてDefault IME var Last = GetWindowRectAndTexts(GetCmdWindows(hWnd, API.GETWINDOW_CMD.GW_HWNDLAST, LOOP_LIMIT));//TextはすべてProgram Manager var Nexts = GetWindowRectAndTexts(GetCmdWindows(hWnd, API.GETWINDOW_CMD.GW_HWNDNEXT, LOOP_LIMIT));//右クリックメニューの影ウィンドウ、それ以降は関係ないアプリ var Prevs = GetWindowRectAndTexts(GetCmdWindows(hWnd, API.GETWINDOW_CMD.GW_HWNDPREV, LOOP_LIMIT));//8個noneが続いたあと関係ないアプリ var Owners = GetWindowRectAndTexts(GetCmdWindows(hWnd, API.GETWINDOW_CMD.GW_OWNER, LOOP_LIMIT));//none } } //指定したAPI.GETWINDOW_CMDを収集 private List<IntPtr> GetCmdWindows(IntPtr hWnd, API.GETWINDOW_CMD cmd, int loopCount) { List<IntPtr> v = new(); IntPtr temp = API.GetWindow(hWnd, cmd); for (int i = 0; i < loopCount; i++) { v.Add(temp); temp = API.GetWindow(temp, cmd); } return v; } //ウィンドウハンドルからText(タイトル名)やRECTを取得 private (IntPtr, API.RECT re, string text) GetWindowRectAndText(IntPtr hWnd) { return (hWnd, GetWindowRect(hWnd), GetWindowText(hWnd)); } private (List<IntPtr> ptrs, List<API.RECT> rs, List<string> strs) GetWindowRectAndTexts(List<IntPtr> pList) { List<IntPtr> ptrs = new(); List<API.RECT> rs = new(); List<string> strs = new(); foreach (var item in pList) { ptrs.Add(item); rs.Add(GetWindowRect(item)); strs.Add(GetWindowText(item)); } return (ptrs, rs, strs); } //ウィンドウハンドルからRECT取得 private API.RECT GetWindowRect(IntPtr hWnd) { _ = API.GetWindowRect(hWnd, out API.RECT re); return re; } //ウィンドウハンドルからText取得 private string GetWindowText(IntPtr hWnd) { var text = new StringBuilder(65535); _ = API.GetWindowText(hWnd, text, 65535); return text.ToString(); } } }
WinAPIを使って最前面ウィンドウのハンドルやそのRectとか取得する、一時停止で確認する
一時停止の場所は132行目
取得タイミングはホットキーを押した瞬間
ホットキーはPrintScreenキー
ウィンドウハンドルからRECTとText(タイトル名?)を取得する
これでRect(座標とサイズ)とText(タイトル名)から、何のウィンドウなのか判別できる
↑のをまとめたもの
ハンドルを渡すとRECTとTextを返す
↑のをListにしただけ
これでまとめて確認できる
APIのGetWindow()用
GetWindowにAPI.GETWINDOW_CMDのNEXTを渡すと、
ウィンドウの下にあるウィンドウを取得できる
NEXTの代わりにPREVを渡すと上にあるウィンドウを取得できる
繰り返せばどんどん辿って行けるので
CMDの指定と、たどる回数の上限値を指定してまとめて取得できるようにしたもの
あとはWinAPIの中から適当にそれっぽいのを使って、取得したウィンドウハンドルを渡して、一時停止して確認
WinAPIのGet~をいくつか試した過程
デスクトップ画面左上にあるメモ帳
右クリックメニューを表示した状態で、ホットキーに指定してあるPrintScreenキーを押して確認
GetForegroundwindow()はメモ帳自体のウィンドウハンドルを取得しているのがわかる
それ以外のメソッドは関係ないか何も取得できていない
つまりGetForegroundwindow()にしか期待できない
|WinAPI|結果|
|---|---|
|GetForegroundwindow()|アプリのウィンドウ|
|GetFocus()|none|
|GetShellWindow()|関係ないウィンドウ|
Rectを確認
GetForegroundwindowで取得したウィンドウハンドルの、Rectに合わせた半透明の黒画像を重ねてみたところ
ウィンドウ枠より一回り大きいのは、枠のドロップシャドウ部分を含んでいるから、これであっている
GetForegroundwindow()で得たウィンドウハンドル(メモ帳)を渡す
WinAPI | 結果 |
---|---|
GetAncestor + PARENT | none |
GetAncestor + ROOT | アプリのウィンドウ |
GetAncestor + ROOTOWNER | アプリのウィンドウ |
GetLastActivePopup | アプリのウィンドウ |
GetMenu | none |
GetParent | none |
GetTopWindow | アプリのクライアント領域ウィンドウ |
一時停止
どれも違う
CMD各種
それぞれ3つまで辿ってみる
GW_CHILD
最初のがそれっぽいけど、Rectをあわせてみると
メモ帳のクライアント領域だった
GW_ENABLEDPOPUP
Popupっていう名前からして期待していたけど、何も得られず
GW_HWNDFIRST
Default IMEっていうTextがついた0x0のウィンドウハンドルが得られただけ
GW_HWNDLAST
デスクトップと同じ大きさのRect、TextはProgram Manager、これも関係ない
GW_HWNDNEXT
下にあるウィンドウ3枚、どれも関係ない
GW_HWNDPREV
上にあるウィンドウ3枚、なんか下にあるウィンドウ3枚と似てる
GW_OWNER
何も取得できていない
まとめると
GetWindowにCMD各種 | 結果 |
---|---|
CHILD | アプリのクライアント領域ウィンドウのあとは全部none |
ENABLEDPOPUP | 全部none |
FIRST | 全部none |
LAST | 関係ないウィンドウ |
NEXT | 関係ないウィンドウ |
PREV | 関係ないウィンドウ |
OWNER | 全部none |
GetWindowも全滅
ってことで、ここまでの方法では右クリックメニューのウィンドウハンドルを取得することができなかった
逆に
じゃあ次は右クリックメニューのウィンドウハンドルから元のアプリ、ここではメモ帳のウィンドウハンドルを取得することができれば、関連していることがわかるからそれでもいいかなと
カーソル下のウィンドウハンドル取得
右クリックメニューの上にマウスカーソルを置いて
これで得られたRectを確認してみると
右クリックメニューにピッタリ合ったので、これで取得できている
でも、このままだと何のウィンドウなのか不明なので、このウィンドウハンドルはメモ帳の右クリックメニューです、っていうことが確認できればいい
名前的にはGetParentやGetAncestor、GetWindowのOWNERとかで取得できそうなんだけどねえ(できなかった)
右クリックメニューのウィンドウハンドルを各種Get~に渡した結果
WinAPI | 結果 |
---|---|
GetAncestor + PARENT | Textなし、RECTは全画面 |
GetAncestor + ROOT | 右クリックメニュー |
GetAncestor + ROOTOWNER | 右クリックメニュー |
GetLastActivePopup | 右クリックメニュー |
GetMenu | none |
GetParent | none |
GetTopWindow | none |
メモ帳のウィンドウハンドルは取得できず
次
GetWindow()でCMD各種
hWndが右クリックメニューのウィンドウハンドル
GW_CHILD
何も取得できず
GW_ENABLEDPOPUP
これも、何も取得できず
GW_HWNDFIRST
またIMEかあ
GW_HWNDLAST
またProgram Managerかあ
GW_HWNDNEXT
なんか取得できた
[0]のRectを確認してみると
右クリックメニューより右と下に5ピクセル大きいこのRectは、ドロップシャドウ専用ウィンドウ?だった、ぬか喜び
他の[1][2]も関係ないウィンドウ
GW_HWNDPREV
PREVは上のウィンドウだから何も取得できず
GW_OWNER
OWNERには期待していたけど、何も得られず
右クリックメニューのウィンドウハンドルに対してGetWindowにCMD各種
CMD | 結果 |
---|---|
CHILD | 全部none |
ENABLEDPOPUP | 全部none |
FIRST | 全部none |
LAST | 関係ないウィンドウ |
NEXT | 関係ないウィンドウ |
PREV | 全部none |
OWNER | 全部none |
ってことで、これも全滅
この状態はメモ帳以外のアプリでも同じ
根本的に間違っているのかも
おわり
不可解
右クリックメニューに階層がある場合は取得できる
サブメニューっていうのかな、>マークが付いているメニュー項目を選択すると、さらにメニューウィンドウがある場合、そのウィンドウハンドルは
取得できる
103行目、メモ帳のウィンドウハンドルをGetWindow()にGW_ENABLEDPOPUPとともに渡したところ
[0]にあるRectを確認してみると
右クリックメニューにピッタリ重なった
しかも逆に辿ることができる
GetAncestorのROOTOWNERとGetParentでメモ帳のウィンドウハンドルが取得できている
関連記事
次回のWPF記事は2日後
前回のWPF記事は5日前
1ヶ月前
gogowaten.hatenablog.com
これで、ウィンドウ枠外の右クリックメニューとかを切り抜いたスクショを撮りたくて、もがいているのが最近の記事