본문 바로가기

Programming/Win32&MFC&COM

제어판의 전원 옵션 구현하기

반응형

제어판의 전원 옵션 메뉴에는 전원을 관리하기 위한 옵션들을 수정할 수 있습니다.

기본적으로 균형 조정, 고성능, 절전의 옵션이 존재합니다.

일부 노트북이나 대기업 PC의 경우 다른 옵션이 있을 수도 있습니다.

설정 변경에 들어가면 디스플레이 끄기 시간과 절전 모드로 진입하는 시간을 설정할 수 있습니다.

그리고 고급 전원 관리 옵션 설정 변경(C)를 누르면 세부 설정이 가능합니다.

이 설정을 직접 가져오고 수정할 수 있는 API가 제공됩니다.

Power Management Reference는 아래 링크를 통해서 확인할 수 있습니다.

https://msdn.microsoft.com/en-us/library/windows/desktop/aa373170(v=vs.85).aspx

실제 값을 가져오기 위한 간단한 코드는 다음과 같습니다.

#include <Windows.h>
#include <PowrProf.h>
#include <iostream>
#include <string>

const std::wstring GetPowerReadFriendlyName(const GUID* SchemeGuid, const GUID* SubGroupOfPowerSettingsGuid = &NO_SUBGROUP_GUID, const GUID* PowerSettingGuid = nullptr)
{
	DWORD dwLength = 0;
	std::wstring szName;
	if (ERROR_SUCCESS == ::PowerReadFriendlyName(nullptr, SchemeGuid, SubGroupOfPowerSettingsGuid, PowerSettingGuid, nullptr, &dwLength))
	{
		UCHAR* szFriendlyName = new UCHAR[dwLength];
		if (ERROR_SUCCESS == ::PowerReadFriendlyName(nullptr, SchemeGuid, SubGroupOfPowerSettingsGuid, PowerSettingGuid, szFriendlyName, &dwLength))
		{
			szName.assign((wchar_t*)szFriendlyName);
		}
		delete[] szFriendlyName;
	}
	return szName;
}

const std::wstring GetUnitSpecifier(const GUID* SubGroupOfPowerSettingsGuid, const GUID* PowerSettingGuid)
{
	DWORD dwLength = 0;
	std::wstring szUnitSpecifier;
	if (ERROR_SUCCESS == ::PowerReadValueUnitsSpecifier(nullptr, SubGroupOfPowerSettingsGuid, PowerSettingGuid, nullptr, &dwLength))
	{
		UCHAR* szUnits = new UCHAR[dwLength];
		if (ERROR_SUCCESS == ::PowerReadValueUnitsSpecifier(nullptr, SubGroupOfPowerSettingsGuid, PowerSettingGuid, szUnits, &dwLength))
		{
			szUnitSpecifier.assign((wchar_t*)szUnits);
		}
		delete[] szUnits;
	}			
	return szUnitSpecifier;
}

int main()
{
	std::wcout.imbue(std::locale(""));

	// Get Active Scheme.
	GUID* pActivePolicyGuid = nullptr;
	if (ERROR_SUCCESS != ::PowerGetActiveScheme(nullptr, &pActivePolicyGuid))
		return -1;

	GUID activePolicyGuid = *pActivePolicyGuid;
	::LocalFree(pActivePolicyGuid);

	// Enumerate power settings directly under the activePolicyGuid
	std::wcout << GetPowerReadFriendlyName(&activePolicyGuid) << std::endl;
	for (ULONG ulIndex = 0; ; ++ulIndex)
	{
		GUID guidSetting;
		DWORD dwSettingLen = sizeof(guidSetting);
		DWORD nRtn = ::PowerEnumerate(nullptr, &activePolicyGuid, &NO_SUBGROUP_GUID, ACCESS_INDIVIDUAL_SETTING, ulIndex, (UCHAR*)&guidSetting, &dwSettingLen);
		if (ERROR_MORE_DATA == nRtn || ERROR_FILE_NOT_FOUND == nRtn)
			continue;
		else if (ERROR_NO_MORE_ITEMS == nRtn)
			break;

		std::wcout << L"\t" << GetPowerReadFriendlyName(&activePolicyGuid, &NO_SUBGROUP_GUID, &guidSetting) << std::endl;
		
		DWORD AcValueIndex = 0;
		::PowerReadACValueIndex(nullptr, &activePolicyGuid, &NO_SUBGROUP_GUID, &guidSetting, &AcValueIndex);

		std::wstring szUnitSpecifier = GetUnitSpecifier(&NO_SUBGROUP_GUID, &guidSetting);
		std::wcout << L"\t\t" << AcValueIndex << szUnitSpecifier << std::endl;
	}
	// Enumerate SubGroup power settings
	for (ULONG ulIndex = 0; ; ++ulIndex)
	{
		GUID guidSubGroup = GUID_NULL;
		DWORD dwSubGroupLen = sizeof(guidSubGroup);
		DWORD nRtn = ::PowerEnumerate(nullptr, &activePolicyGuid, nullptr, ACCESS_SUBGROUP, ulIndex, (UCHAR*)&guidSubGroup, &dwSubGroupLen);
		if (ERROR_MORE_DATA == nRtn || ERROR_FILE_NOT_FOUND == nRtn)
			continue;
		else if (ERROR_NO_MORE_ITEMS == nRtn)
			break;

		std::wcout << GetPowerReadFriendlyName(&activePolicyGuid, &guidSubGroup) << std::endl;

		// Enumerate Individual power settings
		for (ULONG ulSubIndex = 0; ; ++ulSubIndex)
		{
			GUID guidSetting = GUID_NULL;
			DWORD dwSettingLen = sizeof(guidSetting);
			nRtn = ::PowerEnumerate(nullptr, &activePolicyGuid, &guidSubGroup, ACCESS_INDIVIDUAL_SETTING, ulSubIndex, (UCHAR*)&guidSetting, &dwSettingLen);
			if (ERROR_MORE_DATA == nRtn || ERROR_FILE_NOT_FOUND == nRtn)
				continue;
			else if (ERROR_NO_MORE_ITEMS == nRtn)
				break;

			std::wcout << L"\t" << GetPowerReadFriendlyName(&activePolicyGuid, &guidSubGroup, &guidSetting) << std::endl;

			// Get Current Setting Value
			DWORD AcValueIndex = 0;
			::PowerReadACValueIndex(nullptr, &activePolicyGuid, &NO_SUBGROUP_GUID, &guidSetting, &AcValueIndex);

			std::wstring szUnitSpecifier = GetUnitSpecifier(&NO_SUBGROUP_GUID, &guidSetting);
			std::wcout << L"\t\t" << AcValueIndex << szUnitSpecifier << std::endl;
		}
	}
	return 0;
}

먼저 PowerGetActiveScheme()를 통해서 현재 설정(균형 조정, 고성능, 절전)의 GUID를 가져옵니다.

전원 설정은 세부적인 설정까지 GUID로 지정되어 있습니다.

PowerEnumerate()를 호출하면 설정을 열거할 수 있습니다.

처음 for문은 하위 그룹이 아닌 현재 설정의 바로 하위의 설정 값을 가져오기 위해서 입니다.

그 이후에 이제 하위 그룹 > 설정 값을 가져오기 위한 for문을 돌립니다.

GetPowerReadFriendlyName()는 GUID를 실제 설정 이름으로 변경합니다.

그리고 현재의 설정값은 PowerReadACValueIndex()를 통해서 인덱스를 가져올 수 있습니다.

배터리 사용시에는 PowerReadDCValueIndex()를 사용하면 됩니다.

PowerReadValueUnitsSpecifier()는 단위를 가져옵니다.

디스플레이 밝기 등에서는 %가 리턴됩니다.

실제 사용해보면 제어판의 전원 옵션보다 훨씬 많은 설정을 확인할 수 있습니다.

다만 일부 옵션에서 설정 이름을 정상적으로 가져오지 못하는 것이 확인되었습니다.

API를 좀 더 봐야할 것 같습니다.

반응형