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