那么我们就把不可能变成可能, 无非就是熟悉一下微软的游戏规则而已.
下面给出的代码,在整个程序开始时, 调用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
11
static BOOL g_bPowerEnd = FALSE;
12
static HANDLE g_hNoti = NULL;
13
static HANDLE g_hMsgQ = NULL;
14
static HANDLE g_hPowerThread = NULL;
15
16
17
DWORD 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
57
BOOL InitPowerNotify()
58

{
59
BOOL result = FALSE;
60
MSGQUEUEOPTIONS options;
61
62
DBGMSG(ZONE_LOG, (TEXT("++InitPowerNofityn")));
63
64
memset(&options, 0, sizeof(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
114
cleanup:
115
DBGMSG(ZONE_LOG, (TEXT("--InitPowerNofityn")));
116
return result;
117
}
118
119
BOOL 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, 0, sizeof(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), 1000, 0) )
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 exit
n")));
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
181
cleanup:
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
#include <windows.h> 2
#include <pm.h>3
#include <Msgqueue.h>4

5
#define QUEUE_ENTRIES 3 6
#define MAX_NAMELEN 2007
#define QUEUE_SIZE (QUEUE_ENTRIES * sizeof(POWER_BROADCAST) + MAX_NAMELEN)8
#define MSGQ_NAME TEXT("PowerNotify")9
#define EXIT_THREAD_MSG 0x12345678 10

11
static BOOL g_bPowerEnd = FALSE;12
static HANDLE g_hNoti = NULL;13
static HANDLE g_hMsgQ = NULL; 14
static HANDLE g_hPowerThread = NULL;15

16

17
DWORD WINAPI PowerThread(PVOID pParam)18


{ 19
BYTE buf[QUEUE_SIZE];20
DWORD dwRead, dwFlag;21
22
DBGMSG(ZONE_LOG, (TEXT("++PowerThreadn")));23
24
do25

{ 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键按下,系统RESUME35
//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
else44

{ 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

57
BOOL InitPowerNotify()58


{ 59
BOOL result = FALSE;60
MSGQUEUEOPTIONS options;61

62
DBGMSG(ZONE_LOG, (TEXT("++InitPowerNofityn")));63
64
memset(&options, 0, sizeof(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
else87

{ 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
else100

{ 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

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

119
BOOL 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, 0, sizeof(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), 1000, 0) ) 148

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

{ 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 exit
n"))); 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
else177

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

181
cleanup: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就是检测不到。
由于按下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就是检测不到。

RSS订阅