为什么 GetWindowRect 在我的 WPF window 中包含标题栏?
Why does GetWindowRect include the title bar in my WPF window?
我正在尝试使用 GetWindowRect()
(和 GetGUIThreadInfo()
)获得插入符位置:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Runtime.InteropServices;
namespace WpfApplication1
{
public class CaretInfo
{
public double Width { get; private set; }
public double Height { get; private set; }
public double Left { get; private set; }
public double Top { get; private set; }
public CaretInfo(double width, double height, double left, double top)
{
Width = width;
Height = height;
Left = left;
Top = top;
}
}
public class CaretHelper
{
public static CaretInfo GetCaretPosition()
{
// Get GUI info containing caret poisition
var guiInfo = new GUITHREADINFO();
guiInfo.cbSize = (uint)Marshal.SizeOf(guiInfo);
GetGUIThreadInfo(0, out guiInfo);
// Get width/height
double width = guiInfo.rcCaret.right - guiInfo.rcCaret.left;
double height = guiInfo.rcCaret.bottom - guiInfo.rcCaret.top;
// Get left/top relative to screen
RECT rect;
GetWindowRect(guiInfo.hwndFocus, out rect);
double left = guiInfo.rcCaret.left + rect.left + 2;
double top = guiInfo.rcCaret.top + rect.top + 2;
int capacity = GetWindowTextLength(guiInfo.hwndFocus) * 2;
StringBuilder stringBuilder = new StringBuilder(capacity);
GetWindowText(guiInfo.hwndFocus, stringBuilder, stringBuilder.Capacity);
Console.WriteLine("Window: " + stringBuilder);
Console.WriteLine("Caret: " + guiInfo.rcCaret.left + ", " + guiInfo.rcCaret.top);
Console.WriteLine("Rect : " + rect.left + ", " + rect.top);
return new CaretInfo(width, height, left, top);
}
[DllImport("user32.dll", EntryPoint = "GetGUIThreadInfo")]
public static extern bool GetGUIThreadInfo(uint tId, out GUITHREADINFO threadInfo);
[DllImport("user32.dll")]
public static extern bool ClientToScreen(IntPtr hWnd, out Point position);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr handle, out RECT lpRect);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetClientRect(IntPtr hWnd, ref Rect rect);
[StructLayout(LayoutKind.Sequential)]
public struct GUITHREADINFO
{
public uint cbSize;
public uint flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCaret;
public RECT rcCaret;
};
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowTextLe
对于记事本和几乎任何其他地方都可以正确获取坐标:
在我的 WPF(和任何其他 WPF)中 window,但是,GetWindowRect()
决定包含标题栏并将插入符号顶部位置偏移标题栏的高度:
知道为什么吗?
我也尝试使用 DwmGetWindowAttribute()
,但它获得的 WPF window 坐标与 GetWindowRect()
.
相同
编辑:
有了 Brian Reichle 的回答,我已经能够确定一种获取客户区坐标的方法:
[DllImport("user32.dll")]
public static extern bool ClientToScreen(IntPtr hWnd, ref System.Drawing.Point lpPoint);
System.Drawing.Point point = new System.Drawing.Point(0, 0);
ClientToScreen(guiInfo.hwndFocus, ref point)
0,0
是guiInfo.hwndFocus
指定的window客户区的左上角坐标,总是0,0
,因为它是相对于window的客户区。 ClientToScreen()
将坐标转换为相对于屏幕的坐标(必须是 System.Drawing.Point
,System.Windows.Point
将不起作用)。
包含标题栏是因为它是 window 的一部分,如果您不想要 non-client 区域,则需要请求客户区域矩形 (GetClientRect
) .
记事本造成的混淆可能是因为您使用的是文本框的 window 句柄而不是 window 本身。请记住,WPF 对整个 window 使用单个句柄,而 win32 通常(但不总是)对 window.
中的每个控件使用单独的句柄
在您提到 GetClientRect
'returned' 0,0
的评论中,您是否检查过它返回的是 true(成功)还是 false(失败)?如果返回false,你检查GetLastError()
的结果了吗?
我正在尝试使用 GetWindowRect()
(和 GetGUIThreadInfo()
)获得插入符位置:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Runtime.InteropServices;
namespace WpfApplication1
{
public class CaretInfo
{
public double Width { get; private set; }
public double Height { get; private set; }
public double Left { get; private set; }
public double Top { get; private set; }
public CaretInfo(double width, double height, double left, double top)
{
Width = width;
Height = height;
Left = left;
Top = top;
}
}
public class CaretHelper
{
public static CaretInfo GetCaretPosition()
{
// Get GUI info containing caret poisition
var guiInfo = new GUITHREADINFO();
guiInfo.cbSize = (uint)Marshal.SizeOf(guiInfo);
GetGUIThreadInfo(0, out guiInfo);
// Get width/height
double width = guiInfo.rcCaret.right - guiInfo.rcCaret.left;
double height = guiInfo.rcCaret.bottom - guiInfo.rcCaret.top;
// Get left/top relative to screen
RECT rect;
GetWindowRect(guiInfo.hwndFocus, out rect);
double left = guiInfo.rcCaret.left + rect.left + 2;
double top = guiInfo.rcCaret.top + rect.top + 2;
int capacity = GetWindowTextLength(guiInfo.hwndFocus) * 2;
StringBuilder stringBuilder = new StringBuilder(capacity);
GetWindowText(guiInfo.hwndFocus, stringBuilder, stringBuilder.Capacity);
Console.WriteLine("Window: " + stringBuilder);
Console.WriteLine("Caret: " + guiInfo.rcCaret.left + ", " + guiInfo.rcCaret.top);
Console.WriteLine("Rect : " + rect.left + ", " + rect.top);
return new CaretInfo(width, height, left, top);
}
[DllImport("user32.dll", EntryPoint = "GetGUIThreadInfo")]
public static extern bool GetGUIThreadInfo(uint tId, out GUITHREADINFO threadInfo);
[DllImport("user32.dll")]
public static extern bool ClientToScreen(IntPtr hWnd, out Point position);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr handle, out RECT lpRect);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetClientRect(IntPtr hWnd, ref Rect rect);
[StructLayout(LayoutKind.Sequential)]
public struct GUITHREADINFO
{
public uint cbSize;
public uint flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCaret;
public RECT rcCaret;
};
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowTextLe
对于记事本和几乎任何其他地方都可以正确获取坐标:
在我的 WPF(和任何其他 WPF)中 window,但是,GetWindowRect()
决定包含标题栏并将插入符号顶部位置偏移标题栏的高度:
知道为什么吗?
我也尝试使用 DwmGetWindowAttribute()
,但它获得的 WPF window 坐标与 GetWindowRect()
.
编辑:
有了 Brian Reichle 的回答,我已经能够确定一种获取客户区坐标的方法:
[DllImport("user32.dll")]
public static extern bool ClientToScreen(IntPtr hWnd, ref System.Drawing.Point lpPoint);
System.Drawing.Point point = new System.Drawing.Point(0, 0);
ClientToScreen(guiInfo.hwndFocus, ref point)
0,0
是guiInfo.hwndFocus
指定的window客户区的左上角坐标,总是0,0
,因为它是相对于window的客户区。 ClientToScreen()
将坐标转换为相对于屏幕的坐标(必须是 System.Drawing.Point
,System.Windows.Point
将不起作用)。
包含标题栏是因为它是 window 的一部分,如果您不想要 non-client 区域,则需要请求客户区域矩形 (GetClientRect
) .
记事本造成的混淆可能是因为您使用的是文本框的 window 句柄而不是 window 本身。请记住,WPF 对整个 window 使用单个句柄,而 win32 通常(但不总是)对 window.
中的每个控件使用单独的句柄在您提到 GetClientRect
'returned' 0,0
的评论中,您是否检查过它返回的是 true(成功)还是 false(失败)?如果返回false,你检查GetLastError()
的结果了吗?