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

在使用 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,  0 0 sizeof (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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值