マウスカーソルの下にあるウィンドウのRect取得してみた、GetWindowRectとGetClientRect
2020WPF/20201111_カーソル下のウィンドウ取得
github.com
GetWindowRectはタイトルバーや枠も含めた領域
GetClientRectは枠の内側の領域
MainWindow.xaml
<Window x:Class="_20201111_カーソル下のウィンドウ取得.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:_20201111_カーソル下のウィンドウ取得" mc:Ignorable="d" Title="MainWindow" Height="120" Width="600"> <Grid> <StackPanel> <TextBlock x:Name="MyTextBlock1" Text="text" Margin="8,2"/> <TextBlock x:Name="MyTextBlock2" Text="text" Margin="8,2"/> <TextBlock x:Name="MyTextBlock3" Text="text" Margin="8,2"/> </StackPanel> </Grid> </Window>
MainWindow.xaml.cs
using System; using System.Text; using System.Windows; using System.Runtime.InteropServices; using System.Windows.Threading; //1秒毎にマウスカーソルの下にあるウィンドウのRectを取得 namespace _20201111_カーソル下のウィンドウ取得 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { #region WindowsAPI^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //Rect取得用 private struct RECT { //型はlongじゃなくてintが正解!!!!!!!!!!!!!! //longだとおかしな値になる public int left; public int top; public int right; public int bottom; } //座標取得用 private struct POINT { public int x; public int y; } //ウィンドウのクライアント領域のRect取得 [DllImport("user32.dll")] private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect); //ウィンドウのRect取得 [DllImport("user32.dll")] private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); //手前にあるウィンドウのハンドル取得 [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); //指定座標にあるウィンドウのハンドル取得 [DllImport("user32.dll")] private static extern IntPtr WindowFromPoint(POINT pOINT); //ウィンドウ名取得 [DllImport("user32.dll")] private static extern int GetWindowText(IntPtr hWin, StringBuilder lpString, int nMaxCount); //マウスカーソルの位置取得 [DllImport("user32.dll")] private static extern bool GetCursorPos(out POINT lpPoint); //ウィンドウ系のAPI //Windows(Windowsおよびメッセージ)-Win32アプリ | Microsoft Docs // https://docs.microsoft.com/en-us/windows/win32/winmsg/windows // スクリーン上でのウィンドウクライアント領域の取得 - 捨てられたブログ //https://blog.recyclebin.jp/archives/863 // 【C#】アクティブウィンドウのウィンドウ名を取得 - プログラミングとかブログ //https://shirakamisauto.hatenablog.com/entry/2016/03/26/110000 #endregion ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DispatcherTimer MyTimer; public MainWindow() { InitializeComponent(); //1秒毎のタイマー MyTimer = new DispatcherTimer(); MyTimer.Interval = new TimeSpan(0, 0, 0, 0, 1000); MyTimer.Tick += MyTimer_Tick; MyTimer.Start(); } private void MyTimer_Tick(object sender, EventArgs e) { //一番手前のウィンドウのハンドル取得 //IntPtr hw = GetForegroundWindow(); //マウスカーソルの位置取得 GetCursorPos(out POINT cursorP); //マウスカーソルの下にあるウィンドウのハンドル取得 //右クリックメニューやボタン、テキストボックスとかのコントロールも取得される IntPtr handleWin = WindowFromPoint(cursorP); //ウィンドウのRect取得、これは透明や半透明の枠も含むので見た目より大きな値になる //座標は画面全体での位置になる if (GetWindowRect(handleWin, out RECT wRect)) { MyTextBlock1.Text = $"WindowRect 左上座標({wRect.left}, {wRect.top}) 右下({wRect.right}, {wRect.bottom})"; } //ウィンドウのクライアント領域(枠の内側領域)のRect取得 //leftとtopは常に0、なので実質、rightは横幅、bottomは縦幅ってことになる if (GetClientRect(handleWin, out RECT cRect)) { MyTextBlock2.Text = $"ClientRect ({cRect.left}, {cRect.top}) (横幅:{cRect.right}, 縦幅:{cRect.bottom})"; }; //ウィンドウの名前表示 var winName = new StringBuilder(65535); GetWindowText(handleWin, winName, 65535); MyTextBlock3.Text = $"ウィンドウ名:{winName}"; } } }
今回もWindowsAPIばかりで、WPFあんまり関係ないね
青がウィンドウ領域で、紫がクライアント領域
ウィンドウの左右と下側の枠は半透明になっていて、ここもウィンドウの領域になるので、見た目より大きなサイズになっているみたい
メニューもウィンドウとして取得される
メモ帳のメニューの書式を開いて、その上にマウスカーソルを置いたところ、メモ帳とは別のウィンドウとして取得された
サイズを見てみるとウィンドウサイズは横幅が1405-1220=185、縦幅は447-397=50
その領域を青にしてみると
多分こんなかんじ
メニューには右下に影を落とす処理がされているけど、この部分は領域外みたいねえ
クライアント領域サイズは179と44
ピンクにしてみると
両方重ねてみると
こうかなあ
ボタンもウィンドウ?
ウィンドウ名にはボタンに書いてある文字が表示された、このアプリはWindowsFormで作ったもの
WPFで作ったのは?
ボタンの上においてもボタンじゃなくて、アプリのウィンドウが取得された
同じボタンでもアプリによって違うんだなあ
参照したところ
Windows(Windowsおよびメッセージ)-Win32アプリ | Microsoft Docs
docs.microsoft.com
スクリーン上でのウィンドウクライアント領域の取得 - 捨てられたブログ
blog.recyclebin.jp
【C#】アクティブウィンドウのウィンドウ名を取得 - プログラミングとかブログ
shirakamisauto.hatenablog.com
関連記事
前回のWindowsAPI記事は昨日
gogowaten.hatenablog.com
次回は4日後