Как использовать Win32 GetMonitorInfo() in.NET c#?
Я должен реализовать функцию, в которой сохраняется последняя позиция окна. При запуске приложения эта позиция должна быть получена и восстановлена.
теперь может быть, что второй монитор демонтирован. Если последняя позиция находится на Теперь невидимом мониторе (другими словами, сохраненные координаты находятся вне видимых координат), этот случай должен быть пойман, и координаты должны быть установлены по умолчанию, а не в последней позиции.
в порядке чтобы получить информацию о мониторах, мне нужно использовать Win32. Мне нелегко заставить это работать.
Я создал вспомогательный класс:
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);
любые предложения, что мне нужно сделать, чтобы исправить это?
2 ответов
вместо вызова собственного API вы должны использовать System.Windows.Forms.Screen
. Он должен иметь все, что вам нужно, и быть гораздо проще в использовании.
Screen.FromPoint
является управляемым эквивалентом вашего . Я просто заметил, что вы не используете эту опцию, поэтому вам может потребоваться написать свои собственные или использовать правильные подписи 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;
}
если вы предпочитаете делать вызовы 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;
}
ваш Rectangle2 должны использовать Int32
или просто int
, а не Int64
. Более подробную информацию можно найти здесь.
также это должна быть структура, а не класс. То же самое касается вашего класса MonitorInfo (это должна быть структура). Я бы рекомендовал попробовать версию по ссылке выше или сравнить их с вашими версиями.