Windows Mobile 6:保持显示屏打开

I think the most popular question in our Windows Mobile Programming zone is about the backlight - we all want to keep it on when our application is running.

我认为Windows Mobile编程区域中最流行的问题是关于背光的照明-我们所有人都希望在应用程序运行时保持背光照明。

Few years ago the function SystemIdleTimerReset() did this job. On our side we had to detect the device idle time and call this function appropriately. In Windows Mobile 6 this function keeps the system running, but the display is turned off.

几年前,函数SystemIdleTimerReset()完成了这项工作。 在我们这边,我们必须检测设备的空闲时间并适当地调用此函数。 在Windows Mobile 6中,此功能可使系统保持运行状态,但是显示屏已关闭。

How to keep the backlight on?

如何保持背光灯亮?

If you need to keep your device at full power, you can use the following code:

如果需要使设备保持全功率,则可以使用以下代码:

HANDLE hBacklight = SetPowerRequirement(L"BKL1:", D0, POWER_NAME, NULL, 0);

Do not forget to release handle when you close application:

关闭应用程序时不要忘记释放手柄:

ReleasePowerRequirement(hBacklight)
SystemIdleTimerReset() should be used also - this function keeps the device running. If you will forget about it, the display will be on, but the device will go to sleep together with your application. It looks like your application gets stuck. SystemIdleTimerReset() -此函数可保持设备运行。 如果您忘记了它,显示屏将打开,但是设备将与您的应用程序一起进入睡眠状态。 您的应用程序似乎卡住了。

More details about this approach and a working example you can find in MSDN: Program Applications to Turn the Smartphone Backlight Off and On

您可以在MSDN中找到有关此方法的更多详细信息和一个工作示例: 程序应用程序,用于打开和关闭智能手机背光。

Bruce Eitman proposed a new solution in his article Windows CE: Keeping the Backlight On
.

Bruce Eitman在他的文章Windows CE:保持背光源中提出了一种新的解决方案。

He found out that the power manager is monitoring a named event. The name of this event can be obtained from the registry:

他发现电源管理器正在监视命名事件。 可以从注册表中获取此事件的名称:

const static LPCWSTR s_szGWE_REG_PATH = L"SYSTEM\\GWE";
const static LPCWSTR s_szActivityKey = L"ActivityEvent";
 
DWORD EventName(LPWSTR& lpszName)
{
   HKEY hKey = NULL;
   DWORD nResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, s_szGWE_REG_PATH, 0, 0, &hKey);
   if (nResult != ERROR_SUCCESS)
      return 0;
 
   DWORD nNumBytes = 0;
   DWORD nType;
   nResult = RegQueryValueEx(hKey, s_szActivityKey, NULL, &nType, NULL, &nNumBytes);a
   if (nResult == ERROR_SUCCESS)
   {
      nResult = 0;
      if (nNumBytes > 0)
      {
         lpszName = (LPWSTR)malloc(nNumBytes + 2);
         if (lpszName != NULL)
         {
            ZeroMemory(lpszName, nNumBytes + 2);
            nResult = RegQueryValueEx(hKey, s_szActivityKey, NULL, &nType, (LPBYTE)lpszName, &nNumBytes);
            nResult = wcslen(lpszName);
         }
      }
      RegCloseKey(hKey);
   }
   return nResult;
};

If we have the name, we can create this event and raise it periodically.

如果我们有名称,则可以创建此事件并定期引发它。

In order to test this approach I made a simple class CPowerEvent:

为了测试这种方法,我制作了一个简单的类CPowerEvent:

#pragma once
 
class CPowerEvent
{
   enum enumHandles
   {
      HANDLE_THREAD = 0,
      HANDLE_POWER_EVENT,
      HANDLE_STOP,
      HANDLE_START,
      HANDLE_EXIT,
      HANDLES
   };
 
   enum enumTime
   {
      TIME_EXIT_THREAD = 1000,
      TIME_IDLE        = 5000
   };
 
   LPWSTR   m_lpszName;
   HANDLE   m_arrHandles[HANDLES];
   DWORD   m_nIdle;
 
   static DWORD WINAPI Run(LPVOID pParam);
 
public:
   CPowerEvent();
   virtual ~CPowerEvent();
 
   static DWORD EventName(LPWSTR& lpszName);
 
   BOOL Start();
   BOOL Stop();
 
   BOOL SetIdle(DWORD nTime);
 
   inline BOOL IsActive() 
   { return (m_arrHandles[HANDLE_THREAD] != NULL); };
 
   void Clear();
};

And the implementation is the following:

实现如下:

#include "StdAfx.h"
#include "PowerEvent.h"
 
const static LPCWSTR s_szGWE_REG_PATH   = L"SYSTEM\\GWE";
const static LPCWSTR s_szActivityKey   = L"ActivityEvent";
 
CPowerEvent::CPowerEvent()
{
   m_lpszName   = NULL;
   m_nIdle      = TIME_IDLE;
   ZeroMemory(m_arrHandles, HANDLES * sizeof(HANDLE));
}
 
CPowerEvent::~CPowerEvent()
{
   Clear();
}
 
void CPowerEvent::Clear()
{
   if (m_arrHandles[HANDLE_THREAD] != NULL)
   {
      SetEvent(m_arrHandles[HANDLE_EXIT]);
      DWORD nWait = WaitForSingleObject(m_arrHandles[HANDLE_THREAD], TIME_EXIT_THREAD);
      if (nWait != WAIT_OBJECT_0)
         TerminateThread(m_arrHandles[HANDLE_THREAD], 2);
   }
   int nCnt = 0;
   do 
   {
      if (m_arrHandles[nCnt] != NULL)
      {
         CloseHandle(m_arrHandles[nCnt]);
         m_arrHandles[nCnt] = NULL;
      }
      nCnt++;
   } while(nCnt < HANDLES);
 
   m_nIdle = TIME_IDLE;
 
   ZeroMemory(m_arrHandles, HANDLES * sizeof(HANDLE));
   if (m_lpszName != NULL)
   {
      free(m_lpszName);
      m_lpszName = NULL;
   }
}
 
DWORD CPowerEvent::EventName(LPWSTR& lpszName)
{
   HKEY hKey = NULL;
   DWORD nResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, s_szGWE_REG_PATH, 0, 0, &hKey);
   if (nResult != ERROR_SUCCESS)
      return 0;
 
   DWORD nNumBytes = 0;
   DWORD nType;
   nResult = RegQueryValueEx(hKey, s_szActivityKey, NULL, &nType, NULL, &nNumBytes);
   if (nResult == ERROR_SUCCESS)
   {
      nResult = 0;
      if (nNumBytes > 0)
      {
         lpszName = (LPWSTR)malloc(nNumBytes + 2);
         if (lpszName != NULL)
         {
            ZeroMemory(lpszName, nNumBytes + 2);
            nResult = RegQueryValueEx(hKey, s_szActivityKey, NULL, &nType, (LPBYTE)lpszName, &nNumBytes);
            nResult = wcslen(lpszName);
         }
      }
      RegCloseKey(hKey);
   }
   return nResult;
}
 
BOOL CPowerEvent::Start()
{
   if (m_arrHandles[HANDLE_THREAD] != NULL)
   {
      SetEvent(m_arrHandles[HANDLE_START]);
      return TRUE;
   }
 
   if (m_lpszName == NULL)
   {
      DWORD nSize = EventName(m_lpszName);
      if (nSize == 0 || m_lpszName == NULL)
         return FALSE;
   }
 
   m_arrHandles[HANDLE_POWER_EVENT] = CreateEvent(NULL, FALSE, FALSE, m_lpszName);
   if (m_arrHandles[HANDLE_POWER_EVENT] == NULL)
      return FALSE;
 
   int nCnt = HANDLE_STOP;
   while (nCnt < HANDLES)
   {
      m_arrHandles[nCnt] = CreateEvent(NULL, FALSE, FALSE, NULL);
      nCnt++;
   }
   m_arrHandles[HANDLE_THREAD] = CreateThread(NULL, 0, Run, (LPVOID)this, 0, NULL);
   if (m_arrHandles[HANDLE_THREAD] == NULL)
   {
      Clear();
      return FALSE;
   }
 
   return TRUE;
}
 
BOOL CPowerEvent::Stop()
{
   if (m_arrHandles[HANDLE_THREAD] == NULL)
      return FALSE;
   SetEvent(m_arrHandles[HANDLE_STOP]);
   return TRUE;
}
 
BOOL CPowerEvent::SetIdle(DWORD nTime)
{
   if (m_arrHandles[HANDLE_THREAD] != NULL)
      return FALSE;
   m_nIdle = nTime;
   return TRUE;
}
 
DWORD WINAPI CPowerEvent::Run(LPVOID pParam)
{
   CPowerEvent* pSelf = (CPowerEvent*)pParam;
 
   DWORD nIdle = TIME_IDLE;
   if (pSelf->m_nIdle > 0 && pSelf->m_nIdle != nIdle)
      nIdle = pSelf->m_nIdle;
 
   HANDLE arrWait[2] = { pSelf->m_arrHandles[HANDLE_STOP], pSelf->m_arrHandles[HANDLE_EXIT] };
   HANDLE arrPause[2] = { pSelf->m_arrHandles[HANDLE_START], pSelf->m_arrHandles[HANDLE_EXIT] };
 
   DWORD nWait = WAIT_OBJECT_0;
   BOOL bExit = FALSE;
 
   do 
   {
      SetEvent(pSelf->m_arrHandles[HANDLE_POWER_EVENT]);
 
      nWait = WaitForMultipleObjects(2, arrWait, FALSE, nIdle);
      if (nWait == WAIT_OBJECT_0)
      {
         nWait = WaitForMultipleObjects(2, arrPause, FALSE, INFINITE);
         if (nWait == WAIT_OBJECT_0 + 1)
            bExit = TRUE;
      }
 
      else if (nWait == WAIT_OBJECT_0 + 1)
         bExit = TRUE;
 
   } while(!bExit);
 
   return 0;
};

My test application is a simple dialog-based MFC application. I added CPowerEven oject into the dialog class as a private member. On the dialog form I put 2 buttons: On and Off. The buttons' click handlers are trivial:

我的测试应用程序是一个简单的基于对话框的MFC应用程序。 我将CPowerEven对象作为私有成员添加到对话框类中。 在对话框中,我放置了2个按钮:“打开”和“关闭”。 按钮的单击处理程序很简单:

1. Button "On" calls method Start() from the CPowerEvent object.

1.按钮“打开”从CPowerEvent对象调用方法Start()。

2. Button "Off" calls method Stop().

2.“关闭”按钮调用方法Stop()。

I tested this approach with the power event on few Windows Mobile 6.1 devices. I found one device where this code didn't work. The approach described in the beginning of the article fails also. Probably, the device has a different power manager, as can be the case with OEM devices.

我在一些Windows Mobile 6.1设备上通过电源事件测试了这种方法。 我找到了一个无法使用此代码的设备。 本文开头描述的方法也失败了。 该设备可能具有不同的电源管理器,就像OEM设备一样。

Like always, the simplest solution for this "Display On" ("Backlight On") problem can be found on the application level - the device is on all the time when the user type something on the keyboard. So, if I will periodically emulate the keyboard input the device will never "go to sleep".

像往常一样,可以在应用程序级别上找到“显示开”(“背光开”)问题的最简单解决方案-用户一直在键盘上键入内容时,设备始终处于打开状态。 因此,如果我会定期模拟键盘输入,则该设备将永远不会“进入睡眠状态”。

The following code emulate the keyboard input that keeps the device on:

以下代码模拟了使设备保持开启状态的键盘输入:

void EmulateKeyboard()
{
   EnableHardwareKeyboard(FALSE);
   keybd_event(0xE9, 0, KEYEVENTF_SILENT, 0);
   keybd_event(0xE9, 0, KEYEVENTF_SILENT | KEYEVENTF_KEYUP, 0);
}

Few more important points about the subject of this article:

关于本文主题的几个重要点:

1. We need to remember that we are working with the mobile devices and the effective power management is a critical issue. The code represented here does not save the battery. It does not overload the CPU, but keeping the backlight on all the time is, definitely, against all Microsoft recommendations for power effective applications.

1.我们需要记住,我们正在使用移动设备,有效的电源管理是一个关键问题。 此处显示的代码不会节省电池。 它不会使CPU过载,但是始终保持背光源始终与Microsoft有关节能应用程序的所有建议背道而驰

2. I assume that tomorrow I will see another device with Windows Mobile (or CE) 5 or 6 where all described techniques will not work. OEMs (device manufacturers) always build and tailor their own platforms for their devices. They adopt the operating system for their hardware. In many cases OEM's develop their own drivers based on the Microsoft samples. It is even not necessary to follow the Microsoft recommendations. So due to the customization an OEM may have done, the programs that use the registry information, OEM's keyboard codes, etc., as the examples in this article, may not work on a specific Windows CE/Mobile device.

2.我假设明天我将看到另一台装有Windows Mobile(或CE)5或6的设备,其中所有描述的技术都将不起作用。 OEM(设备制造商)始终为设备构建和定制自己的平台。 他们将操作系统用于其硬件。 在许多情况下,OEM都会根据Microsoft样本开发自己的驱动程序。 甚至没有必要遵循Microsoft的建议。 因此,由于OEM可能已经进行了自定义,因此,使用注册表信息,OEM的键盘代码等的程序(如本文中的示例)可能无法在特定的Windows CE / Mobile设备上运行。

翻译自: https://www.experts-exchange.com/articles/1255/Windows-Mobile-6-Keep-the-Display-On.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值