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