使用WMI改变显示器亮度

文章目录

前言

最近遇到了新的需求,需要通过代码去改变显示器的亮度。通过调研发现,改变显示器亮度的方式有三种

1.调节伽马值

2.使用WMI

3.使用DDC/CI协议

然而这三个方法都各有缺点:

第一个方式:调节伽马值,效果会收到显示器的影响,有的显示器,或者驱动,会去校准显示器亮度。如果你改变了伽马值,在你的鼠标脱离程序的时候,屏幕亮度就会被校准回去。

第二个方式:使用WMI。使用WMI是不支持台式电脑的,只能在笔记本上面生效。这个也是我在调试的时候发现的,总是被拒绝访问,去查了才知道台式不支持。然后在笔记本下做了校验,发现确实是可以实现的。

第三个方式:使用DDC/CI协议。DDC/CI,全称为 Display Data Channel / Command Interface,是一种用于计算机显示设备(如显示器、投影仪等)之间通信的协议。它允许计算机与显示器共享信息,使得计算机能够读取显示器的状态和特性,例如分辨率、色彩特性等。

DDC/CI 的构成

DDC/CI 协议主要构建在两个较早的标准之上:

DDC (Display Data Channel):

DDC 是一种用于监视器和计算机之间通信的协议,允许计算机访问显示器的 EDID(Extended Display Identification Data)信息,EDID 是描述显示器特性的标准化数据结构。

CI (Command Interface):

Command Interface 允许计算机向显示器发送命令,包括但不限于调节明亮度、对比度、开启或关闭显示器等功能。

DDC/CI 的工作原理

I²C 通信: DDC/CI 的底层协议使用 I²C(Inter-Integrated Circuit)总线,使其可以支持主设备和从设备的双向通信。通常情况下,计算机作为主设备,显示器作为从设备。

EDID 读取: 计算机在启动时通过 DDC 读取显示器的 EDID,以确定最佳的分辨率和刷新率等设置。

命令发送: 计算机可以通过 DDC/CI 向显示器发送各种控制命令,比如:

调整亮度和对比度

切换输入信号源(如 HDMI、DisplayPort 等)

查询显示器当前的状态和设置

DDC/CI 的应用

显示器控制: DDC/CI 允许用户通过软件来控制显示器的许多设置,例如调节亮度、对比度和色温。许多监视器和显示器厂商都提供支持 DDC/CI 的软件工具来实现这些功能。

自动化脚本: 一些高级用户和系统管理员可以利用 DDC/CI 编写自动化脚本,以便远程管理和控制多个显示器的设置。

多显示器支持: 在多显示器环境中,DDC/CI 使得通过计算机系统统一管理多个显示器的设置成为可能。

如何使用 DDC/CI

软件工具

有几种工具可以帮助用户利用 DDC/CI 控制显示器:

DDC/CI 控制工具: 许多开源和商业软件,如 Monitorian (Windows 上的应用程序),可以通过 DDC/CI 来调整监视器的亮度和其他设置。

命令行工具: 例如 ddcutil 在 Linux 平台上,可以用来通过命令行与 DDC/CI 兼容的显示器进行交互。

注意事项

显示器支持: 并非所有显示器都支持 DDC/CI,因此确保你的显示器具有此功能。

驱动问题: 某些情况下,操作系统或显卡驱动程序可能需要支持 DDC/CI,以确保正常工作。

使用WMI调节显示器亮度

直接上代码吧,代码其实都是差不多的,主要在于你执行怎样的WQL操作,做什么样的操作。其余步骤都是差不多的。

头文件

cpp 复制代码
#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_QtTestPro.h"

class QtTestPro : public QMainWindow
{
    Q_OBJECT

public:
    QtTestPro(QWidget *parent = Q_NULLPTR);

    
    int Init();

    int GetBrightness();
	void PrintError(HRESULT hres);

    int SetBrightness(int brightness);

    void Cleanup();

    ~QtTestPro();


private slots:
    void on_btnUp_clicked();
    void on_btnDown_clicked();

private:
    Ui::QtTestProClass ui;
};

cpp文件

cpp 复制代码
#include "QtTestPro.h"

#include <QPushButton>
#include <iostream>
#include <string>
#include <windows.h>
#include <objbase.h>
#include <wbemidl.h>
#include <comdef.h>
#include <mutex>
#include<QDebug>

#pragma comment(lib, "wbemuuid.lib")
#pragma comment(lib, "comsuppw.lib")

using namespace std;

// wmi namespace
IWbemLocator* wmiLocator = NULL;
IWbemServices* wmiNamespace = 0;
BSTR wmiPath = SysAllocString(L"root\\wmi");
HRESULT hr = S_OK;

// brightnessAdjustmentClass
IWbemClassObject* brightnessAdjustmentClass = NULL;
IWbemClassObject* brightnessAdjustmentClassInstant = NULL;
IWbemClassObject* brightnessAdjustmentClassObject = NULL;
IWbemClassObject* brightnessAdjustmentMethodInstant = NULL;
IEnumWbemClassObject* brightnessAdjustmentClassEnum = NULL;

BSTR brightnessAdjustmentClassPath = SysAllocString(L"WmiMonitorBrightnessMethods");
BSTR brightnessAdjustmentMethodName = SysAllocString(L"WmiSetBrightness");
BSTR brightnessAdjustmentMethodArgName1 = SysAllocString(L"Timeout");
BSTR brightnessAdjustmentMethodArgName2 = SysAllocString(L"Brightness");
BSTR brightnessAdjustmentClassQuery = SysAllocString(L"Select * from WmiMonitorBrightnessMethods");


// brightnessClass
IEnumWbemClassObject* brightnessClassEnum = NULL;
//IWbemClassObject *brightnessClass = NULL;
IWbemClassObject* brightnessClassObject = NULL;

BSTR brightnessClassPath = SysAllocString(L"WmiMonitorBrightness");
BSTR brightnessVariableName = SysAllocString(L"CurrentBrightness");
BSTR brightnessQuery = SysAllocString(L"Select * from WmiMonitorBrightness");



QtTestPro::QtTestPro(QWidget* parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);
	connect(ui.btnUp, &QPushButton::clicked, this, &QtTestPro::on_btnUp_clicked);
	connect(ui.btnDown, &QPushButton::clicked, this, &QtTestPro::on_btnDown_clicked);
	// 全局唯一
	//auto m = CreateMutexA(NULL, TRUE, "{CAF16FA1-1E0C-419B-9D45-99B5719ED318}");

	//if (ERROR_ALREADY_EXISTS == GetLastError())
	//	return;

	int r = Init();
	if (r != 0)
		return;

}

QtTestPro::~QtTestPro() {
	// 清理
	//UnregisterHotKey(hwnd, hotKeyId1);
	//UnregisterHotKey(hwnd, hotKeyId2);
	//GlobalDeleteAtom(hotKeyId1);
	//GlobalDeleteAtom(hotKeyId2);
	//Cleanup();
}

//
int QtTestPro::Init()
{

	// Initialize COM and connect up to CIMOM  
	hr = CoInitialize(0);
	if (FAILED(hr))
		return -1;
	hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
	if (FAILED(hr))
		return -1;
	hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&wmiLocator);
	if (FAILED(hr))
		return -1;
	hr = wmiLocator->ConnectServer(_bstr_t(L"ROOT\\WMI"), NULL, NULL, NULL, 0, NULL, NULL, &wmiNamespace);
	if (hr != WBEM_S_NO_ERROR)
		return -1;
	hr = CoSetProxyBlanket(wmiNamespace, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
	if (hr != WBEM_S_NO_ERROR)
		return -1;

	//_bstr_t(L"ROOT\\CIMV2");
	// query variable enum
	hr = wmiNamespace->ExecQuery(_bstr_t(L"WQL"), _bstr_t(L"Select * from WmiMonitorBrightnessMethods"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &brightnessAdjustmentClassEnum);
	if (hr != WBEM_S_NO_ERROR)
		return -1;
	/*hr = wmiNamespace->ExecQuery(_bstr_t(L"WQL"), brightnessQuery, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &brightnessClassEnum);
	if (hr != WBEM_S_NO_ERROR)
		return -1;*/


		// get class obj
	ULONG ret;
	hr = brightnessAdjustmentClassEnum->Next(WBEM_INFINITE, 1, &brightnessAdjustmentClassObject, &ret);
	if (hr != WBEM_S_NO_ERROR)
	{
		qDebug() << "Failed to retrieve the next object. Error code = 0x"
			<< hex << hr << dec << endl;
		return -1;
	}
		

	hr = wmiNamespace->GetObject(brightnessAdjustmentClassPath, 0, NULL, &brightnessAdjustmentClass, NULL);
	if (hr != WBEM_S_NO_ERROR)
		return -1;

	// get brightness adjust method instant
	hr = brightnessAdjustmentClass->GetMethod(brightnessAdjustmentMethodName, 0, &brightnessAdjustmentClassInstant, NULL);
	if (hr != WBEM_S_NO_ERROR)
		return -1;
	hr = brightnessAdjustmentClassInstant->SpawnInstance(0, &brightnessAdjustmentMethodInstant);
	if (hr != WBEM_S_NO_ERROR)
		return -1;

	return 0;


		//HRESULT hres;

		 Step 1: --------------------------------------------------
		 Initialize COM. ------------------------------------------

		hres = CoInitializeEx(0, COINIT_MULTITHREADED);
		//hres = CoInitialize(0);
		//if (FAILED(hres))
		//{
		//	PrintError(hres);
		//	qDebug() << "Failed to initialize COM library. Error code = 0x"
		//		<< hex << hres << endl;
		//	return 1;                  // Program has failed.
		//}

		 Step 2: --------------------------------------------------
		 Set general COM security levels --------------------------

		//hres = CoInitializeSecurity(
		//	NULL,
		//	-1,                          // COM authentication
		//	NULL,                        // Authentication services
		//	NULL,                        // Reserved
		//	RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication
		//	RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
		//	NULL,                        // Authentication info
		//	EOAC_NONE,                   // Additional capabilities
		//	NULL                         // Reserved
		//	);


		//if (FAILED(hres))
		//{
		//	cout << "Failed to initialize security. Error code = 0x"
		//		<< hex << hres << endl;
		//	CoUninitialize();
		//	return 1;                    // Program has failed.
		//}

		 Step 3: ---------------------------------------------------
		 Obtain the initial locator to WMI -------------------------

		//IWbemLocator *pLoc = NULL;

		//hres = CoCreateInstance(
		//	CLSID_WbemLocator,
		//	0,
		//	CLSCTX_INPROC_SERVER,
		//	IID_IWbemLocator, (LPVOID *)&pLoc);

		//if (FAILED(hres))
		//{
		//	cout << "Failed to create IWbemLocator object."
		//		<< " Err code = 0x"
		//		<< hex << hres << endl;
		//	CoUninitialize();
		//	return 1;                 // Program has failed.
		//}

		 Step 4: -----------------------------------------------------
		 Connect to WMI through the IWbemLocator::ConnectServer method

		//IWbemServices *pSvc = NULL;

		 Connect to the root\cimv2 namespace with
		 the current user and obtain pointer pSvc
		 to make IWbemServices calls.
		//hres = pLoc->ConnectServer(
		//	_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
		//	NULL,                    // User name. NULL = current user
		//	NULL,                    // User password. NULL = current
		//	0,                       // Locale. NULL indicates current
		//	NULL,                    // Security flags.
		//	0,                       // Authority (for example, Kerberos)
		//	0,                       // Context object
		//	&pSvc                    // pointer to IWbemServices proxy
		//	);

		//if (FAILED(hres))
		//{
		//	cout << "Could not connect. Error code = 0x"
		//		<< hex << hres << endl;
		//	pLoc->Release();
		//	CoUninitialize();
		//	return 1;                // Program has failed.
		//}

		//cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;


		 Step 5: --------------------------------------------------
		 Set security levels on the proxy -------------------------

		//hres = CoSetProxyBlanket(
		//	pSvc,                        // Indicates the proxy to set
		//	RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
		//	RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
		//	NULL,                        // Server principal name
		//	RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx
		//	RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
		//	NULL,                        // client identity
		//	EOAC_NONE                    // proxy capabilities
		//	);

		//if (FAILED(hres))
		//{
		//	cout << "Could not set proxy blanket. Error code = 0x"
		//		<< hex << hres << endl;
		//	pSvc->Release();
		//	pLoc->Release();
		//	CoUninitialize();
		//	return 1;               // Program has failed.
		//}

		 Step 6: --------------------------------------------------
		 Use the IWbemServices pointer to make requests of WMI ----

		 For example, get the name of the operating system
		//IEnumWbemClassObject* pEnumerator = NULL;
		//hres = pSvc->ExecQuery(
		//	bstr_t("WQL"),
		//	bstr_t("SELECT * FROM Win32_DesktopMonitor"),//L"Select * from WmiMonitorBrightnessMethods  "SELECT * FROM Win32_OperatingSystem" "SELECT * FROM Win32_DesktopMonitor"
		//	WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
		//	NULL,
		//	&pEnumerator);

		//if (FAILED(hres))
		//{
		//	cout << "Query for operating system name failed."
		//		<< " Error code = 0x"
		//		<< hex << hres << endl;
		//	pSvc->Release();
		//	pLoc->Release();
		//	CoUninitialize();
		//	return 1;               // Program has failed.
		//}

		 Step 7: -------------------------------------------------
		 Get the data from the query in step 6 -------------------

		//IWbemClassObject *pclsObj = NULL;
		//ULONG uReturn = 0;

		//while (pEnumerator)
		//{
		//	HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
		//		&pclsObj, &uReturn);

		//	if (0 == uReturn)
		//	{
		//		break;
		//	}

		//	VARIANT vtProp;

		//	VariantInit(&vtProp);
		//	// Get the value of the Name property
		//	hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
		//	qDebug() << " OS Name : " << vtProp.bstrVal << endl;
		//	VariantClear(&vtProp);

		//	pclsObj->Release();
		//}

		 Cleanup
		 ========

		//pSvc->Release();
		//pLoc->Release();
		//pEnumerator->Release();
		//CoUninitialize();

		//return 0;   // Program successfully completed.

	
}


void QtTestPro::PrintError(HRESULT hres)
{
	LPVOID lpMsgBuf;
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		hres,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPWSTR)&lpMsgBuf,
		0, NULL);

	qDebug()<< L"Error: " << (LPWSTR)lpMsgBuf << endl;
	LocalFree(lpMsgBuf);
}

int QtTestPro::GetBrightness()
{
	// 每次都需要查询
	if (brightnessClassEnum) brightnessClassEnum->Release();
	if (brightnessClassObject) brightnessClassObject->Release();

	HRESULT hr = wmiNamespace->ExecQuery(_bstr_t(L"WQL"), brightnessQuery, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &brightnessClassEnum);
	if (hr != WBEM_S_NO_ERROR)
		return -1;

	DWORD ret;
	hr = brightnessClassEnum->Next(WBEM_INFINITE, 1, &brightnessClassObject, &ret);
	if (hr != WBEM_S_NO_ERROR)
		return -1;

	// 获得亮度值
	VARIANT brightnessValue;
	VariantInit(&brightnessValue);
	hr = brightnessClassObject->Get(brightnessVariableName, 0, &brightnessValue, 0, 0);
	if (hr != WBEM_S_NO_ERROR)
		return -1;
	ui.label->setText(QString::number(brightnessValue.uintVal));
	return brightnessValue.uintVal;
}

int QtTestPro::SetBrightness(int brightness)
{
	// 亮度范围是 [0, 100]
	brightness = min(max(brightness, 0), 100);
	// write brightness adjust params
	VARIANT var;
	VariantInit(&var);
	V_VT(&var) = VT_BSTR;

	// write timeout param
	V_BSTR(&var) = SysAllocString(L"0");
	hr = brightnessAdjustmentMethodInstant->Put(brightnessAdjustmentMethodArgName1, 0, &var, CIM_UINT32);
	if (hr != WBEM_S_NO_ERROR)
		return -1;

	// write brightness param
	V_BSTR(&var) = SysAllocString(to_wstring(brightness).c_str());
	hr = brightnessAdjustmentMethodInstant->Put(brightnessAdjustmentMethodArgName2, 0, &var, CIM_UINT8);
	VariantClear(&var);
	if (hr != WBEM_S_NO_ERROR)
		return -1;

	// 获取 method instant path 和 execute
	VARIANT pathVariable;
	VariantInit(&pathVariable);
	hr = brightnessAdjustmentClassObject->Get(_bstr_t(L"__PATH"), 0, &pathVariable, NULL, NULL);
	if (hr != WBEM_S_NO_ERROR)
		return -1;
	hr = wmiNamespace->ExecMethod(pathVariable.bstrVal, brightnessAdjustmentMethodName, 0, NULL, brightnessAdjustmentMethodInstant, NULL, NULL);
	VariantClear(&pathVariable);
	if (hr != WBEM_S_NO_ERROR)
		return -1;
	return 0;
}

void QtTestPro::Cleanup()
{
	// 清理
	SysFreeString(wmiPath);
	SysFreeString(brightnessAdjustmentClassPath);
	SysFreeString(brightnessAdjustmentMethodName);
	SysFreeString(brightnessAdjustmentMethodArgName1);
	SysFreeString(brightnessAdjustmentMethodArgName2);
	SysFreeString(brightnessAdjustmentClassQuery);

	SysFreeString(brightnessClassPath);
	SysFreeString(brightnessVariableName);
	SysFreeString(brightnessQuery);

	brightnessAdjustmentClass->Release();
	brightnessAdjustmentMethodInstant->Release();
	brightnessAdjustmentClassInstant->Release();
	brightnessAdjustmentClassObject->Release();
	brightnessAdjustmentClassEnum->Release();

	//if (brightnessClass) brightnessClass->Release();
	brightnessClassObject->Release();
	brightnessClassEnum->Release();

	wmiNamespace->Release();
	wmiLocator->Release();

	CoUninitialize();
}


// 亮度进阶值
void QtTestPro::on_btnUp_clicked() {
	GetBrightness();
	SetBrightness(ui.lineEdit->text().toInt());
}

void QtTestPro::on_btnDown_clicked() {
	GetBrightness();
	SetBrightness(ui.lineEdit->text().toInt());
}
相关推荐
永霖光电_UVLED10 小时前
KAIST 团队研发出高效、超高分辨率的红色微米发光二极管(Micro-LED)显示器
计算机外设
春日见2 天前
车辆动力学:前后轮车轴
java·开发语言·驱动开发·docker·计算机外设
PHOSKEY2 天前
光子精密QM系列闪测仪在鼠标电路板部件质量控制中的核心应用
计算机外设
墩墩冰2 天前
计算机图形学 分析选择缓冲区中的数字
计算机外设
UI设计兰亭妙微2 天前
中车株州所显示器界面设计
计算机外设·界面设计
墩墩冰2 天前
计算机图形学 多视区的显示
计算机外设
墩墩冰2 天前
计算机图形学 GLU库中的二次曲面函数
计算机外设
墩墩冰2 天前
计算机图形学 利用鼠标实现橡皮筋技术
计算机外设
企鹅侠客4 天前
鼠标键盘按键统计工具
计算机外设·键盘·鼠标
华一精品Adreamer5 天前
便携式显示器供应链与成本结构:挑战与机遇
计算机外设