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