如何从hWnd获取监视器屏幕分辨率?

25

如何从hWnd获取显示器屏幕分辨率?

我使用hWnd,因为窗口可以位于多个监视器中的任何一个上。

例如,hWnd的顶部/左侧坐标位于具有800 x 600屏幕分辨率的监视器上。

我使用一种称为PL/B的编程语言,它允许调用Windows API。

可以使用哪些Window API?

6个回答

27

这是一个对我有效的 C++ 代码示例:

HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(monitor, &info);
int monitor_width = info.rcMonitor.right - info.rcMonitor.left;
int monitor_height = info.rcMonitor.bottom - info.rcMonitor.top;

25
user32函数MonitorFromWindow可接受hwnd参数,并返回它所在的监视器的句柄(或默认值——请参见链接的MSDN文章了解详情)。使用该句柄,您可以调用GetMonitorInfo来检索一个包含详细分辨率的RECT的MONITORINFO结构体。 有关更多详细信息,请参见MSDN中的多屏幕参考部分。 我很想添加示例代码,但我不知道您提到的语言是什么,也不知道C#示例代码对您是否有用。如果您认为会有帮助,请告诉我,我会快速编写一些示例代码。

5

还有GetSystemMetrics,可以在msdn上查看。


3
确实,不过在用户拥有多个显示器的情况下,使用MonitorFromWindow会更加有效。 - sidewinderguy
@sidewinderguy,MONITORINFO结构体中的RECT rcWork是什么意思?我不明白MSDN上所说的“显示监视器的工作区矩形”。 - proton

4

这里是一段C#代码,通过P/Invoke获取分辨率(以DPI为单位):

public static void GetWindowDpi(IntPtr hwnd, out int dpiX, out int dpiY)
{
    var handle = MonitorFromWindow(hwnd, MonitorFlag.MONITOR_DEFAULTTOPRIMARY);

    GetDpiForMonitor(handle, MonitorDpiType.MDT_EFFECTIVE_DPI, out dpiX, out dpiY);
}

/// <summary>
/// Determines the function's return value if the window does not intersect any display monitor.
/// </summary>
[SuppressMessage("ReSharper", "IdentifierTypo")]
[SuppressMessage("ReSharper", "UnusedMember.Local")]
private enum MonitorFlag : uint
{
    /// <summary>Returns NULL.</summary>
    MONITOR_DEFAULTTONULL = 0,
    /// <summary>Returns a handle to the primary display monitor.</summary>
    MONITOR_DEFAULTTOPRIMARY = 1,
    /// <summary>Returns a handle to the display monitor that is nearest to the window.</summary>
    MONITOR_DEFAULTTONEAREST = 2
}

[DllImport("user32.dll")]
private static extern IntPtr MonitorFromWindow(IntPtr hwnd, MonitorFlag flag);

[SuppressMessage("ReSharper", "IdentifierTypo")]
[SuppressMessage("ReSharper", "UnusedMember.Local")]
private enum MonitorDpiType
{
    /// <summary>
    /// The effective DPI.
    /// This value should be used when determining the correct scale factor for scaling UI elements.
    /// This incorporates the scale factor set by the user for this specific display.
    /// </summary>
    MDT_EFFECTIVE_DPI = 0,
    /// <summary>
    /// The angular DPI.
    /// This DPI ensures rendering at a compliant angular resolution on the screen.
    /// This does not include the scale factor set by the user for this specific display.
    /// </summary>
    MDT_ANGULAR_DPI = 1,
    /// <summary>
    /// The raw DPI.
    /// This value is the linear DPI of the screen as measured on the screen itself.
    /// Use this value when you want to read the pixel density and not the recommended scaling setting.
    /// This does not include the scale factor set by the user for this specific display and is not guaranteed to be a supported DPI value.
    /// </summary>
    MDT_RAW_DPI = 2
}

[DllImport("user32.dll")]
private static extern bool GetDpiForMonitor(IntPtr hwnd, MonitorDpiType dpiType, out int dpiX, out int dpiY);

由于GetDpiForMonitor方法仅支持Windows 8.1及以下版本,因此此方法在较新的系统上不再适用。 - Filipsi
@Filipsi 你确定吗?我在编写这段代码的时候是使用的Windows 10。 - Drew Noakes
使用[DllImport("Shcore.dll")]导入Win 8.1及以上版本的GetDpiForMonitor方法。 - Yevheniy Tymchishin

0

对于高分辨率2K、4K并且>1920像素的显示器

void GetDesktopResolution(int* horizontal, int* vertical)
{

    HDC hScreenDC = GetDC(GetDesktopWindow());
    int width = GetDeviceCaps(hScreenDC, HORZRES);
    int height = GetDeviceCaps(hScreenDC, VERTRES);
    ReleaseDC(GetDesktopWindow(), hScreenDC);

    RECT desktop;
    const HWND hDesktop = GetDesktopWindow();
    GetWindowRect(hDesktop, &desktop);
    
    if (width > 2000)
    {
        const POINT ptZero = { 0, 0 };
        HMONITOR mon = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);

        DEVICE_SCALE_FACTOR f;// vers < win 8 = GetScaleFactorForDevice(DEVICE_PRIMARY);
        GetScaleFactorForMonitor(mon,&f);
        if (f > 110)
        {
            *horizontal = width * ((f+10) / 100.0);
            *vertical = height * ((f+10) / 100.0);
        }
        else
        {
            *horizontal = width;
            *vertical = height;
        }
    }
    else
    {
        *horizontal = desktop.right;
        *vertical = desktop.bottom;
    }
}

需要包含 "shellscalingapi.h"。 - Shriram Panchal

-2
RECT windowsize;    // get the height and width of the screen
GetClientRect(hwnd, &windowsize);

int srcheight = windowsize.bottom;
int srcwidth = windowsize.right;

这是一个窗口大小,而不是屏幕大小。 - NateS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接