J2ME之家

匿名投稿 投稿指南 RSS订阅 J2ME通告:
搜索: 您的位置主页>Windows Mobile>

在Windows mobile应用层代码检测POWER键RESUME动作

2008-8-20 21:37:55 来源: 责任编辑: 【 点击: 我要投稿 [进入论坛]

今天有个客户在我的MOBILE手机上做开发,遇到个需要检测POWER键RESUME的问题. 他们直接说在应用层检测这个是不可能的.
那么我们就把不可能变成可能, 无非就是熟悉一下微软的游戏规则而已.

下面给出的代码,在整个程序开始时, 调用InitPowerNotify一下, 建立起MSG QUEUE和NOTIFY, 然后开个线程读MSG QUEUE等待RESUME触发. 如果等到RESUME事件, 则在PowerThread的TBD处加入处理代码, 如果程序结束, 那么调用一下EndPowerNotify, 把线程结束掉把HANDLE清理掉.

以下代码在WM6.1上验证过可用。里面我写了很多DBGMSG, 这个是我自己做的一个把LOG写到文件里的函数, 用户可以删掉. 由于程序去检测POWER RESUME, 之前一定会有一次POWER SLEEP, 那么USB线连着VS2005调试就断掉了,所以只能把LOG写到文件里来看,而无法单步调试或把LOG输出到VS2005的OUTPUT窗口.

最后我有个疑问, 在反初始化时, 我调用StopPowerNotifications结果返回值是FALSE, 代表该函数失败,但是立刻GetLastError得到的ERR号却也是0. 有没有高人能够解释一下?

  1#include <windows.h>


  2#include <pm.h>
  3#include <Msgqueue.h>
  4
  5#define QUEUE_ENTRIES 3
  6#define MAX_NAMELEN 200
  7#define QUEUE_SIZE (QUEUE_ENTRIES * sizeof(POWER_BROADCAST) + MAX_NAMELEN)
  8#define MSGQ_NAME TEXT("PowerNotify")
  9#define EXIT_THREAD_MSG 0x12345678


 10
 11static BOOL g_bPowerEnd = FALSE;
 12static HANDLE g_hNoti = NULL;
 13static HANDLE g_hMsgQ = NULL;


 14static HANDLE g_hPowerThread = NULL;
 15
 16
 17DWORD WINAPI PowerThread(PVOID pParam)
 18{


 19    BYTE buf[QUEUE_SIZE];
 20    DWORD dwRead, dwFlag;
 21    
 22    DBGMSG(ZONE_LOG, (TEXT("++PowerThreadn")));
 23
 24    do
 25    {
 26        if( ReadMsgQueue(g_hMsgQ, &buf, QUEUE_SIZE, &dwRead, 10&dwFlag) )
 27        {

 28            POWER_BROADCAST* pBroad = (POWER_BROADCAST*)&buf;
 29
 30            if(pBroad->Message == PBT_RESUME)


 31            {
 32        DBGMSG(ZONE_LOG, (TEXT("PowerThread detected RESUMEn")));
 33
 34                //检测到POWER键按下,系统RESUME
 35                //TBD: 把RESUME时的处理写这儿
 36            }

 37        else if(pBroad->Message == EXIT_THREAD_MSG)
 38        {

 39                DBGMSG(ZONE_LOG, (TEXT("PowerThread deteced EXITn")));
 40        g_bPowerEnd = TRUE;
 41        break;
 42        }

 43        else
 44        {
 45        DBGMSG(ZONE_LOG, (TEXT("PowerNotify detected nothingn")));
 46        }

 47        }

 48        
 49    }

 50    while(!g_bPowerEnd);
 51
 52    DBGMSG(ZONE_LOG, (TEXT("--PowerThreadn")));


 53
 54    return 1;
 55}

 56
 57BOOL InitPowerNotify()
 58{

 59    BOOL result = FALSE;
 60    MSGQUEUEOPTIONS options;
 61
 62    DBGMSG(ZONE_LOG, (TEXT("++InitPowerNofityn")));
 63
 64    memset(&options, 0sizeof(options));
 65
 66    if(g_hPowerThread) //等待线程已经存在了,该模块已启动
 67    {
 68        result = TRUE;
 69        goto cleanup;
 70    }

 71    
 72    options.dwSize = sizeof(MSGQUEUEOPTIONS);
 73    options.dwFlags = MSGQUEUE_ALLOW_BROKEN;
 74    options.dwMaxMessages = QUEUE_ENTRIES;
 75    options.cbMaxMessage = sizeof(POWER_BROADCAST) + MAX_NAMELEN;
 76    options.bReadAccess = TRUE;
 77
 78    g_hMsgQ = CreateMsgQueue(MSGQ_NAME, &options);
 79
 80    if(!g_hMsgQ)
 81    {
 82        ASSERT(0);
 83        DBGMSG(ZONE_LOG, (TEXT("CreateMsgQueue for power notify failedn")));
 84        goto cleanup;
 85    }


 86    else
 87    {
 88    DBGMSG(ZONE_LOG, (TEXT("CreateMsgQueue for power notify successn")));
 89    }

 90
 91    g_hNoti = RequestPowerNotifications(g_hMsgQ, PBT_RESUME);
 92    
 93    if(!g_hNoti)
 94    {
 95        ASSERT(0);
 96        DBGMSG(ZONE_LOG, (TEXT("RequestPowerNotifications failedn")));
 97        goto cleanup;
 98    }

 99    else
100    {

101    DBGMSG(ZONE_LOG, (TEXT("RequestPowerNotifications successn")));
102    }

103
104    g_bPowerEnd = FALSE;

105    g_hPowerThread = CreateThread(NULL, 0, PowerThread, NULL, 0, NULL);
106    
107    if(!g_hPowerThread)
108    {

109        ASSERT(0);
110        DBGMSG(ZONE_LOG, (TEXT("CreateThread for PowerNotify failedn")));
111        goto cleanup;
112    }

113
114cleanup:
115    DBGMSG(ZONE_LOG, (TEXT("--InitPowerNofityn")));
116    return result;
117}

118
119BOOL EndPowerNotify()
120{
121    BOOL bRet = FALSE;
122    HANDLE hWriteMsgQ = NULL;
123    MSGQUEUEOPTIONS options;
124
125    DBGMSG(ZONE_LOG, (TEXT("++EndPowerNotifyn")));
126
127    if(!g_hPowerThread)
128    {


129        DBGMSG(ZONE_LOG, (TEXT("PowerThread has been exitn")));
130    goto cleanup;
131    }

132    
133    memset(&options, 0sizeof(options));
134    
135    options.dwSize = sizeof(MSGQUEUEOPTIONS);
136    options.dwFlags = MSGQUEUE_ALLOW_BROKEN;
137    options.dwMaxMessages = QUEUE_ENTRIES;
138    options.cbMaxMessage = sizeof(POWER_BROADCAST) + MAX_NAMELEN;
139    options.bReadAccess = FALSE;


140    
141    hWriteMsgQ = CreateMsgQueue(MSGQ_NAME, &options);
142
143    if(hWriteMsgQ)
144    {
145        POWER_BROADCAST writebuf;
146        writebuf.Message = EXIT_THREAD_MSG;
147        if(FALSE == WriteMsgQueue(hWriteMsgQ, &writebuf, sizeof(writebuf), 10000) )

148        {
149            DBGMSG(ZONE_LOG, (TEXT("WriteMsgQueue failedn")));
150        }

151        else
152        {
153            DBGMSG(ZONE_LOG, (TEXT("WriteMsgQueue succeedn")));
154        }

155        
156        if(FALSE == CloseMsgQueue(hWriteMsgQ))
157        {
158            DBGMSG(ZONE_LOG, (TEXT("CloseMsgQueue failedn")));
159        }

160    }

161    else
162    {


163    DBGMSG(ZONE_LOG, (TEXT("WriteMsgQ create failedn")));
164    }

165    
166    DBGMSG(ZONE_LOG, (TEXT("Wait for PowerThread exitn")));

167    
168    g_bPowerEnd = TRUE;
169    
170    if(    WaitForSingleObject(g_hPowerThread, 1000== WAIT_OBJECT_0 )


171    {
172    DBGMSG(ZONE_LOG, (TEXT("PowerThread exit successn")));
173    g_hPowerThread = NULL;
174    bRet = TRUE;
175    }


176    else
177    {

178    DBGMSG(ZONE_LOG, (TEXT("PowerThread exit failed timeoutn")));
179    }

180
181cleanup:
182

183    if(g_hNoti)
184    {   
185        if( FALSE == StopPowerNotifications(g_hNoti) )
186        {

187            DBGMSG(ZONE_LOG, (TEXT("StopPowerNotifications failed, err = %dn"), GetLastError()));
188        }

189        
190        g_hNoti = NULL;
191    }

192
193    if(g_hMsgQ)
194    {    
195    if(!CloseMsgQueue(g_hMsgQ))
196    {


197           DBGMSG(ZONE_LOG, (TEXT("CloseMsgQueue failedn")));
198    }

199        
200    g_hMsgQ = NULL;
201    }

202
203    DBGMSG(ZONE_LOG, (TEXT("--EndPowerNotifyn")));
204    return bRet;
205}

206
看完你的标题,我第一个想到的就是用WM 5/6 SDK的例子Powermanager里面办法,通过屏幕变化的消息状态来捕获Power键的按下事件。近来细看,果然如此。

由于按下Power键会让电脑和手机断开,调试这个例子的时候的确只能用写log文件的方法来跟踪。当时我在调试这个例子的时候,发现一个屏幕点亮的事件,会在消息队列中增加3~4个消息,而且其中2~3个消息是完全相同的。

在最后关闭电源通知调用StopPowerNotifications()的时候,你失败的原因会不会是因为你只检测了一个消息,没处理完消息队列中的所有消息,导致的StopPowerNotifications()失败?sdk例子上关闭消息的写法和你的不同,它是:

while(WaitForMultipleObjects(2, rgHandles, FALSE, INFINITE) == WAIT_OBJECT_0)
{
DWORD cbRead;
DWORD dwFlags;
POWER_BROADCAST *ppb = (POWER_BROADCAST*) new BYTE[cbPowerMsgSize];

// loop through in case there is more than 1 msg
while(ReadMsgQueue(hPowerMsgQ, ppb, cbPowerMsgSize, &cbRead,
0, &dwFlags))
{
switch (ppb->Message)
{
case PBT_TRANSITION:
if (ppb->Length)
{
...
}
break;

case PBT_RESUME:
break;

case PBT_POWERINFOCHANGE:
{
PPOWER_BROADCAST_POWER_INFO ppbpi =
(PPOWER_BROADCAST_POWER_INFO) ppb->SystemPowerState;
if (ppbpi)
{
...
}
break;
}

default:
break;
}

UpdatePowerState();
}

delete[] ppb;
}

Error:
if (hPowerNotifications)
StopPowerNotifications(hPowerNotifications);

if (hPowerMsgQ)
CloseMsgQueue(hPowerMsgQ);


另外说点我研究这个例子的发现,POWER_BROADCAST这个结构体的SystemPowerState字段基本上就2种:ScreenOn和ScreenOff。flag字段的值和msdn上的解释有些对不上,不知道是不是厂商根据不同型号的手机的硬件作了某些修改,我测试用的HTC 838 pro,在屏幕点亮的时候,MSDN上给的状态是POWER_STATE_ON(0x00010000),但是我的机器是flag值是0x10010000,用POWER_STATE_ON就是检测不到。

Tag:动作 检测 代码 应用   " TEXT DBGMSG ZONE_LOG
责任编辑:
  • 用户名: (新注册)密码: 匿名:  请文明参与讨论,禁止漫骂攻击。
    评论总数: [ 查看全部 ] 网友评论
    热门文章
    关于我们 - 联系我们 - 广告服务 - 法律声明 - RSS订阅 - 网站地图 - 返回顶部