* Sync to trunk HEAD (r53473).
[reactos.git] / dll / win32 / user32 / windows / message.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS user32.dll
4 * FILE: lib/user32/windows/message.c
5 * PURPOSE: Messages
6 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * UPDATE HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 #include <user32.h>
12
13 #include <wine/debug.h>
14 WINE_DEFAULT_DEBUG_CHANNEL(user32);
15
16 /* From wine: */
17 /* flag for messages that contain pointers */
18 /* 32 messages per entry, messages 0..31 map to bits 0..31 */
19
20 #define SET(msg) (1 << ((msg) & 31))
21
22 static const unsigned int message_pointer_flags[] =
23 {
24 /* 0x00 - 0x1f */
25 SET(WM_CREATE) | SET(WM_SETTEXT) | SET(WM_GETTEXT) |
26 SET(WM_WININICHANGE) | SET(WM_DEVMODECHANGE),
27 /* 0x20 - 0x3f */
28 SET(WM_GETMINMAXINFO) | SET(WM_DRAWITEM) | SET(WM_MEASUREITEM) | SET(WM_DELETEITEM) |
29 SET(WM_COMPAREITEM),
30 /* 0x40 - 0x5f */
31 SET(WM_WINDOWPOSCHANGING) | SET(WM_WINDOWPOSCHANGED) | SET(WM_COPYDATA) |
32 SET(WM_COPYGLOBALDATA) | SET(WM_NOTIFY) | SET(WM_HELP),
33 /* 0x60 - 0x7f */
34 SET(WM_STYLECHANGING) | SET(WM_STYLECHANGED),
35 /* 0x80 - 0x9f */
36 SET(WM_NCCREATE) | SET(WM_NCCALCSIZE) | SET(WM_GETDLGCODE),
37 /* 0xa0 - 0xbf */
38 SET(EM_GETSEL) | SET(EM_GETRECT) | SET(EM_SETRECT) | SET(EM_SETRECTNP),
39 /* 0xc0 - 0xdf */
40 SET(EM_REPLACESEL) | SET(EM_GETLINE) | SET(EM_SETTABSTOPS),
41 /* 0xe0 - 0xff */
42 SET(SBM_GETRANGE) | SET(SBM_SETSCROLLINFO) | SET(SBM_GETSCROLLINFO) | SET(SBM_GETSCROLLBARINFO),
43 /* 0x100 - 0x11f */
44 0,
45 /* 0x120 - 0x13f */
46 0,
47 /* 0x140 - 0x15f */
48 SET(CB_GETEDITSEL) | SET(CB_ADDSTRING) | SET(CB_DIR) | SET(CB_GETLBTEXT) |
49 SET(CB_INSERTSTRING) | SET(CB_FINDSTRING) | SET(CB_SELECTSTRING) |
50 SET(CB_GETDROPPEDCONTROLRECT) | SET(CB_FINDSTRINGEXACT),
51 /* 0x160 - 0x17f */
52 0,
53 /* 0x180 - 0x19f */
54 SET(LB_ADDSTRING) | SET(LB_INSERTSTRING) | SET(LB_GETTEXT) | SET(LB_SELECTSTRING) |
55 SET(LB_DIR) | SET(LB_FINDSTRING) |
56 SET(LB_GETSELITEMS) | SET(LB_SETTABSTOPS) | SET(LB_ADDFILE) | SET(LB_GETITEMRECT),
57 /* 0x1a0 - 0x1bf */
58 SET(LB_FINDSTRINGEXACT),
59 /* 0x1c0 - 0x1df */
60 0,
61 /* 0x1e0 - 0x1ff */
62 0,
63 /* 0x200 - 0x21f */
64 SET(WM_NEXTMENU) | SET(WM_SIZING) | SET(WM_MOVING) | SET(WM_DEVICECHANGE),
65 /* 0x220 - 0x23f */
66 SET(WM_MDICREATE) | SET(WM_MDIGETACTIVE) | SET(WM_DROPOBJECT) |
67 SET(WM_QUERYDROPOBJECT) | SET(WM_DRAGLOOP) | SET(WM_DRAGSELECT) | SET(WM_DRAGMOVE),
68 /* 0x240 - 0x25f */
69 0,
70 /* 0x260 - 0x27f */
71 0,
72 /* 0x280 - 0x29f */
73 0,
74 /* 0x2a0 - 0x2bf */
75 0,
76 /* 0x2c0 - 0x2df */
77 0,
78 /* 0x2e0 - 0x2ff */
79 0,
80 /* 0x300 - 0x31f */
81 SET(WM_ASKCBFORMATNAME)
82 };
83
84 /* check whether a given message type includes pointers */
85 static inline int is_pointer_message( UINT message )
86 {
87 if (message >= 8*sizeof(message_pointer_flags)) return FALSE;
88 return (message_pointer_flags[message / 32] & SET(message)) != 0;
89 }
90
91 /* DDE message exchange
92 *
93 * - Session initialization
94 * Client sends a WM_DDE_INITIATE message, usually a broadcast message. lParam of
95 * this message contains a pair of global atoms, the Application and Topic atoms.
96 * The client must destroy the atoms.
97 * Server window proc handles the WM_DDE_INITIATE message and if the Application
98 * and Topic atoms are recognized sends a WM_DDE_ACK message to the client. lParam
99 * of the reply message contains another pair of global atoms (Application and
100 * Topic again), which must be destroyed by the server.
101 *
102 * - Execute
103 * Client posts a WM_DDE_EXECUTE message to the server window. lParam of that message
104 * is a global memory handle containing the string to execute. After the command has
105 * been executed the server posts a WM_DDE_ACK message to the client, which contains
106 * a packed lParam which in turn contains that global memory handle. The client takes
107 * ownership of both the packed lParam (meaning it needs to call FreeDDElParam() on
108 * it and the global memory handle.
109 * This might work nice and easy in Win3.1, but things are more complicated for NT.
110 * Global memory handles in NT are not really global, they're still local to the
111 * process. So, what happens under the hood is that PostMessage must handle the
112 * WM_DDE_EXECUTE message specially. It will obtain the contents of the global memory
113 * area, repack that into a new structure together with the original memory handle
114 * and pass that off to the win32k. Win32k will marshall that data over to the target
115 * (server) process where it will be unpacked and stored in a newly allocated global
116 * memory area. The handle of that area will then be sent to the window proc, after
117 * storing it together with the "original" (client) handle in a table.
118 * The server will eventually post the WM_DDE_ACK response, containing the global
119 * memory handle it received. PostMessage must then lookup that memory handle (only
120 * valid in the server process) and replace it with the corresponding client memory
121 * handle. To avoid memory leaks, the server-side global memory block must be freed.
122 * Also, the WM_DDE_ACK lParam (a PackDDElParam() result) is unpacked and the
123 * individual components are handed to win32k.sys to post to the client side. Since
124 * the server side app hands over ownership of the packed lParam when it calls
125 * PostMessage(), the packed lParam needs to be freed on the server side too.
126 * When the WM_DDE_ACK message (containing the client-side global memory handle)
127 * arrives at the client side a new lParam is PackDDElParam()'ed and this is handed
128 * to the client side window proc which is expected to free/reuse it.
129 */
130
131 /* since the WM_DDE_ACK response to a WM_DDE_EXECUTE message should contain the handle
132 * to the memory handle, we keep track (in the server side) of all pairs of handle
133 * used (the client passes its value and the content of the memory handle), and
134 * the server stored both values (the client, and the local one, created after the
135 * content). When a ACK message is generated, the list of pair is searched for a
136 * matching pair, so that the client memory handle can be returned.
137 */
138
139 typedef struct tagDDEPAIR
140 {
141 HGLOBAL ClientMem;
142 HGLOBAL ServerMem;
143 } DDEPAIR, *PDDEPAIR;
144
145 static PDDEPAIR DdePairs = NULL;
146 static unsigned DdeNumAlloc = 0;
147 static unsigned DdeNumUsed = 0;
148 static CRITICAL_SECTION DdeCrst;
149
150 static BOOL FASTCALL
151 DdeAddPair(HGLOBAL ClientMem, HGLOBAL ServerMem)
152 {
153 unsigned i;
154
155 EnterCriticalSection(&DdeCrst);
156
157 /* now remember the pair of hMem on both sides */
158 if (DdeNumUsed == DdeNumAlloc)
159 {
160 #define GROWBY 4
161 PDDEPAIR New;
162 if (NULL != DdePairs)
163 {
164 New = HeapReAlloc(GetProcessHeap(), 0, DdePairs,
165 (DdeNumAlloc + GROWBY) * sizeof(DDEPAIR));
166 }
167 else
168 {
169 New = HeapAlloc(GetProcessHeap(), 0,
170 (DdeNumAlloc + GROWBY) * sizeof(DDEPAIR));
171 }
172
173 if (NULL == New)
174 {
175 LeaveCriticalSection(&DdeCrst);
176 return FALSE;
177 }
178 DdePairs = New;
179 /* zero out newly allocated part */
180 memset(&DdePairs[DdeNumAlloc], 0, GROWBY * sizeof(DDEPAIR));
181 DdeNumAlloc += GROWBY;
182 #undef GROWBY
183 }
184
185 for (i = 0; i < DdeNumAlloc; i++)
186 {
187 if (NULL == DdePairs[i].ServerMem)
188 {
189 DdePairs[i].ClientMem = ClientMem;
190 DdePairs[i].ServerMem = ServerMem;
191 DdeNumUsed++;
192 break;
193 }
194 }
195 LeaveCriticalSection(&DdeCrst);
196
197 return TRUE;
198 }
199
200 static HGLOBAL FASTCALL
201 DdeGetPair(HGLOBAL ServerMem)
202 {
203 unsigned i;
204 HGLOBAL Ret = NULL;
205
206 EnterCriticalSection(&DdeCrst);
207 for (i = 0; i < DdeNumAlloc; i++)
208 {
209 if (DdePairs[i].ServerMem == ServerMem)
210 {
211 /* free this pair */
212 DdePairs[i].ServerMem = 0;
213 DdeNumUsed--;
214 Ret = DdePairs[i].ClientMem;
215 break;
216 }
217 }
218 LeaveCriticalSection(&DdeCrst);
219
220 return Ret;
221 }
222
223 static
224 BOOL FASTCALL
225 MsgiUMToKMMessage(PMSG UMMsg, PMSG KMMsg, BOOL Posted)
226 {
227 *KMMsg = *UMMsg;
228
229 switch (UMMsg->message)
230 {
231 case WM_DDE_ACK:
232 {
233 PKMDDELPARAM DdeLparam;
234 DdeLparam = HeapAlloc(GetProcessHeap(), 0, sizeof(KMDDELPARAM));
235 if (NULL == DdeLparam)
236 {
237 return FALSE;
238 }
239 if (Posted)
240 {
241 DdeLparam->Packed = TRUE;
242 if (! UnpackDDElParam(UMMsg->message, UMMsg->lParam,
243 &DdeLparam->Value.Packed.uiLo,
244 &DdeLparam->Value.Packed.uiHi))
245 {
246 return FALSE;
247 }
248 if (0 != HIWORD(DdeLparam->Value.Packed.uiHi))
249 {
250 /* uiHi should contain a hMem from WM_DDE_EXECUTE */
251 HGLOBAL h = DdeGetPair((HGLOBAL)(ULONG_PTR)DdeLparam->Value.Packed.uiHi);
252 if (NULL != h)
253 {
254 GlobalFree((HGLOBAL)(ULONG_PTR)DdeLparam->Value.Packed.uiHi);
255 DdeLparam->Value.Packed.uiHi = (UINT_PTR) h;
256 }
257 }
258 FreeDDElParam(UMMsg->message, UMMsg->lParam);
259 }
260 else
261 {
262 DdeLparam->Packed = FALSE;
263 DdeLparam->Value.Unpacked = UMMsg->lParam;
264 }
265 KMMsg->lParam = (LPARAM) DdeLparam;
266 }
267 break;
268
269 case WM_DDE_EXECUTE:
270 {
271 SIZE_T Size;
272 PKMDDEEXECUTEDATA KMDdeExecuteData;
273 PVOID Data;
274
275 Size = GlobalSize((HGLOBAL) UMMsg->lParam);
276 Data = GlobalLock((HGLOBAL) UMMsg->lParam);
277 if (NULL == Data)
278 {
279 SetLastError(ERROR_INVALID_HANDLE);
280 return FALSE;
281 }
282 KMDdeExecuteData = HeapAlloc(GetProcessHeap(), 0, sizeof(KMDDEEXECUTEDATA) + Size);
283 if (NULL == KMDdeExecuteData)
284 {
285 SetLastError(ERROR_OUTOFMEMORY);
286 return FALSE;
287 }
288 KMDdeExecuteData->Sender = (HWND) UMMsg->wParam;
289 KMDdeExecuteData->ClientMem = (HGLOBAL) UMMsg->lParam;
290 memcpy((PVOID) (KMDdeExecuteData + 1), Data, Size);
291 KMMsg->wParam = sizeof(KMDDEEXECUTEDATA) + Size;
292 KMMsg->lParam = (LPARAM) KMDdeExecuteData;
293 GlobalUnlock((HGLOBAL) UMMsg->lParam);
294 }
295 break;
296
297 case WM_COPYDATA:
298 {
299 PCOPYDATASTRUCT pUMCopyData = (PCOPYDATASTRUCT)UMMsg->lParam;
300 PCOPYDATASTRUCT pKMCopyData;
301
302 pKMCopyData = HeapAlloc(GetProcessHeap(), 0,
303 sizeof(COPYDATASTRUCT) + pUMCopyData->cbData);
304 if (pKMCopyData == NULL)
305 {
306 SetLastError(ERROR_OUTOFMEMORY);
307 return FALSE;
308 }
309
310 pKMCopyData->dwData = pUMCopyData->dwData;
311 pKMCopyData->cbData = pUMCopyData->cbData;
312 pKMCopyData->lpData = pKMCopyData + 1;
313
314 RtlCopyMemory(pKMCopyData + 1, pUMCopyData->lpData,
315 pUMCopyData->cbData);
316
317 KMMsg->lParam = (LPARAM)pKMCopyData;
318 }
319 break;
320
321 default:
322 break;
323 }
324
325 return TRUE;
326 }
327
328 static
329 VOID FASTCALL
330 MsgiUMToKMCleanup(PMSG UMMsg, PMSG KMMsg)
331 {
332 switch (KMMsg->message)
333 {
334 case WM_DDE_ACK:
335 case WM_DDE_EXECUTE:
336 case WM_COPYDATA:
337 HeapFree(GetProcessHeap(), 0, (LPVOID) KMMsg->lParam);
338 break;
339 default:
340 break;
341 }
342
343 return;
344 }
345
346 static BOOL FASTCALL
347 MsgiKMToUMMessage(PMSG KMMsg, PMSG UMMsg)
348 {
349 *UMMsg = *KMMsg;
350
351 switch (UMMsg->message)
352 {
353 case WM_CREATE:
354 case WM_NCCREATE:
355 {
356 CREATESTRUCTW *Cs = (CREATESTRUCTW *) KMMsg->lParam;
357 PCHAR Class;
358 Cs->lpszName = (LPCWSTR) ((PCHAR) Cs + (DWORD_PTR) Cs->lpszName);
359 Class = (PCHAR) Cs + (DWORD_PTR) Cs->lpszClass;
360 if (L'A' == *((WCHAR *) Class))
361 {
362 Class += sizeof(WCHAR);
363 Cs->lpszClass = (LPCWSTR)(DWORD_PTR) (*((ATOM *) Class));
364 }
365 else
366 {
367 ASSERT(L'S' == *((WCHAR *) Class));
368 Class += sizeof(WCHAR);
369 Cs->lpszClass = (LPCWSTR) Class;
370 }
371 }
372 break;
373
374 case WM_DDE_ACK:
375 {
376 PKMDDELPARAM DdeLparam = (PKMDDELPARAM) KMMsg->lParam;
377 if (DdeLparam->Packed)
378 {
379 UMMsg->lParam = PackDDElParam(KMMsg->message,
380 DdeLparam->Value.Packed.uiLo,
381 DdeLparam->Value.Packed.uiHi);
382 }
383 else
384 {
385 UMMsg->lParam = DdeLparam->Value.Unpacked;
386 }
387 }
388 break;
389
390 case WM_DDE_EXECUTE:
391 {
392 PKMDDEEXECUTEDATA KMDdeExecuteData;
393 HGLOBAL GlobalData;
394 PVOID Data;
395
396 KMDdeExecuteData = (PKMDDEEXECUTEDATA) KMMsg->lParam;
397 GlobalData = GlobalAlloc(GMEM_MOVEABLE, KMMsg->wParam - sizeof(KMDDEEXECUTEDATA));
398 if (NULL == GlobalData)
399 {
400 return FALSE;
401 }
402 Data = GlobalLock(GlobalData);
403 if (NULL == Data)
404 {
405 GlobalFree(GlobalData);
406 return FALSE;
407 }
408 memcpy(Data, (PVOID) (KMDdeExecuteData + 1), KMMsg->wParam - sizeof(KMDDEEXECUTEDATA));
409 GlobalUnlock(GlobalData);
410 if (! DdeAddPair(KMDdeExecuteData->ClientMem, GlobalData))
411 {
412 GlobalFree(GlobalData);
413 return FALSE;
414 }
415 UMMsg->wParam = (WPARAM) KMDdeExecuteData->Sender;
416 UMMsg->lParam = (LPARAM) GlobalData;
417 }
418 break;
419
420 case WM_COPYDATA:
421 {
422 PCOPYDATASTRUCT pKMCopyData = (PCOPYDATASTRUCT)KMMsg->lParam;
423 pKMCopyData->lpData = pKMCopyData + 1;
424 }
425 break;
426
427 default:
428 break;
429 }
430
431 return TRUE;
432 }
433
434 static VOID FASTCALL
435 MsgiKMToUMCleanup(PMSG KMMsg, PMSG UMMsg)
436 {
437 switch (KMMsg->message)
438 {
439 case WM_DDE_EXECUTE:
440 #ifdef TODO
441 HeapFree(GetProcessHeap(), 0, (LPVOID) KMMsg->lParam);
442 GlobalUnlock((HGLOBAL) UMMsg->lParam);
443 #endif
444 break;
445 default:
446 break;
447 }
448
449 return;
450 }
451
452 static BOOL FASTCALL
453 MsgiKMToUMReply(PMSG KMMsg, PMSG UMMsg, LRESULT *Result)
454 {
455 MsgiKMToUMCleanup(KMMsg, UMMsg);
456
457 return TRUE;
458 }
459
460 static BOOL FASTCALL
461 MsgiAnsiToUnicodeMessage(HWND hwnd, LPMSG UnicodeMsg, LPMSG AnsiMsg)
462 {
463 UNICODE_STRING UnicodeString;
464
465 *UnicodeMsg = *AnsiMsg;
466
467 switch (AnsiMsg->message)
468 {
469 case WM_GETTEXT:
470 case WM_ASKCBFORMATNAME:
471 {
472 LPWSTR Buffer = HeapAlloc(GetProcessHeap(), 0,
473 AnsiMsg->wParam * sizeof(WCHAR));
474 if (!Buffer)
475 {
476 return FALSE;
477 }
478 UnicodeMsg->lParam = (LPARAM)Buffer;
479 break;
480 }
481
482 /* AnsiMsg->lParam is string (0-terminated) */
483 case WM_SETTEXT:
484 case WM_WININICHANGE:
485 case WM_DEVMODECHANGE:
486 case CB_DIR:
487 case LB_DIR:
488 case LB_ADDFILE:
489 case EM_REPLACESEL:
490 {
491 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)AnsiMsg->lParam);
492 UnicodeMsg->lParam = (LPARAM)UnicodeString.Buffer;
493 break;
494 }
495
496 case LB_ADDSTRING:
497 case LB_ADDSTRING_LOWER:
498 case LB_ADDSTRING_UPPER:
499 case LB_INSERTSTRING:
500 case LB_INSERTSTRING_UPPER:
501 case LB_INSERTSTRING_LOWER:
502 case LB_FINDSTRING:
503 case LB_FINDSTRINGEXACT:
504 case LB_SELECTSTRING:
505 {
506 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
507 if (!(dwStyle & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) &&
508 (dwStyle & LBS_HASSTRINGS))
509 {
510 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)AnsiMsg->lParam);
511 UnicodeMsg->lParam = (LPARAM)UnicodeString.Buffer;
512 }
513 break;
514 }
515
516 case CB_ADDSTRING:
517 case CB_INSERTSTRING:
518 case CB_FINDSTRING:
519 case CB_FINDSTRINGEXACT:
520 case CB_SELECTSTRING:
521 {
522 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
523 if (!(dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) &&
524 (dwStyle & CBS_HASSTRINGS))
525 {
526 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)AnsiMsg->lParam);
527 UnicodeMsg->lParam = (LPARAM)UnicodeString.Buffer;
528 }
529 break;
530 }
531
532 case WM_NCCREATE:
533 case WM_CREATE:
534 {
535 MDICREATESTRUCTW mdi_cs;
536 struct s
537 {
538 CREATESTRUCTW cs; /* new structure */
539 LPCWSTR lpszName; /* allocated Name */
540 LPCWSTR lpszClass; /* allocated Class */
541 };
542
543 struct s *xs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct s));
544 if (!xs)
545 {
546 return FALSE;
547 }
548 xs->cs = *(CREATESTRUCTW *)AnsiMsg->lParam;
549 if (!IS_INTRESOURCE(xs->cs.lpszName))
550 {
551 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)xs->cs.lpszName);
552 xs->lpszName = xs->cs.lpszName = UnicodeString.Buffer;
553 }
554 if (!IS_ATOM(xs->cs.lpszClass))
555 {
556 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)xs->cs.lpszClass);
557 xs->lpszClass = xs->cs.lpszClass = UnicodeString.Buffer;
558 }
559
560 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
561 {
562 mdi_cs = *(MDICREATESTRUCTW *)xs->cs.lpCreateParams;
563 mdi_cs.szTitle = xs->cs.lpszName;
564 mdi_cs.szClass = xs->cs.lpszClass;
565 xs->cs.lpCreateParams = &mdi_cs;
566 }
567
568 UnicodeMsg->lParam = (LPARAM)xs;
569 break;
570 }
571
572 case WM_MDICREATE:
573 {
574 MDICREATESTRUCTW *cs =
575 (MDICREATESTRUCTW *)HeapAlloc(GetProcessHeap(), 0, sizeof(*cs));
576
577 if (!cs)
578 {
579 return FALSE;
580 }
581
582 *cs = *(MDICREATESTRUCTW *)AnsiMsg->lParam;
583
584 if (!IS_ATOM(cs->szClass))
585 {
586 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)cs->szClass);
587 cs->szClass = UnicodeString.Buffer;
588 }
589
590 RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)cs->szTitle);
591 cs->szTitle = UnicodeString.Buffer;
592
593 UnicodeMsg->lParam = (LPARAM)cs;
594 break;
595 }
596 }
597
598 return TRUE;
599 }
600
601
602 static BOOL FASTCALL
603 MsgiAnsiToUnicodeCleanup(LPMSG UnicodeMsg, LPMSG AnsiMsg)
604 {
605 UNICODE_STRING UnicodeString;
606
607 switch (AnsiMsg->message)
608 {
609 case WM_GETTEXT:
610 case WM_ASKCBFORMATNAME:
611 {
612 HeapFree(GetProcessHeap(), 0, (PVOID) UnicodeMsg->lParam);
613 break;
614 }
615
616 case WM_SETTEXT:
617 case WM_WININICHANGE:
618 case WM_DEVMODECHANGE:
619 case CB_DIR:
620 case LB_DIR:
621 case LB_ADDFILE:
622 case EM_REPLACESEL:
623 {
624 RtlInitUnicodeString(&UnicodeString, (PCWSTR)UnicodeMsg->lParam);
625 RtlFreeUnicodeString(&UnicodeString);
626 break;
627 }
628
629 case LB_ADDSTRING:
630 case LB_ADDSTRING_LOWER:
631 case LB_ADDSTRING_UPPER:
632 case LB_INSERTSTRING:
633 case LB_INSERTSTRING_UPPER:
634 case LB_INSERTSTRING_LOWER:
635 case LB_FINDSTRING:
636 case LB_FINDSTRINGEXACT:
637 case LB_SELECTSTRING:
638 {
639 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
640 if (!(dwStyle & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) &&
641 (dwStyle & LBS_HASSTRINGS))
642 {
643 RtlInitUnicodeString(&UnicodeString, (PCWSTR)UnicodeMsg->lParam);
644 RtlFreeUnicodeString(&UnicodeString);
645 }
646 break;
647 }
648
649 case CB_ADDSTRING:
650 case CB_INSERTSTRING:
651 case CB_FINDSTRING:
652 case CB_FINDSTRINGEXACT:
653 case CB_SELECTSTRING:
654 {
655 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
656 if (!(dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) &&
657 (dwStyle & CBS_HASSTRINGS))
658 {
659 RtlInitUnicodeString(&UnicodeString, (PCWSTR)UnicodeMsg->lParam);
660 RtlFreeUnicodeString(&UnicodeString);
661 }
662 break;
663 }
664
665 case WM_NCCREATE:
666 case WM_CREATE:
667 {
668 struct s
669 {
670 CREATESTRUCTW cs; /* new structure */
671 LPWSTR lpszName; /* allocated Name */
672 LPWSTR lpszClass; /* allocated Class */
673 };
674
675 struct s *xs = (struct s *)UnicodeMsg->lParam;
676 if (xs->lpszName)
677 {
678 RtlInitUnicodeString(&UnicodeString, (PCWSTR)xs->lpszName);
679 RtlFreeUnicodeString(&UnicodeString);
680 }
681 if (xs->lpszClass)
682 {
683 RtlInitUnicodeString(&UnicodeString, (PCWSTR)xs->lpszClass);
684 RtlFreeUnicodeString(&UnicodeString);
685 }
686 HeapFree(GetProcessHeap(), 0, xs);
687 break;
688 }
689
690 case WM_MDICREATE:
691 {
692 MDICREATESTRUCTW *cs = (MDICREATESTRUCTW *)UnicodeMsg->lParam;
693 RtlInitUnicodeString(&UnicodeString, (PCWSTR)cs->szTitle);
694 RtlFreeUnicodeString(&UnicodeString);
695 if (!IS_ATOM(cs->szClass))
696 {
697 RtlInitUnicodeString(&UnicodeString, (PCWSTR)cs->szClass);
698 RtlFreeUnicodeString(&UnicodeString);
699 }
700 HeapFree(GetProcessHeap(), 0, cs);
701 break;
702 }
703 }
704
705 return(TRUE);
706 }
707
708
709 static BOOL FASTCALL
710 MsgiAnsiToUnicodeReply(LPMSG UnicodeMsg, LPMSG AnsiMsg, LRESULT *Result)
711 {
712 switch (AnsiMsg->message)
713 {
714 case WM_GETTEXT:
715 case WM_ASKCBFORMATNAME:
716 {
717 LPWSTR Buffer = (LPWSTR)UnicodeMsg->lParam;
718 LPSTR AnsiBuffer = (LPSTR)AnsiMsg->lParam;
719 if (UnicodeMsg->wParam > 0 &&
720 !WideCharToMultiByte(CP_ACP, 0, Buffer, -1,
721 AnsiBuffer, UnicodeMsg->wParam, NULL, NULL))
722 {
723 AnsiBuffer[UnicodeMsg->wParam - 1] = 0;
724 }
725 break;
726 }
727 }
728
729 MsgiAnsiToUnicodeCleanup(UnicodeMsg, AnsiMsg);
730
731 return TRUE;
732 }
733
734
735 static BOOL FASTCALL
736 MsgiUnicodeToAnsiMessage(HWND hwnd, LPMSG AnsiMsg, LPMSG UnicodeMsg)
737 {
738 ANSI_STRING AnsiString;
739 UNICODE_STRING UnicodeString;
740
741 *AnsiMsg = *UnicodeMsg;
742
743 switch(UnicodeMsg->message)
744 {
745 case WM_CREATE:
746 case WM_NCCREATE:
747 {
748 MDICREATESTRUCTA mdi_cs;
749 CREATESTRUCTA* CsA;
750 CREATESTRUCTW* CsW;
751 NTSTATUS Status;
752
753 CsW = (CREATESTRUCTW*)(UnicodeMsg->lParam);
754 CsA = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(CREATESTRUCTA));
755 if (NULL == CsA)
756 {
757 return FALSE;
758 }
759 memcpy(CsA, CsW, sizeof(CREATESTRUCTW));
760
761 RtlInitUnicodeString(&UnicodeString, CsW->lpszName);
762 Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
763 if (! NT_SUCCESS(Status))
764 {
765 RtlFreeHeap(GetProcessHeap(), 0, CsA);
766 return FALSE;
767 }
768 CsA->lpszName = AnsiString.Buffer;
769 if (HIWORD((ULONG_PTR)CsW->lpszClass) != 0)
770 {
771 RtlInitUnicodeString(&UnicodeString, CsW->lpszClass);
772 Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
773 if (! NT_SUCCESS(Status))
774 {
775 RtlInitAnsiString(&AnsiString, CsA->lpszName);
776 RtlFreeAnsiString(&AnsiString);
777 RtlFreeHeap(GetProcessHeap(), 0, CsA);
778 return FALSE;
779 }
780 CsA->lpszClass = AnsiString.Buffer;
781 }
782
783 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
784 {
785 mdi_cs = *(MDICREATESTRUCTA *)CsW->lpCreateParams;
786 mdi_cs.szTitle = CsA->lpszName;
787 mdi_cs.szClass = CsA->lpszClass;
788 CsA->lpCreateParams = &mdi_cs;
789 }
790
791 AnsiMsg->lParam = (LPARAM)CsA;
792 break;
793 }
794 case WM_GETTEXT:
795 {
796 /* Ansi string might contain MBCS chars so we need 2 * the number of chars */
797 AnsiMsg->wParam = UnicodeMsg->wParam * 2;
798 AnsiMsg->lParam = (LPARAM) RtlAllocateHeap(GetProcessHeap(), 0, AnsiMsg->wParam);
799 if (NULL == (PVOID) AnsiMsg->lParam)
800 {
801 return FALSE;
802 }
803 break;
804 }
805 case WM_SETTEXT:
806 case CB_DIR:
807 case LB_DIR:
808 case LB_ADDFILE:
809 {
810 RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam);
811 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
812 &UnicodeString,
813 TRUE)))
814 {
815 return FALSE;
816 }
817 AnsiMsg->lParam = (LPARAM) AnsiString.Buffer;
818 break;
819 }
820
821 case LB_ADDSTRING:
822 case LB_ADDSTRING_LOWER:
823 case LB_ADDSTRING_UPPER:
824 case LB_INSERTSTRING:
825 case LB_INSERTSTRING_UPPER:
826 case LB_INSERTSTRING_LOWER:
827 case LB_FINDSTRING:
828 case LB_FINDSTRINGEXACT:
829 case LB_SELECTSTRING:
830 {
831 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
832 if (!(dwStyle & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) &&
833 (dwStyle & LBS_HASSTRINGS))
834 {
835 RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam);
836 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
837 &UnicodeString,
838 TRUE)))
839 {
840 return FALSE;
841 }
842 AnsiMsg->lParam = (LPARAM) AnsiString.Buffer;
843 }
844 break;
845 }
846
847 case CB_ADDSTRING:
848 case CB_INSERTSTRING:
849 case CB_FINDSTRING:
850 case CB_FINDSTRINGEXACT:
851 case CB_SELECTSTRING:
852 {
853 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
854 if (!(dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) &&
855 (dwStyle & CBS_HASSTRINGS))
856 {
857 RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam);
858 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
859 &UnicodeString,
860 TRUE)))
861 {
862 return FALSE;
863 }
864 AnsiMsg->lParam = (LPARAM) AnsiString.Buffer;
865 }
866 break;
867 }
868
869 case WM_MDICREATE:
870 {
871 MDICREATESTRUCTA *cs =
872 (MDICREATESTRUCTA *)HeapAlloc(GetProcessHeap(), 0, sizeof(*cs));
873
874 if (!cs)
875 {
876 return FALSE;
877 }
878
879 *cs = *(MDICREATESTRUCTA *)UnicodeMsg->lParam;
880
881 if (!IS_ATOM(cs->szClass))
882 {
883 RtlInitUnicodeString(&UnicodeString, (LPCWSTR)cs->szClass);
884 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
885 &UnicodeString,
886 TRUE)))
887 {
888 return FALSE;
889 }
890 cs->szClass = AnsiString.Buffer;
891 }
892
893 RtlInitUnicodeString(&UnicodeString, (LPCWSTR)cs->szTitle);
894 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
895 &UnicodeString,
896 TRUE)))
897 {
898 if (!IS_ATOM(cs->szClass))
899 {
900 RtlInitAnsiString(&AnsiString, cs->szClass);
901 RtlFreeAnsiString(&AnsiString);
902 }
903 return FALSE;
904 }
905 cs->szTitle = AnsiString.Buffer;
906
907 AnsiMsg->lParam = (LPARAM)cs;
908 break;
909 }
910 }
911
912 return TRUE;
913 }
914
915
916 static BOOL FASTCALL
917 MsgiUnicodeToAnsiCleanup(LPMSG AnsiMsg, LPMSG UnicodeMsg)
918 {
919 ANSI_STRING AnsiString;
920
921 switch(UnicodeMsg->message)
922 {
923 case WM_GETTEXT:
924 {
925 RtlFreeHeap(GetProcessHeap(), 0, (PVOID) AnsiMsg->lParam);
926 break;
927 }
928 case WM_SETTEXT:
929 {
930 RtlInitAnsiString(&AnsiString, (PSTR) AnsiMsg->lParam);
931 RtlFreeAnsiString(&AnsiString);
932 break;
933 }
934 case WM_CREATE:
935 case WM_NCCREATE:
936 {
937 CREATESTRUCTA* Cs;
938
939 Cs = (CREATESTRUCTA*) AnsiMsg->lParam;
940 RtlInitAnsiString(&AnsiString, Cs->lpszName);
941 RtlFreeAnsiString(&AnsiString);
942 if (HIWORD((ULONG_PTR)Cs->lpszClass) != 0)
943 {
944 RtlInitAnsiString(&AnsiString, Cs->lpszClass);
945 RtlFreeAnsiString(&AnsiString);
946 }
947 RtlFreeHeap(GetProcessHeap(), 0, Cs);
948 break;
949 }
950
951 case LB_ADDSTRING:
952 case LB_ADDSTRING_LOWER:
953 case LB_ADDSTRING_UPPER:
954 case LB_INSERTSTRING:
955 case LB_INSERTSTRING_UPPER:
956 case LB_INSERTSTRING_LOWER:
957 case LB_FINDSTRING:
958 case LB_FINDSTRINGEXACT:
959 case LB_SELECTSTRING:
960 {
961 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
962 if (!(dwStyle & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) &&
963 (dwStyle & LBS_HASSTRINGS))
964 {
965 RtlInitAnsiString(&AnsiString, (PSTR) AnsiMsg->lParam);
966 RtlFreeAnsiString(&AnsiString);
967 }
968 break;
969 }
970
971 case CB_ADDSTRING:
972 case CB_INSERTSTRING:
973 case CB_FINDSTRING:
974 case CB_FINDSTRINGEXACT:
975 case CB_SELECTSTRING:
976 {
977 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
978 if (!(dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) &&
979 (dwStyle & CBS_HASSTRINGS))
980 {
981 RtlInitAnsiString(&AnsiString, (PSTR) AnsiMsg->lParam);
982 RtlFreeAnsiString(&AnsiString);
983 }
984 break;
985 }
986
987 case WM_MDICREATE:
988 {
989 MDICREATESTRUCTA *cs = (MDICREATESTRUCTA *)AnsiMsg->lParam;
990 RtlInitAnsiString(&AnsiString, (PCSTR)cs->szTitle);
991 RtlFreeAnsiString(&AnsiString);
992 if (!IS_ATOM(cs->szClass))
993 {
994 RtlInitAnsiString(&AnsiString, (PCSTR)cs->szClass);
995 RtlFreeAnsiString(&AnsiString);
996 }
997 HeapFree(GetProcessHeap(), 0, cs);
998 break;
999 }
1000
1001 }
1002
1003 return TRUE;
1004 }
1005
1006
1007 static BOOL FASTCALL
1008 MsgiUnicodeToAnsiReply(LPMSG AnsiMsg, LPMSG UnicodeMsg, LRESULT *Result)
1009 {
1010 switch (UnicodeMsg->message)
1011 {
1012 case WM_GETTEXT:
1013 case WM_ASKCBFORMATNAME:
1014 {
1015 LPSTR Buffer = (LPSTR) AnsiMsg->lParam;
1016 LPWSTR UBuffer = (LPWSTR) UnicodeMsg->lParam;
1017 if (0 < AnsiMsg->wParam &&
1018 ! MultiByteToWideChar(CP_ACP, 0, Buffer, -1, UBuffer, UnicodeMsg->wParam))
1019 {
1020 UBuffer[UnicodeMsg->wParam - 1] = L'\0';
1021 }
1022 break;
1023 }
1024 }
1025
1026 MsgiUnicodeToAnsiCleanup(AnsiMsg, UnicodeMsg);
1027
1028 return TRUE;
1029 }
1030
1031 /*
1032 * @implemented
1033 */
1034 LPARAM
1035 WINAPI
1036 GetMessageExtraInfo(VOID)
1037 {
1038 return NtUserxGetMessageExtraInfo();
1039 }
1040
1041
1042 /*
1043 * @implemented
1044 */
1045 DWORD
1046 WINAPI
1047 GetMessagePos(VOID)
1048 {
1049 return NtUserxGetMessagePos();
1050 }
1051
1052
1053 /*
1054 * @implemented
1055 */
1056 LONG WINAPI
1057 GetMessageTime(VOID)
1058 {
1059 return NtUserGetThreadState(THREADSTATE_GETMESSAGETIME);
1060 }
1061
1062
1063 /*
1064 * @unimplemented
1065 */
1066 BOOL
1067 WINAPI
1068 InSendMessage(VOID)
1069 {
1070 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
1071 if ( pcti )
1072 {
1073 if (pcti->CTI_flags & CTI_INSENDMESSAGE)
1074 {
1075 return TRUE;
1076 }
1077 }
1078 return(NtUserGetThreadState(THREADSTATE_INSENDMESSAGE) != ISMEX_NOSEND);
1079 }
1080
1081
1082 /*
1083 * @unimplemented
1084 */
1085 DWORD
1086 WINAPI
1087 InSendMessageEx(
1088 LPVOID lpReserved)
1089 {
1090 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
1091 if (pcti && !(pcti->CTI_flags & CTI_INSENDMESSAGE))
1092 return ISMEX_NOSEND;
1093 else
1094 return NtUserGetThreadState(THREADSTATE_INSENDMESSAGE);
1095 }
1096
1097
1098 /*
1099 * @implemented
1100 */
1101 BOOL
1102 WINAPI
1103 ReplyMessage(LRESULT lResult)
1104 {
1105 return NtUserxReplyMessage(lResult);
1106 }
1107
1108
1109 /*
1110 * @implemented
1111 */
1112 LPARAM
1113 WINAPI
1114 SetMessageExtraInfo(
1115 LPARAM lParam)
1116 {
1117 return NtUserxSetMessageExtraInfo(lParam);
1118 }
1119
1120 LRESULT FASTCALL
1121 IntCallWindowProcW(BOOL IsAnsiProc,
1122 WNDPROC WndProc,
1123 PWND pWnd,
1124 HWND hWnd,
1125 UINT Msg,
1126 WPARAM wParam,
1127 LPARAM lParam)
1128 {
1129 MSG AnsiMsg;
1130 MSG UnicodeMsg;
1131 BOOL Hook = FALSE, MsgOverride = FALSE, Dialog;
1132 LRESULT Result = 0, PreResult = 0;
1133 DWORD Data = 0;
1134
1135 if (WndProc == NULL)
1136 {
1137 WARN("IntCallWindowsProcW() called with WndProc = NULL!\n");
1138 return FALSE;
1139 }
1140
1141 if (pWnd)
1142 Dialog = (pWnd->fnid == FNID_DIALOG);
1143 else
1144 Dialog = FALSE;
1145
1146 Hook = BeginIfHookedUserApiHook();
1147 if (Hook)
1148 {
1149 if (!Dialog)
1150 MsgOverride = IsMsgOverride( Msg, &guah.WndProcArray);
1151 else
1152 MsgOverride = IsMsgOverride( Msg, &guah.DlgProcArray);
1153 }
1154
1155 if (IsAnsiProc)
1156 {
1157 UnicodeMsg.hwnd = hWnd;
1158 UnicodeMsg.message = Msg;
1159 UnicodeMsg.wParam = wParam;
1160 UnicodeMsg.lParam = lParam;
1161 if (! MsgiUnicodeToAnsiMessage(hWnd, &AnsiMsg, &UnicodeMsg))
1162 {
1163 goto Exit;
1164 }
1165
1166 if (Hook && MsgOverride)
1167 {
1168 _SEH2_TRY
1169 {
1170 if (!Dialog)
1171 PreResult = guah.PreWndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1172 else
1173 PreResult = guah.PreDefDlgProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1174 }
1175 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1176 {
1177 }
1178 _SEH2_END;
1179 }
1180
1181 if (PreResult) goto Exit;
1182
1183 _SEH2_TRY // wine does this.
1184 {
1185 Result = WndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam);
1186 }
1187 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1188 {
1189 }
1190 _SEH2_END;
1191
1192 if (Hook && MsgOverride)
1193 {
1194 _SEH2_TRY
1195 {
1196 if (!Dialog)
1197 guah.PostWndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1198 else
1199 guah.PostDefDlgProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1200 }
1201 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1202 {
1203 }
1204 _SEH2_END;
1205 }
1206
1207 if (! MsgiUnicodeToAnsiReply(&AnsiMsg, &UnicodeMsg, &Result))
1208 {
1209 goto Exit;
1210 }
1211 }
1212 else
1213 {
1214 if (Hook && MsgOverride)
1215 {
1216 _SEH2_TRY
1217 {
1218 if (!Dialog)
1219 PreResult = guah.PreWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1220 else
1221 PreResult = guah.PreDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1222 }
1223 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1224 {
1225 }
1226 _SEH2_END;
1227 }
1228
1229 if (PreResult) goto Exit;
1230
1231 _SEH2_TRY
1232 {
1233 Result = WndProc(hWnd, Msg, wParam, lParam);
1234 }
1235 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1236 {
1237 }
1238 _SEH2_END;
1239
1240 if (Hook && MsgOverride)
1241 {
1242 _SEH2_TRY
1243 {
1244 if (!Dialog)
1245 guah.PostWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1246 else
1247 guah.PostDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1248 }
1249 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1250 {
1251 }
1252 _SEH2_END;
1253 }
1254 }
1255
1256 Exit:
1257 if (Hook) EndUserApiHook();
1258 return Result;
1259 }
1260
1261 static LRESULT FASTCALL
1262 IntCallWindowProcA(BOOL IsAnsiProc,
1263 WNDPROC WndProc,
1264 PWND pWnd,
1265 HWND hWnd,
1266 UINT Msg,
1267 WPARAM wParam,
1268 LPARAM lParam)
1269 {
1270 MSG AnsiMsg;
1271 MSG UnicodeMsg;
1272 BOOL Hook = FALSE, MsgOverride = FALSE, Dialog;
1273 LRESULT Result = 0, PreResult = 0;
1274 DWORD Data = 0;
1275
1276 if (WndProc == NULL)
1277 {
1278 WARN("IntCallWindowsProcA() called with WndProc = NULL!\n");
1279 return FALSE;
1280 }
1281
1282 if (pWnd)
1283 Dialog = (pWnd->fnid == FNID_DIALOG);
1284 else
1285 Dialog = FALSE;
1286
1287 Hook = BeginIfHookedUserApiHook();
1288 if (Hook)
1289 {
1290 if (!Dialog)
1291 MsgOverride = IsMsgOverride( Msg, &guah.WndProcArray);
1292 else
1293 MsgOverride = IsMsgOverride( Msg, &guah.DlgProcArray);
1294 }
1295
1296 if (IsAnsiProc)
1297 {
1298 if (Hook && MsgOverride)
1299 {
1300 _SEH2_TRY
1301 {
1302 if (!Dialog)
1303 PreResult = guah.PreWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1304 else
1305 PreResult = guah.PreDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1306 }
1307 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1308 {
1309 }
1310 _SEH2_END;
1311 }
1312
1313 if (PreResult) goto Exit;
1314
1315 _SEH2_TRY
1316 {
1317 Result = WndProc(hWnd, Msg, wParam, lParam);
1318 }
1319 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1320 {
1321 }
1322 _SEH2_END;
1323
1324 if (Hook && MsgOverride)
1325 {
1326 _SEH2_TRY
1327 {
1328 if (!Dialog)
1329 guah.PostWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1330 else
1331 guah.PostDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1332 }
1333 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1334 {
1335 }
1336 _SEH2_END;
1337 }
1338 }
1339 else
1340 {
1341 AnsiMsg.hwnd = hWnd;
1342 AnsiMsg.message = Msg;
1343 AnsiMsg.wParam = wParam;
1344 AnsiMsg.lParam = lParam;
1345 if (! MsgiAnsiToUnicodeMessage(hWnd, &UnicodeMsg, &AnsiMsg))
1346 {
1347 goto Exit;
1348 }
1349
1350 if (Hook && MsgOverride)
1351 {
1352 _SEH2_TRY
1353 {
1354 if (!Dialog)
1355 PreResult = guah.PreWndProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1356 else
1357 PreResult = guah.PreDefDlgProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1358 }
1359 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1360 {
1361 }
1362 _SEH2_END;
1363 }
1364
1365 if (PreResult) goto Exit;
1366
1367 _SEH2_TRY
1368 {
1369 Result = WndProc(UnicodeMsg.hwnd, UnicodeMsg.message,
1370 UnicodeMsg.wParam, UnicodeMsg.lParam);
1371 }
1372 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1373 {
1374 }
1375 _SEH2_END;
1376
1377 if (Hook && MsgOverride)
1378 {
1379 _SEH2_TRY
1380 {
1381 if (!Dialog)
1382 guah.PostWndProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1383 else
1384 guah.PostDefDlgProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1385 }
1386 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1387 {
1388 }
1389 _SEH2_END;
1390 }
1391
1392 if (! MsgiAnsiToUnicodeReply(&UnicodeMsg, &AnsiMsg, &Result))
1393 {
1394 goto Exit;
1395 }
1396 }
1397
1398 Exit:
1399 if (Hook) EndUserApiHook();
1400 return Result;
1401 }
1402
1403
1404 static LRESULT WINAPI
1405 IntCallMessageProc(IN PWND Wnd, IN HWND hWnd, IN UINT Msg, IN WPARAM wParam, IN LPARAM lParam, IN BOOL Ansi)
1406 {
1407 WNDPROC WndProc;
1408 BOOL IsAnsi;
1409 PCLS Class;
1410
1411 Class = DesktopPtrToUser(Wnd->pcls);
1412 WndProc = NULL;
1413
1414 if ( Wnd->head.pti != GetW32ThreadInfo())
1415 { // Must be inside the same thread!
1416 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
1417 return 0;
1418 }
1419 /*
1420 This is the message exchange for user32. If there's a need to monitor messages,
1421 do it here!
1422 */
1423 TRACE("HWND 0x%x, MSG %d, WPARAM 0x%x, LPARAM 0x%x, Ansi &d\n",hWnd,Msg,wParam,lParam,Ansi);
1424 // if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON )
1425 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_FIRST )
1426 {
1427 if (Ansi)
1428 {
1429 if (GETPFNCLIENTW(Class->fnid) == Wnd->lpfnWndProc)
1430 WndProc = GETPFNCLIENTA(Class->fnid);
1431 }
1432 else
1433 {
1434 if (GETPFNCLIENTA(Class->fnid) == Wnd->lpfnWndProc)
1435 WndProc = GETPFNCLIENTW(Class->fnid);
1436 }
1437
1438 IsAnsi = Ansi;
1439
1440 if (!WndProc)
1441 {
1442 IsAnsi = !Wnd->Unicode;
1443 WndProc = Wnd->lpfnWndProc;
1444 }
1445 }
1446 else
1447 {
1448 IsAnsi = !Wnd->Unicode;
1449 WndProc = Wnd->lpfnWndProc;
1450 }
1451 /*
1452 Message caller can be Ansi/Unicode and the receiver can be Unicode/Ansi or
1453 the same.
1454 */
1455 if (!Ansi)
1456 return IntCallWindowProcW(IsAnsi, WndProc, Wnd, hWnd, Msg, wParam, lParam);
1457 else
1458 return IntCallWindowProcA(IsAnsi, WndProc, Wnd, hWnd, Msg, wParam, lParam);
1459 }
1460
1461
1462 /*
1463 * @implemented
1464 */
1465 LRESULT WINAPI
1466 CallWindowProcA(WNDPROC lpPrevWndFunc,
1467 HWND hWnd,
1468 UINT Msg,
1469 WPARAM wParam,
1470 LPARAM lParam)
1471 {
1472 PWND pWnd;
1473 PCALLPROCDATA CallProc;
1474
1475 if (lpPrevWndFunc == NULL)
1476 {
1477 WARN("CallWindowProcA: lpPrevWndFunc == NULL!\n");
1478 return 0;
1479 }
1480
1481 pWnd = ValidateHwnd(hWnd);
1482
1483 if (!IsCallProcHandle(lpPrevWndFunc))
1484 return IntCallWindowProcA(TRUE, lpPrevWndFunc, pWnd, hWnd, Msg, wParam, lParam);
1485 else
1486 {
1487 CallProc = ValidateCallProc((HANDLE)lpPrevWndFunc);
1488 if (CallProc != NULL)
1489 {
1490 return IntCallWindowProcA(!(CallProc->wType & UserGetCPDA2U),
1491 CallProc->pfnClientPrevious,
1492 pWnd,
1493 hWnd,
1494 Msg,
1495 wParam,
1496 lParam);
1497 }
1498 else
1499 {
1500 WARN("CallWindowProcA: can not dereference WndProcHandle\n");
1501 return 0;
1502 }
1503 }
1504 }
1505
1506
1507 /*
1508 * @implemented
1509 */
1510 LRESULT WINAPI
1511 CallWindowProcW(WNDPROC lpPrevWndFunc,
1512 HWND hWnd,
1513 UINT Msg,
1514 WPARAM wParam,
1515 LPARAM lParam)
1516 {
1517 PWND pWnd;
1518 PCALLPROCDATA CallProc;
1519
1520 /* FIXME - can the first parameter be NULL? */
1521 if (lpPrevWndFunc == NULL)
1522 {
1523 WARN("CallWindowProcA: lpPrevWndFunc == NULL!\n");
1524 return 0;
1525 }
1526
1527 pWnd = ValidateHwnd(hWnd);
1528
1529 if (!IsCallProcHandle(lpPrevWndFunc))
1530 return IntCallWindowProcW(FALSE, lpPrevWndFunc, pWnd, hWnd, Msg, wParam, lParam);
1531 else
1532 {
1533 CallProc = ValidateCallProc((HANDLE)lpPrevWndFunc);
1534 if (CallProc != NULL)
1535 {
1536 return IntCallWindowProcW(!(CallProc->wType & UserGetCPDA2U),
1537 CallProc->pfnClientPrevious,
1538 pWnd,
1539 hWnd,
1540 Msg,
1541 wParam,
1542 lParam);
1543 }
1544 else
1545 {
1546 WARN("CallWindowProcW: can not dereference WndProcHandle\n");
1547 return 0;
1548 }
1549 }
1550 }
1551
1552
1553 /*
1554 * @implemented
1555 */
1556 LRESULT WINAPI
1557 DispatchMessageA(CONST MSG *lpmsg)
1558 {
1559 LRESULT Ret = 0;
1560 MSG UnicodeMsg;
1561 PWND Wnd;
1562
1563 if ( lpmsg->message & ~WM_MAXIMUM )
1564 {
1565 SetLastError( ERROR_INVALID_PARAMETER );
1566 return 0;
1567 }
1568
1569 if (lpmsg->hwnd != NULL)
1570 {
1571 Wnd = ValidateHwnd(lpmsg->hwnd);
1572 if (!Wnd) return 0;
1573 }
1574 else
1575 Wnd = NULL;
1576
1577 if (is_pointer_message(lpmsg->message))
1578 {
1579 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
1580 return 0;
1581 }
1582
1583 if ((lpmsg->message == WM_TIMER || lpmsg->message == WM_SYSTIMER) && lpmsg->lParam != 0)
1584 {
1585 WNDPROC WndProc = (WNDPROC)lpmsg->lParam;
1586
1587 if ( lpmsg->message == WM_SYSTIMER )
1588 return NtUserDispatchMessage( (PMSG)lpmsg );
1589
1590 if (!NtUserValidateTimerCallback(lpmsg->hwnd, lpmsg->wParam, lpmsg->lParam)) return 0;
1591
1592 _SEH2_TRY // wine does this. Hint: Prevents call to another thread....
1593 {
1594 Ret = WndProc(lpmsg->hwnd,
1595 lpmsg->message,
1596 lpmsg->wParam,
1597 GetTickCount());
1598 }
1599 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1600 {
1601 }
1602 _SEH2_END;
1603 }
1604 else if (Wnd != NULL)
1605 {
1606 if ( (lpmsg->message != WM_PAINT) && !(Wnd->state & WNDS_SERVERSIDEWINDOWPROC) )
1607 {
1608 Ret = IntCallMessageProc(Wnd,
1609 lpmsg->hwnd,
1610 lpmsg->message,
1611 lpmsg->wParam,
1612 lpmsg->lParam,
1613 TRUE);
1614 }
1615 else
1616 {
1617 if (!MsgiAnsiToUnicodeMessage(lpmsg->hwnd, &UnicodeMsg, (LPMSG)lpmsg))
1618 {
1619 return FALSE;
1620 }
1621
1622 Ret = NtUserDispatchMessage(&UnicodeMsg);
1623
1624 if (!MsgiAnsiToUnicodeReply(&UnicodeMsg, (LPMSG)lpmsg, &Ret))
1625 {
1626 return FALSE;
1627 }
1628 }
1629 }
1630 return Ret;
1631 }
1632
1633
1634 /*
1635 * @implemented
1636 */
1637 LRESULT WINAPI
1638 DispatchMessageW(CONST MSG *lpmsg)
1639 {
1640 LRESULT Ret = 0;
1641 PWND Wnd;
1642
1643 if ( lpmsg->message & ~WM_MAXIMUM )
1644 {
1645 SetLastError( ERROR_INVALID_PARAMETER );
1646 return 0;
1647 }
1648
1649 if (lpmsg->hwnd != NULL)
1650 {
1651 Wnd = ValidateHwnd(lpmsg->hwnd);
1652 if (!Wnd) return 0;
1653 }
1654 else
1655 Wnd = NULL;
1656
1657 if (is_pointer_message(lpmsg->message))
1658 {
1659 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
1660 return 0;
1661 }
1662
1663 if ((lpmsg->message == WM_TIMER || lpmsg->message == WM_SYSTIMER) && lpmsg->lParam != 0)
1664 {
1665 WNDPROC WndProc = (WNDPROC)lpmsg->lParam;
1666
1667 if ( lpmsg->message == WM_SYSTIMER )
1668 return NtUserDispatchMessage( (PMSG) lpmsg );
1669
1670 if (!NtUserValidateTimerCallback(lpmsg->hwnd, lpmsg->wParam, lpmsg->lParam)) return 0;
1671
1672 _SEH2_TRY
1673 {
1674 Ret = WndProc(lpmsg->hwnd,
1675 lpmsg->message,
1676 lpmsg->wParam,
1677 GetTickCount());
1678 }
1679 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1680 {
1681 }
1682 _SEH2_END;
1683 }
1684 else if (Wnd != NULL)
1685 {
1686 if ( (lpmsg->message != WM_PAINT) && !(Wnd->state & WNDS_SERVERSIDEWINDOWPROC) )
1687 {
1688 Ret = IntCallMessageProc(Wnd,
1689 lpmsg->hwnd,
1690 lpmsg->message,
1691 lpmsg->wParam,
1692 lpmsg->lParam,
1693 FALSE);
1694 }
1695 else
1696 Ret = NtUserDispatchMessage( (PMSG) lpmsg );
1697 }
1698
1699 return Ret;
1700 }
1701
1702
1703 /*
1704 * @implemented
1705 */
1706 BOOL WINAPI
1707 GetMessageA(LPMSG lpMsg,
1708 HWND hWnd,
1709 UINT wMsgFilterMin,
1710 UINT wMsgFilterMax)
1711 {
1712 BOOL Res;
1713
1714 if ( (wMsgFilterMin|wMsgFilterMax) & ~WM_MAXIMUM )
1715 {
1716 SetLastError( ERROR_INVALID_PARAMETER );
1717 return FALSE;
1718 }
1719
1720 Res = NtUserGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
1721 if (-1 == (int) Res)
1722 {
1723 return Res;
1724 }
1725
1726 return Res;
1727 }
1728
1729 /*
1730 * @implemented
1731 */
1732 BOOL WINAPI
1733 GetMessageW(LPMSG lpMsg,
1734 HWND hWnd,
1735 UINT wMsgFilterMin,
1736 UINT wMsgFilterMax)
1737 {
1738 BOOL Res;
1739
1740 if ( (wMsgFilterMin|wMsgFilterMax) & ~WM_MAXIMUM )
1741 {
1742 SetLastError( ERROR_INVALID_PARAMETER );
1743 return FALSE;
1744 }
1745
1746 Res = NtUserGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
1747 if (-1 == (int) Res)
1748 {
1749 return Res;
1750 }
1751
1752 return Res;
1753 }
1754
1755 BOOL WINAPI
1756 PeekMessageWorker( PMSG pMsg,
1757 HWND hWnd,
1758 UINT wMsgFilterMin,
1759 UINT wMsgFilterMax,
1760 UINT wRemoveMsg)
1761 {
1762 PCLIENTINFO pci;
1763 PCLIENTTHREADINFO pcti;
1764 pci = GetWin32ClientInfo();
1765 pcti = pci->pClientThreadInfo;
1766
1767 if (!hWnd && pci && pcti)
1768 {
1769 pci->cSpins++;
1770
1771 if ((pci->cSpins >= 100) && (pci->dwTIFlags & TIF_SPINNING))
1772 { // Yield after 100 spin cycles and ready to swap vinyl.
1773 if (!(pci->dwTIFlags & TIF_WAITFORINPUTIDLE))
1774 { // Not waiting for idle event.
1775 if (!pcti->fsChangeBits && !pcti->fsWakeBits)
1776 { // No messages are available.
1777 if ((GetTickCount() - pcti->tickLastMsgChecked) > 1000)
1778 { // Up the msg read count if over 1 sec.
1779 NtUserGetThreadState(THREADSTATE_UPTIMELASTREAD);
1780 }
1781 pci->cSpins = 0;
1782 ZwYieldExecution();
1783 FIXME("seeSpins!\n");
1784 return FALSE;
1785 }
1786 }
1787 }
1788 }
1789 return NtUserPeekMessage(pMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
1790 }
1791
1792 /*
1793 * @implemented
1794 */
1795 BOOL WINAPI
1796 PeekMessageA(LPMSG lpMsg,
1797 HWND hWnd,
1798 UINT wMsgFilterMin,
1799 UINT wMsgFilterMax,
1800 UINT wRemoveMsg)
1801 {
1802 BOOL Res;
1803
1804 Res = PeekMessageWorker(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
1805 if (-1 == (int) Res || !Res)
1806 {
1807 return FALSE;
1808 }
1809
1810 return Res;
1811 }
1812
1813
1814 /*
1815 * @implemented
1816 */
1817 BOOL
1818 WINAPI
1819 PeekMessageW(
1820 LPMSG lpMsg,
1821 HWND hWnd,
1822 UINT wMsgFilterMin,
1823 UINT wMsgFilterMax,
1824 UINT wRemoveMsg)
1825 {
1826 BOOL Res;
1827
1828 Res = PeekMessageWorker(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
1829 if (-1 == (int) Res || !Res)
1830 {
1831 return FALSE;
1832 }
1833
1834 return Res;
1835 }
1836
1837 /*
1838 * @implemented
1839 */
1840 BOOL
1841 WINAPI
1842 PostMessageA(
1843 HWND hWnd,
1844 UINT Msg,
1845 WPARAM wParam,
1846 LPARAM lParam)
1847 {
1848 LRESULT Ret;
1849
1850 /* Check for combo box or a list box to send names. */
1851 if (Msg == CB_DIR || Msg == LB_DIR)
1852 {
1853 /*
1854 Set DDL_POSTMSGS, so use the PostMessage function to send messages to the
1855 combo/list box. Forces a call like DlgDirListComboBox.
1856 */
1857 //wParam |= DDL_POSTMSGS;
1858 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
1859 }
1860
1861 /* No drop files or current Process, just post message. */
1862 if ( (Msg != WM_DROPFILES) ||
1863 ( NtUserQueryWindow( hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID) ==
1864 PtrToUint(NtCurrentTeb()->ClientId.UniqueProcess) ) )
1865 {
1866 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
1867 }
1868
1869 /* We have drop files and this is not the same process for this window. */
1870
1871 /* Just incase, check wParam for Global memory handle and send size. */
1872 Ret = SendMessageA( hWnd,
1873 WM_COPYGLOBALDATA,
1874 (WPARAM)GlobalSize((HGLOBAL)wParam), // Zero if not a handle.
1875 (LPARAM)wParam); // Send wParam as lParam.
1876
1877 if ( Ret ) return NtUserPostMessage(hWnd, Msg, (WPARAM)Ret, lParam);
1878
1879 return FALSE;
1880 }
1881
1882 /*
1883 * @implemented
1884 */
1885 BOOL
1886 WINAPI
1887 PostMessageW(
1888 HWND hWnd,
1889 UINT Msg,
1890 WPARAM wParam,
1891 LPARAM lParam)
1892 {
1893 LRESULT Ret;
1894
1895 /* Check for combo box or a list box to send names. */
1896 if (Msg == CB_DIR || Msg == LB_DIR)
1897 {
1898 /*
1899 Set DDL_POSTMSGS, so use the PostMessage function to send messages to the
1900 combo/list box. Forces a call like DlgDirListComboBox.
1901 */
1902 //wParam |= DDL_POSTMSGS;
1903 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
1904 }
1905
1906 /* No drop files or current Process, just post message. */
1907 if ( (Msg != WM_DROPFILES) ||
1908 ( NtUserQueryWindow( hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID) ==
1909 PtrToUint(NtCurrentTeb()->ClientId.UniqueProcess) ) )
1910 {
1911 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
1912 }
1913
1914 /* We have drop files and this is not the same process for this window. */
1915
1916 /* Just incase, check wParam for Global memory handle and send size. */
1917 Ret = SendMessageW( hWnd,
1918 WM_COPYGLOBALDATA,
1919 (WPARAM)GlobalSize((HGLOBAL)wParam), // Zero if not a handle.
1920 (LPARAM)wParam); // Send wParam as lParam.
1921
1922 if ( Ret ) return NtUserPostMessage(hWnd, Msg, (WPARAM)Ret, lParam);
1923
1924 return FALSE;
1925 }
1926
1927 /*
1928 * @implemented
1929 */
1930 VOID
1931 WINAPI
1932 PostQuitMessage(
1933 int nExitCode)
1934 {
1935 NtUserxPostQuitMessage(nExitCode);
1936 }
1937
1938
1939 /*
1940 * @implemented
1941 */
1942 BOOL
1943 WINAPI
1944 PostThreadMessageA(
1945 DWORD idThread,
1946 UINT Msg,
1947 WPARAM wParam,
1948 LPARAM lParam)
1949 {
1950 return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
1951 }
1952
1953
1954 /*
1955 * @implemented
1956 */
1957 BOOL
1958 WINAPI
1959 PostThreadMessageW(
1960 DWORD idThread,
1961 UINT Msg,
1962 WPARAM wParam,
1963 LPARAM lParam)
1964 {
1965 return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
1966 }
1967
1968
1969 /*
1970 * @implemented
1971 */
1972 LRESULT WINAPI
1973 SendMessageW(HWND Wnd,
1974 UINT Msg,
1975 WPARAM wParam,
1976 LPARAM lParam)
1977 {
1978 MSG UMMsg, KMMsg;
1979 LRESULT Result;
1980 PWND Window;
1981 PTHREADINFO ti = GetW32ThreadInfo();
1982
1983 if ( Msg & ~WM_MAXIMUM )
1984 {
1985 SetLastError( ERROR_INVALID_PARAMETER );
1986 return 0;
1987 }
1988
1989 if (Wnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
1990 {
1991 Window = ValidateHwnd(Wnd);
1992
1993 if ( Window != NULL &&
1994 Window->head.pti == ti &&
1995 // !IsThreadHooked(GetWin32ClientInfo()) && // Enable to test message system bug.
1996 !ISITHOOKED(WH_CALLWNDPROC) &&
1997 !ISITHOOKED(WH_CALLWNDPROCRET) &&
1998 !(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
1999 {
2000 /* NOTE: We can directly send messages to the window procedure
2001 if *all* the following conditions are met:
2002
2003 * Window belongs to calling thread
2004 * The calling thread is not being hooked for CallWndProc
2005 * Not calling a server side proc:
2006 Desktop, Switch, ScrollBar, Menu, IconTitle, or hWndMessage
2007 */
2008
2009 return IntCallMessageProc(Window, Wnd, Msg, wParam, lParam, FALSE);
2010 }
2011 }
2012
2013 UMMsg.hwnd = Wnd;
2014 UMMsg.message = Msg;
2015 UMMsg.wParam = wParam;
2016 UMMsg.lParam = lParam;
2017
2018 if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, FALSE))
2019 {
2020 return FALSE;
2021 }
2022
2023 Result = NtUserMessageCall( Wnd,
2024 KMMsg.message,
2025 KMMsg.wParam,
2026 KMMsg.lParam,
2027 (ULONG_PTR)&Result,
2028 FNID_SENDMESSAGE,
2029 FALSE);
2030
2031 MsgiUMToKMCleanup(&UMMsg, &KMMsg);
2032
2033 return Result;
2034 }
2035
2036
2037 /*
2038 * @implemented
2039 */
2040 LRESULT WINAPI
2041 SendMessageA(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
2042 {
2043 MSG AnsiMsg, UcMsg, KMMsg;
2044 LRESULT Result;
2045 PWND Window;
2046 PTHREADINFO ti = GetW32ThreadInfo();
2047
2048 if ( Msg & ~WM_MAXIMUM )
2049 {
2050 SetLastError( ERROR_INVALID_PARAMETER );
2051 return 0;
2052 }
2053
2054 if (Wnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
2055 {
2056 Window = ValidateHwnd(Wnd);
2057
2058 if ( Window != NULL &&
2059 Window->head.pti == ti &&
2060 // !IsThreadHooked(GetWin32ClientInfo()) && // Enable to test message system bug.
2061 !ISITHOOKED(WH_CALLWNDPROC) &&
2062 !ISITHOOKED(WH_CALLWNDPROCRET) &&
2063 !(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
2064 {
2065 /* NOTE: We can directly send messages to the window procedure
2066 if *all* the following conditions are met:
2067
2068 * Window belongs to calling thread
2069 * The calling thread is not being hooked for CallWndProc
2070 * Not calling a server side proc:
2071 Desktop, Switch, ScrollBar, Menu, IconTitle, or hWndMessage
2072 */
2073
2074 return IntCallMessageProc(Window, Wnd, Msg, wParam, lParam, TRUE);
2075 }
2076 }
2077
2078 AnsiMsg.hwnd = Wnd;
2079 AnsiMsg.message = Msg;
2080 AnsiMsg.wParam = wParam;
2081 AnsiMsg.lParam = lParam;
2082
2083 if (!MsgiAnsiToUnicodeMessage(Wnd, &UcMsg, &AnsiMsg))
2084 {
2085 return FALSE;
2086 }
2087
2088 if (!MsgiUMToKMMessage(&UcMsg, &KMMsg, FALSE))
2089 {
2090 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
2091 return FALSE;
2092 }
2093
2094 Result = NtUserMessageCall( Wnd,
2095 KMMsg.message,
2096 KMMsg.wParam,
2097 KMMsg.lParam,
2098 (ULONG_PTR)&Result,
2099 FNID_SENDMESSAGE,
2100 TRUE);
2101
2102 MsgiUMToKMCleanup(&UcMsg, &KMMsg);
2103 MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result);
2104
2105 return Result;
2106 }
2107
2108 /*
2109 * @implemented
2110 */
2111 BOOL
2112 WINAPI
2113 SendMessageCallbackA(
2114 HWND hWnd,
2115 UINT Msg,
2116 WPARAM wParam,
2117 LPARAM lParam,
2118 SENDASYNCPROC lpCallBack,
2119 ULONG_PTR dwData)
2120 {
2121 BOOL Result;
2122 MSG AnsiMsg, UcMsg;
2123 CALL_BACK_INFO CallBackInfo;
2124
2125 if (is_pointer_message(Msg))
2126 {
2127 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
2128 return FALSE;
2129 }
2130
2131 CallBackInfo.CallBack = lpCallBack;
2132 CallBackInfo.Context = dwData;
2133
2134 AnsiMsg.hwnd = hWnd;
2135 AnsiMsg.message = Msg;
2136 AnsiMsg.wParam = wParam;
2137 AnsiMsg.lParam = lParam;
2138
2139 if (!MsgiAnsiToUnicodeMessage(hWnd, &UcMsg, &AnsiMsg))
2140 {
2141 return FALSE;
2142 }
2143
2144 Result = NtUserMessageCall( hWnd,
2145 UcMsg.message,
2146 UcMsg.wParam,
2147 UcMsg.lParam,
2148 (ULONG_PTR)&CallBackInfo,
2149 FNID_SENDMESSAGECALLBACK,
2150 TRUE);
2151
2152 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
2153
2154 return Result;
2155 }
2156
2157 /*
2158 * @implemented
2159 */
2160 BOOL
2161 WINAPI
2162 SendMessageCallbackW(
2163 HWND hWnd,
2164 UINT Msg,
2165 WPARAM wParam,
2166 LPARAM lParam,
2167 SENDASYNCPROC lpCallBack,
2168 ULONG_PTR dwData)
2169 {
2170 CALL_BACK_INFO CallBackInfo;
2171
2172 if (is_pointer_message(Msg))
2173 {
2174 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
2175 return FALSE;
2176 }
2177
2178 CallBackInfo.CallBack = lpCallBack;
2179 CallBackInfo.Context = dwData;
2180
2181 return NtUserMessageCall(hWnd,
2182 Msg,
2183 wParam,
2184 lParam,
2185 (ULONG_PTR)&CallBackInfo,
2186 FNID_SENDMESSAGECALLBACK,
2187 FALSE);
2188 }
2189
2190 /*
2191 * @implemented
2192 */
2193 LRESULT
2194 WINAPI
2195 SendMessageTimeoutA(
2196 HWND hWnd,
2197 UINT Msg,
2198 WPARAM wParam,
2199 LPARAM lParam,
2200 UINT fuFlags,
2201 UINT uTimeout,
2202 PDWORD_PTR lpdwResult)
2203 {
2204 MSG AnsiMsg, UcMsg;
2205 LRESULT Result;
2206 DOSENDMESSAGE dsm;
2207 PWND Window;
2208 PTHREADINFO ti = GetW32ThreadInfo();
2209
2210 if ( Msg & ~WM_MAXIMUM || fuFlags & ~(SMTO_NOTIMEOUTIFNOTHUNG|SMTO_ABORTIFHUNG|SMTO_BLOCK))
2211 {
2212 SetLastError( ERROR_INVALID_PARAMETER );
2213 return 0;
2214 }
2215
2216 if (lpdwResult) *lpdwResult = 0;
2217
2218 if (hWnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
2219 {
2220 Window = ValidateHwnd(hWnd);
2221
2222 if ( Window != NULL &&
2223 Window->head.pti == ti &&
2224 !ISITHOOKED(WH_CALLWNDPROC) &&
2225 !ISITHOOKED(WH_CALLWNDPROCRET) &&
2226 !(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
2227 {
2228 Result = IntCallMessageProc(Window, hWnd, Msg, wParam, lParam, TRUE);
2229 if (lpdwResult) *lpdwResult = Result;
2230 return TRUE;
2231 }
2232 }
2233 SPY_EnterMessage(SPY_SENDMESSAGE, hWnd, Msg, wParam, lParam);
2234
2235 dsm.uFlags = fuFlags;
2236 dsm.uTimeout = uTimeout;
2237
2238 AnsiMsg.hwnd = hWnd;
2239 AnsiMsg.message = Msg;
2240 AnsiMsg.wParam = wParam;
2241 AnsiMsg.lParam = lParam;
2242
2243 if (! MsgiAnsiToUnicodeMessage(hWnd, &UcMsg, &AnsiMsg))
2244 {
2245 return FALSE;
2246 }
2247
2248 Result = NtUserMessageCall( hWnd,
2249 UcMsg.message,
2250 UcMsg.wParam,
2251 UcMsg.lParam,
2252 (ULONG_PTR)&dsm,
2253 FNID_SENDMESSAGETIMEOUT,
2254 TRUE);
2255
2256 MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result);
2257
2258 if (lpdwResult) *lpdwResult = dsm.Result;
2259
2260 SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
2261
2262 return Result;
2263 }
2264
2265
2266 /*
2267 * @implemented
2268 */
2269 LRESULT
2270 WINAPI
2271 SendMessageTimeoutW(
2272 HWND hWnd,
2273 UINT Msg,
2274 WPARAM wParam,
2275 LPARAM lParam,
2276 UINT fuFlags,
2277 UINT uTimeout,
2278 PDWORD_PTR lpdwResult)
2279 {
2280 LRESULT Result;
2281 DOSENDMESSAGE dsm;
2282 PWND Window;
2283 PTHREADINFO ti = GetW32ThreadInfo();
2284
2285 if ( Msg & ~WM_MAXIMUM || fuFlags & ~(SMTO_NOTIMEOUTIFNOTHUNG|SMTO_ABORTIFHUNG|SMTO_BLOCK))
2286 {
2287 SetLastError( ERROR_INVALID_PARAMETER );
2288 return 0;
2289 }
2290
2291 if (lpdwResult) *lpdwResult = 0;
2292
2293 if (hWnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
2294 {
2295 Window = ValidateHwnd(hWnd);
2296
2297 if ( Window != NULL &&
2298 Window->head.pti == ti &&
2299 !ISITHOOKED(WH_CALLWNDPROC) &&
2300 !ISITHOOKED(WH_CALLWNDPROCRET) &&
2301 !(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
2302 {
2303 Result = IntCallMessageProc(Window, hWnd, Msg, wParam, lParam, FALSE);
2304 if (lpdwResult) *lpdwResult = Result;
2305 return TRUE;
2306 }
2307 }
2308 SPY_EnterMessage(SPY_SENDMESSAGE, hWnd, Msg, wParam, lParam);
2309
2310 dsm.uFlags = fuFlags;
2311 dsm.uTimeout = uTimeout;
2312
2313 Result = NtUserMessageCall( hWnd,
2314 Msg,
2315 wParam,
2316 lParam,
2317 (ULONG_PTR)&dsm,
2318 FNID_SENDMESSAGETIMEOUT,
2319 FALSE);
2320
2321 if (lpdwResult) *lpdwResult = dsm.Result;
2322
2323 SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
2324
2325 return Result;
2326 }
2327
2328 /*
2329 * @implemented
2330 */
2331 BOOL
2332 WINAPI
2333 SendNotifyMessageA(
2334 HWND hWnd,
2335 UINT Msg,
2336 WPARAM wParam,
2337 LPARAM lParam)
2338 {
2339 BOOL Ret;
2340 MSG AnsiMsg, UcMsg;
2341
2342 if (is_pointer_message(Msg))
2343 {
2344 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
2345 return FALSE;
2346 }
2347
2348 AnsiMsg.hwnd = hWnd;
2349 AnsiMsg.message = Msg;
2350 AnsiMsg.wParam = wParam;
2351 AnsiMsg.lParam = lParam;
2352 if (! MsgiAnsiToUnicodeMessage(hWnd, &UcMsg, &AnsiMsg))
2353 {
2354 return FALSE;
2355 }
2356 Ret = SendNotifyMessageW(hWnd, UcMsg.message, UcMsg.wParam, UcMsg.lParam);
2357
2358 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
2359
2360 return Ret;
2361 }
2362
2363 /*
2364 * @implemented
2365 */
2366 BOOL
2367 WINAPI
2368 SendNotifyMessageW(
2369 HWND hWnd,
2370 UINT Msg,
2371 WPARAM wParam,
2372 LPARAM lParam)
2373 {
2374 MSG UMMsg, KMMsg;
2375 LRESULT Result;
2376
2377 if (is_pointer_message(Msg))
2378 {
2379 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
2380 return FALSE;
2381 }
2382
2383 UMMsg.hwnd = hWnd;
2384 UMMsg.message = Msg;
2385 UMMsg.wParam = wParam;
2386 UMMsg.lParam = lParam;
2387 if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, TRUE))
2388 {
2389 return FALSE;
2390 }
2391 Result = NtUserMessageCall( hWnd,
2392 KMMsg.message,
2393 KMMsg.wParam,
2394 KMMsg.lParam,
2395 0,
2396 FNID_SENDNOTIFYMESSAGE,
2397 FALSE);
2398
2399 MsgiUMToKMCleanup(&UMMsg, &KMMsg);
2400
2401 return Result;
2402 }
2403
2404 /*
2405 * @implemented
2406 */
2407 BOOL WINAPI
2408 TranslateMessageEx(CONST MSG *lpMsg, UINT Flags)
2409 {
2410 switch (lpMsg->message)
2411 {
2412 case WM_KEYDOWN:
2413 case WM_KEYUP:
2414 case WM_SYSKEYDOWN:
2415 case WM_SYSKEYUP:
2416 return(NtUserTranslateMessage((LPMSG)lpMsg, Flags));
2417
2418 default:
2419 if ( lpMsg->message & ~WM_MAXIMUM )
2420 SetLastError(ERROR_INVALID_PARAMETER);
2421 return FALSE;
2422 }
2423 }
2424
2425
2426 /*
2427 * @implemented
2428 */
2429 BOOL WINAPI
2430 TranslateMessage(CONST MSG *lpMsg)
2431 {
2432 BOOL Ret = FALSE;
2433
2434 // Ref: msdn ImmGetVirtualKey:
2435 // http://msdn.microsoft.com/en-us/library/aa912145.aspx
2436 /*
2437 if ( (LOWORD(lpMsg->wParam) != VK_PROCESSKEY) ||
2438 !(Ret = IMM_ImmTranslateMessage( lpMsg->hwnd,
2439 lpMsg->message,
2440 lpMsg->wParam,
2441 lpMsg->lParam)) )*/
2442 {
2443 Ret = TranslateMessageEx((LPMSG)lpMsg, 0);
2444 }
2445 return Ret;
2446 }
2447
2448
2449 /*
2450 * @implemented
2451 */
2452 UINT WINAPI
2453 RegisterWindowMessageA(LPCSTR lpString)
2454 {
2455 UNICODE_STRING String;
2456 BOOLEAN Result;
2457 UINT Atom;
2458
2459 Result = RtlCreateUnicodeStringFromAsciiz(&String, (PCSZ)lpString);
2460 if (!Result)
2461 {
2462 return(0);
2463 }
2464 Atom = NtUserRegisterWindowMessage(&String);
2465 RtlFreeUnicodeString(&String);
2466 return(Atom);
2467 }
2468
2469
2470 /*
2471 * @implemented
2472 */
2473 UINT WINAPI
2474 RegisterWindowMessageW(LPCWSTR lpString)
2475 {
2476 UNICODE_STRING String;
2477
2478 RtlInitUnicodeString(&String, lpString);
2479 return(NtUserRegisterWindowMessage(&String));
2480 }
2481
2482 /*
2483 * @implemented
2484 */
2485 HWND WINAPI
2486 GetCapture(VOID)
2487 {
2488 return (HWND)NtUserGetThreadState(THREADSTATE_CAPTUREWINDOW);
2489 }
2490
2491 /*
2492 * @implemented
2493 */
2494 BOOL WINAPI
2495 ReleaseCapture(VOID)
2496 {
2497 return NtUserxReleaseCapture();
2498 }
2499
2500
2501 /*
2502 * @implemented
2503 */
2504 DWORD
2505 WINAPI
2506 RealGetQueueStatus(UINT flags)
2507 {
2508 #define QS_TEMPALLINPUT 255 // ATM, do not support QS_RAWINPUT
2509 if (flags & ~(QS_SMRESULT|QS_ALLPOSTMESSAGE|QS_TEMPALLINPUT))
2510 {
2511 SetLastError( ERROR_INVALID_FLAGS );
2512 return 0;
2513 }
2514 return NtUserxGetQueueStatus(flags);
2515 }
2516
2517
2518 /*
2519 * @implemented
2520 */
2521 BOOL WINAPI GetInputState(VOID)
2522 {
2523 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
2524
2525 if ((!pcti) || (pcti->fsChangeBits & (QS_KEY|QS_MOUSEBUTTON)))
2526 return (BOOL)NtUserGetThreadState(THREADSTATE_GETINPUTSTATE);
2527
2528 return FALSE;
2529 }
2530
2531
2532 NTSTATUS WINAPI
2533 User32CallWindowProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
2534 {
2535 PWINDOWPROC_CALLBACK_ARGUMENTS CallbackArgs;
2536 MSG KMMsg, UMMsg;
2537 PWND pWnd = NULL;
2538 PCLIENTINFO pci = GetWin32ClientInfo();
2539
2540 /* Make sure we don't try to access mem beyond what we were given */
2541 if (ArgumentLength < sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
2542 {
2543 return STATUS_INFO_LENGTH_MISMATCH;
2544 }
2545
2546 CallbackArgs = (PWINDOWPROC_CALLBACK_ARGUMENTS) Arguments;
2547 KMMsg.hwnd = CallbackArgs->Wnd;
2548 KMMsg.message = CallbackArgs->Msg;
2549 KMMsg.wParam = CallbackArgs->wParam;
2550 /* Check if lParam is really a pointer and adjust it if it is */
2551 if (0 <= CallbackArgs->lParamBufferSize)
2552 {
2553 if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)
2554 + CallbackArgs->lParamBufferSize)
2555 {
2556 return STATUS_INFO_LENGTH_MISMATCH;
2557 }
2558 KMMsg.lParam = (LPARAM) ((char *) CallbackArgs + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS));
2559 }
2560 else
2561 {
2562 if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
2563 {
2564 return STATUS_INFO_LENGTH_MISMATCH;
2565 }
2566 KMMsg.lParam = CallbackArgs->lParam;
2567 }
2568
2569 if (WM_NCCALCSIZE == CallbackArgs->Msg && CallbackArgs->wParam)
2570 {
2571 NCCALCSIZE_PARAMS *Params = (NCCALCSIZE_PARAMS *) KMMsg.lParam;
2572 Params->lppos = (PWINDOWPOS) (Params + 1);
2573 }
2574
2575 if (! MsgiKMToUMMessage(&KMMsg, &UMMsg))
2576 {
2577 }
2578
2579 if (pci->CallbackWnd.hWnd == UMMsg.hwnd)
2580 pWnd = pci->CallbackWnd.pWnd;
2581
2582 CallbackArgs->Result = IntCallWindowProcW( CallbackArgs->IsAnsiProc,
2583 CallbackArgs->Proc,
2584 pWnd,
2585 UMMsg.hwnd,
2586 UMMsg.message,
2587 UMMsg.wParam,
2588 UMMsg.lParam);
2589
2590 if (! MsgiKMToUMReply(&KMMsg, &UMMsg, &CallbackArgs->Result))
2591 {
2592 }
2593
2594 return ZwCallbackReturn(CallbackArgs, ArgumentLength, STATUS_SUCCESS);
2595 }
2596
2597 /*
2598 * @implemented
2599 */
2600 BOOL WINAPI SetMessageQueue(int cMessagesMax)
2601 {
2602 /* Function does nothing on 32 bit windows */
2603 return TRUE;
2604 }
2605 typedef DWORD (WINAPI * RealGetQueueStatusProc)(UINT flags);
2606 typedef DWORD (WINAPI * RealMsgWaitForMultipleObjectsExProc)(DWORD nCount, CONST HANDLE *lpHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags);
2607 typedef BOOL (WINAPI * RealInternalGetMessageProc)(LPMSG,HWND,UINT,UINT,UINT,BOOL);
2608 typedef BOOL (WINAPI * RealWaitMessageExProc)(DWORD,UINT);
2609
2610 typedef struct _USER_MESSAGE_PUMP_ADDRESSES {
2611 DWORD cbSize;
2612 RealInternalGetMessageProc NtUserRealInternalGetMessage;
2613 RealWaitMessageExProc NtUserRealWaitMessageEx;
2614 RealGetQueueStatusProc RealGetQueueStatus;
2615 RealMsgWaitForMultipleObjectsExProc RealMsgWaitForMultipleObjectsEx;
2616 } USER_MESSAGE_PUMP_ADDRESSES, * PUSER_MESSAGE_PUMP_ADDRESSES;
2617
2618 DWORD
2619 WINAPI
2620 RealMsgWaitForMultipleObjectsEx(
2621 DWORD nCount,
2622 CONST HANDLE *pHandles,
2623 DWORD dwMilliseconds,
2624 DWORD dwWakeMask,
2625 DWORD dwFlags);
2626
2627 typedef BOOL (WINAPI * MESSAGEPUMPHOOKPROC)(BOOL Unregistering,PUSER_MESSAGE_PUMP_ADDRESSES MessagePumpAddresses);
2628
2629 CRITICAL_SECTION gcsMPH;
2630 MESSAGEPUMPHOOKPROC gpfnInitMPH;
2631 DWORD gcLoadMPH = 0;
2632 USER_MESSAGE_PUMP_ADDRESSES gmph = {sizeof(USER_MESSAGE_PUMP_ADDRESSES),
2633 NtUserRealInternalGetMessage,
2634 NtUserRealWaitMessageEx,
2635 RealGetQueueStatus,
2636 RealMsgWaitForMultipleObjectsEx
2637 };
2638
2639 DWORD gfMessagePumpHook = 0;
2640
2641 BOOL WINAPI IsInsideMessagePumpHook()
2642 { // FF uses this and polls it when Min/Max
2643 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
2644 return (gfMessagePumpHook && pcti && (pcti->dwcPumpHook > 0));
2645 }
2646
2647 void WINAPI ResetMessagePumpHook(PUSER_MESSAGE_PUMP_ADDRESSES Addresses)
2648 {
2649 Addresses->cbSize = sizeof(USER_MESSAGE_PUMP_ADDRESSES);
2650 Addresses->NtUserRealInternalGetMessage = NtUserRealInternalGetMessage;
2651 Addresses->NtUserRealWaitMessageEx = NtUserRealWaitMessageEx;
2652 Addresses->RealGetQueueStatus = RealGetQueueStatus;
2653 Addresses->RealMsgWaitForMultipleObjectsEx = RealMsgWaitForMultipleObjectsEx;
2654 }
2655
2656 BOOL WINAPI RegisterMessagePumpHook(MESSAGEPUMPHOOKPROC Hook)
2657 {
2658 EnterCriticalSection(&gcsMPH);
2659 if(!Hook) {
2660 SetLastError(ERROR_INVALID_PARAMETER);
2661 LeaveCriticalSection(&gcsMPH);
2662 return FALSE;
2663 }
2664 if(!gcLoadMPH) {
2665 USER_MESSAGE_PUMP_ADDRESSES Addresses;
2666 gpfnInitMPH = Hook;
2667 ResetMessagePumpHook(&Addresses);
2668 if(!Hook(FALSE, &Addresses) || !Addresses.cbSize) {
2669 LeaveCriticalSection(&gcsMPH);
2670 return FALSE;
2671 }
2672 memcpy(&gmph, &Addresses, Addresses.cbSize);
2673 } else {
2674 if(gpfnInitMPH != Hook) {
2675 LeaveCriticalSection(&gcsMPH);
2676 return FALSE;
2677 }
2678 }
2679 if(NtUserxInitMessagePump()) {
2680 LeaveCriticalSection(&gcsMPH);
2681 return FALSE;
2682 }
2683 if (!gcLoadMPH++) {
2684 InterlockedExchange((PLONG)&gfMessagePumpHook, 1);
2685 }
2686 LeaveCriticalSection(&gcsMPH);
2687 return TRUE;
2688 }
2689
2690 BOOL WINAPI UnregisterMessagePumpHook(VOID)
2691 {
2692 EnterCriticalSection(&gcsMPH);
2693 if(gcLoadMPH > 0) {
2694 if(NtUserxUnInitMessagePump()) {
2695 gcLoadMPH--;
2696 if(!gcLoadMPH) {
2697 InterlockedExchange((PLONG)&gfMessagePumpHook, 0);
2698 gpfnInitMPH(TRUE, NULL);
2699 ResetMessagePumpHook(&gmph);
2700 gpfnInitMPH = 0;
2701 }
2702 LeaveCriticalSection(&gcsMPH);
2703 return TRUE;
2704 }
2705 }
2706 LeaveCriticalSection(&gcsMPH);
2707 return FALSE;
2708 }
2709
2710 DWORD WINAPI GetQueueStatus(UINT flags)
2711 {
2712 return IsInsideMessagePumpHook() ? gmph.RealGetQueueStatus(flags) : RealGetQueueStatus(flags);
2713 }
2714
2715 /**
2716 * @name RealMsgWaitForMultipleObjectsEx
2717 *
2718 * Wait either for either message arrival or for one of the passed events
2719 * to be signalled.
2720 *
2721 * @param nCount
2722 * Number of handles in the pHandles array.
2723 * @param pHandles
2724 * Handles of events to wait for.
2725 * @param dwMilliseconds
2726 * Timeout interval.
2727 * @param dwWakeMask
2728 * Mask specifying on which message events we should wakeup.
2729 * @param dwFlags
2730 * Wait type (see MWMO_* constants).
2731 *
2732 * @implemented
2733 */
2734
2735 DWORD WINAPI
2736 RealMsgWaitForMultipleObjectsEx(
2737 DWORD nCount,
2738 const HANDLE *pHandles,
2739 DWORD dwMilliseconds,
2740 DWORD dwWakeMask,
2741 DWORD dwFlags)
2742 {
2743 LPHANDLE RealHandles;
2744 HANDLE MessageQueueHandle;
2745 DWORD Result;
2746 PCLIENTINFO pci;
2747 PCLIENTTHREADINFO pcti;
2748
2749 if (dwFlags & ~(MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE))
2750 {
2751 SetLastError(ERROR_INVALID_PARAMETER);
2752 return WAIT_FAILED;
2753 }
2754
2755 pci = GetWin32ClientInfo();
2756 if (!pci) return WAIT_FAILED;
2757
2758 pcti = pci->pClientThreadInfo;
2759 if (pcti && ( !nCount || !(dwFlags & MWMO_WAITALL) ))
2760 {
2761 if ( (pcti->fsChangeBits & LOWORD(dwWakeMask)) ||
2762 ( (dwFlags & MWMO_INPUTAVAILABLE) && (pcti->fsWakeBits & LOWORD(dwWakeMask)) ) )
2763 {
2764 //FIXME("Chg 0x%x Wake 0x%x Mask 0x%x nCnt %d\n",pcti->fsChangeBits, pcti->fsWakeBits, dwWakeMask, nCount);
2765 return nCount;
2766 }
2767 }
2768
2769 MessageQueueHandle = NtUserxMsqSetWakeMask(MAKELONG(dwWakeMask, dwFlags));
2770 if (MessageQueueHandle == NULL)
2771 {
2772 SetLastError(0); /* ? */
2773 return WAIT_FAILED;
2774 }
2775
2776 RealHandles = HeapAlloc(GetProcessHeap(), 0, (nCount + 1) * sizeof(HANDLE));
2777 if (RealHandles == NULL)
2778 {
2779 NtUserxMsqClearWakeMask();
2780 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2781 return WAIT_FAILED;
2782 }
2783
2784 RtlCopyMemory(RealHandles, pHandles, nCount * sizeof(HANDLE));
2785 RealHandles[nCount] = MessageQueueHandle;
2786
2787 Result = WaitForMultipleObjectsEx(nCount + 1, RealHandles,
2788 dwFlags & MWMO_WAITALL,
2789 dwMilliseconds, dwFlags & MWMO_ALERTABLE);
2790
2791 HeapFree(GetProcessHeap(), 0, RealHandles);
2792 NtUserxMsqClearWakeMask();
2793 //FIXME("Result 0X%x\n",Result);
2794 return Result;
2795 }
2796
2797 /*
2798 * @implemented
2799 */
2800 DWORD WINAPI
2801 MsgWaitForMultipleObjectsEx(
2802 DWORD nCount,
2803 CONST HANDLE *lpHandles,
2804 DWORD dwMilliseconds,
2805 DWORD dwWakeMask,
2806 DWORD dwFlags)
2807 {
2808 return IsInsideMessagePumpHook() ? gmph.RealMsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds, dwWakeMask, dwFlags) : RealMsgWaitForMultipleObjectsEx(nCount, lpHandles,dwMilliseconds, dwWakeMask, dwFlags);
2809 }
2810
2811 /*
2812 * @implemented
2813 */
2814 DWORD WINAPI
2815 MsgWaitForMultipleObjects(
2816 DWORD nCount,
2817 CONST HANDLE *lpHandles,
2818 BOOL fWaitAll,
2819 DWORD dwMilliseconds,
2820 DWORD dwWakeMask)
2821 {
2822 return MsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds,
2823 dwWakeMask, fWaitAll ? MWMO_WAITALL : 0);
2824 }
2825
2826
2827 BOOL FASTCALL MessageInit(VOID)
2828 {
2829 InitializeCriticalSection(&DdeCrst);
2830 InitializeCriticalSection(&gcsMPH);
2831
2832 return TRUE;
2833 }
2834
2835 VOID FASTCALL MessageCleanup(VOID)
2836 {
2837 DeleteCriticalSection(&DdeCrst);
2838 DeleteCriticalSection(&gcsMPH);
2839 }
2840
2841 /***********************************************************************
2842 * map_wparam_AtoW
2843 *
2844 * Convert the wparam of an ASCII message to Unicode.
2845 */
2846 static WPARAM
2847 map_wparam_AtoW( UINT message, WPARAM wparam )
2848 {
2849 switch(message)
2850 {
2851 case WM_CHARTOITEM:
2852 case EM_SETPASSWORDCHAR:
2853 case WM_CHAR:
2854 case WM_DEADCHAR:
2855 case WM_SYSCHAR:
2856 case WM_SYSDEADCHAR:
2857 case WM_MENUCHAR:
2858 {
2859 char ch[2];
2860 WCHAR wch[2];
2861 ch[0] = (wparam & 0xff);
2862 ch[1] = (wparam >> 8);
2863 MultiByteToWideChar(CP_ACP, 0, ch, 2, wch, 2);
2864 wparam = MAKEWPARAM(wch[0], wch[1]);
2865 }
2866 break;
2867 case WM_IME_CHAR:
2868 {
2869 char ch[2];
2870 WCHAR wch;
2871 ch[0] = (wparam >> 8);
2872 ch[1] = (wparam & 0xff);
2873 if (ch[0]) MultiByteToWideChar(CP_ACP, 0, ch, 2, &wch, 1);
2874 else MultiByteToWideChar(CP_ACP, 0, &ch[1], 1, &wch, 1);
2875 wparam = MAKEWPARAM( wch, HIWORD(wparam) );
2876 }
2877 break;
2878 }
2879 return wparam;
2880 }
2881
2882 /*
2883 * @implemented
2884 */
2885 BOOL WINAPI
2886 IsDialogMessageA( HWND hwndDlg, LPMSG pmsg )
2887 {
2888 MSG msg = *pmsg;
2889 msg.wParam = map_wparam_AtoW( msg.message, msg.wParam );
2890 return IsDialogMessageW( hwndDlg, &msg );
2891 }
2892
2893 LONG
2894 WINAPI
2895 IntBroadcastSystemMessage(
2896 DWORD dwflags,
2897 LPDWORD lpdwRecipients,
2898 UINT uiMessage,
2899 WPARAM wParam,
2900 LPARAM lParam,
2901 PBSMINFO pBSMInfo,
2902 BOOL Ansi)
2903 {
2904 BROADCASTPARM parm;
2905 DWORD recips = BSM_ALLCOMPONENTS;
2906 BOOL ret = -1; // Set to return fail
2907 static const DWORD all_flags = ( BSF_QUERY | BSF_IGNORECURRENTTASK | BSF_FLUSHDISK | BSF_NOHANG
2908 | BSF_POSTMESSAGE | BSF_FORCEIFHUNG | BSF_NOTIMEOUTIFNOTHUNG
2909 | BSF_ALLOWSFW | BSF_SENDNOTIFYMESSAGE | BSF_RETURNHDESK | BSF_LUID );
2910
2911 if ((dwflags & ~all_flags) ||
2912 (!pBSMInfo && (dwflags & (BSF_RETURNHDESK|BSF_LUID))) )
2913 {
2914 SetLastError(ERROR_INVALID_PARAMETER);
2915 return 0;
2916 }
2917
2918 if(uiMessage >= WM_USER && uiMessage < 0xC000)
2919 {
2920 SetLastError(ERROR_INVALID_PARAMETER);
2921 return 0;
2922 }
2923
2924 if (dwflags & BSF_FORCEIFHUNG) dwflags |= BSF_NOHANG;
2925
2926 if (dwflags & BSF_QUERY) dwflags &= ~BSF_SENDNOTIFYMESSAGE|BSF_POSTMESSAGE;
2927
2928 if (!lpdwRecipients)
2929 lpdwRecipients = &recips;
2930
2931 if (*lpdwRecipients & ~(BSM_APPLICATIONS|BSM_ALLDESKTOPS|BSM_INSTALLABLEDRIVERS|BSM_NETDRIVER|BSM_VXDS))
2932 {
2933 SetLastError(ERROR_INVALID_PARAMETER);
2934 return 0;
2935 }
2936
2937 if ( pBSMInfo && (dwflags & BSF_QUERY) )
2938 {
2939 if (pBSMInfo->cbSize != sizeof(BSMINFO))
2940 {
2941 SetLastError(ERROR_INVALID_PARAMETER);
2942 return 0;
2943 }
2944 }
2945
2946 parm.hDesk = NULL;
2947 parm.hWnd = NULL;
2948 parm.flags = dwflags;
2949 parm.recipients = *lpdwRecipients;
2950
2951 if (dwflags & BSF_LUID) parm.luid = pBSMInfo->luid;
2952
2953 if (*lpdwRecipients & BSM_APPLICATIONS)
2954 {
2955 ret = NtUserMessageCall(GetDesktopWindow(),
2956 uiMessage,
2957 wParam,
2958 lParam,
2959 (ULONG_PTR)&parm,
2960 FNID_BROADCASTSYSTEMMESSAGE,
2961 Ansi);
2962 }
2963
2964 if (!ret)
2965 {
2966 if ( pBSMInfo && (dwflags & BSF_QUERY) )
2967 {
2968 pBSMInfo->hdesk = parm.hDesk;
2969 pBSMInfo->hwnd = parm.hWnd;
2970 }
2971 }
2972 return ret;
2973 }
2974
2975 /*
2976 * @implemented
2977 */
2978 LONG
2979 WINAPI
2980 BroadcastSystemMessageA(
2981 DWORD dwFlags,
2982 LPDWORD lpdwRecipients,
2983 UINT uiMessage,
2984 WPARAM wParam,
2985 LPARAM lParam)
2986 {
2987 return IntBroadcastSystemMessage( dwFlags, lpdwRecipients, uiMessage, wParam, lParam, NULL, TRUE );
2988 }
2989
2990 /*
2991 * @implemented
2992 */
2993 LONG
2994 WINAPI
2995 BroadcastSystemMessageW(
2996 DWORD dwFlags,
2997 LPDWORD lpdwRecipients,
2998 UINT uiMessage,
2999 WPARAM wParam,
3000 LPARAM lParam)
3001 {
3002 return IntBroadcastSystemMessage( dwFlags, lpdwRecipients, uiMessage, wParam, lParam, NULL, FALSE );
3003 }
3004
3005 /*
3006 * @implemented
3007 */
3008 LONG
3009 WINAPI
3010 BroadcastSystemMessageExA(
3011 DWORD dwflags,
3012 LPDWORD lpdwRecipients,
3013 UINT uiMessage,
3014 WPARAM wParam,
3015 LPARAM lParam,
3016 PBSMINFO pBSMInfo)
3017 {
3018 return IntBroadcastSystemMessage( dwflags, lpdwRecipients, uiMessage, wParam, lParam , pBSMInfo, TRUE );
3019 }
3020
3021 /*
3022 * @implemented
3023 */
3024 LONG
3025 WINAPI
3026 BroadcastSystemMessageExW(
3027 DWORD dwflags,
3028 LPDWORD lpdwRecipients,
3029 UINT uiMessage,
3030 WPARAM wParam,
3031 LPARAM lParam,
3032 PBSMINFO pBSMInfo)
3033 {
3034 return IntBroadcastSystemMessage( dwflags, lpdwRecipients, uiMessage, wParam, lParam , pBSMInfo, FALSE );
3035 }
3036