How to use GetMonitorCapabilities and GetMonitorBrightness functions
Asked Answered
B

1

7

I'm trying to adjust my monitor brightness programmatically. After little bit of research, I came up with this link, and wrote the following code (mostly copy paste from other links that one lead me).

#include "Windows.h"
#include "WinUser.h"
#include "PhysicalMonitorEnumerationAPI.h"
#include "HighLevelMonitorConfigurationAPI.h"
#include <strsafe.h>

void ShowError(LPTSTR lpszFunction);

int main()
{
    HMONITOR hMonitor = NULL;
    DWORD cPhysicalMonitors;
    LPPHYSICAL_MONITOR pPhysicalMonitors = NULL;

    HWND hWnd = GetDesktopWindow();

    // Get the monitor handle.
    hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY);

    // Get the number of physical monitors.
    BOOL bSuccess = GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, &cPhysicalMonitors);

    if (bSuccess)
    {
        // Allocate the array of PHYSICAL_MONITOR structures.
        pPhysicalMonitors = (LPPHYSICAL_MONITOR)malloc(cPhysicalMonitors* sizeof(PHYSICAL_MONITOR));

        if (pPhysicalMonitors != NULL)
        {
            // Get the array.
            bSuccess = GetPhysicalMonitorsFromHMONITOR( hMonitor, cPhysicalMonitors, pPhysicalMonitors);

            // Get physical monitor handle.
            HANDLE hPhysicalMonitor = pPhysicalMonitors[0].hPhysicalMonitor;

            LPDWORD pdwMinimumBrightness = NULL;
            LPDWORD pdwCurrentBrightness = NULL;
            LPDWORD pdwMaximumBrightness = NULL;
            bSuccess = GetMonitorBrightness(hPhysicalMonitor, pdwMinimumBrightness, pdwCurrentBrightness, pdwMaximumBrightness);
            if (bSuccess == FALSE)
            {
                ShowError(TEXT("GetMonitorBrightness"));
            }

            // Close the monitor handles.
            bSuccess = DestroyPhysicalMonitors(cPhysicalMonitors, pPhysicalMonitors);

            // Free the array.
            free(pPhysicalMonitors);
        }
    }
    return 0;
}

void ShowError(LPTSTR lpszFunction)
{
    // Retrieve the system error message for the last-error code
    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError();

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

    // Display the error message and exit the process
    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
        (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
    StringCchPrintf((LPTSTR)lpDisplayBuf,
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"),
        lpszFunction, dw, lpMsgBuf);
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
}

This code crashes when executing this line:

bSuccess = GetMonitorBrightness(hPhysicalMonitor, pdwMinimumBrightness, pdwCurrentBrightness, pdwMaximumBrightness);

According to documentation, that function might not be supported.

If this function is supported, the GetMonitorCapabilities function returns the MC_CAPS_BRIGHTNESS flag.

So, in order to check that, I add the following block to my code, just before calling GetMonitorBrightness.

LPDWORD pdwMonitorCapabilities = NULL;
LPDWORD pdwSupportedColorTemperatures = NULL;
bSuccess = GetMonitorCapabilities(hPhysicalMonitor, pdwMonitorCapabilities, pdwSupportedColorTemperatures);
if (bSuccess == FALSE)
{
    ShowError(TEXT("GetMonitorCapabilities"));
}

Unfortunately after I added that block, I received the following error:

enter image description here

Again, according to documentation, GetMonitorCapabilities function fails if the monitor does not support DDC/CI.

Then I checked if my monitor is supporting DDC/CI, and found out that it is. Moreover, when I manually disable DDC/CI support from monitor settings, previous error message switches to following one, so now I'm pretty sure my monitor has DDC/CI support.

enter image description here

I feel like I'm doing everything correct but apparently I'm not. In short, GetMonitorCapabilities function fails with an error message that I can't give any meaning, and GetMonitorBrightness function gets crashed.

Notes:

My monitor is Dell U2713H.

I'm on 64 bit Windows 7.

I'm using Microsoft Visual C++ Compiler 12.0 (x86)

Bibliotherapy answered 4/12, 2015 at 15:40 Comment(0)
K
7

Your calls to GetMonitorBrightness() and GetMonitorCapabilities() are wrong. You are passing NULL pointers, but they expect pointers to actual DWORD variables instead:

DWORD dwMinimumBrightness = 0;
DWORD dwCurrentBrightness = 0;
DWORD dwMaximumBrightness = 0;
bSuccess = GetMonitorBrightness(hPhysicalMonitor, &dwMinimumBrightness, &dwCurrentBrightness, &dwMaximumBrightness);

DWORD dwMonitorCapabilities = 0;
DWORD dwSupportedColorTemperatures = 0;
bSuccess = GetMonitorCapabilities(hPhysicalMonitor, &dwMonitorCapabilities, &dwSupportedColorTemperatures);
Kalgan answered 4/12, 2015 at 17:9 Comment(4)
Wow, rookie mistake. Thanks. Documentation was saying LPDWORD that got me confused. It is working perfectly now.Bibliotherapy
The documentation also says they are _Out_ parameters, so they have to write output to something. NULLs are not allowed unless they are _Out_Opt_ instead. See SAL Annotations.Kalgan
Yes, my bad. as I said, rookie mistake.Bibliotherapy
So the thing is, I define variables as LPDWORD but apparently I should have define those as DWORD and make them LPDWORD by sending its address via &.Bibliotherapy

© 2022 - 2024 — McMap. All rights reserved.