[USERENV][USER32]
[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 #if 0
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 #endif
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 UINT Atom;
2679
2680 if (!RtlCreateUnicodeStringFromAsciiz(&String, (PCSZ)lpString))
2681 {
2682 return(0);
2683 }
2684 Atom = NtUserRegisterWindowMessage(&String);
2685 RtlFreeUnicodeString(&String);
2686 return(Atom);
2687 }
2688
2689
2690 /*
2691 * @implemented
2692 */
2693 UINT WINAPI
2694 RegisterWindowMessageW(LPCWSTR lpString)
2695 {
2696 UNICODE_STRING String;
2697
2698 RtlInitUnicodeString(&String, lpString);
2699 return(NtUserRegisterWindowMessage(&String));
2700 }
2701
2702 /*
2703 * @implemented
2704 */
2705 HWND WINAPI
2706 GetCapture(VOID)
2707 {
2708 return (HWND)NtUserGetThreadState(THREADSTATE_CAPTUREWINDOW);
2709 }
2710
2711 /*
2712 * @implemented
2713 */
2714 BOOL WINAPI
2715 ReleaseCapture(VOID)
2716 {
2717 return NtUserxReleaseCapture();
2718 }
2719
2720
2721 /*
2722 * @implemented
2723 */
2724 DWORD
2725 WINAPI
2726 RealGetQueueStatus(UINT flags)
2727 {
2728 #define QS_TEMPALLINPUT 255 // ATM, do not support QS_RAWINPUT
2729 if (flags & ~(QS_SMRESULT|QS_ALLPOSTMESSAGE|QS_TEMPALLINPUT))
2730 {
2731 SetLastError( ERROR_INVALID_FLAGS );
2732 return 0;
2733 }
2734 return NtUserxGetQueueStatus(flags);
2735 }
2736
2737
2738 /*
2739 * @implemented
2740 */
2741 BOOL WINAPI GetInputState(VOID)
2742 {
2743 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
2744
2745 if ((!pcti) || (pcti->fsChangeBits & (QS_KEY|QS_MOUSEBUTTON)))
2746 return (BOOL)NtUserGetThreadState(THREADSTATE_GETINPUTSTATE);
2747
2748 return FALSE;
2749 }
2750
2751
2752 NTSTATUS WINAPI
2753 User32CallWindowProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
2754 {
2755 PWINDOWPROC_CALLBACK_ARGUMENTS CallbackArgs;
2756 MSG KMMsg, UMMsg;
2757 PWND pWnd = NULL;
2758 PCLIENTINFO pci = GetWin32ClientInfo();
2759
2760 /* Make sure we don't try to access mem beyond what we were given */
2761 if (ArgumentLength < sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
2762 {
2763 return STATUS_INFO_LENGTH_MISMATCH;
2764 }
2765
2766 CallbackArgs = (PWINDOWPROC_CALLBACK_ARGUMENTS) Arguments;
2767 KMMsg.hwnd = CallbackArgs->Wnd;
2768 KMMsg.message = CallbackArgs->Msg;
2769 KMMsg.wParam = CallbackArgs->wParam;
2770 /* Check if lParam is really a pointer and adjust it if it is */
2771 if (0 <= CallbackArgs->lParamBufferSize)
2772 {
2773 if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)
2774 + CallbackArgs->lParamBufferSize)
2775 {
2776 return STATUS_INFO_LENGTH_MISMATCH;
2777 }
2778 KMMsg.lParam = (LPARAM) ((char *) CallbackArgs + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS));
2779 }
2780 else
2781 {
2782 if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
2783 {
2784 return STATUS_INFO_LENGTH_MISMATCH;
2785 }
2786 KMMsg.lParam = CallbackArgs->lParam;
2787 }
2788
2789 if (WM_NCCALCSIZE == CallbackArgs->Msg && CallbackArgs->wParam)
2790 {
2791 NCCALCSIZE_PARAMS *Params = (NCCALCSIZE_PARAMS *) KMMsg.lParam;
2792 Params->lppos = (PWINDOWPOS) (Params + 1);
2793 }
2794
2795 if (! MsgiKMToUMMessage(&KMMsg, &UMMsg))
2796 {
2797 }
2798
2799 if (pci->CallbackWnd.hWnd == UMMsg.hwnd)
2800 pWnd = pci->CallbackWnd.pWnd;
2801
2802 CallbackArgs->Result = IntCallWindowProcW( CallbackArgs->IsAnsiProc,
2803 CallbackArgs->Proc,
2804 pWnd,
2805 UMMsg.hwnd,
2806 UMMsg.message,
2807 UMMsg.wParam,
2808 UMMsg.lParam);
2809
2810 if (! MsgiKMToUMReply(&KMMsg, &UMMsg, &CallbackArgs->Result))
2811 {
2812 }
2813
2814 return ZwCallbackReturn(CallbackArgs, ArgumentLength, STATUS_SUCCESS);
2815 }
2816
2817 /*
2818 * @implemented
2819 */
2820 BOOL WINAPI SetMessageQueue(int cMessagesMax)
2821 {
2822 /* Function does nothing on 32 bit windows */
2823 return TRUE;
2824 }
2825 typedef DWORD (WINAPI * RealGetQueueStatusProc)(UINT flags);
2826 typedef DWORD (WINAPI * RealMsgWaitForMultipleObjectsExProc)(DWORD nCount, CONST HANDLE *lpHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags);
2827 typedef BOOL (WINAPI * RealInternalGetMessageProc)(LPMSG,HWND,UINT,UINT,UINT,BOOL);
2828 typedef BOOL (WINAPI * RealWaitMessageExProc)(DWORD,UINT);
2829
2830 typedef struct _USER_MESSAGE_PUMP_ADDRESSES {
2831 DWORD cbSize;
2832 RealInternalGetMessageProc NtUserRealInternalGetMessage;
2833 RealWaitMessageExProc NtUserRealWaitMessageEx;
2834 RealGetQueueStatusProc RealGetQueueStatus;
2835 RealMsgWaitForMultipleObjectsExProc RealMsgWaitForMultipleObjectsEx;
2836 } USER_MESSAGE_PUMP_ADDRESSES, * PUSER_MESSAGE_PUMP_ADDRESSES;
2837
2838 DWORD
2839 WINAPI
2840 RealMsgWaitForMultipleObjectsEx(
2841 DWORD nCount,
2842 CONST HANDLE *pHandles,
2843 DWORD dwMilliseconds,
2844 DWORD dwWakeMask,
2845 DWORD dwFlags);
2846
2847 typedef BOOL (WINAPI * MESSAGEPUMPHOOKPROC)(BOOL Unregistering,PUSER_MESSAGE_PUMP_ADDRESSES MessagePumpAddresses);
2848
2849 CRITICAL_SECTION gcsMPH;
2850 MESSAGEPUMPHOOKPROC gpfnInitMPH;
2851 DWORD gcLoadMPH = 0;
2852 USER_MESSAGE_PUMP_ADDRESSES gmph = {sizeof(USER_MESSAGE_PUMP_ADDRESSES),
2853 NtUserRealInternalGetMessage,
2854 NtUserRealWaitMessageEx,
2855 RealGetQueueStatus,
2856 RealMsgWaitForMultipleObjectsEx
2857 };
2858
2859 DWORD gfMessagePumpHook = 0;
2860
2861 BOOL WINAPI IsInsideMessagePumpHook()
2862 { // FF uses this and polls it when Min/Max
2863 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
2864 return (gfMessagePumpHook && pcti && (pcti->dwcPumpHook > 0));
2865 }
2866
2867 void WINAPI ResetMessagePumpHook(PUSER_MESSAGE_PUMP_ADDRESSES Addresses)
2868 {
2869 Addresses->cbSize = sizeof(USER_MESSAGE_PUMP_ADDRESSES);
2870 Addresses->NtUserRealInternalGetMessage = NtUserRealInternalGetMessage;
2871 Addresses->NtUserRealWaitMessageEx = NtUserRealWaitMessageEx;
2872 Addresses->RealGetQueueStatus = RealGetQueueStatus;
2873 Addresses->RealMsgWaitForMultipleObjectsEx = RealMsgWaitForMultipleObjectsEx;
2874 }
2875
2876 BOOL WINAPI RegisterMessagePumpHook(MESSAGEPUMPHOOKPROC Hook)
2877 {
2878 EnterCriticalSection(&gcsMPH);
2879 if(!Hook) {
2880 SetLastError(ERROR_INVALID_PARAMETER);
2881 LeaveCriticalSection(&gcsMPH);
2882 return FALSE;
2883 }
2884 if(!gcLoadMPH) {
2885 USER_MESSAGE_PUMP_ADDRESSES Addresses;
2886 gpfnInitMPH = Hook;
2887 ResetMessagePumpHook(&Addresses);
2888 if(!Hook(FALSE, &Addresses) || !Addresses.cbSize) {
2889 LeaveCriticalSection(&gcsMPH);
2890 return FALSE;
2891 }
2892 memcpy(&gmph, &Addresses, Addresses.cbSize);
2893 } else {
2894 if(gpfnInitMPH != Hook) {
2895 LeaveCriticalSection(&gcsMPH);
2896 return FALSE;
2897 }
2898 }
2899 if(NtUserxInitMessagePump()) {
2900 LeaveCriticalSection(&gcsMPH);
2901 return FALSE;
2902 }
2903 if (!gcLoadMPH++) {
2904 InterlockedExchange((PLONG)&gfMessagePumpHook, 1);
2905 }
2906 LeaveCriticalSection(&gcsMPH);
2907 return TRUE;
2908 }
2909
2910 BOOL WINAPI UnregisterMessagePumpHook(VOID)
2911 {
2912 EnterCriticalSection(&gcsMPH);
2913 if(gcLoadMPH > 0) {
2914 if(NtUserxUnInitMessagePump()) {
2915 gcLoadMPH--;
2916 if(!gcLoadMPH) {
2917 InterlockedExchange((PLONG)&gfMessagePumpHook, 0);
2918 gpfnInitMPH(TRUE, NULL);
2919 ResetMessagePumpHook(&gmph);
2920 gpfnInitMPH = 0;
2921 }
2922 LeaveCriticalSection(&gcsMPH);
2923 return TRUE;
2924 }
2925 }
2926 LeaveCriticalSection(&gcsMPH);
2927 return FALSE;
2928 }
2929
2930 DWORD WINAPI GetQueueStatus(UINT flags)
2931 {
2932 return IsInsideMessagePumpHook() ? gmph.RealGetQueueStatus(flags) : RealGetQueueStatus(flags);
2933 }
2934
2935 /**
2936 * @name RealMsgWaitForMultipleObjectsEx
2937 *
2938 * Wait either for either message arrival or for one of the passed events
2939 * to be signalled.
2940 *
2941 * @param nCount
2942 * Number of handles in the pHandles array.
2943 * @param pHandles
2944 * Handles of events to wait for.
2945 * @param dwMilliseconds
2946 * Timeout interval.
2947 * @param dwWakeMask
2948 * Mask specifying on which message events we should wakeup.
2949 * @param dwFlags
2950 * Wait type (see MWMO_* constants).
2951 *
2952 * @implemented
2953 */
2954
2955 DWORD WINAPI
2956 RealMsgWaitForMultipleObjectsEx(
2957 DWORD nCount,
2958 const HANDLE *pHandles,
2959 DWORD dwMilliseconds,
2960 DWORD dwWakeMask,
2961 DWORD dwFlags)
2962 {
2963 LPHANDLE RealHandles;
2964 HANDLE MessageQueueHandle;
2965 DWORD Result;
2966 PCLIENTINFO pci;
2967 PCLIENTTHREADINFO pcti;
2968
2969 if (dwFlags & ~(MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE))
2970 {
2971 SetLastError(ERROR_INVALID_PARAMETER);
2972 return WAIT_FAILED;
2973 }
2974
2975 pci = GetWin32ClientInfo();
2976 if (!pci) return WAIT_FAILED;
2977
2978 pcti = pci->pClientThreadInfo;
2979 if (pcti && ( !nCount || !(dwFlags & MWMO_WAITALL) ))
2980 {
2981 if ( (pcti->fsChangeBits & LOWORD(dwWakeMask)) ||
2982 ( (dwFlags & MWMO_INPUTAVAILABLE) && (pcti->fsWakeBits & LOWORD(dwWakeMask)) ) )
2983 {
2984 //FIXME("Chg 0x%x Wake 0x%x Mask 0x%x nCnt %d\n",pcti->fsChangeBits, pcti->fsWakeBits, dwWakeMask, nCount);
2985 return nCount;
2986 }
2987 }
2988
2989 MessageQueueHandle = NtUserxMsqSetWakeMask(MAKELONG(dwWakeMask, dwFlags));
2990 if (MessageQueueHandle == NULL)
2991 {
2992 SetLastError(0); /* ? */
2993 return WAIT_FAILED;
2994 }
2995
2996 RealHandles = HeapAlloc(GetProcessHeap(), 0, (nCount + 1) * sizeof(HANDLE));
2997 if (RealHandles == NULL)
2998 {
2999 NtUserxMsqClearWakeMask();
3000 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3001 return WAIT_FAILED;
3002 }
3003
3004 RtlCopyMemory(RealHandles, pHandles, nCount * sizeof(HANDLE));
3005 RealHandles[nCount] = MessageQueueHandle;
3006
3007 Result = WaitForMultipleObjectsEx(nCount + 1, RealHandles,
3008 dwFlags & MWMO_WAITALL,
3009 dwMilliseconds, dwFlags & MWMO_ALERTABLE);
3010
3011 HeapFree(GetProcessHeap(), 0, RealHandles);
3012 NtUserxMsqClearWakeMask();
3013 //FIXME("Result 0X%x\n",Result);
3014 return Result;
3015 }
3016
3017 /*
3018 * @implemented
3019 */
3020 DWORD WINAPI
3021 MsgWaitForMultipleObjectsEx(
3022 DWORD nCount,
3023 CONST HANDLE *lpHandles,
3024 DWORD dwMilliseconds,
3025 DWORD dwWakeMask,
3026 DWORD dwFlags)
3027 {
3028 return IsInsideMessagePumpHook() ? gmph.RealMsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds, dwWakeMask, dwFlags) : RealMsgWaitForMultipleObjectsEx(nCount, lpHandles,dwMilliseconds, dwWakeMask, dwFlags);
3029 }
3030
3031 /*
3032 * @implemented
3033 */
3034 DWORD WINAPI
3035 MsgWaitForMultipleObjects(
3036 DWORD nCount,
3037 CONST HANDLE *lpHandles,
3038 BOOL fWaitAll,
3039 DWORD dwMilliseconds,
3040 DWORD dwWakeMask)
3041 {
3042 return MsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds,
3043 dwWakeMask, fWaitAll ? MWMO_WAITALL : 0);
3044 }
3045
3046
3047 BOOL FASTCALL MessageInit(VOID)
3048 {
3049 InitializeCriticalSection(&DdeCrst);
3050 InitializeCriticalSection(&gcsMPH);
3051
3052 return TRUE;
3053 }
3054
3055 VOID FASTCALL MessageCleanup(VOID)
3056 {
3057 DeleteCriticalSection(&DdeCrst);
3058 DeleteCriticalSection(&gcsMPH);
3059 }
3060
3061 /*
3062 * @implemented
3063 */
3064 BOOL WINAPI
3065 IsDialogMessageA( HWND hwndDlg, LPMSG pmsg )
3066 {
3067 MSG msg = *pmsg;
3068 msg.wParam = map_wparam_AtoW( msg.message, msg.wParam );
3069 return IsDialogMessageW( hwndDlg, &msg );
3070 }
3071
3072 LONG
3073 WINAPI
3074 IntBroadcastSystemMessage(
3075 DWORD dwflags,
3076 LPDWORD lpdwRecipients,
3077 UINT uiMessage,
3078 WPARAM wParam,
3079 LPARAM lParam,
3080 PBSMINFO pBSMInfo,
3081 BOOL Ansi)
3082 {
3083 BROADCASTPARM parm;
3084 DWORD recips = BSM_ALLCOMPONENTS;
3085 BOOL ret = -1; // Set to return fail
3086 static const DWORD all_flags = ( BSF_QUERY | BSF_IGNORECURRENTTASK | BSF_FLUSHDISK | BSF_NOHANG
3087 | BSF_POSTMESSAGE | BSF_FORCEIFHUNG | BSF_NOTIMEOUTIFNOTHUNG
3088 | BSF_ALLOWSFW | BSF_SENDNOTIFYMESSAGE | BSF_RETURNHDESK | BSF_LUID );
3089
3090 if ((dwflags & ~all_flags) ||
3091 (!pBSMInfo && (dwflags & (BSF_RETURNHDESK|BSF_LUID))) )
3092 {
3093 SetLastError(ERROR_INVALID_PARAMETER);
3094 return 0;
3095 }
3096
3097 if(uiMessage >= WM_USER && uiMessage < 0xC000)
3098 {
3099 SetLastError(ERROR_INVALID_PARAMETER);
3100 return 0;
3101 }
3102
3103 if (dwflags & BSF_FORCEIFHUNG) dwflags |= BSF_NOHANG;
3104
3105 if (dwflags & BSF_QUERY) dwflags &= ~BSF_SENDNOTIFYMESSAGE|BSF_POSTMESSAGE;
3106
3107 if (!lpdwRecipients)
3108 lpdwRecipients = &recips;
3109
3110 if (*lpdwRecipients & ~(BSM_APPLICATIONS|BSM_ALLDESKTOPS|BSM_INSTALLABLEDRIVERS|BSM_NETDRIVER|BSM_VXDS))
3111 {
3112 SetLastError(ERROR_INVALID_PARAMETER);
3113 return 0;
3114 }
3115
3116 if ( pBSMInfo && (dwflags & BSF_QUERY) )
3117 {
3118 if (pBSMInfo->cbSize != sizeof(BSMINFO))
3119 {
3120 SetLastError(ERROR_INVALID_PARAMETER);
3121 return 0;
3122 }
3123 }
3124
3125 parm.hDesk = NULL;
3126 parm.hWnd = NULL;
3127 parm.flags = dwflags;
3128 parm.recipients = *lpdwRecipients;
3129
3130 if (dwflags & BSF_LUID) parm.luid = pBSMInfo->luid;
3131
3132 ret = NtUserMessageCall(GetDesktopWindow(),
3133 uiMessage,
3134 wParam,
3135 lParam,
3136 (ULONG_PTR)&parm,
3137 FNID_BROADCASTSYSTEMMESSAGE,
3138 Ansi);
3139
3140 if (!ret)
3141 {
3142 if ( pBSMInfo && (dwflags & BSF_QUERY) )
3143 {
3144 pBSMInfo->hdesk = parm.hDesk;
3145 pBSMInfo->hwnd = parm.hWnd;
3146 }
3147 }
3148 return ret;
3149 }
3150
3151 /*
3152 * @implemented
3153 */
3154 LONG
3155 WINAPI
3156 BroadcastSystemMessageA(
3157 DWORD dwFlags,
3158 LPDWORD lpdwRecipients,
3159 UINT uiMessage,
3160 WPARAM wParam,
3161 LPARAM lParam)
3162 {
3163 return IntBroadcastSystemMessage( dwFlags, lpdwRecipients, uiMessage, wParam, lParam, NULL, TRUE );
3164 }
3165
3166 /*
3167 * @implemented
3168 */
3169 LONG
3170 WINAPI
3171 BroadcastSystemMessageW(
3172 DWORD dwFlags,
3173 LPDWORD lpdwRecipients,
3174 UINT uiMessage,
3175 WPARAM wParam,
3176 LPARAM lParam)
3177 {
3178 return IntBroadcastSystemMessage( dwFlags, lpdwRecipients, uiMessage, wParam, lParam, NULL, FALSE );
3179 }
3180
3181 /*
3182 * @implemented
3183 */
3184 LONG
3185 WINAPI
3186 BroadcastSystemMessageExA(
3187 DWORD dwflags,
3188 LPDWORD lpdwRecipients,
3189 UINT uiMessage,
3190 WPARAM wParam,
3191 LPARAM lParam,
3192 PBSMINFO pBSMInfo)
3193 {
3194 return IntBroadcastSystemMessage( dwflags, lpdwRecipients, uiMessage, wParam, lParam , pBSMInfo, TRUE );
3195 }
3196
3197 /*
3198 * @implemented
3199 */
3200 LONG
3201 WINAPI
3202 BroadcastSystemMessageExW(
3203 DWORD dwflags,
3204 LPDWORD lpdwRecipients,
3205 UINT uiMessage,
3206 WPARAM wParam,
3207 LPARAM lParam,
3208 PBSMINFO pBSMInfo)
3209 {
3210 return IntBroadcastSystemMessage( dwflags, lpdwRecipients, uiMessage, wParam, lParam , pBSMInfo, FALSE );
3211 }
3212