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