gpt4 book ai didi

c# - 如何在 .NET c# 中使用 Win32 GetMonitorInfo()?

转载 作者:太空狗 更新时间:2023-10-29 21:14:34 25 4
gpt4 key购买 nike

我必须实现一个保存窗口最后位置的功能。当应用程序启动时,需要获取并恢复这个位置。

现在可能是拆除了第二台显示器。如果最后一个位置在现在不可见的监视器上(换句话说,保存的坐标在可见坐标之外),则应捕获这种情况并将坐标设置为默认位置而不是最后一个位置。

为了检索有关监视器的信息,我需要使用 Win32。完成这项工作对我来说并不容易。

我创建了一个 Helper 类:

public static class DisplayHelper
{
private const int MONITOR_DEFAULTTONEAREST = 2;

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern int GetSystemMetrics(int nIndex);

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern UInt32 MonitorFromPoint(Point pt, UInt32 dwFlags);

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern bool GetMonitorInfo(UInt32 monitorHandle, ref MonitorInfo mInfo);


public static void GetMonitorInfoNow(MonitorInfo mi, Point pt)
{
UInt32 mh = MonitorFromPoint(pt, 0);
mi.cbSize = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(typeof(MonitorInfo));
mi.dwFlags = 0;
bool result = GetMonitorInfo(mh, ref mi);

}
}

这些是我创建 MonitorInfo 和 Rect 类的尝试:

[StructLayout(LayoutKind.Sequential)]
public class MonitorInfo
{
public UInt32 cbSize;
public Rectangle2 rcMonitor;
public Rectangle2 rcWork;
public UInt32 dwFlags;

public MonitorInfo()
{
rcMonitor = new Rectangle2();
rcWork = new Rectangle2();

cbSize = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(typeof(MonitorInfo));
dwFlags = 0;
}
}

[StructLayout(LayoutKind.Sequential)]
public class Rectangle2
{
public UInt64 left;
public UInt64 top;
public UInt64 right;
public UInt64 bottom;

public Rectangle2()
{
left = 0;
top = 0;
right = 0;
bottom = 0;
}
}

我正在使用这样的代码来获取可见监视器:

//80 means it counts only visible display monitors.
int lcdNr = DisplayHelper.GetSystemMetrics(80);
var point = new System.Drawing.Point((int) workSpaceWindow.Left, (int) workSpaceWindow.Top);
MonitorInfo monitorInfo = new MonitorInfo();
DisplayHelper.GetMonitorInfoNow(monitorInfo, point);

最后一个方法在尝试执行时抛出异常

bool result = GetMonitorInfo(mh, ref mi);

有什么建议可以解决这个问题吗?

最佳答案

与其调用 native API,不如使用 System.Windows.Forms.Screen .它应该拥有您需要的一切,并且更易于使用。

Screen.FromPoint是具有 MONITOR_DEFAULTTONEAREST 选项的 GetMonitorInfoNow 函数的托管等效项。我只是注意到您没有使用该选项,因此您可能必须自己编写或使用正确的 P/Invoke 签名。

如果您只引用 System.DrawingSystem.Windows.Forms,编写您自己的应该相当简单。这两个都应该有效:

static Screen ScreenFromPoint1(Point p)
{
System.Drawing.Point pt = new System.Drawing.Point((int)p.X, (int)p.Y);
return Screen.AllScreens
.Where(scr => scr.Bounds.Contains(pt))
.FirstOrDefault();
}

static Screen ScreenFromPoint2(Point p)
{
System.Drawing.Point pt = new System.Drawing.Point((int)p.X, (int)p.Y);
var scr = Screen.FromPoint(pt);
return scr.Bounds.Contains(pt) ? scr : null;
}

如果您更喜欢自己进行 Win32 调用,则需要调用的函数的正确 P/Invoke 签名(即您从反编译 .Net DLL 中获得的签名)是:

    [DllImport("User32.dll", CharSet=CharSet.Auto)] 
public static extern bool GetMonitorInfo(HandleRef hmonitor, [In, Out]MONITORINFOEX info);
[DllImport("User32.dll", ExactSpelling=true)]
public static extern IntPtr MonitorFromPoint(POINTSTRUCT pt, int flags);

[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto, Pack=4)]
public class MONITORINFOEX {
public int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX));
public RECT rcMonitor = new RECT();
public RECT rcWork = new RECT();
public int dwFlags = 0;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=32)]
public char[] szDevice = new char[32];
}

[StructLayout(LayoutKind.Sequential)]
public struct POINTSTRUCT {
public int x;
public int y;
public POINTSTRUCT(int x, int y) {
this.x = x;
this.y = y;
}
}

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

关于c# - 如何在 .NET c# 中使用 Win32 GetMonitorInfo()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6279076/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com