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