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