私はGetWindowRect()
(およびGetGUIThreadInfo()
)を使用して、キャレット位置を取得しようとしているメモ帳の場合GetWindowRectにWPFウィンドウのタイトルバーが表示されるのはなぜですか?
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のウィンドウでは、GetWindowRect()
はタイトルバーを含め、キャレットのトップ位置をタイトルバーの高さでオフセットすることを決めます。
何故でしょうか?
DwmGetWindowAttribute()
も試してみましたが、WPFウィンドウの座標は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
で指定されたウィンドウのクライアント領域です。ウィンドウのクライアント領域に相対的なので、常に0,0
です。 ClientToScreen()
は座標を画面の相対座標に変換します(System.Drawing.Point
、System.Windows.Point
は動作しません)。
タイトルバーが含まれているのは、ウィンドウの一部です。クライアント以外の領域を必要としない場合は、クライアント領域rect(GetClientRect)を要求する必要があります。メモ帳の混乱はおそらく、ウィンドウ自体ではなくテキストボックスのウィンドウハンドルを使用しているためです。 WPFはウィンドウ全体に単一のハンドルを使用するのに対し、win32はしばしばウィンドウ内の各コントロールに別々のハンドルを使用します(常にそうとは限りません)。 –
'GetClientRect()'は0,0を返しますが、ウィンドウハンドルについてはあなたが正しいと思います。私はSpy ++で少なくとも確認することができます。 – Woodgnome