Reputation: 39
I'm working on C++ display brightness regulation program for windows 10. The setup is: notebook with internal display + external HDMI display.
#include <Windows.h>
#include <iostream>
#include <vector>
#include <highlevelmonitorconfigurationapi.h>
#pragma comment(lib, "Dxva2.lib")
void ListMonitorsAndAdapters()
{
DISPLAY_DEVICE displayDevice;
displayDevice.cb = sizeof(DISPLAY_DEVICE);
for (DWORD deviceIndex = 0; EnumDisplayDevices(nullptr, deviceIndex, &displayDevice, 0); deviceIndex++)
{
std::wcout << "Monitor: " << displayDevice.DeviceName << " Video Adapter: " << displayDevice.DeviceString << std::endl;
}
}
void SetMonitorBrightness_f(HANDLE hMonitor, DWORD newBrightness)
{
DWORD minBrightness, maxBrightness, currentBrightness;
if (GetMonitorBrightness(hMonitor, &minBrightness, ¤tBrightness, &maxBrightness))
{
DWORD newNormalizedBrightness = (newBrightness * (maxBrightness - minBrightness)) / 100 + minBrightness;
SetMonitorBrightness(hMonitor, newNormalizedBrightness);
}
}
std::vector<HANDLE> GetPhysicalMonitors()
{
std::vector<HANDLE> physicalMonitors;
std::vector<HMONITOR> monitors;
EnumDisplayMonitors(NULL, NULL, [](HMONITOR monitor, HDC, LPRECT, LPARAM lParam) -> BOOL {
std::vector<HMONITOR>* monitors = reinterpret_cast<std::vector<HMONITOR>*>(lParam);
monitors->push_back(monitor);
return TRUE;
}, reinterpret_cast<LPARAM>(&monitors));
for (HMONITOR monitor : monitors)
{
DWORD numPhysicalMonitors;
if (GetNumberOfPhysicalMonitorsFromHMONITOR(monitor, &numPhysicalMonitors))
{
if (numPhysicalMonitors == 1)
{
// Laptop monitor
PHYSICAL_MONITOR physicalMonitor;
if (GetPhysicalMonitorsFromHMONITOR(monitor, 1, &physicalMonitor))
{
physicalMonitors.push_back(physicalMonitor.hPhysicalMonitor);
}
}
else
{
// Secondary monitor (HDMI monitor, etc.)
PHYSICAL_MONITOR* physicalMonitorArray = new PHYSICAL_MONITOR[numPhysicalMonitors];
if (GetPhysicalMonitorsFromHMONITOR(monitor, numPhysicalMonitors, physicalMonitorArray))
{
for (DWORD i = 0; i < numPhysicalMonitors; ++i)
{
physicalMonitors.push_back(physicalMonitorArray[i].hPhysicalMonitor);
}
}
delete[] physicalMonitorArray;
}
}
}
return physicalMonitors;
}
int main()
{
ListMonitorsAndAdapters();
std::vector<HANDLE> physicalMonitors = GetPhysicalMonitors();
if (physicalMonitors.empty())
{
std::cerr << "Both laptop monitor and HDMI monitor are not detected." << std::endl;
return 1;
}
// Adjust brightness of the laptop monitor (primary monitor)
DWORD laptopBrightness = 20; // Adjust the value as desired (0-100)
SetMonitorBrightness_f(physicalMonitors[0], laptopBrightness);
// Adjust brightness of the HDMI monitor (secondary monitor)
if (physicalMonitors.size() > 1)
{
DWORD hdmiBrightness = 50; // Adjust the value as desired (0-100)
SetMonitorBrightness_f(physicalMonitors[1], hdmiBrightness);
}
}
The problem is that brightness is changing only for HDMI display but not for internal notebook display.
ListMonitorsAndAdapters() function cout:
Monitor: \\.\DISPLAY1 Video Adapter: AMD Radeon(TM) Graphics
Monitor: \\.\DISPLAY2 Video Adapter: AMD Radeon(TM) Graphics
Monitor: \\.\DISPLAY3 Video Adapter: NVIDIA GeForce RTX 3060 Laptop GPU
Monitor: \\.\DISPLAY4 Video Adapter: NVIDIA GeForce RTX 3060 Laptop GPU
Monitor: \\.\DISPLAY5 Video Adapter: NVIDIA GeForce RTX 3060 Laptop GPU
Monitor: \\.\DISPLAY6 Video Adapter: NVIDIA GeForce RTX 3060 Laptop GPU
I tried different methods to open internal notebook display like
HANDLE hMonitor = CreateFile(L"\\\\.\\LCD", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
but still no luck.
Upvotes: 0
Views: 619
Reputation: 39
I found the solution to change laptop display brightness by using WMI from this topic. It's a bit dirty method but it works (should be something like this, but I never had to make it work). So the final code for changing both HDMI and notebook displays brightness:
#include <Windows.h> // Windows API
#include <ShellAPI.h> // ShellExecute
#include <string> // std::wstring
#include <iostream> // std::cout, std::cerr
#include <highlevelmonitorconfigurationapi.h> // Display brightness functions
#pragma comment(lib, "Dxva2.lib") // Link Dxva2.lib library
HANDLE hMonitor{ nullptr }; // Handle to the monitor
// Function to retrieve the handle of the monitor
HANDLE GetMonitor() {
DWORD NumberOfPhysicalMonitors{ 0 };
PHYSICAL_MONITOR* PhysicalMonitors{ nullptr };
// Get the handle of the monitor from the top-level window
HMONITOR hMonitor{ MonitorFromWindow(GetTopWindow(nullptr), NULL) };
// Return INVALID_HANDLE_VALUE if the monitor handle is invalid
if (!hMonitor || hMonitor == INVALID_HANDLE_VALUE) {
return INVALID_HANDLE_VALUE;
}
// Get the number of physical monitors and allocate memory for the physical monitors
if (!GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, &NumberOfPhysicalMonitors)) {
return INVALID_HANDLE_VALUE;
}
PhysicalMonitors = static_cast<PHYSICAL_MONITOR*>(malloc(
NumberOfPhysicalMonitors * sizeof(PHYSICAL_MONITOR)
));
// Get the physical monitors from the monitor handle
if (!GetPhysicalMonitorsFromHMONITOR(hMonitor,
NumberOfPhysicalMonitors,
PhysicalMonitors)) {
free(PhysicalMonitors);
return INVALID_HANDLE_VALUE;
}
// Return the handle of the physical monitor
return PhysicalMonitors->hPhysicalMonitor;
}
int main()
{
int HDMI_DisplayBrightnessLevel = 50; // The desired HDMI display brightness level
int Laptop_DisplayBrightnessLevel = 70; // The desired laptop display brightness level
// Get the current brightness of the monitor
DWORD Min, Current, Max;
if (!GetMonitorBrightness(hMonitor = GetMonitor(), &Min, &Current, &Max)) {
std::cerr << "Failed to get display brightness. Error code: " << GetLastError() << std::endl;
return -1;
}
// Set the brightness of the HDMI display
if (!SetMonitorBrightness(hMonitor, HDMI_DisplayBrightnessLevel)) {
std::cerr << "Failed to set HDMI display brightness. Error code: " << GetLastError() << std::endl;
return -1;
}
// Set the brightness of the laptop display using PowerShell command
std::wstring command = L"powershell.exe -Command \"(Get-WmiObject -Namespace root\\wmi -Class WmiMonitorBrightnessMethods).WmiSetBrightness(0," + std::to_wstring(Laptop_DisplayBrightnessLevel) + L")\"";
int result = (int)ShellExecute(nullptr, L"open", L"powershell.exe", command.c_str(), nullptr, SW_HIDE);
if (result <= 32)
{
std::cout << "Failed to execute PowerShell command. Error code: " << result << std::endl;
return -1;
}
return 0;
}
UPD. Finlay got it works with WMI Class. So now you have 2 functions to control notebook display brightness (WMI or PowerShell) and 1 for HDMI display:
#include <objbase.h> // provides COM (Component Object Model) initialization and uninitialization functions. COM is a binary interface standard for software components to interact with each other.
#include <stdio.h> // provides standard I/O functions like printf and scanf for input and output operations.
#include <comdef.h> // provides COM utility functions, including helper classes and macros for COM programming.
#include <wbemidl.h> // provides WMI (Windows Management Instrumentation) COM interfaces. WMI is a Microsoft technology for managing and accessing system information in a Windows environment.
#include <windows.h> // provides the Windows API, which includes functions, constants, and data types for interacting with the Windows operating system.
#include <ShellAPI.h> // provides the ShellExecute function, which allows you to execute a file or open it with its associated application.
#include <string> // provides the std::wstring class, which represents a wide string of characters. Wide strings are used to store Unicode text.
#include <iostream> // provides the std::cout and std::cerr objects for console output. std::cout is used for standard output, while std::cerr is used for error output.
#include <highlevelmonitorconfigurationapi.h> // provides functions for controlling display brightness at a high level. It allows you to adjust the brightness of monitors connected to the system.
#include <chrono> // provides facilities for measuring and manipulating time. It includes the std::chrono namespace, which contains classes and functions for time-related operations.
#include <thread> // provides facilities for creating and managing threads. It includes the std::thread class, which represents a single thread of execution.
#pragma comment(lib, "Dxva2.lib") // pragma directive instructs the linker to link the Dxva2.lib library. The library contains functions and resources related to DirectX Video Acceleration (DXVA), which is a Microsoft API for hardware-accelerated video decoding.
#pragma comment(lib, "wbemuuid.lib") // pragma directive instructs the linker to link the wbemuuid.lib library. The library contains the UUID (Universally Unique Identifier) definitions required for using WMI COM interfaces.
using namespace std; // directive that allows you to use names from the std namespace without explicitly qualifying them with the namespace prefix.
HANDLE hMonitor{ nullptr }; // Handle to the monitor
// Function to retrieve the handle of the monitor
HANDLE GetMonitor() {
DWORD NumberOfPhysicalMonitors{ 0 };
PHYSICAL_MONITOR* PhysicalMonitors{ nullptr };
// Get the handle of the monitor from the top-level window
HMONITOR hMonitor{ MonitorFromWindow(GetTopWindow(nullptr), NULL) };
// Return INVALID_HANDLE_VALUE if the monitor handle is invalid
if (!hMonitor || hMonitor == INVALID_HANDLE_VALUE) {
return INVALID_HANDLE_VALUE;
}
// Get the number of physical monitors and allocate memory for the physical monitors
if (!GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, &NumberOfPhysicalMonitors)) {
return INVALID_HANDLE_VALUE;
}
PhysicalMonitors = static_cast<PHYSICAL_MONITOR*>(malloc(
NumberOfPhysicalMonitors * sizeof(PHYSICAL_MONITOR)
));
// Get the physical monitors from the monitor handle
if (!GetPhysicalMonitorsFromHMONITOR(hMonitor,
NumberOfPhysicalMonitors,
PhysicalMonitors)) {
free(PhysicalMonitors);
return INVALID_HANDLE_VALUE;
}
// Return the handle of the physical monitor
return PhysicalMonitors->hPhysicalMonitor;
}
// Function to set HDMI display brightness using WinAPI
int setHDMIDisplayBrightness_WinAPI(uint8_t brightness) {
if (brightness > 100) brightness = 100; // check if brightness value is out of range
// Get the current brightness of the of the HDMI display
DWORD Min, Current, Max;
if (!GetMonitorBrightness(hMonitor = GetMonitor(), &Min, &Current, &Max)) {
std::cerr << "Failed to get display brightness. Error code: " << GetLastError() << std::endl;
return -1;
}
// Set the brightness of the HDMI display
if (!SetMonitorBrightness(hMonitor, brightness)) {
std::cerr << "Failed to set HDMI display brightness. Error code: " << GetLastError() << std::endl;
return -1;
}
}
// Function to set notebook display brightness using Windows Management Instrumentation (WMI)
int setNotebookDisplayBrightness_WMI(uint8_t brightness) {
if (brightness > 100) brightness = 100; // check if brightness value is out of range
IWbemLocator* pLocator = NULL; // Pointer to the IWbemLocator interface
IWbemServices* pNamespace = 0; // Pointer to the IWbemServices interface
IWbemClassObject* pClass = NULL; // Pointer to the IWbemClassObject interface
IWbemClassObject* pInClass = NULL; // Pointer to the IWbemClassObject interface for input arguments
IWbemClassObject* pInInst = NULL; // Pointer to the IWbemClassObject interface for input instance
IEnumWbemClassObject* pEnum = NULL; // Pointer to the IEnumWbemClassObject interface for enumerating objects
HRESULT hr = S_OK; // HRESULT variable for storing function return values
BSTR path = SysAllocString(L"root\\wmi"); // Allocate a BSTR and initialize it with the specified string
BSTR ClassPath = SysAllocString(L"WmiMonitorBrightnessMethods"); // Allocate a BSTR and initialize it with the specified string
BSTR MethodName = SysAllocString(L"WmiSetBrightness"); // Allocate a BSTR and initialize it with the specified string
BSTR ArgName0 = SysAllocString(L"Timeout"); // Allocate a BSTR and initialize it with the specified string
BSTR ArgName1 = SysAllocString(L"Brightness"); // Allocate a BSTR and initialize it with the specified string
BSTR bstrQuery = SysAllocString(L"Select * from WmiMonitorBrightnessMethods"); // Allocate a BSTR and initialize it with the specified string
// Checks if any of the variables path, ClassPath, MethodName, or ArgName0 is null
if (!path || !ClassPath || !MethodName || !ArgName0)
{
printf("SysAllocString failed. Out of memory.\n");
goto cleanup;
}
// Initialize Component Object Model (COM)
hr = CoInitialize(0);
if (FAILED(hr))
{
printf("CoInitialize returned 0x%x:", hr);
goto cleanup;
}
// Initialize COM security settings
hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_SECURE_REFS, //change to EOAC_NONE if you change dwAuthnLevel to RPC_C_AUTHN_LEVEL_NONE
NULL);
if (FAILED(hr))
{
printf("CoInitializeSecurity returned 0x%x:", hr);
goto cleanup;
}
// Create an instance of the WbemLocator object
hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID*)&pLocator);
if (FAILED(hr))
{
printf("CoCreateInstance returned 0x%x:", hr);
goto cleanup;
}
// Connect to the WMI server
hr = pLocator->ConnectServer(path, NULL, NULL, NULL, 0, NULL, NULL, &pNamespace);
printf("\n\nConnectServer returned 0x%x:", hr);
if (hr != WBEM_S_NO_ERROR)
goto cleanup;
// Set the security blanket on the proxy
hr = CoSetProxyBlanket(pNamespace,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
NULL,
RPC_C_AUTHN_LEVEL_PKT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE
);
if (hr != WBEM_S_NO_ERROR)
goto cleanup;
// Execute a query on the namespace
hr = pNamespace->ExecQuery(_bstr_t(L"WQL"), //Query Language
bstrQuery, //Query to Execute
WBEM_FLAG_RETURN_IMMEDIATELY, //Make a semi-synchronous call
NULL, //Context
&pEnum //Enumeration Interface
);
if (hr != WBEM_S_NO_ERROR)
goto cleanup;
hr = WBEM_S_NO_ERROR;
// Iterate through the objects returned by the query
while (WBEM_S_NO_ERROR == hr)
{
// Get the next object from the collection
ULONG ulReturned;
IWbemClassObject* pObj;
DWORD retVal = 0;
hr = pEnum->Next(WBEM_INFINITE, //Timeout
1, //No of objects requested
&pObj, //Returned Object
&ulReturned //No of object returned
);
if (hr != WBEM_S_NO_ERROR)
goto cleanup;
// Get the class object
hr = pNamespace->GetObject(ClassPath, 0, NULL, &pClass, NULL);
printf("\nGetObject returned 0x%x:", hr);
if (hr != WBEM_S_NO_ERROR)
goto cleanup;
// Get the input argument and set the property
hr = pClass->GetMethod(MethodName, 0, &pInClass, NULL);
printf("\nGetMethod returned 0x%x:", hr);
if (hr != WBEM_S_NO_ERROR)
goto cleanup;
// Create an instance of the input argument class
hr = pInClass->SpawnInstance(0, &pInInst);
printf("\nSpawnInstance returned 0x%x:", hr);
if (hr != WBEM_S_NO_ERROR)
goto cleanup;
// Set the value of the first argument (timeout)
VARIANT var1;
VariantInit(&var1);
V_VT(&var1) = VT_BSTR;
V_BSTR(&var1) = SysAllocString(L"0");
hr = pInInst->Put(ArgName0, 0, &var1, CIM_UINT32); //CIM_UINT64
printf("\nPut ArgName0 returned 0x%x:", hr);
VariantClear(&var1);
if (hr != WBEM_S_NO_ERROR)
goto cleanup;
// Set the value of the second argument (brightness)
VARIANT var;
VariantInit(&var);
var.vt = VT_UI1;
var.uiVal = brightness;
hr = pInInst->Put(ArgName1, 0, &var, 0);
VariantClear(&var);
printf("\nPut ArgName1 returned 0x%x:", hr);
if (hr != WBEM_S_NO_ERROR)
goto cleanup;
// Call the method
VARIANT pathVariable;
VariantInit(&pathVariable);
hr = pObj->Get(_bstr_t(L"__PATH"), 0, &pathVariable, NULL, NULL);
printf("\npObj Get returned 0x%x:", hr);
if (hr != WBEM_S_NO_ERROR)
goto cleanup;
hr = pNamespace->ExecMethod(pathVariable.bstrVal, MethodName, 0, NULL, pInInst, NULL, NULL);
VariantClear(&pathVariable);
printf("\nExecMethod returned 0x%x:", hr);
if (hr != WBEM_S_NO_ERROR)
goto cleanup;
}
printf("Terminating normally\n");
// Free up resources
cleanup:
SysFreeString(path); // Free the BSTR
SysFreeString(ClassPath); // Free the BSTR
SysFreeString(MethodName); // Free the BSTR
SysFreeString(ArgName0); // Free the BSTR
SysFreeString(ArgName1); // Free the BSTR
SysFreeString(bstrQuery); // Free the BSTR
if (pClass)
pClass->Release(); // Release the IWbemClassObject interface
if (pInInst)
pInInst->Release(); // Release the IWbemClassObject interface
if (pInClass)
pInClass->Release(); // Release the IWbemClassObject interface
if (pLocator)
pLocator->Release(); // Release the IWbemLocator interface
if (pNamespace)
pNamespace->Release(); // Release the IWbemServices interface
CoUninitialize(); // Uninitialize the COM library
return 0; // Return 0 to indicate successful execution
}
// Function to set notebook display brightness using Windows PowerShell
int setNotebookDisplayBrightness_PShell(uint8_t brightness) {
if (brightness > 100) brightness = 100; // check if brightness value is out of range
// Set the brightness of the laptop display using PowerShell command
std::wstring command = L"powershell.exe -Command \"(Get-WmiObject -Namespace root\\wmi -Class WmiMonitorBrightnessMethods).WmiSetBrightness(0," + std::to_wstring(brightness) + L")\"";
int result = (int)ShellExecute(nullptr, L"open", L"powershell.exe", command.c_str(), nullptr, SW_HIDE);
if (result <= 32)
{
std::cout << "Failed to execute PowerShell command. Error code: " << result << std::endl;
return -1;
}
}
int main(int iArgCnt, char** argv)
{
int HDMI_DisplayBrightnessLevel = 40; // The desired HDMI display brightness level
int Laptop_DisplayBrightnessLevel = 70; // The desired laptop display brightness level
// Check if the required command-line arguments are provided
if (iArgCnt != 3)
{
std::cerr << "Insufficient command-line arguments. Usage: Brightness_control.exe HDMI_Brightness_Level% Laptop_Brightness_Level%" << std::endl;
std::cout << "For example: Brightness_control.exe 20 30" << std::endl;
//return 1;
}
else{
// Parse the command-line arguments and set the display brightness levels
HDMI_DisplayBrightnessLevel = std::stoi(argv[1]);
Laptop_DisplayBrightnessLevel = std::stoi(argv[2]);
}
setHDMIDisplayBrightness_WinAPI(HDMI_DisplayBrightnessLevel); // use WinAPI to set HDMI display brightness level
this_thread::sleep_for(chrono::milliseconds(1000)); // Thread delayed for 1 seconds
setNotebookDisplayBrightness_WMI(Laptop_DisplayBrightnessLevel); // use WMI Class to change Notebook Display Brightness level
// OR
this_thread::sleep_for(chrono::milliseconds(1000)); // Thread delayed for 1 seconds
setNotebookDisplayBrightness_PShell(Laptop_DisplayBrightnessLevel-50); // use Power Shell command to change Notebook Display Brightness level
return 0;
}
Upvotes: 2