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