ClientToScreen意外返回值?

时间:2015-12-30 17:33:09

标签: c#

我之前从未使用过Windows。我花了很多精力来获得正确的X和Y坐标和窗口大小,以及窗口客户区域的大小。

不幸的是,客户区的X和Y始终为零。我在文档中查找了它,它应该是零。

在SO上,我发现我需要将客户端 - 通过传递给ClientToScreen()来协调屏幕坐标。但是,结果并不是我所期望的结果。

而不是Point(50,50)(或类似),我得到一个点(1,57027688545264E-312,0)。

有人可以告诉我什么是错的吗?

这是我的代码,到目前为止:

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool GetClientRect(IntPtr hWnd, out Rect rect);

    [DllImport("user32.dll")]
    static extern bool ClientToScreen(IntPtr hWnd, ref System.Windows.Point lpPoint);

    [StructLayout(LayoutKind.Sequential)]
    public struct Rect
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }

    static Rectangle GetClientRect(IntPtr handle)
    {
        Rect rect;
        GetClientRect(handle, out rect);
        System.Windows.Point p = new System.Windows.Point(0, 0);
        ClientToScreen(handle, ref p);
        rect.Left = (int)p.X;
        rect.Top = (int)p.Y;
        return new Rectangle(rect.Left, rect.Top, rect.Right, rect.Bottom);
    }

2 个答案:

答案 0 :(得分:3)

System.Windows.Point结构与ClientToScreen不兼容。您应该使用System.Drawing.Point代替。

答案 1 :(得分:1)

以下是如何将窗口坐标中的点转换为屏幕坐标以及如何获取窗口的大小:

XAML:

<Window x:Class="WpfApplication2.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:WpfApplication2"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <Button x:Name="ButtonClientToScreen" Content="ButtonClientToScreen" Height="20" Click="ButtonClientToScreen_Click"></Button>
            <Button x:Name="ButtonGetClientRect" Content="ButtonGetClientRect" Height="20" Click="ButtonGetClientRect_Click"  ></Button>
        </StackPanel>
    </Grid>
</Window>

代码隐藏:

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;

namespace WpfApplication2
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private IntPtr GetHandle()
        {
            var helper = new WindowInteropHelper(this);
            var handle = helper.Handle;
            return handle;
        }

        private void ButtonClientToScreen_Click(object sender, RoutedEventArgs e)
        {
            // convert a point in window coords to screen coords
            var handle = GetHandle();
            var point = new NativePoint {x = 50, y = 50};
            var clientToScreen = NativeMethods.ClientToScreen(handle, ref point);
            if (clientToScreen)
            {
                MessageBox.Show(this, string.Format("ClientToScreen: {0}", point));
            }
        }

        private void ButtonGetClientRect_Click(object sender, RoutedEventArgs e)
        {
            // get window size
            var handle = GetHandle();
            NativeRect rect;
            var clientRect = NativeMethods.GetClientRect(handle, out rect);
            if (clientRect)
            {
                MessageBox.Show(this, string.Format("GetClientRect: {0}", rect));
            }
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct NativeRect
    {
        public int left;
        public int top;
        public int right;
        public int bottom;

        public override string ToString()
        {
            return $"Left: {left}, Top: {top}, Right: {right}, Bottom: {bottom}";
        }
    }


    [StructLayout(LayoutKind.Sequential)]
    public struct NativePoint
    {
        public int x;
        public int y;

        public override string ToString()
        {
            return $"X: {x}, Y: {y}";
        }
    }

    public class NativeMethods
    {
        [DllImport("user32.dll", EntryPoint = "GetClientRect")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetClientRect([In] IntPtr hWnd, [Out] out NativeRect lpRect);

        [DllImport("user32.dll", EntryPoint = "ClientToScreen")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool ClientToScreen([In] IntPtr hWnd, ref NativePoint lpPoint);
    }
}

将窗口rect转换为屏幕坐标:

  • 致电GetClientRect
  • 调用ClientToScreen,x = 0,y = 0
  • 由GetClientRect按照ClientToScreen收到的金额
  • 收到的偏移

编辑1:

尝试移动/调整窗口大小并按下按钮,您将了解这一切是如何工作的。

编辑2:

以下是将窗口坐标/尺寸转换为屏幕的方法:

    private void ButtonWindowToScreenRect_Click(object sender, RoutedEventArgs e)
    {
        var handle = GetHandle();
        var point = new NativePoint();
        NativeMethods.ClientToScreen(handle, ref point);
        NativeRect rect;
        NativeMethods.GetClientRect(handle, out rect);

        var win2screenRect = new NativeRect
        {
            left = rect.left + point.x,
            right = rect.right + point.x,
            top = rect.top + point.y,
            bottom = rect.bottom + point.y
        };
        MessageBox.Show(this, win2screenRect.ToString());
    }