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