Hou*_*man 6 .net c# winapi multiple-monitors user32
我必须实现一个保存窗口最后位置的功能.当应用程序启动时,需要获取并恢复该位置.
现在可能会拆除第二台显示器.如果最后一个位置在现在不可见的监视器上(换句话说,保存的坐标在可见坐标之外),则应捕获此情况并将坐标设置为默认位置而不是最后位置.
为了检索有关监视器的信息,我需要使用Win32.我不容易做这项工作.
我创建了一个Helper CLass:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
这些是我尝试创建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;
}
}
Run Code Online (Sandbox Code Playgroud)
我正在使用这样的代码来获取可见的监视器:
//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);
Run Code Online (Sandbox Code Playgroud)
最后一个方法在尝试执行时抛出异常
bool result = GetMonitorInfo(mh, ref mi);
Run Code Online (Sandbox Code Playgroud)
有什么建议我需要做些什么来解决这个问题?
您应该使用而不是调用本机API System.Windows.Forms.Screen
.它应该拥有您需要的一切,并且更容易使用.
Screen.FromPoint
是GetMonitorInfoNow
使用该MONITOR_DEFAULTTONEAREST
选项的函数的托管等效项.我刚刚注意到你没有使用该选项,所以你可能必须自己编写或使用正确的P/Invoke签名.
如果你只是参考System.Drawing
和编写自己的应该是相当简单的System.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;
}
Run Code Online (Sandbox Code Playgroud)
如果您更喜欢自己进行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;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
9961 次 |
最近记录: |