【WCE】显示器电源管理 (Standard Shell)

本文介绍如何在StandardShell下实现显示器的节电模式切换。利用PowerManager和GWES组件,结合不同BSP特性,通过代码实现显示器在用户闲置和活跃时自动进入和退出节电模式。

在使用 Standard Shell 的情况下,出于节约用电和保护显示器的目的,我们需要在 User Idle 时进入显示器节电模式 (ScreenOff),在 User Active 时退出显示器节电模式 (ScreenOn)。

该项功能要依靠 Power Manager 和 GWES 来实现,具体为:

  • Power Manager 维护显示器电源状态,通过设备驱动控制显示器进入/退出节电模式。
  • GWES 监视用户输入事件 (User Active) 并通知 Power Manager。

由于不少 BSP 未提供任何设备驱动来管理显示器,故我们需自行实现显示器电源管理功能。

在 $(_WINCEROOT)/PUBLIC/COMMON/OAK/FILES/common.reg 中存在:

[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power]
    "DisableGwesPowerOff"=dword:0
    "ScreenPowerOff"=DWORD:300

根据 "DisableGwesPowerOff" 的值,存在两种实现方式:

  • 当 "DisableGwesPowerOff"=dword:0,GWES 会发送 WM_POWERBROADCAST 消息给任务栏,具体可在 $(_WINCEROOT)/PUBLIC/SHELL/OAK/HPC/EXPLORER/TASKBAR/taskbar.cpp 中找到如下代码段:  
        case WM_POWERBROADCAST:
        {
            
const WCHAR g_MessengerWindowClass[] = L"MSGSBlObj";
            HWND hwndMessenger;

            hwndMessenger 
= FindWindow(g_MessengerWindowClass, NULL);
            
if (hwndMessenger)
            {
                
// Notify Messenger of idle state
                PostMessage(
                                FindWindow(g_MessengerWindowClass, NULL),
                                msg,
                                wParam,
                                lParam
);
            }
        }
            
// Place holder for real screen saver implementation
            switch(wParam)
            {
                
case PBT_APMUSERIDLE:
                    
// ScreenSaver start
                    RETAILMSG(TRUE, (L"Screen Saver Started. "));
                    
break;

                
// Screen saver app should be looking for this message
                case PBT_APMUSERACTIVE:
                    
// ScreenSaver end
                    RETAILMSG(TRUE, (L"Screen Saver Ended. "));
                    
break;
            }

            
break;

 该段代码在 User Idle 时,调试输出“屏保已启动”;在 User Active 时,调试输出“屏保已结束”。考虑到多数 BSP 支持 GETPOWERMANAGEMENT / SETPOWERMANAGEMENT escape function,调用 ExtEscape 函数就可进入/退出节电显示器模式,修改后的代码如下: 

                case PBT_APMUSERIDLE:
                    
// ScreenOff
                    SetScreenPower(FALSE);
                    
break;

                
case PBT_APMUSERACTIVE:
                    
// ScreenOn
                    SetScreenPower(TRUE);
                    
break;

其中,函数 SetScreenPower 的实现代码如下:

DWORD SetScreenPower(BOOL bScreenOn)
{
    HDC hDC(GetDC(NULL));
    
if (!hDC) return GetLastError();

    _ATLTRY
    {
        DWORD dwQuery(GETPOWERMANAGEMENT);
        
if (ExtEscape(hDC, QUERYESCSUPPORT, sizeof(DWORD), (LPCSTR)&dwQuery, 0, NULL) <= 0)
            AtlThrowLastWin32();

        VIDEO_POWER_MANAGEMENT power;
        power.Length 
= sizeof(power);
        
if (ExtEscape(hDC, GETPOWERMANAGEMENT, 00sizeof(power), (LPSTR)&power) != sizeof(power))
            AtlThrowLastWin32();

        power.PowerState 
= bScreenOn ? VideoPowerOn : VideoPowerOff;
        
if (ExtEscape(hDC, SETPOWERMANAGEMENT, sizeof(power), (LPSTR)&power, 0, NULL) <= 0)
            AtlThrowLastWin32();
    }
    _ATLCATCH(e)
    {
        ATLVERIFY(ReleaseDC(NULL, hDC));
        
return HRESULT_CODE((HRESULT)e);
    }

    ATLVERIFY(ReleaseDC(NULL, hDC);
    
return NO_ERROR;
}
  • 当 "DisableGwesPowerOff"=dword:1,这时 GWES 不会发送 WM_POWERBROADCAST 消息给任务栏了。那么我们需要通过调用 RequestPowerNotifications 函数要求 Power Manager 将电源通告写入指定的消息队列。
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    
// 消息队列参数
    MSGQUEUEOPTIONS qo;
    qo.dwSize 
= sizeof(MSGQUEUEOPTIONS);
    qo.dwFlags 
= MSGQUEUE_NOPRECOMMIT;
    qo.dwMaxMessages 
= 0;
    qo.cbMaxMessage 
= 256;
    qo.bReadAccess 
= TRUE;

    
// 创建消息队列
    CSafeHandle<HANDLE, CloseMsgQueue> hPowerNMsgQ(CreateMsgQueue(NULL, &qo));

    
// 请求电源通告
    CSafeHandle<HANDLE, (BOOL(__stdcall*)(HANDLE))StopPowerNotifications> hNotify(RequestPowerNotifications(hPowerNMsgQ, PBT_TRANSITION));  
 
    
while (TRUE)
    {
        
// 判断消息队列是否有数据写入
        if (WaitForSingleObject(hPowerNMsgQ, INFINITE) == WAIT_FAILED)
            
return GetLastError();

        
// 从消息队列读取数据
        BYTE buffer[256];
        DWORD cRead, dwFlags;   
        
if (!ReadMsgQueue(hPowerNMsgQ, buffer, sizeof(buffer), &cRead, INFINITE, &dwFlags))
            
return GetLastError();

        
// 根据 Power Manager 维护的显示器电源状态,进入/退出节电模式
        PPOWER_BROADCAST pPowerBroadcast((PPOWER_BROADCAST)buffer);
        
if (!_tcsicmp(pPowerBroadcast->SystemPowerState, TEXT("On")))
            SetScreenPower(TRUE);
        
else if (!_tcsicmp(pPowerBroadcast->SystemPowerState, TEXT("SystemIdle")))
            SetScreenPower(FALSE);
    }

    
return NO_ERROR;
}
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值