C# 通过注册表、API两种方式获取显示器的分辨率尺寸
还是那个项目……还是那个领导……要求获取用户的显示器尺寸。一脸懵逼???还是照做……
获取显示器的尺寸,有两种方法。第一种是通过查询注册表中,存储的指定显示器的相关信息;第二种是通过windows API
1、查询注册表中存储的显示器信息
/// <summary> /// 获取显示器的相关硬件ID /// </summary> /// <returns></returns> public static List<string> GetMonitorPnpDeviceId() { List<string> rt = new List<string>(); using (ManagementClass mc = new ManagementClass("Win32_DesktopMonitor")) { using (ManagementObjectCollection moc = mc.GetInstances()) { foreach (var o in moc) { var each = (ManagementObject)o; object obj = each.Properties["PNPDeviceID"].Value; if (obj == null) continue; rt.Add(obj.ToString()); } } } return rt; } /// <summary> /// 通过硬件ID查找系统存储的相关信息 /// </summary> /// <param name="monitorPnpDevId"></param> /// <returns></returns> public static byte[] GetMonitorEdid(string monitorPnpDevId) { return (byte[])Registry.GetValue(@"HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\" + monitorPnpDevId + @"\Device Parameters", "EDID", new byte[] { }); } /// <summary> /// 获取显示器物理尺寸(cm) /// </summary> /// <param name="monitorPnpDevId">屏幕信息</param> /// <returns>物理尺寸</returns> public static Size GetMonitorPhysicalSize(string monitorPnpDevId) { byte[] edid = GetMonitorEdid(monitorPnpDevId); if (edid.Length < 23) return Size.Empty; return new Size(edid[21], edid[22]); } /// <summary> /// 通过屏显示器理尺寸转换为显示器大小(inch) /// </summary> /// <param name="moniPhySize"></param> /// <returns></returns> public static float MonitorScaler(Size moniPhySize) { double mDSize = Math.Sqrt(Math.Pow(moniPhySize.Width, 2) + Math.Pow(moniPhySize.Height, 2)) / 2.54d; return (float)Math.Round(mDSize, 1); }
使用上述方法,稍微有点繁琐,需要调用多次,才能获得相关的信息。但好处是,可以获得多个显示器的尺寸信息。问题是……公司用的是云桌面,虚拟机,TMD这个方法获取不到数据(不知道是不是我操作的不对……)???所以又老老实实使用API来获取了。
2、使用Windows API 查询显示器信息
1、使用GetSystemMetrics API获取
GetSystemMetrics API最为简单,直接引用API,传入对应的变量,获得相关的数据,引用API调用即可:
[DllImport("user32")] public static extern int GetSystemMetrics(int nIndex);
其中,nIndex的类型如下:
class SystemMetricsType { const int SM_CXSCREEN = 0;//屏幕宽度 const int SM_CYSCREEN = 1;//屏幕高度 const int SM_CXVSCROLL = 2;//垂直滚动条的宽度 const int SM_CYHSCROLL = 3;//水平滚动条的宽度 const int SM_CYCAPTION = 4;//Height of windows caption 实际标题高度加上SM_CYBORDER const int SM_CXBORDER = 5;//Width of no-sizable borders 无法测量的窗口框架宽度 const int SM_CYBORDER = 6;//Height of non-sizable borders 无法测量的窗口框架高度 const int SM_CXDLGFRAME = 7;//Width of dialog box borders const int SM_CYDLGFRAME = 8;//Height of dialog box borders const int SM_CYHTHUMB = 9;//Height of scroll box on horizontal scroll bar 水平滚动条上滑块的高度 const int SM_CXHTHUMB = 10;// Width of scroll box on horizontal scroll bar 水平滚动条上滑块的宽度 const int SM_CXICON = 11;//Width of standard icon 图标宽度 const int SM_CYICON = 12;//Height of standard icon 图标高度 const int SM_CXCURSOR = 13;//Width of standard cursor 光标宽度 const int SM_CYCURSOR = 14;//Height of standard cursor 光标高度 const int SM_CYMENU = 15;//Height of menu 以像素计算的单个菜单条的高度 const int SM_CXFULLSCREEN = 16;//Width of client area of maximized window const int SM_CYFULLSCREEN = 17;//Height of client area of maximized window const int SM_CYKANJIWINDOW = 18;//Height of Kanji window const int SM_MOUSEPRESENT = 19;//True is a mouse is present 如果为TRUE或不为0的值则安装了鼠标,否则没有安装。 const int SM_CYVSCROLL = 20;//Height of arrow in vertical scroll bar const int SM_CXHSCROLL = 21;//Width of arrow in vertical scroll bar const int SM_DEBUG = 22;//True if deugging version of windows is running const int SM_SWAPBUTTON = 23;//True if left and right buttons are swapped. const int SM_CXMIN = 28;//Minimum width of window const int SM_CYMIN = 29;//Minimum height of window const int SM_CXSIZE = 30;//Width of title bar bitmaps const int SM_CYSIZE = 31;//height of title bar bitmaps const int SM_CXMINTRACK = 34;//Minimum tracking width of window const int SM_CYMINTRACK = 35;//Minimum tracking height of window const int SM_CXDOUBLECLK = 36;//double click width const int SM_CYDOUBLECLK = 37;//double click height const int SM_CXICONSPACING = 38;//width between desktop icons const int SM_CYICONSPACING = 39;//height between desktop icons const int SM_MENUDROPALIGNMENT = 40;//Zero if popup menus are aligned to the left of the memu bar item. True if it is aligned to the right. const int SM_PENWINDOWS = 41;//The handle of the pen windows DLL if loaded. const int SM_DBCSENABLED = 42;//True if double byte characteds are enabled const int SM_CMOUSEBUTTONS = 43;//Number of mouse buttons. const int SM_CMETRICS = 44;//Number of system metrics const int SM_CLEANBOOT = 67;//Windows 95 boot mode. 0 = normal; 1 = safe; 2 = safe with network const int SM_CXMAXIMIZED = 61;//default width of win95 maximised window const int SM_CXMAXTRACK = 59;//maximum width when resizing win95 windows const int SM_CXMENUCHECK = 71;//width of menu checkmark bitmap const int SM_CXMENUSIZE = 54;//width of button on menu bar const int SM_CXMINIMIZED = 57;//width of rectangle into which minimised windows must fit. const int SM_CYMAXIMIZED = 62;//default height of win95 maximised window const int SM_CYMAXTRACK = 60;//maximum width when resizing win95 windows const int SM_CYMENUCHECK = 72;//height of menu checkmark bitmap const int SM_CYMENUSIZE = 55;//height of button on menu bar const int SM_CYMINIMIZED = 58;//height of rectangle into which minimised windows must fit. const int SM_CYSMCAPTION = 51;//height of windows 95 small caption const int SM_MIDEASTENABLED = 74;//Hebrw and Arabic enabled for windows 95 const int SM_NETWORK = 63;//bit o is set if a network is present. const int SM_SECURE = 44;//True if security is present on windows 95 system const int SM_SLOWMACHINE = 73;//true if machine is too slow to run win95. }
踩过了坑,才知道哪里会有坑……所以,只有分辨率?没有物理尺寸大小???上GetDeviceCaps API。
2、使用GetDeviceCaps API获取
使用GetDeviceCaps API时,需要传入一个句柄,需要使用GetDC API,但是……GetDC和ReleaseDC两个API是成对出现的,必须要释放句柄,否则容易造成内存泄漏。
/// <summary> /// 获取DC句柄 /// </summary> [DllImport("user32.dll")] static extern IntPtr GetDC(IntPtr hdc); /// <summary> /// 释放DC句柄 /// </summary> [DllImport("user32.dll", EntryPoint = "ReleaseDC")] static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hdc); /// <summary> /// 获取句柄指定的数据 /// </summary> [DllImport("gdi32.dll")] static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
以下是使用上述API获取屏幕尺寸的示例代码,不知道怎么用的可以看看。但是这个API获取的是当前屏幕的尺寸……
class MonitorHelper { /// <summary> /// 获取DC句柄 /// </summary> [DllImport("user32.dll")] static extern IntPtr GetDC(IntPtr hdc); /// <summary> /// 释放DC句柄 /// </summary> [DllImport("user32.dll", EntryPoint = "ReleaseDC")] static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hdc); /// <summary> /// 获取句柄指定的数据 /// </summary> [DllImport("gdi32.dll")] static extern int GetDeviceCaps(IntPtr hdc, int nIndex); /// <summary> /// 获取分辨率 /// </summary> /// <returns></returns> public static Size GetResolution() { Size size = new Size(); IntPtr hdc = GetDC(IntPtr.Zero); size.Width = GetDeviceCaps(hdc, DeviceCapsType.DESKTOPHORZRES); size.Height = GetDeviceCaps(hdc, DeviceCapsType.DESKTOPVERTRES); ReleaseDC(IntPtr.Zero, hdc); return size; } /// <summary> /// 获取屏幕物理尺寸(mm,mm) /// </summary> /// <returns></returns> public static Size GetScreenSize() { Size size = new Size(); IntPtr hdc = GetDC(IntPtr.Zero); size.Width = GetDeviceCaps(hdc, DeviceCapsType.HORZSIZE); size.Height = GetDeviceCaps(hdc, DeviceCapsType.VERTSIZE); ReleaseDC(IntPtr.Zero, hdc); return size; } /// <summary> /// 获取屏幕的尺寸---inch /// </summary> /// <returns></returns> public static float GetScreenInch() { Size size = GetScreenSize(); double inch = Math.Round(Math.Sqrt(Math.Pow(size.Width, 2) + Math.Pow(size.Height, 2)) / 25.4, 1); return (float)inch; } }
GetDeviceCaps的第二个参数,值可以是:
/// <summary> /// GetDeviceCaps 的 nidex值 /// </summary> class DeviceCapsType { const int DRIVERVERSION = 0; const int TECHNOLOGY = 2; const int HORZSIZE = 4;//以毫米为单位的显示宽度 const int VERTSIZE = 6;//以毫米为单位的显示高度 const int HORZRES = 8; const int VERTRES = 10; const int BITSPIXEL = 12; const int PLANES = 14; const int NUMBRUSHES = 16; const int NUMPENS = 18; const int NUMMARKERS = 20; const int NUMFONTS = 22; const int NUMCOLORS = 24; const int PDEVICESIZE = 26; const int CURVECAPS = 28; const int LINECAPS = 30; const int POLYGONALCAPS = 32; const int TEXTCAPS = 34; const int CLIPCAPS = 36; const int RASTERCAPS = 38; const int ASPECTX = 40; const int ASPECTY = 42; const int ASPECTXY = 44; const int SHADEBLENDCAPS = 45; const int LOGPIXELSX = 88;//像素/逻辑英寸(水平) const int LOGPIXELSY = 90; //像素/逻辑英寸(垂直) const int SIZEPALETTE = 104; const int NUMRESERVED = 106; const int COLORRES = 108; const int PHYSICALWIDTH = 110; const int PHYSICALHEIGHT = 111; const int PHYSICALOFFSETX = 112; const int PHYSICALOFFSETY = 113; const int SCALINGFACTORX = 114; const int SCALINGFACTORY = 115; const int VREFRESH = 116; const int DESKTOPVERTRES = 117;//垂直分辨率 const int DESKTOPHORZRES = 118;//水平分辨率 const int BLTALIGNMENT = 119; }
2024-11-01 15:51:25【出处】:https://www.cnblogs.com/pilgrim/p/15115925.html
=======================================================================================
个人使用
根据上面所说的,我自己做了一个应用。
需求:每次打开虚拟机的窗口大小不是我想要的大小,随说可以使用鼠标拖动窗口大小,但无法准确窗口位置和大小,所以想使用程序重设窗口位置和大小。以下是临时解决方案代码:
// Win32 API程序 using System; using System.Collections.Generic; using System.Linq; namespace ReSizeApp { using System.Diagnostics; using System.Runtime.InteropServices; public class Win32 { [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); [DllImport("user32.dll")] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); #region 设置窗口位置 [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); public const uint SWP_NOSIZE = 0x1; public const uint SWP_NOMOVE = 0x2; public const uint SWP_SHOWWINDOW = 0x40; public const uint wndInsertAfter = 0x0; #endregion #region 使用Windows API 查询显示器信息 internal enum IndexType { SM_CXSCREEN = 0,//屏幕宽度 SM_CYSCREEN = 1,//屏幕高度 SM_CXVSCROLL = 2,//垂直滚动条的宽度 SM_CYHSCROLL = 3,//水平滚动条的宽度 SM_CYCAPTION = 4,//Height of windows caption 实际标题高度加上SM_CYBORDER SM_CXBORDER = 5,//Width of no-sizable borders 无法测量的窗口框架宽度 SM_CYBORDER = 6,//Height of non-sizable borders 无法测量的窗口框架高度 SM_CXDLGFRAME = 7,//Width of dialog box borders SM_CYDLGFRAME = 8,//Height of dialog box borders SM_CYHTHUMB = 9,//Height of scroll box on horizontal scroll bar 水平滚动条上滑块的高度 SM_CXHTHUMB = 10,// Width of scroll box on horizontal scroll bar 水平滚动条上滑块的宽度 SM_CXICON = 11,//Width of standard icon 图标宽度 SM_CYICON = 12,//Height of standard icon 图标高度 SM_CXCURSOR = 13,//Width of standard cursor 光标宽度 SM_CYCURSOR = 14,//Height of standard cursor 光标高度 SM_CYMENU = 15,//Height of menu 以像素计算的单个菜单条的高度 SM_CXFULLSCREEN = 16,//Width of client area of maximized window SM_CYFULLSCREEN = 17,//Height of client area of maximized window SM_CYKANJIWINDOW = 18,//Height of Kanji window SM_MOUSEPRESENT = 19,//True is a mouse is present 如果为TRUE或不为0的值则安装了鼠标,否则没有安装。 SM_CYVSCROLL = 20,//Height of arrow in vertical scroll bar SM_CXHSCROLL = 21,//Width of arrow in vertical scroll bar SM_DEBUG = 22,//True if deugging version of windows is running SM_SWAPBUTTON = 23,//True if left and right buttons are swapped. SM_CXMIN = 28,//Minimum width of window SM_CYMIN = 29,//Minimum height of window SM_CXSIZE = 30,//Width of title bar bitmaps SM_CYSIZE = 31,//height of title bar bitmaps SM_CXMINTRACK = 34,//Minimum tracking width of window SM_CYMINTRACK = 35,//Minimum tracking height of window SM_CXDOUBLECLK = 36,//double click width SM_CYDOUBLECLK = 37,//double click height SM_CXICONSPACING = 38,//width between desktop icons SM_CYICONSPACING = 39,//height between desktop icons SM_MENUDROPALIGNMENT = 40,//Zero if popup menus are aligned to the left of the memu bar item. True if it is aligned to the right. SM_PENWINDOWS = 41,//The handle of the pen windows DLL if loaded. SM_DBCSENABLED = 42,//True if double byte characteds are enabled SM_CMOUSEBUTTONS = 43,//Number of mouse buttons. SM_CMETRICS = 44,//Number of system metrics SM_CLEANBOOT = 67,//Windows 95 boot mode. 0 = normal, 1 = safe, 2 = safe with network SM_CXMAXIMIZED = 61,//default width of win95 maximised window SM_CXMAXTRACK = 59,//maximum width when resizing win95 windows SM_CXMENUCHECK = 71,//width of menu checkmark bitmap SM_CXMENUSIZE = 54,//width of button on menu bar SM_CXMINIMIZED = 57,//width of rectangle into which minimised windows must fit. SM_CYMAXIMIZED = 62,//default height of win95 maximised window SM_CYMAXTRACK = 60,//maximum width when resizing win95 windows SM_CYMENUCHECK = 72,//height of menu checkmark bitmap SM_CYMENUSIZE = 55,//height of button on menu bar SM_CYMINIMIZED = 58,//height of rectangle into which minimised windows must fit. SM_CYSMCAPTION = 51,//height of windows 95 small caption SM_MIDEASTENABLED = 74,//Hebrw and Arabic enabled for windows 95 SM_NETWORK = 63,//bit o is set if a network is present. SM_SECURE = 44,//True if security is present on windows 95 system SM_SLOWMACHINE = 73,//true if machine is too slow to run win95. } [DllImport("user32")] public static extern int GetSystemMetrics(int nIndex); public static ValueTuple<int, int> GetScreen() { int w = GetSystemMetrics(((int)IndexType.SM_CXSCREEN)); int h = GetSystemMetrics(((int)IndexType.SM_CYSCREEN)); return (w, h); } public static ValueTuple<int, int> GetScreenWorkingArea() { int w = GetSystemMetrics(16); int h = GetSystemMetrics(17); return (w, h); } #endregion [DllImport("user32.dll")] public static extern IntPtr FindWindowByProcessId(int processId, int threadId); // 根据进程ID获取窗口句柄 public static IntPtr GetWindowHandleByProcessIdByApi(int processId) { IntPtr hwnd = FindWindowByProcessId(processId, 0); return hwnd; } // 根据进程ID获取窗口句柄 public static IntPtr GetWindowHandleByProcessIdByProcess(int processId) { Process pro = Process.GetProcessById(processId); return pro.MainWindowHandle; } public static IntPtr GetWindowHandleByProcessNameByProcess(string processName) { Process pro = Process.GetProcessesByName(processName).FirstOrDefault(); return pro.MainWindowHandle; } } } //主程序 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ReSizeApp { internal class Program { static void Main(string[] args) { string pk = "", pv = ""; try { if (args.Length == 1) { pk = args[0].Split(':')[0].TrimStart('/').TrimStart('-'); pv = args[0].Split(':')[1].Trim(); } else showHelp(); } catch (Exception ex) { Console.WriteLine("发生异常:" + ex); showHelp(); return; } IntPtr hd = IntPtr.Zero; if (pk.ToLower() == "name") { var processName = pv; if (Path.GetExtension(processName) == ".exe") processName = processName.Replace(".exe", ""); hd = Win32.GetWindowHandleByProcessNameByProcess(processName); } if (pk.ToLower() == "id") { hd = Win32.GetWindowHandleByProcessIdByProcess(int.Parse(pv)); } if (hd != IntPtr.Zero) { var workArea = Win32.GetScreenWorkingArea(); Console.WriteLine(workArea.ToString()); //Win32.SetWindowPos(hd, 0, 0, 0, workArea.Item1, workArea.Item2 +23, Win32.SWP_SHOWWINDOW); Win32.SetWindowPos(hd, IntPtr.Zero, 0, 0, 1920, 1040, Win32.SWP_SHOWWINDOW); } } private static void showHelp() { Console.WriteLine("参数用法:使用name或id参数,只能使用一种"); Console.WriteLine("格式:"); Console.WriteLine("-name:notepad.exe 或者 -id:12345"); Console.WriteLine("/name:notepad.exe 或者 /id:12345"); } } }
因为以上是临时代码,很多都是写死的代码,容错,参数等都有待完善,后面改用python实现。
具体可参考: Python获取屏幕分辨率,工作区间,任务栏高度
关注我】。(●'◡'●)
如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的【因为,我的写作热情也离不开您的肯定与支持,感谢您的阅读,我是【Jack_孟】!
本文来自博客园,作者:jack_Meng,转载请注明原文链接:https://www.cnblogs.com/mq0036/p/18520416
【免责声明】本文来自源于网络,如涉及版权或侵权问题,请及时联系我们,我们将第一时间删除或更改!