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