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