Merge my current work done on the kd++ branch:
[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 ULONG_PTR LowLimit;
1292 BOOL Hook = FALSE, MsgOverride = FALSE, Dialog;
1293 LRESULT Result = 0, PreResult = 0;
1294 DWORD Data = 0;
1295
1296 if (WndProc == NULL)
1297 {
1298 WARN("IntCallWindowsProcW() called with WndProc = NULL!\n");
1299 return FALSE;
1300 }
1301
1302 // Safeguard against excessive recursions.
1303 LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
1304 if (((ULONG_PTR)&lParam - LowLimit) < PAGE_SIZE )
1305 {
1306 ERR("IntCallWindowsProcW() Exceeded Stack!\n");
1307 return FALSE;
1308 }
1309
1310 if (pWnd)
1311 Dialog = (pWnd->fnid == FNID_DIALOG);
1312 else
1313 Dialog = FALSE;
1314
1315 Hook = BeginIfHookedUserApiHook();
1316 if (Hook)
1317 {
1318 if (!Dialog)
1319 MsgOverride = IsMsgOverride( Msg, &guah.WndProcArray);
1320 else
1321 MsgOverride = IsMsgOverride( Msg, &guah.DlgProcArray);
1322 }
1323
1324 if (IsAnsiProc)
1325 {
1326 UnicodeMsg.hwnd = hWnd;
1327 UnicodeMsg.message = Msg;
1328 UnicodeMsg.wParam = wParam;
1329 UnicodeMsg.lParam = lParam;
1330 if (! MsgiUnicodeToAnsiMessage(hWnd, &AnsiMsg, &UnicodeMsg))
1331 {
1332 goto Exit;
1333 }
1334
1335 if (Hook && MsgOverride)
1336 {
1337 _SEH2_TRY
1338 {
1339 if (!Dialog)
1340 PreResult = guah.PreWndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1341 else
1342 PreResult = guah.PreDefDlgProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1343 }
1344 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1345 {
1346 }
1347 _SEH2_END;
1348 }
1349
1350 if (PreResult) goto Exit;
1351
1352 _SEH2_TRY // wine does this.
1353 {
1354 Result = WndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam);
1355 }
1356 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1357 {
1358 ERR("Got exception when calling Ansi WndProc %p Msg %d \n",WndProc,Msg);
1359 }
1360 _SEH2_END;
1361
1362 if (Hook && MsgOverride)
1363 {
1364 _SEH2_TRY
1365 {
1366 if (!Dialog)
1367 guah.PostWndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1368 else
1369 guah.PostDefDlgProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1370 }
1371 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1372 {
1373 }
1374 _SEH2_END;
1375 }
1376
1377 if (! MsgiUnicodeToAnsiReply(&AnsiMsg, &UnicodeMsg, &Result))
1378 {
1379 goto Exit;
1380 }
1381 }
1382 else
1383 {
1384 if (Hook && MsgOverride)
1385 {
1386 _SEH2_TRY
1387 {
1388 if (!Dialog)
1389 PreResult = guah.PreWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1390 else
1391 PreResult = guah.PreDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1392 }
1393 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1394 {
1395 }
1396 _SEH2_END;
1397 }
1398
1399 if (PreResult) goto Exit;
1400
1401 _SEH2_TRY
1402 {
1403 Result = WndProc(hWnd, Msg, wParam, lParam);
1404 }
1405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1406 {
1407 ERR("Got exception when calling unicode WndProc %p Msg %d \n",WndProc, Msg);
1408 }
1409 _SEH2_END;
1410
1411 if (Hook && MsgOverride)
1412 {
1413 _SEH2_TRY
1414 {
1415 if (!Dialog)
1416 guah.PostWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1417 else
1418 guah.PostDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1419 }
1420 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1421 {
1422 }
1423 _SEH2_END;
1424 }
1425 }
1426
1427 Exit:
1428 if (Hook) EndUserApiHook();
1429 return Result;
1430 }
1431
1432 static LRESULT FASTCALL
1433 IntCallWindowProcA(BOOL IsAnsiProc,
1434 WNDPROC WndProc,
1435 PWND pWnd,
1436 HWND hWnd,
1437 UINT Msg,
1438 WPARAM wParam,
1439 LPARAM lParam)
1440 {
1441 MSG AnsiMsg;
1442 MSG UnicodeMsg;
1443 ULONG_PTR LowLimit;
1444 BOOL Hook = FALSE, MsgOverride = FALSE, Dialog;
1445 LRESULT Result = 0, PreResult = 0;
1446 DWORD Data = 0;
1447
1448 if (WndProc == NULL)
1449 {
1450 WARN("IntCallWindowsProcA() called with WndProc = NULL!\n");
1451 return FALSE;
1452 }
1453
1454 LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
1455 if (((ULONG_PTR)&lParam - LowLimit) < PAGE_SIZE )
1456 {
1457 ERR("IntCallWindowsProcA() Exceeded Stack!\n");
1458 return FALSE;
1459 }
1460
1461 if (pWnd)
1462 Dialog = (pWnd->fnid == FNID_DIALOG);
1463 else
1464 Dialog = FALSE;
1465
1466 Hook = BeginIfHookedUserApiHook();
1467 if (Hook)
1468 {
1469 if (!Dialog)
1470 MsgOverride = IsMsgOverride( Msg, &guah.WndProcArray);
1471 else
1472 MsgOverride = IsMsgOverride( Msg, &guah.DlgProcArray);
1473 }
1474
1475 if (IsAnsiProc)
1476 {
1477 if (Hook && MsgOverride)
1478 {
1479 _SEH2_TRY
1480 {
1481 if (!Dialog)
1482 PreResult = guah.PreWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1483 else
1484 PreResult = guah.PreDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1485 }
1486 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1487 {
1488 }
1489 _SEH2_END;
1490 }
1491
1492 if (PreResult) goto Exit;
1493
1494 _SEH2_TRY
1495 {
1496 Result = WndProc(hWnd, Msg, wParam, lParam);
1497 }
1498 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1499 {
1500 ERR("Got exception when calling Ansi WndProc %p Msg %d \n",WndProc,Msg);
1501 }
1502 _SEH2_END;
1503
1504 if (Hook && MsgOverride)
1505 {
1506 _SEH2_TRY
1507 {
1508 if (!Dialog)
1509 guah.PostWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1510 else
1511 guah.PostDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1512 }
1513 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1514 {
1515 }
1516 _SEH2_END;
1517 }
1518 }
1519 else
1520 {
1521 AnsiMsg.hwnd = hWnd;
1522 AnsiMsg.message = Msg;
1523 AnsiMsg.wParam = wParam;
1524 AnsiMsg.lParam = lParam;
1525 if (! MsgiAnsiToUnicodeMessage(hWnd, &UnicodeMsg, &AnsiMsg))
1526 {
1527 goto Exit;
1528 }
1529
1530 if (Hook && MsgOverride)
1531 {
1532 _SEH2_TRY
1533 {
1534 if (!Dialog)
1535 PreResult = guah.PreWndProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1536 else
1537 PreResult = guah.PreDefDlgProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1538 }
1539 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1540 {
1541 }
1542 _SEH2_END;
1543 }
1544
1545 if (PreResult) goto Exit;
1546
1547 _SEH2_TRY
1548 {
1549 Result = WndProc(UnicodeMsg.hwnd, UnicodeMsg.message,
1550 UnicodeMsg.wParam, UnicodeMsg.lParam);
1551 }
1552 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1553 {
1554 ERR("Got exception when calling unicode WndProc %p Msg %d \n",WndProc, Msg);
1555 }
1556 _SEH2_END;
1557
1558 if (Hook && MsgOverride)
1559 {
1560 _SEH2_TRY
1561 {
1562 if (!Dialog)
1563 guah.PostWndProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1564 else
1565 guah.PostDefDlgProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1566 }
1567 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1568 {
1569 }
1570 _SEH2_END;
1571 }
1572
1573 if (! MsgiAnsiToUnicodeReply(&UnicodeMsg, &AnsiMsg, &Result))
1574 {
1575 goto Exit;
1576 }
1577 }
1578
1579 Exit:
1580 if (Hook) EndUserApiHook();
1581 return Result;
1582 }
1583
1584
1585 static LRESULT WINAPI
1586 IntCallMessageProc(IN PWND Wnd, IN HWND hWnd, IN UINT Msg, IN WPARAM wParam, IN LPARAM lParam, IN BOOL Ansi)
1587 {
1588 WNDPROC WndProc;
1589 BOOL IsAnsi;
1590 PCLS Class;
1591
1592 Class = DesktopPtrToUser(Wnd->pcls);
1593 WndProc = NULL;
1594
1595 if ( Wnd->head.pti != GetW32ThreadInfo())
1596 { // Must be inside the same thread!
1597 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
1598 return 0;
1599 }
1600 /*
1601 This is the message exchange for user32. If there's a need to monitor messages,
1602 do it here!
1603 */
1604 TRACE("HWND %p, MSG %u, WPARAM %p, LPARAM %p, Ansi %d\n", hWnd, Msg, wParam, lParam, Ansi);
1605 // if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON )
1606 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_FIRST )
1607 {
1608 if (Ansi)
1609 {
1610 if (GETPFNCLIENTW(Class->fnid) == Wnd->lpfnWndProc)
1611 WndProc = GETPFNCLIENTA(Class->fnid);
1612 }
1613 else
1614 {
1615 if (GETPFNCLIENTA(Class->fnid) == Wnd->lpfnWndProc)
1616 WndProc = GETPFNCLIENTW(Class->fnid);
1617 }
1618
1619 IsAnsi = Ansi;
1620
1621 if (!WndProc)
1622 {
1623 IsAnsi = !Wnd->Unicode;
1624 WndProc = Wnd->lpfnWndProc;
1625 }
1626 }
1627 else
1628 {
1629 IsAnsi = !Wnd->Unicode;
1630 WndProc = Wnd->lpfnWndProc;
1631 }
1632 /*
1633 Message caller can be Ansi/Unicode and the receiver can be Unicode/Ansi or
1634 the same.
1635 */
1636 if (!Ansi)
1637 return IntCallWindowProcW(IsAnsi, WndProc, Wnd, hWnd, Msg, wParam, lParam);
1638 else
1639 return IntCallWindowProcA(IsAnsi, WndProc, Wnd, hWnd, Msg, wParam, lParam);
1640 }
1641
1642
1643 /*
1644 * @implemented
1645 */
1646 LRESULT WINAPI
1647 CallWindowProcA(WNDPROC lpPrevWndFunc,
1648 HWND hWnd,
1649 UINT Msg,
1650 WPARAM wParam,
1651 LPARAM lParam)
1652 {
1653 PWND pWnd;
1654 PCALLPROCDATA CallProc;
1655
1656 if (lpPrevWndFunc == NULL)
1657 {
1658 WARN("CallWindowProcA: lpPrevWndFunc == NULL!\n");
1659 return 0;
1660 }
1661
1662 pWnd = ValidateHwnd(hWnd);
1663
1664 if (!IsCallProcHandle(lpPrevWndFunc))
1665 return IntCallWindowProcA(TRUE, lpPrevWndFunc, pWnd, hWnd, Msg, wParam, lParam);
1666 else
1667 {
1668 CallProc = ValidateCallProc((HANDLE)lpPrevWndFunc);
1669 if (CallProc != NULL)
1670 {
1671 return IntCallWindowProcA(!(CallProc->wType & UserGetCPDA2U),
1672 CallProc->pfnClientPrevious,
1673 pWnd,
1674 hWnd,
1675 Msg,
1676 wParam,
1677 lParam);
1678 }
1679 else
1680 {
1681 WARN("CallWindowProcA: can not dereference WndProcHandle\n");
1682 return 0;
1683 }
1684 }
1685 }
1686
1687
1688 /*
1689 * @implemented
1690 */
1691 LRESULT WINAPI
1692 CallWindowProcW(WNDPROC lpPrevWndFunc,
1693 HWND hWnd,
1694 UINT Msg,
1695 WPARAM wParam,
1696 LPARAM lParam)
1697 {
1698 PWND pWnd;
1699 PCALLPROCDATA CallProc;
1700
1701 /* FIXME - can the first parameter be NULL? */
1702 if (lpPrevWndFunc == NULL)
1703 {
1704 WARN("CallWindowProcA: lpPrevWndFunc == NULL!\n");
1705 return 0;
1706 }
1707
1708 pWnd = ValidateHwnd(hWnd);
1709
1710 if (!IsCallProcHandle(lpPrevWndFunc))
1711 return IntCallWindowProcW(FALSE, lpPrevWndFunc, pWnd, hWnd, Msg, wParam, lParam);
1712 else
1713 {
1714 CallProc = ValidateCallProc((HANDLE)lpPrevWndFunc);
1715 if (CallProc != NULL)
1716 {
1717 return IntCallWindowProcW(!(CallProc->wType & UserGetCPDA2U),
1718 CallProc->pfnClientPrevious,
1719 pWnd,
1720 hWnd,
1721 Msg,
1722 wParam,
1723 lParam);
1724 }
1725 else
1726 {
1727 WARN("CallWindowProcW: can not dereference WndProcHandle\n");
1728 return 0;
1729 }
1730 }
1731 }
1732
1733
1734 /*
1735 * @implemented
1736 */
1737 LRESULT WINAPI
1738 DispatchMessageA(CONST MSG *lpmsg)
1739 {
1740 LRESULT Ret = 0;
1741 MSG UnicodeMsg;
1742 PWND Wnd;
1743 BOOL Hit = FALSE;
1744
1745 if ( lpmsg->message & ~WM_MAXIMUM )
1746 {
1747 SetLastError( ERROR_INVALID_PARAMETER );
1748 return 0;
1749 }
1750
1751 if (lpmsg->hwnd != NULL)
1752 {
1753 Wnd = ValidateHwnd(lpmsg->hwnd);
1754 if (!Wnd) return 0;
1755 }
1756 else
1757 Wnd = NULL;
1758
1759 if (is_pointer_message(lpmsg->message))
1760 {
1761 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
1762 return 0;
1763 }
1764
1765 if ((lpmsg->message == WM_TIMER || lpmsg->message == WM_SYSTIMER) && lpmsg->lParam != 0)
1766 {
1767 WNDPROC WndProc = (WNDPROC)lpmsg->lParam;
1768
1769 if ( lpmsg->message == WM_SYSTIMER )
1770 return NtUserDispatchMessage( (PMSG)lpmsg );
1771
1772 if (!NtUserValidateTimerCallback(lpmsg->hwnd, lpmsg->wParam, lpmsg->lParam))
1773 {
1774 WARN("Validating Timer Callback failed!\n");
1775 return 0;
1776 }
1777
1778 _SEH2_TRY // wine does this. Hint: Prevents call to another thread....
1779 {
1780 Ret = WndProc(lpmsg->hwnd,
1781 lpmsg->message,
1782 lpmsg->wParam,
1783 GetTickCount());
1784 }
1785 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1786 {
1787 Hit = TRUE;
1788 }
1789 _SEH2_END;
1790 }
1791 else if (Wnd != NULL)
1792 {
1793 if ( (lpmsg->message != WM_PAINT) && !(Wnd->state & WNDS_SERVERSIDEWINDOWPROC) )
1794 {
1795 Ret = IntCallMessageProc(Wnd,
1796 lpmsg->hwnd,
1797 lpmsg->message,
1798 lpmsg->wParam,
1799 lpmsg->lParam,
1800 TRUE);
1801 }
1802 else
1803 {
1804 if (!MsgiAnsiToUnicodeMessage(lpmsg->hwnd, &UnicodeMsg, (LPMSG)lpmsg))
1805 {
1806 return FALSE;
1807 }
1808
1809 Ret = NtUserDispatchMessage(&UnicodeMsg);
1810
1811 if (!MsgiAnsiToUnicodeReply(&UnicodeMsg, (LPMSG)lpmsg, &Ret))
1812 {
1813 return FALSE;
1814 }
1815 }
1816 }
1817
1818 if (Hit)
1819 {
1820 WARN("Exception in Timer Callback WndProcA!\n");
1821 }
1822 return Ret;
1823 }
1824
1825
1826 /*
1827 * @implemented
1828 */
1829 LRESULT WINAPI
1830 DispatchMessageW(CONST MSG *lpmsg)
1831 {
1832 LRESULT Ret = 0;
1833 PWND Wnd;
1834 BOOL Hit = FALSE;
1835
1836 if ( lpmsg->message & ~WM_MAXIMUM )
1837 {
1838 SetLastError( ERROR_INVALID_PARAMETER );
1839 return 0;
1840 }
1841
1842 if (lpmsg->hwnd != NULL)
1843 {
1844 Wnd = ValidateHwnd(lpmsg->hwnd);
1845 if (!Wnd) return 0;
1846 }
1847 else
1848 Wnd = NULL;
1849
1850 if (is_pointer_message(lpmsg->message))
1851 {
1852 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
1853 return 0;
1854 }
1855
1856 if ((lpmsg->message == WM_TIMER || lpmsg->message == WM_SYSTIMER) && lpmsg->lParam != 0)
1857 {
1858 WNDPROC WndProc = (WNDPROC)lpmsg->lParam;
1859
1860 if ( lpmsg->message == WM_SYSTIMER )
1861 return NtUserDispatchMessage( (PMSG) lpmsg );
1862
1863 if (!NtUserValidateTimerCallback(lpmsg->hwnd, lpmsg->wParam, lpmsg->lParam))
1864 {
1865 WARN("Validating Timer Callback failed!\n");
1866 return 0;
1867 }
1868
1869 _SEH2_TRY
1870 {
1871 Ret = WndProc(lpmsg->hwnd,
1872 lpmsg->message,
1873 lpmsg->wParam,
1874 GetTickCount());
1875 }
1876 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1877 {
1878 Hit = TRUE;
1879 }
1880 _SEH2_END;
1881 }
1882 else if (Wnd != NULL)
1883 {
1884 if ( (lpmsg->message != WM_PAINT) && !(Wnd->state & WNDS_SERVERSIDEWINDOWPROC) )
1885 {
1886 Ret = IntCallMessageProc(Wnd,
1887 lpmsg->hwnd,
1888 lpmsg->message,
1889 lpmsg->wParam,
1890 lpmsg->lParam,
1891 FALSE);
1892 }
1893 else
1894 Ret = NtUserDispatchMessage( (PMSG) lpmsg );
1895 }
1896
1897 if (Hit)
1898 {
1899 WARN("Exception in Timer Callback WndProcW!\n");
1900 }
1901 return Ret;
1902 }
1903
1904 static VOID
1905 IntConvertMsgToAnsi(LPMSG lpMsg)
1906 {
1907 CHAR ch[2];
1908 WCHAR wch[2];
1909
1910 switch (lpMsg->message)
1911 {
1912 case WM_CHAR:
1913 case WM_DEADCHAR:
1914 case WM_SYSCHAR:
1915 case WM_SYSDEADCHAR:
1916 case WM_MENUCHAR:
1917 wch[0] = LOWORD(lpMsg->wParam);
1918 wch[1] = HIWORD(lpMsg->wParam);
1919 ch[0] = ch[1] = 0;
1920 WideCharToMultiByte(CP_THREAD_ACP, 0, wch, 2, ch, 2, NULL, NULL);
1921 lpMsg->wParam = MAKEWPARAM(ch[0] | (ch[1] << 8), 0);
1922 break;
1923 }
1924 }
1925
1926 /*
1927 * @implemented
1928 */
1929 BOOL WINAPI
1930 GetMessageA(LPMSG lpMsg,
1931 HWND hWnd,
1932 UINT wMsgFilterMin,
1933 UINT wMsgFilterMax)
1934 {
1935 BOOL Res;
1936
1937 if ( (wMsgFilterMin|wMsgFilterMax) & ~WM_MAXIMUM )
1938 {
1939 SetLastError( ERROR_INVALID_PARAMETER );
1940 return FALSE;
1941 }
1942
1943 Res = NtUserGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
1944 if (-1 == (int) Res)
1945 {
1946 return Res;
1947 }
1948
1949 IntConvertMsgToAnsi(lpMsg);
1950
1951 return Res;
1952 }
1953
1954 /*
1955 * @implemented
1956 */
1957 BOOL WINAPI
1958 GetMessageW(LPMSG lpMsg,
1959 HWND hWnd,
1960 UINT wMsgFilterMin,
1961 UINT wMsgFilterMax)
1962 {
1963 BOOL Res;
1964
1965 if ( (wMsgFilterMin|wMsgFilterMax) & ~WM_MAXIMUM )
1966 {
1967 SetLastError( ERROR_INVALID_PARAMETER );
1968 return FALSE;
1969 }
1970
1971 Res = NtUserGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
1972 if (-1 == (int) Res)
1973 {
1974 return Res;
1975 }
1976
1977 return Res;
1978 }
1979
1980 BOOL WINAPI
1981 PeekMessageWorker( PMSG pMsg,
1982 HWND hWnd,
1983 UINT wMsgFilterMin,
1984 UINT wMsgFilterMax,
1985 UINT wRemoveMsg)
1986 {
1987 PCLIENTINFO pci;
1988 PCLIENTTHREADINFO pcti;
1989 pci = GetWin32ClientInfo();
1990 pcti = pci->pClientThreadInfo;
1991
1992 if (!hWnd && pci && pcti)
1993 {
1994 pci->cSpins++;
1995
1996 if ((pci->cSpins >= 100) && (pci->dwTIFlags & TIF_SPINNING))
1997 { // Yield after 100 spin cycles and ready to swap vinyl.
1998 if (!(pci->dwTIFlags & TIF_WAITFORINPUTIDLE))
1999 { // Not waiting for idle event.
2000 if (!pcti->fsChangeBits && !pcti->fsWakeBits)
2001 { // No messages are available.
2002 if ((GetTickCount() - pcti->tickLastMsgChecked) > 1000)
2003 { // Up the msg read count if over 1 sec.
2004 NtUserGetThreadState(THREADSTATE_UPTIMELASTREAD);
2005 }
2006 pci->cSpins = 0;
2007 ZwYieldExecution();
2008 FIXME("seeSpins!\n");
2009 return FALSE;
2010 }
2011 }
2012 }
2013 }
2014 return NtUserPeekMessage(pMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
2015 }
2016
2017 /*
2018 * @implemented
2019 */
2020 BOOL WINAPI
2021 PeekMessageA(LPMSG lpMsg,
2022 HWND hWnd,
2023 UINT wMsgFilterMin,
2024 UINT wMsgFilterMax,
2025 UINT wRemoveMsg)
2026 {
2027 BOOL Res;
2028
2029 Res = PeekMessageWorker(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
2030 if (-1 == (int) Res || !Res)
2031 {
2032 return FALSE;
2033 }
2034
2035 IntConvertMsgToAnsi(lpMsg);
2036
2037 return Res;
2038 }
2039
2040
2041 /*
2042 * @implemented
2043 */
2044 BOOL
2045 WINAPI
2046 PeekMessageW(
2047 LPMSG lpMsg,
2048 HWND hWnd,
2049 UINT wMsgFilterMin,
2050 UINT wMsgFilterMax,
2051 UINT wRemoveMsg)
2052 {
2053 BOOL Res;
2054
2055 Res = PeekMessageWorker(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
2056 if (-1 == (int) Res || !Res)
2057 {
2058 return FALSE;
2059 }
2060
2061 return Res;
2062 }
2063
2064 /*
2065 * @implemented
2066 */
2067 BOOL
2068 WINAPI
2069 PostMessageA(
2070 HWND hWnd,
2071 UINT Msg,
2072 WPARAM wParam,
2073 LPARAM lParam)
2074 {
2075 LRESULT Ret;
2076
2077 /* Check for combo box or a list box to send names. */
2078 if (Msg == CB_DIR || Msg == LB_DIR)
2079 {
2080 /*
2081 Set DDL_POSTMSGS, so use the PostMessage function to send messages to the
2082 combo/list box. Forces a call like DlgDirListComboBox.
2083 */
2084 //wParam |= DDL_POSTMSGS;
2085 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
2086 }
2087
2088 /* No drop files or current Process, just post message. */
2089 if ( (Msg != WM_DROPFILES) ||
2090 ( NtUserQueryWindow( hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID) ==
2091 PtrToUint(NtCurrentTeb()->ClientId.UniqueProcess) ) )
2092 {
2093 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
2094 }
2095
2096 /* We have drop files and this is not the same process for this window. */
2097
2098 /* Just incase, check wParam for Global memory handle and send size. */
2099 Ret = SendMessageA( hWnd,
2100 WM_COPYGLOBALDATA,
2101 (WPARAM)GlobalSize((HGLOBAL)wParam), // Zero if not a handle.
2102 (LPARAM)wParam); // Send wParam as lParam.
2103
2104 if ( Ret ) return NtUserPostMessage(hWnd, Msg, (WPARAM)Ret, lParam);
2105
2106 return FALSE;
2107 }
2108
2109 /*
2110 * @implemented
2111 */
2112 BOOL
2113 WINAPI
2114 PostMessageW(
2115 HWND hWnd,
2116 UINT Msg,
2117 WPARAM wParam,
2118 LPARAM lParam)
2119 {
2120 LRESULT Ret;
2121
2122 /* Check for combo box or a list box to send names. */
2123 if (Msg == CB_DIR || Msg == LB_DIR)
2124 {
2125 /*
2126 Set DDL_POSTMSGS, so use the PostMessage function to send messages to the
2127 combo/list box. Forces a call like DlgDirListComboBox.
2128 */
2129 //wParam |= DDL_POSTMSGS;
2130 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
2131 }
2132
2133 /* No drop files or current Process, just post message. */
2134 if ( (Msg != WM_DROPFILES) ||
2135 ( NtUserQueryWindow( hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID) ==
2136 PtrToUint(NtCurrentTeb()->ClientId.UniqueProcess) ) )
2137 {
2138 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
2139 }
2140
2141 /* We have drop files and this is not the same process for this window. */
2142
2143 /* Just incase, check wParam for Global memory handle and send size. */
2144 Ret = SendMessageW( hWnd,
2145 WM_COPYGLOBALDATA,
2146 (WPARAM)GlobalSize((HGLOBAL)wParam), // Zero if not a handle.
2147 (LPARAM)wParam); // Send wParam as lParam.
2148
2149 if ( Ret ) return NtUserPostMessage(hWnd, Msg, (WPARAM)Ret, lParam);
2150
2151 return FALSE;
2152 }
2153
2154 /*
2155 * @implemented
2156 */
2157 VOID
2158 WINAPI
2159 PostQuitMessage(
2160 int nExitCode)
2161 {
2162 NtUserxPostQuitMessage(nExitCode);
2163 }
2164
2165
2166 /*
2167 * @implemented
2168 */
2169 BOOL
2170 WINAPI
2171 PostThreadMessageA(
2172 DWORD idThread,
2173 UINT Msg,
2174 WPARAM wParam,
2175 LPARAM lParam)
2176 {
2177 return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
2178 }
2179
2180
2181 /*
2182 * @implemented
2183 */
2184 BOOL
2185 WINAPI
2186 PostThreadMessageW(
2187 DWORD idThread,
2188 UINT Msg,
2189 WPARAM wParam,
2190 LPARAM lParam)
2191 {
2192 return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
2193 }
2194
2195
2196 /*
2197 * @implemented
2198 */
2199 LRESULT WINAPI
2200 SendMessageW(HWND Wnd,
2201 UINT Msg,
2202 WPARAM wParam,
2203 LPARAM lParam)
2204 {
2205 MSG UMMsg, KMMsg;
2206 LRESULT Result;
2207 PWND Window;
2208 PTHREADINFO ti = GetW32ThreadInfo();
2209
2210 if ( Msg & ~WM_MAXIMUM )
2211 {
2212 SetLastError( ERROR_INVALID_PARAMETER );
2213 return 0;
2214 }
2215
2216 if (Wnd != HWND_TOPMOST && Wnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
2217 {
2218 Window = ValidateHwnd(Wnd);
2219
2220 if ( Window != NULL &&
2221 Window->head.pti == ti &&
2222 // !IsThreadHooked(GetWin32ClientInfo()) && // Enable to test message system bug.
2223 !ISITHOOKED(WH_CALLWNDPROC) &&
2224 !ISITHOOKED(WH_CALLWNDPROCRET) &&
2225 !(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
2226 {
2227 /* NOTE: We can directly send messages to the window procedure
2228 if *all* the following conditions are met:
2229
2230 * Window belongs to calling thread
2231 * The calling thread is not being hooked for CallWndProc
2232 * Not calling a server side proc:
2233 Desktop, Switch, ScrollBar, Menu, IconTitle, or hWndMessage
2234 */
2235
2236 return IntCallMessageProc(Window, Wnd, Msg, wParam, lParam, FALSE);
2237 }
2238 }
2239
2240 UMMsg.hwnd = Wnd;
2241 UMMsg.message = Msg;
2242 UMMsg.wParam = wParam;
2243 UMMsg.lParam = lParam;
2244
2245 if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, FALSE))
2246 {
2247 return FALSE;
2248 }
2249
2250 Result = NtUserMessageCall( Wnd,
2251 KMMsg.message,
2252 KMMsg.wParam,
2253 KMMsg.lParam,
2254 (ULONG_PTR)&Result,
2255 FNID_SENDMESSAGE,
2256 FALSE);
2257
2258 MsgiUMToKMCleanup(&UMMsg, &KMMsg);
2259
2260 return Result;
2261 }
2262
2263
2264 /*
2265 * @implemented
2266 */
2267 LRESULT WINAPI
2268 SendMessageA(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
2269 {
2270 MSG AnsiMsg, UcMsg, KMMsg;
2271 LRESULT Result;
2272 PWND Window;
2273 PTHREADINFO ti = GetW32ThreadInfo();
2274
2275 if ( Msg & ~WM_MAXIMUM )
2276 {
2277 SetLastError( ERROR_INVALID_PARAMETER );
2278 return 0;
2279 }
2280
2281 if (Wnd != HWND_TOPMOST && Wnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
2282 {
2283 Window = ValidateHwnd(Wnd);
2284
2285 if ( Window != NULL &&
2286 Window->head.pti == ti &&
2287 // !IsThreadHooked(GetWin32ClientInfo()) && // Enable to test message system bug.
2288 !ISITHOOKED(WH_CALLWNDPROC) &&
2289 !ISITHOOKED(WH_CALLWNDPROCRET) &&
2290 !(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
2291 {
2292 /* NOTE: We can directly send messages to the window procedure
2293 if *all* the following conditions are met:
2294
2295 * Window belongs to calling thread
2296 * The calling thread is not being hooked for CallWndProc
2297 * Not calling a server side proc:
2298 Desktop, Switch, ScrollBar, Menu, IconTitle, or hWndMessage
2299 */
2300
2301 return IntCallMessageProc(Window, Wnd, Msg, wParam, lParam, TRUE);
2302 }
2303 }
2304
2305 AnsiMsg.hwnd = Wnd;
2306 AnsiMsg.message = Msg;
2307 AnsiMsg.wParam = wParam;
2308 AnsiMsg.lParam = lParam;
2309
2310 if (!MsgiAnsiToUnicodeMessage(Wnd, &UcMsg, &AnsiMsg))
2311 {
2312 return FALSE;
2313 }
2314
2315 if (!MsgiUMToKMMessage(&UcMsg, &KMMsg, FALSE))
2316 {
2317 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
2318 return FALSE;
2319 }
2320
2321 Result = NtUserMessageCall( Wnd,
2322 KMMsg.message,
2323 KMMsg.wParam,
2324 KMMsg.lParam,
2325 (ULONG_PTR)&Result,
2326 FNID_SENDMESSAGE,
2327 TRUE);
2328
2329 MsgiUMToKMCleanup(&UcMsg, &KMMsg);
2330 MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result);
2331
2332 return Result;
2333 }
2334
2335 /*
2336 * @implemented
2337 */
2338 BOOL
2339 WINAPI
2340 SendMessageCallbackA(
2341 HWND hWnd,
2342 UINT Msg,
2343 WPARAM wParam,
2344 LPARAM lParam,
2345 SENDASYNCPROC lpCallBack,
2346 ULONG_PTR dwData)
2347 {
2348 BOOL Result;
2349 MSG AnsiMsg, UcMsg;
2350 CALL_BACK_INFO CallBackInfo;
2351
2352 if (is_pointer_message(Msg))
2353 {
2354 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
2355 return FALSE;
2356 }
2357
2358 CallBackInfo.CallBack = lpCallBack;
2359 CallBackInfo.Context = dwData;
2360
2361 AnsiMsg.hwnd = hWnd;
2362 AnsiMsg.message = Msg;
2363 AnsiMsg.wParam = wParam;
2364 AnsiMsg.lParam = lParam;
2365
2366 if (!MsgiAnsiToUnicodeMessage(hWnd, &UcMsg, &AnsiMsg))
2367 {
2368 return FALSE;
2369 }
2370
2371 Result = NtUserMessageCall( hWnd,
2372 UcMsg.message,
2373 UcMsg.wParam,
2374 UcMsg.lParam,
2375 (ULONG_PTR)&CallBackInfo,
2376 FNID_SENDMESSAGECALLBACK,
2377 TRUE);
2378
2379 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
2380
2381 return Result;
2382 }
2383
2384 /*
2385 * @implemented
2386 */
2387 BOOL
2388 WINAPI
2389 SendMessageCallbackW(
2390 HWND hWnd,
2391 UINT Msg,
2392 WPARAM wParam,
2393 LPARAM lParam,
2394 SENDASYNCPROC lpCallBack,
2395 ULONG_PTR dwData)
2396 {
2397 CALL_BACK_INFO CallBackInfo;
2398
2399 if (is_pointer_message(Msg))
2400 {
2401 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
2402 return FALSE;
2403 }
2404
2405 CallBackInfo.CallBack = lpCallBack;
2406 CallBackInfo.Context = dwData;
2407
2408 return NtUserMessageCall(hWnd,
2409 Msg,
2410 wParam,
2411 lParam,
2412 (ULONG_PTR)&CallBackInfo,
2413 FNID_SENDMESSAGECALLBACK,
2414 FALSE);
2415 }
2416
2417 /*
2418 * @implemented
2419 */
2420 LRESULT
2421 WINAPI
2422 SendMessageTimeoutA(
2423 HWND hWnd,
2424 UINT Msg,
2425 WPARAM wParam,
2426 LPARAM lParam,
2427 UINT fuFlags,
2428 UINT uTimeout,
2429 PDWORD_PTR lpdwResult)
2430 {
2431 MSG AnsiMsg, UcMsg;
2432 LRESULT Result;
2433 DOSENDMESSAGE dsm;
2434 PWND Window;
2435 PTHREADINFO ti = GetW32ThreadInfo();
2436
2437 if ( Msg & ~WM_MAXIMUM || fuFlags & ~(SMTO_NOTIMEOUTIFNOTHUNG|SMTO_ABORTIFHUNG|SMTO_BLOCK))
2438 {
2439 SetLastError( ERROR_INVALID_PARAMETER );
2440 return 0;
2441 }
2442
2443 if (lpdwResult) *lpdwResult = 0;
2444
2445 //// This is due to message system bug.
2446 if (hWnd != HWND_TOPMOST && hWnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
2447 {
2448 Window = ValidateHwnd(hWnd);
2449
2450 if ( Window != NULL &&
2451 Window->head.pti == ti &&
2452 !ISITHOOKED(WH_CALLWNDPROC) &&
2453 !ISITHOOKED(WH_CALLWNDPROCRET) &&
2454 !(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
2455 {
2456 Result = IntCallMessageProc(Window, hWnd, Msg, wParam, lParam, TRUE);
2457 if (lpdwResult) *lpdwResult = Result;
2458 return TRUE;
2459 }
2460 }
2461 ////
2462 SPY_EnterMessage(SPY_SENDMESSAGE, hWnd, Msg, wParam, lParam);
2463
2464 dsm.uFlags = fuFlags;
2465 dsm.uTimeout = uTimeout;
2466
2467 AnsiMsg.hwnd = hWnd;
2468 AnsiMsg.message = Msg;
2469 AnsiMsg.wParam = wParam;
2470 AnsiMsg.lParam = lParam;
2471
2472 if (! MsgiAnsiToUnicodeMessage(hWnd, &UcMsg, &AnsiMsg))
2473 {
2474 return FALSE;
2475 }
2476
2477 Result = NtUserMessageCall( hWnd,
2478 UcMsg.message,
2479 UcMsg.wParam,
2480 UcMsg.lParam,
2481 (ULONG_PTR)&dsm,
2482 FNID_SENDMESSAGEWTOOPTION,
2483 TRUE);
2484
2485 MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result);
2486
2487 if (lpdwResult) *lpdwResult = dsm.Result;
2488
2489 SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
2490
2491 return Result;
2492 }
2493
2494
2495 /*
2496 * @implemented
2497 */
2498 LRESULT
2499 WINAPI
2500 SendMessageTimeoutW(
2501 HWND hWnd,
2502 UINT Msg,
2503 WPARAM wParam,
2504 LPARAM lParam,
2505 UINT fuFlags,
2506 UINT uTimeout,
2507 PDWORD_PTR lpdwResult)
2508 {
2509 LRESULT Result;
2510 DOSENDMESSAGE dsm;
2511 PWND Window;
2512 PTHREADINFO ti = GetW32ThreadInfo();
2513
2514 if ( Msg & ~WM_MAXIMUM || fuFlags & ~(SMTO_NOTIMEOUTIFNOTHUNG|SMTO_ABORTIFHUNG|SMTO_BLOCK))
2515 {
2516 SetLastError( ERROR_INVALID_PARAMETER );
2517 return 0;
2518 }
2519
2520 if (lpdwResult) *lpdwResult = 0;
2521
2522 //// This is due to message system bug.
2523 if (hWnd != HWND_TOPMOST && hWnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
2524 {
2525 Window = ValidateHwnd(hWnd);
2526
2527 if ( Window != NULL &&
2528 Window->head.pti == ti &&
2529 !ISITHOOKED(WH_CALLWNDPROC) &&
2530 !ISITHOOKED(WH_CALLWNDPROCRET) &&
2531 !(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
2532 {
2533 Result = IntCallMessageProc(Window, hWnd, Msg, wParam, lParam, FALSE);
2534 if (lpdwResult) *lpdwResult = Result;
2535 return TRUE;
2536 }
2537 }
2538 ////
2539 SPY_EnterMessage(SPY_SENDMESSAGE, hWnd, Msg, wParam, lParam);
2540
2541 dsm.uFlags = fuFlags;
2542 dsm.uTimeout = uTimeout;
2543
2544 Result = NtUserMessageCall( hWnd,
2545 Msg,
2546 wParam,
2547 lParam,
2548 (ULONG_PTR)&dsm,
2549 FNID_SENDMESSAGEWTOOPTION,
2550 FALSE);
2551
2552 if (lpdwResult) *lpdwResult = dsm.Result;
2553
2554 SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
2555
2556 return Result;
2557 }
2558
2559 /*
2560 * @implemented
2561 */
2562 BOOL
2563 WINAPI
2564 SendNotifyMessageA(
2565 HWND hWnd,
2566 UINT Msg,
2567 WPARAM wParam,
2568 LPARAM lParam)
2569 {
2570 BOOL Ret;
2571 MSG AnsiMsg, UcMsg;
2572
2573 if (is_pointer_message(Msg))
2574 {
2575 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
2576 return FALSE;
2577 }
2578
2579 AnsiMsg.hwnd = hWnd;
2580 AnsiMsg.message = Msg;
2581 AnsiMsg.wParam = wParam;
2582 AnsiMsg.lParam = lParam;
2583 if (! MsgiAnsiToUnicodeMessage(hWnd, &UcMsg, &AnsiMsg))
2584 {
2585 return FALSE;
2586 }
2587 Ret = SendNotifyMessageW(hWnd, UcMsg.message, UcMsg.wParam, UcMsg.lParam);
2588
2589 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
2590
2591 return Ret;
2592 }
2593
2594 /*
2595 * @implemented
2596 */
2597 BOOL
2598 WINAPI
2599 SendNotifyMessageW(
2600 HWND hWnd,
2601 UINT Msg,
2602 WPARAM wParam,
2603 LPARAM lParam)
2604 {
2605 MSG UMMsg, KMMsg;
2606 LRESULT Result;
2607
2608 if (is_pointer_message(Msg))
2609 {
2610 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
2611 return FALSE;
2612 }
2613
2614 UMMsg.hwnd = hWnd;
2615 UMMsg.message = Msg;
2616 UMMsg.wParam = wParam;
2617 UMMsg.lParam = lParam;
2618 if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, TRUE))
2619 {
2620 return FALSE;
2621 }
2622 Result = NtUserMessageCall( hWnd,
2623 KMMsg.message,
2624 KMMsg.wParam,
2625 KMMsg.lParam,
2626 0,
2627 FNID_SENDNOTIFYMESSAGE,
2628 FALSE);
2629
2630 MsgiUMToKMCleanup(&UMMsg, &KMMsg);
2631
2632 return Result;
2633 }
2634
2635 /*
2636 * @implemented
2637 */
2638 BOOL WINAPI
2639 TranslateMessageEx(CONST MSG *lpMsg, UINT Flags)
2640 {
2641 switch (lpMsg->message)
2642 {
2643 case WM_KEYDOWN:
2644 case WM_KEYUP:
2645 case WM_SYSKEYDOWN:
2646 case WM_SYSKEYUP:
2647 return(NtUserTranslateMessage((LPMSG)lpMsg, Flags));
2648
2649 default:
2650 if ( lpMsg->message & ~WM_MAXIMUM )
2651 SetLastError(ERROR_INVALID_PARAMETER);
2652 return FALSE;
2653 }
2654 }
2655
2656
2657 /*
2658 * @implemented
2659 */
2660 BOOL WINAPI
2661 TranslateMessage(CONST MSG *lpMsg)
2662 {
2663 BOOL Ret = FALSE;
2664
2665 // Ref: msdn ImmGetVirtualKey:
2666 // http://msdn.microsoft.com/en-us/library/aa912145.aspx
2667 /*
2668 if ( (LOWORD(lpMsg->wParam) != VK_PROCESSKEY) ||
2669 !(Ret = IMM_ImmTranslateMessage( lpMsg->hwnd,
2670 lpMsg->message,
2671 lpMsg->wParam,
2672 lpMsg->lParam)) )*/
2673 {
2674 Ret = TranslateMessageEx((LPMSG)lpMsg, 0);
2675 }
2676 return Ret;
2677 }
2678
2679
2680 /*
2681 * @implemented
2682 */
2683 UINT WINAPI
2684 RegisterWindowMessageA(LPCSTR lpString)
2685 {
2686 UNICODE_STRING String;
2687 BOOLEAN Result;
2688 UINT Atom;
2689
2690 Result = RtlCreateUnicodeStringFromAsciiz(&String, (PCSZ)lpString);
2691 if (!Result)
2692 {
2693 return(0);
2694 }
2695 Atom = NtUserRegisterWindowMessage(&String);
2696 RtlFreeUnicodeString(&String);
2697 return(Atom);
2698 }
2699
2700
2701 /*
2702 * @implemented
2703 */
2704 UINT WINAPI
2705 RegisterWindowMessageW(LPCWSTR lpString)
2706 {
2707 UNICODE_STRING String;
2708
2709 RtlInitUnicodeString(&String, lpString);
2710 return(NtUserRegisterWindowMessage(&String));
2711 }
2712
2713 /*
2714 * @implemented
2715 */
2716 HWND WINAPI
2717 GetCapture(VOID)
2718 {
2719 return (HWND)NtUserGetThreadState(THREADSTATE_CAPTUREWINDOW);
2720 }
2721
2722 /*
2723 * @implemented
2724 */
2725 BOOL WINAPI
2726 ReleaseCapture(VOID)
2727 {
2728 return NtUserxReleaseCapture();
2729 }
2730
2731
2732 /*
2733 * @implemented
2734 */
2735 DWORD
2736 WINAPI
2737 RealGetQueueStatus(UINT flags)
2738 {
2739 #define QS_TEMPALLINPUT 255 // ATM, do not support QS_RAWINPUT
2740 if (flags & ~(QS_SMRESULT|QS_ALLPOSTMESSAGE|QS_TEMPALLINPUT))
2741 {
2742 SetLastError( ERROR_INVALID_FLAGS );
2743 return 0;
2744 }
2745 return NtUserxGetQueueStatus(flags);
2746 }
2747
2748
2749 /*
2750 * @implemented
2751 */
2752 BOOL WINAPI GetInputState(VOID)
2753 {
2754 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
2755
2756 if ((!pcti) || (pcti->fsChangeBits & (QS_KEY|QS_MOUSEBUTTON)))
2757 return (BOOL)NtUserGetThreadState(THREADSTATE_GETINPUTSTATE);
2758
2759 return FALSE;
2760 }
2761
2762
2763 NTSTATUS WINAPI
2764 User32CallWindowProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
2765 {
2766 PWINDOWPROC_CALLBACK_ARGUMENTS CallbackArgs;
2767 MSG KMMsg, UMMsg;
2768 PWND pWnd = NULL;
2769 ULONG_PTR LowLimit;
2770 PCLIENTINFO pci = GetWin32ClientInfo();
2771
2772 /* Make sure we don't try to access mem beyond what we were given */
2773 if (ArgumentLength < sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
2774 {
2775 return STATUS_INFO_LENGTH_MISMATCH;
2776 }
2777
2778 LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
2779 if (((ULONG_PTR)&ArgumentLength - LowLimit) < PAGE_SIZE )
2780 {
2781 ERR("Callback from Win32k Exceeded Stack!\n");
2782 return STATUS_BAD_STACK;
2783 }
2784
2785 CallbackArgs = (PWINDOWPROC_CALLBACK_ARGUMENTS) Arguments;
2786 KMMsg.hwnd = CallbackArgs->Wnd;
2787 KMMsg.message = CallbackArgs->Msg;
2788 KMMsg.wParam = CallbackArgs->wParam;
2789 /* Check if lParam is really a pointer and adjust it if it is */
2790 if (0 <= CallbackArgs->lParamBufferSize)
2791 {
2792 if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)
2793 + CallbackArgs->lParamBufferSize)
2794 {
2795 return STATUS_INFO_LENGTH_MISMATCH;
2796 }
2797 KMMsg.lParam = (LPARAM) ((char *) CallbackArgs + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS));
2798 }
2799 else
2800 {
2801 if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
2802 {
2803 return STATUS_INFO_LENGTH_MISMATCH;
2804 }
2805 KMMsg.lParam = CallbackArgs->lParam;
2806 }
2807
2808 if (WM_NCCALCSIZE == CallbackArgs->Msg && CallbackArgs->wParam)
2809 {
2810 NCCALCSIZE_PARAMS *Params = (NCCALCSIZE_PARAMS *) KMMsg.lParam;
2811 Params->lppos = (PWINDOWPOS) (Params + 1);
2812 }
2813
2814 if (! MsgiKMToUMMessage(&KMMsg, &UMMsg))
2815 {
2816 }
2817
2818 if (pci->CallbackWnd.hWnd == UMMsg.hwnd)
2819 pWnd = pci->CallbackWnd.pWnd;
2820
2821 CallbackArgs->Result = IntCallWindowProcW( CallbackArgs->IsAnsiProc,
2822 CallbackArgs->Proc,
2823 pWnd,
2824 UMMsg.hwnd,
2825 UMMsg.message,
2826 UMMsg.wParam,
2827 UMMsg.lParam);
2828
2829 if (! MsgiKMToUMReply(&KMMsg, &UMMsg, &CallbackArgs->Result))
2830 {
2831 }
2832
2833 return ZwCallbackReturn(CallbackArgs, ArgumentLength, STATUS_SUCCESS);
2834 }
2835
2836 /*
2837 * @implemented
2838 */
2839 BOOL WINAPI SetMessageQueue(int cMessagesMax)
2840 {
2841 /* Function does nothing on 32 bit windows */
2842 return TRUE;
2843 }
2844 typedef DWORD (WINAPI * RealGetQueueStatusProc)(UINT flags);
2845 typedef DWORD (WINAPI * RealMsgWaitForMultipleObjectsExProc)(DWORD nCount, CONST HANDLE *lpHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags);
2846 typedef BOOL (WINAPI * RealInternalGetMessageProc)(LPMSG,HWND,UINT,UINT,UINT,BOOL);
2847 typedef BOOL (WINAPI * RealWaitMessageExProc)(DWORD,UINT);
2848
2849 typedef struct _USER_MESSAGE_PUMP_ADDRESSES {
2850 DWORD cbSize;
2851 RealInternalGetMessageProc NtUserRealInternalGetMessage;
2852 RealWaitMessageExProc NtUserRealWaitMessageEx;
2853 RealGetQueueStatusProc RealGetQueueStatus;
2854 RealMsgWaitForMultipleObjectsExProc RealMsgWaitForMultipleObjectsEx;
2855 } USER_MESSAGE_PUMP_ADDRESSES, * PUSER_MESSAGE_PUMP_ADDRESSES;
2856
2857 DWORD
2858 WINAPI
2859 RealMsgWaitForMultipleObjectsEx(
2860 DWORD nCount,
2861 CONST HANDLE *pHandles,
2862 DWORD dwMilliseconds,
2863 DWORD dwWakeMask,
2864 DWORD dwFlags);
2865
2866 typedef BOOL (WINAPI * MESSAGEPUMPHOOKPROC)(BOOL Unregistering,PUSER_MESSAGE_PUMP_ADDRESSES MessagePumpAddresses);
2867
2868 CRITICAL_SECTION gcsMPH;
2869 MESSAGEPUMPHOOKPROC gpfnInitMPH;
2870 DWORD gcLoadMPH = 0;
2871 USER_MESSAGE_PUMP_ADDRESSES gmph = {sizeof(USER_MESSAGE_PUMP_ADDRESSES),
2872 NtUserRealInternalGetMessage,
2873 NtUserRealWaitMessageEx,
2874 RealGetQueueStatus,
2875 RealMsgWaitForMultipleObjectsEx
2876 };
2877
2878 DWORD gfMessagePumpHook = 0;
2879
2880 BOOL WINAPI IsInsideMessagePumpHook()
2881 { // FF uses this and polls it when Min/Max
2882 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
2883 return (gfMessagePumpHook && pcti && (pcti->dwcPumpHook > 0));
2884 }
2885
2886 void WINAPI ResetMessagePumpHook(PUSER_MESSAGE_PUMP_ADDRESSES Addresses)
2887 {
2888 Addresses->cbSize = sizeof(USER_MESSAGE_PUMP_ADDRESSES);
2889 Addresses->NtUserRealInternalGetMessage = NtUserRealInternalGetMessage;
2890 Addresses->NtUserRealWaitMessageEx = NtUserRealWaitMessageEx;
2891 Addresses->RealGetQueueStatus = RealGetQueueStatus;
2892 Addresses->RealMsgWaitForMultipleObjectsEx = RealMsgWaitForMultipleObjectsEx;
2893 }
2894
2895 BOOL WINAPI RegisterMessagePumpHook(MESSAGEPUMPHOOKPROC Hook)
2896 {
2897 EnterCriticalSection(&gcsMPH);
2898 if(!Hook) {
2899 SetLastError(ERROR_INVALID_PARAMETER);
2900 LeaveCriticalSection(&gcsMPH);
2901 return FALSE;
2902 }
2903 if(!gcLoadMPH) {
2904 USER_MESSAGE_PUMP_ADDRESSES Addresses;
2905 gpfnInitMPH = Hook;
2906 ResetMessagePumpHook(&Addresses);
2907 if(!Hook(FALSE, &Addresses) || !Addresses.cbSize) {
2908 LeaveCriticalSection(&gcsMPH);
2909 return FALSE;
2910 }
2911 memcpy(&gmph, &Addresses, Addresses.cbSize);
2912 } else {
2913 if(gpfnInitMPH != Hook) {
2914 LeaveCriticalSection(&gcsMPH);
2915 return FALSE;
2916 }
2917 }
2918 if(NtUserxInitMessagePump()) {
2919 LeaveCriticalSection(&gcsMPH);
2920 return FALSE;
2921 }
2922 if (!gcLoadMPH++) {
2923 InterlockedExchange((PLONG)&gfMessagePumpHook, 1);
2924 }
2925 LeaveCriticalSection(&gcsMPH);
2926 return TRUE;
2927 }
2928
2929 BOOL WINAPI UnregisterMessagePumpHook(VOID)
2930 {
2931 EnterCriticalSection(&gcsMPH);
2932 if(gcLoadMPH > 0) {
2933 if(NtUserxUnInitMessagePump()) {
2934 gcLoadMPH--;
2935 if(!gcLoadMPH) {
2936 InterlockedExchange((PLONG)&gfMessagePumpHook, 0);
2937 gpfnInitMPH(TRUE, NULL);
2938 ResetMessagePumpHook(&gmph);
2939 gpfnInitMPH = 0;
2940 }
2941 LeaveCriticalSection(&gcsMPH);
2942 return TRUE;
2943 }
2944 }
2945 LeaveCriticalSection(&gcsMPH);
2946 return FALSE;
2947 }
2948
2949 DWORD WINAPI GetQueueStatus(UINT flags)
2950 {
2951 return IsInsideMessagePumpHook() ? gmph.RealGetQueueStatus(flags) : RealGetQueueStatus(flags);
2952 }
2953
2954 /**
2955 * @name RealMsgWaitForMultipleObjectsEx
2956 *
2957 * Wait either for either message arrival or for one of the passed events
2958 * to be signalled.
2959 *
2960 * @param nCount
2961 * Number of handles in the pHandles array.
2962 * @param pHandles
2963 * Handles of events to wait for.
2964 * @param dwMilliseconds
2965 * Timeout interval.
2966 * @param dwWakeMask
2967 * Mask specifying on which message events we should wakeup.
2968 * @param dwFlags
2969 * Wait type (see MWMO_* constants).
2970 *
2971 * @implemented
2972 */
2973
2974 DWORD WINAPI
2975 RealMsgWaitForMultipleObjectsEx(
2976 DWORD nCount,
2977 const HANDLE *pHandles,
2978 DWORD dwMilliseconds,
2979 DWORD dwWakeMask,
2980 DWORD dwFlags)
2981 {
2982 LPHANDLE RealHandles;
2983 HANDLE MessageQueueHandle;
2984 DWORD Result;
2985 PCLIENTINFO pci;
2986 PCLIENTTHREADINFO pcti;
2987
2988 if (dwFlags & ~(MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE))
2989 {
2990 SetLastError(ERROR_INVALID_PARAMETER);
2991 return WAIT_FAILED;
2992 }
2993
2994 pci = GetWin32ClientInfo();
2995 if (!pci) return WAIT_FAILED;
2996
2997 pcti = pci->pClientThreadInfo;
2998 if (pcti && ( !nCount || !(dwFlags & MWMO_WAITALL) ))
2999 {
3000 if ( (pcti->fsChangeBits & LOWORD(dwWakeMask)) ||
3001 ( (dwFlags & MWMO_INPUTAVAILABLE) && (pcti->fsWakeBits & LOWORD(dwWakeMask)) ) )
3002 {
3003 //FIXME("Chg 0x%x Wake 0x%x Mask 0x%x nCnt %d\n",pcti->fsChangeBits, pcti->fsWakeBits, dwWakeMask, nCount);
3004 return nCount;
3005 }
3006 }
3007
3008 MessageQueueHandle = NtUserxMsqSetWakeMask(MAKELONG(dwWakeMask, dwFlags));
3009 if (MessageQueueHandle == NULL)
3010 {
3011 SetLastError(0); /* ? */
3012 return WAIT_FAILED;
3013 }
3014
3015 RealHandles = HeapAlloc(GetProcessHeap(), 0, (nCount + 1) * sizeof(HANDLE));
3016 if (RealHandles == NULL)
3017 {
3018 NtUserxMsqClearWakeMask();
3019 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3020 return WAIT_FAILED;
3021 }
3022
3023 RtlCopyMemory(RealHandles, pHandles, nCount * sizeof(HANDLE));
3024 RealHandles[nCount] = MessageQueueHandle;
3025
3026 Result = WaitForMultipleObjectsEx(nCount + 1, RealHandles,
3027 dwFlags & MWMO_WAITALL,
3028 dwMilliseconds, dwFlags & MWMO_ALERTABLE);
3029
3030 HeapFree(GetProcessHeap(), 0, RealHandles);
3031 NtUserxMsqClearWakeMask();
3032 //FIXME("Result 0X%x\n",Result);
3033 return Result;
3034 }
3035
3036 /*
3037 * @implemented
3038 */
3039 DWORD WINAPI
3040 MsgWaitForMultipleObjectsEx(
3041 DWORD nCount,
3042 CONST HANDLE *lpHandles,
3043 DWORD dwMilliseconds,
3044 DWORD dwWakeMask,
3045 DWORD dwFlags)
3046 {
3047 return IsInsideMessagePumpHook() ? gmph.RealMsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds, dwWakeMask, dwFlags) : RealMsgWaitForMultipleObjectsEx(nCount, lpHandles,dwMilliseconds, dwWakeMask, dwFlags);
3048 }
3049
3050 /*
3051 * @implemented
3052 */
3053 DWORD WINAPI
3054 MsgWaitForMultipleObjects(
3055 DWORD nCount,
3056 CONST HANDLE *lpHandles,
3057 BOOL fWaitAll,
3058 DWORD dwMilliseconds,
3059 DWORD dwWakeMask)
3060 {
3061 return MsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds,
3062 dwWakeMask, fWaitAll ? MWMO_WAITALL : 0);
3063 }
3064
3065
3066 BOOL FASTCALL MessageInit(VOID)
3067 {
3068 InitializeCriticalSection(&DdeCrst);
3069 InitializeCriticalSection(&gcsMPH);
3070
3071 return TRUE;
3072 }
3073
3074 VOID FASTCALL MessageCleanup(VOID)
3075 {
3076 DeleteCriticalSection(&DdeCrst);
3077 DeleteCriticalSection(&gcsMPH);
3078 }
3079
3080 /*
3081 * @implemented
3082 */
3083 BOOL WINAPI
3084 IsDialogMessageA( HWND hwndDlg, LPMSG pmsg )
3085 {
3086 MSG msg = *pmsg;
3087 msg.wParam = map_wparam_AtoW( msg.message, msg.wParam );
3088 return IsDialogMessageW( hwndDlg, &msg );
3089 }
3090
3091 LONG
3092 WINAPI
3093 IntBroadcastSystemMessage(
3094 DWORD dwflags,
3095 LPDWORD lpdwRecipients,
3096 UINT uiMessage,
3097 WPARAM wParam,
3098 LPARAM lParam,
3099 PBSMINFO pBSMInfo,
3100 BOOL Ansi)
3101 {
3102 BROADCASTPARM parm;
3103 DWORD recips = BSM_ALLCOMPONENTS;
3104 BOOL ret = -1; // Set to return fail
3105 static const DWORD all_flags = ( BSF_QUERY | BSF_IGNORECURRENTTASK | BSF_FLUSHDISK | BSF_NOHANG
3106 | BSF_POSTMESSAGE | BSF_FORCEIFHUNG | BSF_NOTIMEOUTIFNOTHUNG
3107 | BSF_ALLOWSFW | BSF_SENDNOTIFYMESSAGE | BSF_RETURNHDESK | BSF_LUID );
3108
3109 if ((dwflags & ~all_flags) ||
3110 (!pBSMInfo && (dwflags & (BSF_RETURNHDESK|BSF_LUID))) )
3111 {
3112 SetLastError(ERROR_INVALID_PARAMETER);
3113 return 0;
3114 }
3115
3116 if(uiMessage >= WM_USER && uiMessage < 0xC000)
3117 {
3118 SetLastError(ERROR_INVALID_PARAMETER);
3119 return 0;
3120 }
3121
3122 if (dwflags & BSF_FORCEIFHUNG) dwflags |= BSF_NOHANG;
3123
3124 if (dwflags & BSF_QUERY) dwflags &= ~BSF_SENDNOTIFYMESSAGE|BSF_POSTMESSAGE;
3125
3126 if (!lpdwRecipients)
3127 lpdwRecipients = &recips;
3128
3129 if (*lpdwRecipients & ~(BSM_APPLICATIONS|BSM_ALLDESKTOPS|BSM_INSTALLABLEDRIVERS|BSM_NETDRIVER|BSM_VXDS))
3130 {
3131 SetLastError(ERROR_INVALID_PARAMETER);
3132 return 0;
3133 }
3134
3135 if ( pBSMInfo && (dwflags & BSF_QUERY) )
3136 {
3137 if (pBSMInfo->cbSize != sizeof(BSMINFO))
3138 {
3139 SetLastError(ERROR_INVALID_PARAMETER);
3140 return 0;
3141 }
3142 }
3143
3144 parm.hDesk = NULL;
3145 parm.hWnd = NULL;
3146 parm.flags = dwflags;
3147 parm.recipients = *lpdwRecipients;
3148
3149 if (dwflags & BSF_LUID) parm.luid = pBSMInfo->luid;
3150
3151 ret = NtUserMessageCall(GetDesktopWindow(),
3152 uiMessage,
3153 wParam,
3154 lParam,
3155 (ULONG_PTR)&parm,
3156 FNID_BROADCASTSYSTEMMESSAGE,
3157 Ansi);
3158
3159 if (!ret)
3160 {
3161 if ( pBSMInfo && (dwflags & BSF_QUERY) )
3162 {
3163 pBSMInfo->hdesk = parm.hDesk;
3164 pBSMInfo->hwnd = parm.hWnd;
3165 }
3166 }
3167 return ret;
3168 }
3169
3170 /*
3171 * @implemented
3172 */
3173 LONG
3174 WINAPI
3175 BroadcastSystemMessageA(
3176 DWORD dwFlags,
3177 LPDWORD lpdwRecipients,
3178 UINT uiMessage,
3179 WPARAM wParam,
3180 LPARAM lParam)
3181 {
3182 return IntBroadcastSystemMessage( dwFlags, lpdwRecipients, uiMessage, wParam, lParam, NULL, TRUE );
3183 }
3184
3185 /*
3186 * @implemented
3187 */
3188 LONG
3189 WINAPI
3190 BroadcastSystemMessageW(
3191 DWORD dwFlags,
3192 LPDWORD lpdwRecipients,
3193 UINT uiMessage,
3194 WPARAM wParam,
3195 LPARAM lParam)
3196 {
3197 return IntBroadcastSystemMessage( dwFlags, lpdwRecipients, uiMessage, wParam, lParam, NULL, FALSE );
3198 }
3199
3200 /*
3201 * @implemented
3202 */
3203 LONG
3204 WINAPI
3205 BroadcastSystemMessageExA(
3206 DWORD dwflags,
3207 LPDWORD lpdwRecipients,
3208 UINT uiMessage,
3209 WPARAM wParam,
3210 LPARAM lParam,
3211 PBSMINFO pBSMInfo)
3212 {
3213 return IntBroadcastSystemMessage( dwflags, lpdwRecipients, uiMessage, wParam, lParam , pBSMInfo, TRUE );
3214 }
3215
3216 /*
3217 * @implemented
3218 */
3219 LONG
3220 WINAPI
3221 BroadcastSystemMessageExW(
3222 DWORD dwflags,
3223 LPDWORD lpdwRecipients,
3224 UINT uiMessage,
3225 WPARAM wParam,
3226 LPARAM lParam,
3227 PBSMINFO pBSMInfo)
3228 {
3229 return IntBroadcastSystemMessage( dwflags, lpdwRecipients, uiMessage, wParam, lParam , pBSMInfo, FALSE );
3230 }
3231