加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-15 08:27:45 所属栏目:百科 来源:网络整理
导读:我必须实现一个保存窗口最后位置的功能.当应用程序启动时,需要获取并恢复该位置. 现在可能会拆除第二台显示器.如果最后一个位置在现在不可见的监视器上(换句话说,保存的坐标在可见坐标之外),则应捕获此情况并将坐标设置为默认位置而不是最后位置. 为了检索有
我必须实现一个保存窗口最后位置的功能.当应用程序启动时,需要获取并恢复该位置.

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

为了检索有关监视器的信息,我需要使用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",ExactSpelling = true)]
        private static extern UInt32 MonitorFromPoint(Point pt,UInt32 dwFlags);

        [DllImport("user32.dll",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);

有什么建议我需要做些什么来解决这个问题?

解决方法

您应该使用 System.Windows.Forms.Screen而不是调用本机API.它应该包含您需要的所有内容,并且更易于使用.

Screen.FromPoint是具有MONITOR_DEFAULTTONEAREST选项的GetMonitorInfoNow函数的托管等效项.我刚刚注意到你没有使用该选项,所以你可能必须自己编写或使用正确的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; 
    }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读