[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 mdi_cs;
763 CREATESTRUCTA* CsA;
764 CREATESTRUCTW* CsW;
765 NTSTATUS Status;
766
767 CsW = (CREATESTRUCTW*)(UnicodeMsg->lParam);
768 CsA = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(CREATESTRUCTA));
769 if (NULL == CsA)
770 {
771 return FALSE;
772 }
773 memcpy(CsA, CsW, sizeof(CREATESTRUCTW));
774
775 RtlInitUnicodeString(&UnicodeString, CsW->lpszName);
776 Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
777 if (! NT_SUCCESS(Status))
778 {
779 RtlFreeHeap(GetProcessHeap(), 0, CsA);
780 return FALSE;
781 }
782 CsA->lpszName = AnsiString.Buffer;
783 if (HIWORD((ULONG_PTR)CsW->lpszClass) != 0)
784 {
785 RtlInitUnicodeString(&UnicodeString, CsW->lpszClass);
786 Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
787 if (! NT_SUCCESS(Status))
788 {
789 RtlInitAnsiString(&AnsiString, CsA->lpszName);
790 RtlFreeAnsiString(&AnsiString);
791 RtlFreeHeap(GetProcessHeap(), 0, CsA);
792 return FALSE;
793 }
794 CsA->lpszClass = AnsiString.Buffer;
795 }
796
797 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
798 {
799 mdi_cs = *(MDICREATESTRUCTA *)CsW->lpCreateParams;
800 mdi_cs.szTitle = CsA->lpszName;
801 mdi_cs.szClass = CsA->lpszClass;
802 CsA->lpCreateParams = &mdi_cs;
803 }
804
805 AnsiMsg->lParam = (LPARAM)CsA;
806 break;
807 }
808 case WM_GETTEXT:
809 {
810 /* Ansi string might contain MBCS chars so we need 2 * the number of chars */
811 AnsiMsg->wParam = UnicodeMsg->wParam * 2;
812 AnsiMsg->lParam = (LPARAM) RtlAllocateHeap(GetProcessHeap(), 0, AnsiMsg->wParam);
813 if (NULL == (PVOID) AnsiMsg->lParam)
814 {
815 return FALSE;
816 }
817 break;
818 }
819 case WM_SETTEXT:
820 case CB_DIR:
821 case LB_DIR:
822 case LB_ADDFILE:
823 {
824 RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam);
825 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
826 &UnicodeString,
827 TRUE)))
828 {
829 return FALSE;
830 }
831 AnsiMsg->lParam = (LPARAM) AnsiString.Buffer;
832 break;
833 }
834
835 case LB_ADDSTRING:
836 case LB_ADDSTRING_LOWER:
837 case LB_ADDSTRING_UPPER:
838 case LB_INSERTSTRING:
839 case LB_INSERTSTRING_UPPER:
840 case LB_INSERTSTRING_LOWER:
841 case LB_FINDSTRING:
842 case LB_FINDSTRINGEXACT:
843 case LB_SELECTSTRING:
844 {
845 if (listbox_has_strings(AnsiMsg->hwnd))
846 {
847 RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam);
848 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
849 &UnicodeString,
850 TRUE)))
851 {
852 return FALSE;
853 }
854 AnsiMsg->lParam = (LPARAM) AnsiString.Buffer;
855 }
856 break;
857 }
858
859 case CB_ADDSTRING:
860 case CB_INSERTSTRING:
861 case CB_FINDSTRING:
862 case CB_FINDSTRINGEXACT:
863 case CB_SELECTSTRING:
864 {
865 if (combobox_has_strings(AnsiMsg->hwnd))
866 {
867 RtlInitUnicodeString(&UnicodeString, (PWSTR) UnicodeMsg->lParam);
868 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
869 &UnicodeString,
870 TRUE)))
871 {
872 return FALSE;
873 }
874 AnsiMsg->lParam = (LPARAM) AnsiString.Buffer;
875 }
876 break;
877 }
878
879 case WM_MDICREATE:
880 {
881 MDICREATESTRUCTA *cs =
882 (MDICREATESTRUCTA *)HeapAlloc(GetProcessHeap(), 0, sizeof(*cs));
883
884 if (!cs)
885 {
886 return FALSE;
887 }
888
889 *cs = *(MDICREATESTRUCTA *)UnicodeMsg->lParam;
890
891 if (!IS_ATOM(cs->szClass))
892 {
893 RtlInitUnicodeString(&UnicodeString, (LPCWSTR)cs->szClass);
894 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
895 &UnicodeString,
896 TRUE)))
897 {
898 HeapFree(GetProcessHeap(), 0, cs);
899 return FALSE;
900 }
901 cs->szClass = AnsiString.Buffer;
902 }
903
904 RtlInitUnicodeString(&UnicodeString, (LPCWSTR)cs->szTitle);
905 if (! NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiString,
906 &UnicodeString,
907 TRUE)))
908 {
909 if (!IS_ATOM(cs->szClass))
910 {
911 RtlInitAnsiString(&AnsiString, cs->szClass);
912 RtlFreeAnsiString(&AnsiString);
913 }
914
915 HeapFree(GetProcessHeap(), 0, cs);
916 return FALSE;
917 }
918 cs->szTitle = AnsiString.Buffer;
919
920 AnsiMsg->lParam = (LPARAM)cs;
921 break;
922 }
923 }
924
925 return TRUE;
926 }
927
928 static BOOL FASTCALL
929 MsgiUnicodeToAnsiCleanup(LPMSG AnsiMsg, LPMSG UnicodeMsg)
930 {
931 ANSI_STRING AnsiString;
932
933 switch(UnicodeMsg->message)
934 {
935 case WM_GETTEXT:
936 {
937 RtlFreeHeap(GetProcessHeap(), 0, (PVOID) AnsiMsg->lParam);
938 break;
939 }
940 case WM_SETTEXT:
941 {
942 RtlInitAnsiString(&AnsiString, (PSTR) AnsiMsg->lParam);
943 RtlFreeAnsiString(&AnsiString);
944 break;
945 }
946 case WM_CREATE:
947 case WM_NCCREATE:
948 {
949 CREATESTRUCTA* Cs;
950
951 Cs = (CREATESTRUCTA*) AnsiMsg->lParam;
952 RtlInitAnsiString(&AnsiString, Cs->lpszName);
953 RtlFreeAnsiString(&AnsiString);
954 if (HIWORD((ULONG_PTR)Cs->lpszClass) != 0)
955 {
956 RtlInitAnsiString(&AnsiString, Cs->lpszClass);
957 RtlFreeAnsiString(&AnsiString);
958 }
959 RtlFreeHeap(GetProcessHeap(), 0, Cs);
960 break;
961 }
962
963 case LB_ADDSTRING:
964 case LB_ADDSTRING_LOWER:
965 case LB_ADDSTRING_UPPER:
966 case LB_INSERTSTRING:
967 case LB_INSERTSTRING_UPPER:
968 case LB_INSERTSTRING_LOWER:
969 case LB_FINDSTRING:
970 case LB_FINDSTRINGEXACT:
971 case LB_SELECTSTRING:
972 {
973 if (listbox_has_strings(AnsiMsg->hwnd))
974 {
975 RtlInitAnsiString(&AnsiString, (PSTR) AnsiMsg->lParam);
976 RtlFreeAnsiString(&AnsiString);
977 }
978 break;
979 }
980
981 case CB_ADDSTRING:
982 case CB_INSERTSTRING:
983 case CB_FINDSTRING:
984 case CB_FINDSTRINGEXACT:
985 case CB_SELECTSTRING:
986 {
987 DWORD dwStyle = GetWindowLongPtrW(AnsiMsg->hwnd, GWL_STYLE);
988 if (!(dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) &&
989 (dwStyle & CBS_HASSTRINGS))
990 {
991 RtlInitAnsiString(&AnsiString, (PSTR) AnsiMsg->lParam);
992 RtlFreeAnsiString(&AnsiString);
993 }
994 break;
995 }
996
997 case WM_MDICREATE:
998 {
999 MDICREATESTRUCTA *cs = (MDICREATESTRUCTA *)AnsiMsg->lParam;
1000 RtlInitAnsiString(&AnsiString, (PCSTR)cs->szTitle);
1001 RtlFreeAnsiString(&AnsiString);
1002 if (!IS_ATOM(cs->szClass))
1003 {
1004 RtlInitAnsiString(&AnsiString, (PCSTR)cs->szClass);
1005 RtlFreeAnsiString(&AnsiString);
1006 }
1007 HeapFree(GetProcessHeap(), 0, cs);
1008 break;
1009 }
1010
1011 }
1012
1013 return TRUE;
1014 }
1015
1016 static BOOL FASTCALL
1017 MsgiUnicodeToAnsiReply(LPMSG AnsiMsg, LPMSG UnicodeMsg, LRESULT *Result)
1018 {
1019 LRESULT Size;
1020 switch (UnicodeMsg->message)
1021 {
1022 case WM_GETTEXT:
1023 case WM_ASKCBFORMATNAME:
1024 {
1025 LPSTR Buffer = (LPSTR) AnsiMsg->lParam;
1026 LPWSTR UBuffer = (LPWSTR) UnicodeMsg->lParam;
1027 if (0 < AnsiMsg->wParam &&
1028 ! MultiByteToWideChar(CP_ACP, 0, Buffer, -1, UBuffer, UnicodeMsg->wParam))
1029 {
1030 UBuffer[UnicodeMsg->wParam - 1] = L'\0';
1031 }
1032 break;
1033 }
1034 case LB_GETTEXT:
1035 {
1036 LPSTR Buffer = (LPSTR) AnsiMsg->lParam;
1037 LPWSTR UBuffer = (LPWSTR) UnicodeMsg->lParam;
1038 if (!listbox_has_strings( UnicodeMsg->hwnd )) break;
1039 Size = SendMessageW( UnicodeMsg->hwnd, LB_GETTEXTLEN, UnicodeMsg->wParam, 0 );
1040 if (Size == LB_ERR) break;
1041 Size = Size + 1;
1042 if (1 < Size &&
1043 ! MultiByteToWideChar(CP_ACP, 0, Buffer, -1, UBuffer, Size))
1044 {
1045 UBuffer[Size - 1] = L'\0';
1046 }
1047 break;
1048 }
1049 case CB_GETLBTEXT:
1050 {
1051 LPSTR Buffer = (LPSTR) AnsiMsg->lParam;
1052 LPWSTR UBuffer = (LPWSTR) UnicodeMsg->lParam;
1053 if (!combobox_has_strings( UnicodeMsg->hwnd )) break;
1054 Size = SendMessageW( UnicodeMsg->hwnd, CB_GETLBTEXTLEN, UnicodeMsg->wParam, 0 );
1055 if (Size == CB_ERR) break;
1056 Size = Size + 1;
1057 if (1 < Size &&
1058 ! MultiByteToWideChar(CP_ACP, 0, Buffer, -1, UBuffer, Size))
1059 {
1060 UBuffer[Size - 1] = L'\0';
1061 }
1062 break;
1063 }
1064 }
1065
1066 MsgiUnicodeToAnsiCleanup(AnsiMsg, UnicodeMsg);
1067
1068 return TRUE;
1069 }
1070
1071 /***********************************************************************
1072 * map_wparam_AtoW
1073 *
1074 * Convert the wparam of an ASCII message to Unicode.
1075 */
1076 static WPARAM
1077 map_wparam_AtoW( UINT message, WPARAM wparam )
1078 {
1079 char ch[2];
1080 WCHAR wch[2];
1081
1082 wch[0] = wch[1] = 0;
1083 switch(message)
1084 {
1085 case WM_CHAR:
1086 /* WM_CHAR is magic: a DBCS char can be sent/posted as two consecutive WM_CHAR
1087 * messages, in which case the first char is stored, and the conversion
1088 * to Unicode only takes place once the second char is sent/posted.
1089 */
1090 #if 0
1091 if (mapping != WMCHAR_MAP_NOMAPPING) // NlsMbCodePageTag
1092 {
1093 PCLIENTINFO pci = GetWin32ClientInfo();
1094
1095 struct wm_char_mapping_data *data = get_user_thread_info()->wmchar_data;
1096
1097 BYTE low = LOBYTE(wparam);
1098
1099 if (HIBYTE(wparam))
1100 {
1101 ch[0] = low;
1102 ch[1] = HIBYTE(wparam);
1103 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
1104 TRACE( "map %02x,%02x -> %04x mapping %u\n", (BYTE)ch[0], (BYTE)ch[1], wch[0], mapping );
1105 if (data) data->lead_byte[mapping] = 0;
1106 }
1107 else if (data && data->lead_byte[mapping])
1108 {
1109 ch[0] = data->lead_byte[mapping];
1110 ch[1] = low;
1111 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
1112 TRACE( "map stored %02x,%02x -> %04x mapping %u\n", (BYTE)ch[0], (BYTE)ch[1], wch[0], mapping );
1113 data->lead_byte[mapping] = 0;
1114 }
1115 else if (!IsDBCSLeadByte( low ))
1116 {
1117 ch[0] = low;
1118 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 1 );
1119 TRACE( "map %02x -> %04x\n", (BYTE)ch[0], wch[0] );
1120 if (data) data->lead_byte[mapping] = 0;
1121 }
1122 else /* store it and wait for trail byte */
1123 {
1124 if (!data)
1125 {
1126 if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) )))
1127 return FALSE;
1128 get_user_thread_info()->wmchar_data = data;
1129 }
1130 TRACE( "storing lead byte %02x mapping %u\n", low, mapping );
1131 data->lead_byte[mapping] = low;
1132 return FALSE;
1133 }
1134 wparam = MAKEWPARAM(wch[0], wch[1]);
1135 break;
1136 }
1137 #endif
1138 /* else fall through */
1139 case WM_CHARTOITEM:
1140 case EM_SETPASSWORDCHAR:
1141 case WM_DEADCHAR:
1142 case WM_SYSCHAR:
1143 case WM_SYSDEADCHAR:
1144 case WM_MENUCHAR:
1145 ch[0] = LOBYTE(wparam);
1146 ch[1] = HIBYTE(wparam);
1147 RtlMultiByteToUnicodeN( wch, sizeof(wch), NULL, ch, 2 );
1148 wparam = MAKEWPARAM(wch[0], wch[1]);
1149 break;
1150 case WM_IME_CHAR:
1151 ch[0] = HIBYTE(wparam);
1152 ch[1] = LOBYTE(wparam);
1153 if (ch[0]) RtlMultiByteToUnicodeN( wch, sizeof(wch[0]), NULL, ch, 2 );
1154 else RtlMultiByteToUnicodeN( wch, sizeof(wch[0]), NULL, ch + 1, 1 );
1155 wparam = MAKEWPARAM(wch[0], HIWORD(wparam));
1156 break;
1157 }
1158 return wparam;
1159 }
1160
1161
1162 /*
1163 * @implemented
1164 */
1165 LPARAM
1166 WINAPI
1167 GetMessageExtraInfo(VOID)
1168 {
1169 return NtUserxGetMessageExtraInfo();
1170 }
1171
1172
1173 /*
1174 * @implemented
1175 */
1176 DWORD
1177 WINAPI
1178 GetMessagePos(VOID)
1179 {
1180 return NtUserxGetMessagePos();
1181 }
1182
1183
1184 /*
1185 * @implemented
1186 */
1187 LONG WINAPI
1188 GetMessageTime(VOID)
1189 {
1190 return NtUserGetThreadState(THREADSTATE_GETMESSAGETIME);
1191 }
1192
1193
1194 /*
1195 * @implemented
1196 */
1197 BOOL
1198 WINAPI
1199 InSendMessage(VOID)
1200 {
1201 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
1202 if ( pcti )
1203 {
1204 if (pcti->CTI_flags & CTI_INSENDMESSAGE)
1205 {
1206 return TRUE;
1207 }
1208 }
1209 return(NtUserGetThreadState(THREADSTATE_INSENDMESSAGE) != ISMEX_NOSEND);
1210 }
1211
1212
1213 /*
1214 * @implemented
1215 */
1216 DWORD
1217 WINAPI
1218 InSendMessageEx(
1219 LPVOID lpReserved)
1220 {
1221 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
1222 if (pcti && !(pcti->CTI_flags & CTI_INSENDMESSAGE))
1223 return ISMEX_NOSEND;
1224 else
1225 return NtUserGetThreadState(THREADSTATE_INSENDMESSAGE);
1226 }
1227
1228
1229 /*
1230 * @implemented
1231 */
1232 BOOL
1233 WINAPI
1234 ReplyMessage(LRESULT lResult)
1235 {
1236 return NtUserxReplyMessage(lResult);
1237 }
1238
1239
1240 /*
1241 * @implemented
1242 */
1243 LPARAM
1244 WINAPI
1245 SetMessageExtraInfo(
1246 LPARAM lParam)
1247 {
1248 return NtUserxSetMessageExtraInfo(lParam);
1249 }
1250
1251 LRESULT FASTCALL
1252 IntCallWindowProcW(BOOL IsAnsiProc,
1253 WNDPROC WndProc,
1254 PWND pWnd,
1255 HWND hWnd,
1256 UINT Msg,
1257 WPARAM wParam,
1258 LPARAM lParam)
1259 {
1260 MSG AnsiMsg;
1261 MSG UnicodeMsg;
1262 ULONG_PTR LowLimit;
1263 BOOL Hook = FALSE, MsgOverride = FALSE, Dialog;
1264 LRESULT Result = 0, PreResult = 0;
1265 DWORD Data = 0;
1266
1267 if (WndProc == NULL)
1268 {
1269 WARN("IntCallWindowsProcW() called with WndProc = NULL!\n");
1270 return FALSE;
1271 }
1272
1273 // Safeguard against excessive recursions.
1274 LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
1275 if (((ULONG_PTR)&lParam - LowLimit) < PAGE_SIZE )
1276 {
1277 ERR("IntCallWindowsProcW() Exceeded Stack!\n");
1278 return FALSE;
1279 }
1280
1281 if (pWnd)
1282 Dialog = (pWnd->fnid == FNID_DIALOG);
1283 else
1284 Dialog = FALSE;
1285
1286 Hook = BeginIfHookedUserApiHook();
1287 if (Hook)
1288 {
1289 if (!Dialog)
1290 MsgOverride = IsMsgOverride( Msg, &guah.WndProcArray);
1291 else
1292 MsgOverride = IsMsgOverride( Msg, &guah.DlgProcArray);
1293 }
1294
1295 if (IsAnsiProc)
1296 {
1297 UnicodeMsg.hwnd = hWnd;
1298 UnicodeMsg.message = Msg;
1299 UnicodeMsg.wParam = wParam;
1300 UnicodeMsg.lParam = lParam;
1301 if (! MsgiUnicodeToAnsiMessage(hWnd, &AnsiMsg, &UnicodeMsg))
1302 {
1303 goto Exit;
1304 }
1305
1306 if (Hook && MsgOverride)
1307 {
1308 _SEH2_TRY
1309 {
1310 if (!Dialog)
1311 PreResult = guah.PreWndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1312 else
1313 PreResult = guah.PreDefDlgProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1314 }
1315 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1316 {
1317 }
1318 _SEH2_END;
1319 }
1320
1321 if (PreResult) goto Exit;
1322
1323 _SEH2_TRY // wine does this.
1324 {
1325 Result = WndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam);
1326 }
1327 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1328 {
1329 ERR("Got exception when calling Ansi WndProc %p Msg %d \n",WndProc,Msg);
1330 }
1331 _SEH2_END;
1332
1333 if (Hook && MsgOverride)
1334 {
1335 _SEH2_TRY
1336 {
1337 if (!Dialog)
1338 guah.PostWndProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1339 else
1340 guah.PostDefDlgProc(AnsiMsg.hwnd, AnsiMsg.message, AnsiMsg.wParam, AnsiMsg.lParam, (ULONG_PTR)&Result, &Data );
1341 }
1342 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1343 {
1344 }
1345 _SEH2_END;
1346 }
1347
1348 if (! MsgiUnicodeToAnsiReply(&AnsiMsg, &UnicodeMsg, &Result))
1349 {
1350 goto Exit;
1351 }
1352 }
1353 else
1354 {
1355 if (Hook && MsgOverride)
1356 {
1357 _SEH2_TRY
1358 {
1359 if (!Dialog)
1360 PreResult = guah.PreWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1361 else
1362 PreResult = guah.PreDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1363 }
1364 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1365 {
1366 }
1367 _SEH2_END;
1368 }
1369
1370 if (PreResult) goto Exit;
1371
1372 _SEH2_TRY
1373 {
1374 Result = WndProc(hWnd, Msg, wParam, lParam);
1375 }
1376 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1377 {
1378 ERR("Got exception when calling unicode WndProc %p Msg %d \n",WndProc, Msg);
1379 }
1380 _SEH2_END;
1381
1382 if (Hook && MsgOverride)
1383 {
1384 _SEH2_TRY
1385 {
1386 if (!Dialog)
1387 guah.PostWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1388 else
1389 guah.PostDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1390 }
1391 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1392 {
1393 }
1394 _SEH2_END;
1395 }
1396 }
1397
1398 Exit:
1399 if (Hook) EndUserApiHook();
1400 return Result;
1401 }
1402
1403 static LRESULT FASTCALL
1404 IntCallWindowProcA(BOOL IsAnsiProc,
1405 WNDPROC WndProc,
1406 PWND pWnd,
1407 HWND hWnd,
1408 UINT Msg,
1409 WPARAM wParam,
1410 LPARAM lParam)
1411 {
1412 MSG AnsiMsg;
1413 MSG UnicodeMsg;
1414 ULONG_PTR LowLimit;
1415 BOOL Hook = FALSE, MsgOverride = FALSE, Dialog;
1416 LRESULT Result = 0, PreResult = 0;
1417 DWORD Data = 0;
1418
1419 if (WndProc == NULL)
1420 {
1421 WARN("IntCallWindowsProcA() called with WndProc = NULL!\n");
1422 return FALSE;
1423 }
1424
1425 LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
1426 if (((ULONG_PTR)&lParam - LowLimit) < PAGE_SIZE )
1427 {
1428 ERR("IntCallWindowsProcA() Exceeded Stack!\n");
1429 return FALSE;
1430 }
1431
1432 if (pWnd)
1433 Dialog = (pWnd->fnid == FNID_DIALOG);
1434 else
1435 Dialog = FALSE;
1436
1437 Hook = BeginIfHookedUserApiHook();
1438 if (Hook)
1439 {
1440 if (!Dialog)
1441 MsgOverride = IsMsgOverride( Msg, &guah.WndProcArray);
1442 else
1443 MsgOverride = IsMsgOverride( Msg, &guah.DlgProcArray);
1444 }
1445
1446 if (IsAnsiProc)
1447 {
1448 if (Hook && MsgOverride)
1449 {
1450 _SEH2_TRY
1451 {
1452 if (!Dialog)
1453 PreResult = guah.PreWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1454 else
1455 PreResult = guah.PreDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1456 }
1457 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1458 {
1459 }
1460 _SEH2_END;
1461 }
1462
1463 if (PreResult) goto Exit;
1464
1465 _SEH2_TRY
1466 {
1467 Result = WndProc(hWnd, Msg, wParam, lParam);
1468 }
1469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1470 {
1471 ERR("Got exception when calling Ansi WndProc %p Msg %d \n",WndProc,Msg);
1472 }
1473 _SEH2_END;
1474
1475 if (Hook && MsgOverride)
1476 {
1477 _SEH2_TRY
1478 {
1479 if (!Dialog)
1480 guah.PostWndProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1481 else
1482 guah.PostDefDlgProc(hWnd, Msg, wParam, lParam, (ULONG_PTR)&Result, &Data );
1483 }
1484 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1485 {
1486 }
1487 _SEH2_END;
1488 }
1489 }
1490 else
1491 {
1492 AnsiMsg.hwnd = hWnd;
1493 AnsiMsg.message = Msg;
1494 AnsiMsg.wParam = wParam;
1495 AnsiMsg.lParam = lParam;
1496 if (! MsgiAnsiToUnicodeMessage(hWnd, &UnicodeMsg, &AnsiMsg))
1497 {
1498 goto Exit;
1499 }
1500
1501 if (Hook && MsgOverride)
1502 {
1503 _SEH2_TRY
1504 {
1505 if (!Dialog)
1506 PreResult = guah.PreWndProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1507 else
1508 PreResult = guah.PreDefDlgProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1509 }
1510 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1511 {
1512 }
1513 _SEH2_END;
1514 }
1515
1516 if (PreResult) goto Exit;
1517
1518 _SEH2_TRY
1519 {
1520 Result = WndProc(UnicodeMsg.hwnd, UnicodeMsg.message,
1521 UnicodeMsg.wParam, UnicodeMsg.lParam);
1522 }
1523 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1524 {
1525 ERR("Got exception when calling unicode WndProc %p Msg %d \n",WndProc, Msg);
1526 }
1527 _SEH2_END;
1528
1529 if (Hook && MsgOverride)
1530 {
1531 _SEH2_TRY
1532 {
1533 if (!Dialog)
1534 guah.PostWndProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1535 else
1536 guah.PostDefDlgProc(UnicodeMsg.hwnd, UnicodeMsg.message, UnicodeMsg.wParam, UnicodeMsg.lParam, (ULONG_PTR)&Result, &Data );
1537 }
1538 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1539 {
1540 }
1541 _SEH2_END;
1542 }
1543
1544 if (! MsgiAnsiToUnicodeReply(&UnicodeMsg, &AnsiMsg, &Result))
1545 {
1546 goto Exit;
1547 }
1548 }
1549
1550 Exit:
1551 if (Hook) EndUserApiHook();
1552 return Result;
1553 }
1554
1555
1556 static LRESULT WINAPI
1557 IntCallMessageProc(IN PWND Wnd, IN HWND hWnd, IN UINT Msg, IN WPARAM wParam, IN LPARAM lParam, IN BOOL Ansi)
1558 {
1559 WNDPROC WndProc;
1560 BOOL IsAnsi;
1561 PCLS Class;
1562
1563 Class = DesktopPtrToUser(Wnd->pcls);
1564 WndProc = NULL;
1565
1566 if ( Wnd->head.pti != GetW32ThreadInfo())
1567 { // Must be inside the same thread!
1568 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
1569 return 0;
1570 }
1571 /*
1572 This is the message exchange for user32. If there's a need to monitor messages,
1573 do it here!
1574 */
1575 TRACE("HWND %p, MSG %u, WPARAM %p, LPARAM %p, Ansi %d\n", hWnd, Msg, wParam, lParam, Ansi);
1576 // if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON )
1577 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_FIRST )
1578 {
1579 if (Ansi)
1580 {
1581 if (GETPFNCLIENTW(Class->fnid) == Wnd->lpfnWndProc)
1582 WndProc = GETPFNCLIENTA(Class->fnid);
1583 }
1584 else
1585 {
1586 if (GETPFNCLIENTA(Class->fnid) == Wnd->lpfnWndProc)
1587 WndProc = GETPFNCLIENTW(Class->fnid);
1588 }
1589
1590 IsAnsi = Ansi;
1591
1592 if (!WndProc)
1593 {
1594 IsAnsi = !Wnd->Unicode;
1595 WndProc = Wnd->lpfnWndProc;
1596 }
1597 }
1598 else
1599 {
1600 IsAnsi = !Wnd->Unicode;
1601 WndProc = Wnd->lpfnWndProc;
1602 }
1603 /*
1604 Message caller can be Ansi/Unicode and the receiver can be Unicode/Ansi or
1605 the same.
1606 */
1607 if (!Ansi)
1608 return IntCallWindowProcW(IsAnsi, WndProc, Wnd, hWnd, Msg, wParam, lParam);
1609 else
1610 return IntCallWindowProcA(IsAnsi, WndProc, Wnd, hWnd, Msg, wParam, lParam);
1611 }
1612
1613
1614 /*
1615 * @implemented
1616 */
1617 LRESULT WINAPI
1618 CallWindowProcA(WNDPROC lpPrevWndFunc,
1619 HWND hWnd,
1620 UINT Msg,
1621 WPARAM wParam,
1622 LPARAM lParam)
1623 {
1624 PWND pWnd;
1625 PCALLPROCDATA CallProc;
1626
1627 if (lpPrevWndFunc == NULL)
1628 {
1629 WARN("CallWindowProcA: lpPrevWndFunc == NULL!\n");
1630 return 0;
1631 }
1632
1633 pWnd = ValidateHwnd(hWnd);
1634
1635 if (!IsCallProcHandle(lpPrevWndFunc))
1636 return IntCallWindowProcA(TRUE, lpPrevWndFunc, pWnd, hWnd, Msg, wParam, lParam);
1637 else
1638 {
1639 CallProc = ValidateCallProc((HANDLE)lpPrevWndFunc);
1640 if (CallProc != NULL)
1641 {
1642 return IntCallWindowProcA(!(CallProc->wType & UserGetCPDA2U),
1643 CallProc->pfnClientPrevious,
1644 pWnd,
1645 hWnd,
1646 Msg,
1647 wParam,
1648 lParam);
1649 }
1650 else
1651 {
1652 WARN("CallWindowProcA: can not dereference WndProcHandle\n");
1653 return 0;
1654 }
1655 }
1656 }
1657
1658
1659 /*
1660 * @implemented
1661 */
1662 LRESULT WINAPI
1663 CallWindowProcW(WNDPROC lpPrevWndFunc,
1664 HWND hWnd,
1665 UINT Msg,
1666 WPARAM wParam,
1667 LPARAM lParam)
1668 {
1669 PWND pWnd;
1670 PCALLPROCDATA CallProc;
1671
1672 /* FIXME - can the first parameter be NULL? */
1673 if (lpPrevWndFunc == NULL)
1674 {
1675 WARN("CallWindowProcA: lpPrevWndFunc == NULL!\n");
1676 return 0;
1677 }
1678
1679 pWnd = ValidateHwnd(hWnd);
1680
1681 if (!IsCallProcHandle(lpPrevWndFunc))
1682 return IntCallWindowProcW(FALSE, lpPrevWndFunc, pWnd, hWnd, Msg, wParam, lParam);
1683 else
1684 {
1685 CallProc = ValidateCallProc((HANDLE)lpPrevWndFunc);
1686 if (CallProc != NULL)
1687 {
1688 return IntCallWindowProcW(!(CallProc->wType & UserGetCPDA2U),
1689 CallProc->pfnClientPrevious,
1690 pWnd,
1691 hWnd,
1692 Msg,
1693 wParam,
1694 lParam);
1695 }
1696 else
1697 {
1698 WARN("CallWindowProcW: can not dereference WndProcHandle\n");
1699 return 0;
1700 }
1701 }
1702 }
1703
1704
1705 /*
1706 * @implemented
1707 */
1708 LRESULT WINAPI
1709 DispatchMessageA(CONST MSG *lpmsg)
1710 {
1711 LRESULT Ret = 0;
1712 MSG UnicodeMsg;
1713 PWND Wnd;
1714 BOOL Hit = FALSE;
1715
1716 if ( lpmsg->message & ~WM_MAXIMUM )
1717 {
1718 SetLastError( ERROR_INVALID_PARAMETER );
1719 return 0;
1720 }
1721
1722 if (lpmsg->hwnd != NULL)
1723 {
1724 Wnd = ValidateHwnd(lpmsg->hwnd);
1725 if (!Wnd) return 0;
1726 }
1727 else
1728 Wnd = NULL;
1729
1730 if (is_pointer_message(lpmsg->message))
1731 {
1732 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
1733 return 0;
1734 }
1735
1736 if ((lpmsg->message == WM_TIMER || lpmsg->message == WM_SYSTIMER) && lpmsg->lParam != 0)
1737 {
1738 WNDPROC WndProc = (WNDPROC)lpmsg->lParam;
1739
1740 if ( lpmsg->message == WM_SYSTIMER )
1741 return NtUserDispatchMessage( (PMSG)lpmsg );
1742
1743 if (!NtUserValidateTimerCallback(lpmsg->hwnd, lpmsg->wParam, lpmsg->lParam))
1744 {
1745 WARN("Validating Timer Callback failed!\n");
1746 return 0;
1747 }
1748
1749 _SEH2_TRY // wine does this. Hint: Prevents call to another thread....
1750 {
1751 Ret = WndProc(lpmsg->hwnd,
1752 lpmsg->message,
1753 lpmsg->wParam,
1754 GetTickCount());
1755 }
1756 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1757 {
1758 Hit = TRUE;
1759 }
1760 _SEH2_END;
1761 }
1762 else if (Wnd != NULL)
1763 {
1764 if ( (lpmsg->message != WM_PAINT) && !(Wnd->state & WNDS_SERVERSIDEWINDOWPROC) )
1765 {
1766 Ret = IntCallMessageProc(Wnd,
1767 lpmsg->hwnd,
1768 lpmsg->message,
1769 lpmsg->wParam,
1770 lpmsg->lParam,
1771 TRUE);
1772 }
1773 else
1774 {
1775 if (!MsgiAnsiToUnicodeMessage(lpmsg->hwnd, &UnicodeMsg, (LPMSG)lpmsg))
1776 {
1777 return FALSE;
1778 }
1779
1780 Ret = NtUserDispatchMessage(&UnicodeMsg);
1781
1782 if (!MsgiAnsiToUnicodeReply(&UnicodeMsg, (LPMSG)lpmsg, &Ret))
1783 {
1784 return FALSE;
1785 }
1786 }
1787 }
1788
1789 if (Hit)
1790 {
1791 WARN("Exception in Timer Callback WndProcA!\n");
1792 }
1793 return Ret;
1794 }
1795
1796
1797 /*
1798 * @implemented
1799 */
1800 LRESULT WINAPI
1801 DispatchMessageW(CONST MSG *lpmsg)
1802 {
1803 LRESULT Ret = 0;
1804 PWND Wnd;
1805 BOOL Hit = FALSE;
1806
1807 if ( lpmsg->message & ~WM_MAXIMUM )
1808 {
1809 SetLastError( ERROR_INVALID_PARAMETER );
1810 return 0;
1811 }
1812
1813 if (lpmsg->hwnd != NULL)
1814 {
1815 Wnd = ValidateHwnd(lpmsg->hwnd);
1816 if (!Wnd) return 0;
1817 }
1818 else
1819 Wnd = NULL;
1820
1821 if (is_pointer_message(lpmsg->message))
1822 {
1823 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
1824 return 0;
1825 }
1826
1827 if ((lpmsg->message == WM_TIMER || lpmsg->message == WM_SYSTIMER) && lpmsg->lParam != 0)
1828 {
1829 WNDPROC WndProc = (WNDPROC)lpmsg->lParam;
1830
1831 if ( lpmsg->message == WM_SYSTIMER )
1832 return NtUserDispatchMessage( (PMSG) lpmsg );
1833
1834 if (!NtUserValidateTimerCallback(lpmsg->hwnd, lpmsg->wParam, lpmsg->lParam))
1835 {
1836 WARN("Validating Timer Callback failed!\n");
1837 return 0;
1838 }
1839
1840 _SEH2_TRY
1841 {
1842 Ret = WndProc(lpmsg->hwnd,
1843 lpmsg->message,
1844 lpmsg->wParam,
1845 GetTickCount());
1846 }
1847 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1848 {
1849 Hit = TRUE;
1850 }
1851 _SEH2_END;
1852 }
1853 else if (Wnd != NULL)
1854 {
1855 if ( (lpmsg->message != WM_PAINT) && !(Wnd->state & WNDS_SERVERSIDEWINDOWPROC) )
1856 {
1857 Ret = IntCallMessageProc(Wnd,
1858 lpmsg->hwnd,
1859 lpmsg->message,
1860 lpmsg->wParam,
1861 lpmsg->lParam,
1862 FALSE);
1863 }
1864 else
1865 Ret = NtUserDispatchMessage( (PMSG) lpmsg );
1866 }
1867
1868 if (Hit)
1869 {
1870 WARN("Exception in Timer Callback WndProcW!\n");
1871 }
1872 return Ret;
1873 }
1874
1875 static VOID
1876 IntConvertMsgToAnsi(LPMSG lpMsg)
1877 {
1878 CHAR ch[2];
1879 WCHAR wch[2];
1880
1881 switch (lpMsg->message)
1882 {
1883 case WM_CHAR:
1884 case WM_DEADCHAR:
1885 case WM_SYSCHAR:
1886 case WM_SYSDEADCHAR:
1887 case WM_MENUCHAR:
1888 wch[0] = LOWORD(lpMsg->wParam);
1889 wch[1] = HIWORD(lpMsg->wParam);
1890 ch[0] = ch[1] = 0;
1891 WideCharToMultiByte(CP_THREAD_ACP, 0, wch, 2, ch, 2, NULL, NULL);
1892 lpMsg->wParam = MAKEWPARAM(ch[0] | (ch[1] << 8), 0);
1893 break;
1894 }
1895 }
1896
1897 /*
1898 * @implemented
1899 */
1900 BOOL WINAPI
1901 GetMessageA(LPMSG lpMsg,
1902 HWND hWnd,
1903 UINT wMsgFilterMin,
1904 UINT wMsgFilterMax)
1905 {
1906 BOOL Res;
1907
1908 if ( (wMsgFilterMin|wMsgFilterMax) & ~WM_MAXIMUM )
1909 {
1910 SetLastError( ERROR_INVALID_PARAMETER );
1911 return FALSE;
1912 }
1913
1914 Res = NtUserGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
1915 if (-1 == (int) Res)
1916 {
1917 return Res;
1918 }
1919
1920 IntConvertMsgToAnsi(lpMsg);
1921
1922 return Res;
1923 }
1924
1925 /*
1926 * @implemented
1927 */
1928 BOOL WINAPI
1929 GetMessageW(LPMSG lpMsg,
1930 HWND hWnd,
1931 UINT wMsgFilterMin,
1932 UINT wMsgFilterMax)
1933 {
1934 BOOL Res;
1935
1936 if ( (wMsgFilterMin|wMsgFilterMax) & ~WM_MAXIMUM )
1937 {
1938 SetLastError( ERROR_INVALID_PARAMETER );
1939 return FALSE;
1940 }
1941
1942 Res = NtUserGetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
1943 if (-1 == (int) Res)
1944 {
1945 return Res;
1946 }
1947
1948 return Res;
1949 }
1950
1951 BOOL WINAPI
1952 PeekMessageWorker( PMSG pMsg,
1953 HWND hWnd,
1954 UINT wMsgFilterMin,
1955 UINT wMsgFilterMax,
1956 UINT wRemoveMsg)
1957 {
1958 PCLIENTINFO pci;
1959 PCLIENTTHREADINFO pcti;
1960 pci = GetWin32ClientInfo();
1961 pcti = pci->pClientThreadInfo;
1962
1963 if (!hWnd && pci && pcti)
1964 {
1965 pci->cSpins++;
1966
1967 if ((pci->cSpins >= 100) && (pci->dwTIFlags & TIF_SPINNING))
1968 { // Yield after 100 spin cycles and ready to swap vinyl.
1969 if (!(pci->dwTIFlags & TIF_WAITFORINPUTIDLE))
1970 { // Not waiting for idle event.
1971 if (!pcti->fsChangeBits && !pcti->fsWakeBits)
1972 { // No messages are available.
1973 if ((GetTickCount() - pcti->tickLastMsgChecked) > 1000)
1974 { // Up the msg read count if over 1 sec.
1975 NtUserGetThreadState(THREADSTATE_UPTIMELASTREAD);
1976 }
1977 pci->cSpins = 0;
1978 ZwYieldExecution();
1979 FIXME("seeSpins!\n");
1980 return FALSE;
1981 }
1982 }
1983 }
1984 }
1985 return NtUserPeekMessage(pMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
1986 }
1987
1988 /*
1989 * @implemented
1990 */
1991 BOOL WINAPI
1992 PeekMessageA(LPMSG lpMsg,
1993 HWND hWnd,
1994 UINT wMsgFilterMin,
1995 UINT wMsgFilterMax,
1996 UINT wRemoveMsg)
1997 {
1998 BOOL Res;
1999
2000 Res = PeekMessageWorker(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
2001 if (-1 == (int) Res || !Res)
2002 {
2003 return FALSE;
2004 }
2005
2006 IntConvertMsgToAnsi(lpMsg);
2007
2008 return Res;
2009 }
2010
2011
2012 /*
2013 * @implemented
2014 */
2015 BOOL
2016 WINAPI
2017 PeekMessageW(
2018 LPMSG lpMsg,
2019 HWND hWnd,
2020 UINT wMsgFilterMin,
2021 UINT wMsgFilterMax,
2022 UINT wRemoveMsg)
2023 {
2024 BOOL Res;
2025
2026 Res = PeekMessageWorker(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
2027 if (-1 == (int) Res || !Res)
2028 {
2029 return FALSE;
2030 }
2031
2032 return Res;
2033 }
2034
2035 /*
2036 * @implemented
2037 */
2038 BOOL
2039 WINAPI
2040 PostMessageA(
2041 HWND hWnd,
2042 UINT Msg,
2043 WPARAM wParam,
2044 LPARAM lParam)
2045 {
2046 LRESULT Ret;
2047
2048 /* Check for combo box or a list box to send names. */
2049 if (Msg == CB_DIR || Msg == LB_DIR)
2050 {
2051 /*
2052 Set DDL_POSTMSGS, so use the PostMessage function to send messages to the
2053 combo/list box. Forces a call like DlgDirListComboBox.
2054 */
2055 //wParam |= DDL_POSTMSGS;
2056 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
2057 }
2058
2059 /* No drop files or current Process, just post message. */
2060 if ( (Msg != WM_DROPFILES) ||
2061 ( NtUserQueryWindow( hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID) ==
2062 PtrToUint(NtCurrentTeb()->ClientId.UniqueProcess) ) )
2063 {
2064 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
2065 }
2066
2067 /* We have drop files and this is not the same process for this window. */
2068
2069 /* Just incase, check wParam for Global memory handle and send size. */
2070 Ret = SendMessageA( hWnd,
2071 WM_COPYGLOBALDATA,
2072 (WPARAM)GlobalSize((HGLOBAL)wParam), // Zero if not a handle.
2073 (LPARAM)wParam); // Send wParam as lParam.
2074
2075 if ( Ret ) return NtUserPostMessage(hWnd, Msg, (WPARAM)Ret, lParam);
2076
2077 return FALSE;
2078 }
2079
2080 /*
2081 * @implemented
2082 */
2083 BOOL
2084 WINAPI
2085 PostMessageW(
2086 HWND hWnd,
2087 UINT Msg,
2088 WPARAM wParam,
2089 LPARAM lParam)
2090 {
2091 LRESULT Ret;
2092
2093 /* Check for combo box or a list box to send names. */
2094 if (Msg == CB_DIR || Msg == LB_DIR)
2095 {
2096 /*
2097 Set DDL_POSTMSGS, so use the PostMessage function to send messages to the
2098 combo/list box. Forces a call like DlgDirListComboBox.
2099 */
2100 //wParam |= DDL_POSTMSGS;
2101 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
2102 }
2103
2104 /* No drop files or current Process, just post message. */
2105 if ( (Msg != WM_DROPFILES) ||
2106 ( NtUserQueryWindow( hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID) ==
2107 PtrToUint(NtCurrentTeb()->ClientId.UniqueProcess) ) )
2108 {
2109 return NtUserPostMessage(hWnd, Msg, wParam, lParam);
2110 }
2111
2112 /* We have drop files and this is not the same process for this window. */
2113
2114 /* Just incase, check wParam for Global memory handle and send size. */
2115 Ret = SendMessageW( hWnd,
2116 WM_COPYGLOBALDATA,
2117 (WPARAM)GlobalSize((HGLOBAL)wParam), // Zero if not a handle.
2118 (LPARAM)wParam); // Send wParam as lParam.
2119
2120 if ( Ret ) return NtUserPostMessage(hWnd, Msg, (WPARAM)Ret, lParam);
2121
2122 return FALSE;
2123 }
2124
2125 /*
2126 * @implemented
2127 */
2128 VOID
2129 WINAPI
2130 PostQuitMessage(
2131 int nExitCode)
2132 {
2133 NtUserxPostQuitMessage(nExitCode);
2134 }
2135
2136
2137 /*
2138 * @implemented
2139 */
2140 BOOL
2141 WINAPI
2142 PostThreadMessageA(
2143 DWORD idThread,
2144 UINT Msg,
2145 WPARAM wParam,
2146 LPARAM lParam)
2147 {
2148 return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
2149 }
2150
2151
2152 /*
2153 * @implemented
2154 */
2155 BOOL
2156 WINAPI
2157 PostThreadMessageW(
2158 DWORD idThread,
2159 UINT Msg,
2160 WPARAM wParam,
2161 LPARAM lParam)
2162 {
2163 return NtUserPostThreadMessage(idThread, Msg, wParam, lParam);
2164 }
2165
2166
2167 /*
2168 * @implemented
2169 */
2170 LRESULT WINAPI
2171 SendMessageW(HWND Wnd,
2172 UINT Msg,
2173 WPARAM wParam,
2174 LPARAM lParam)
2175 {
2176 MSG UMMsg, KMMsg;
2177 LRESULT Result;
2178 PWND Window;
2179 PTHREADINFO ti = GetW32ThreadInfo();
2180
2181 if ( Msg & ~WM_MAXIMUM )
2182 {
2183 SetLastError( ERROR_INVALID_PARAMETER );
2184 return 0;
2185 }
2186
2187 if (Wnd != HWND_TOPMOST && Wnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
2188 {
2189 Window = ValidateHwnd(Wnd);
2190
2191 if ( Window != NULL &&
2192 Window->head.pti == ti &&
2193 // !IsThreadHooked(GetWin32ClientInfo()) && // Enable to test message system bug.
2194 !ISITHOOKED(WH_CALLWNDPROC) &&
2195 !ISITHOOKED(WH_CALLWNDPROCRET) &&
2196 !(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
2197 {
2198 /* NOTE: We can directly send messages to the window procedure
2199 if *all* the following conditions are met:
2200
2201 * Window belongs to calling thread
2202 * The calling thread is not being hooked for CallWndProc
2203 * Not calling a server side proc:
2204 Desktop, Switch, ScrollBar, Menu, IconTitle, or hWndMessage
2205 */
2206
2207 return IntCallMessageProc(Window, Wnd, Msg, wParam, lParam, FALSE);
2208 }
2209 }
2210
2211 UMMsg.hwnd = Wnd;
2212 UMMsg.message = Msg;
2213 UMMsg.wParam = wParam;
2214 UMMsg.lParam = lParam;
2215
2216 if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, FALSE))
2217 {
2218 return FALSE;
2219 }
2220
2221 Result = NtUserMessageCall( Wnd,
2222 KMMsg.message,
2223 KMMsg.wParam,
2224 KMMsg.lParam,
2225 (ULONG_PTR)&Result,
2226 FNID_SENDMESSAGE,
2227 FALSE);
2228
2229 MsgiUMToKMCleanup(&UMMsg, &KMMsg);
2230
2231 return Result;
2232 }
2233
2234
2235 /*
2236 * @implemented
2237 */
2238 LRESULT WINAPI
2239 SendMessageA(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
2240 {
2241 MSG AnsiMsg, UcMsg, KMMsg;
2242 LRESULT Result;
2243 PWND Window;
2244 PTHREADINFO ti = GetW32ThreadInfo();
2245
2246 if ( Msg & ~WM_MAXIMUM )
2247 {
2248 SetLastError( ERROR_INVALID_PARAMETER );
2249 return 0;
2250 }
2251
2252 if (Wnd != HWND_TOPMOST && Wnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
2253 {
2254 Window = ValidateHwnd(Wnd);
2255
2256 if ( Window != NULL &&
2257 Window->head.pti == ti &&
2258 // !IsThreadHooked(GetWin32ClientInfo()) && // Enable to test message system bug.
2259 !ISITHOOKED(WH_CALLWNDPROC) &&
2260 !ISITHOOKED(WH_CALLWNDPROCRET) &&
2261 !(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
2262 {
2263 /* NOTE: We can directly send messages to the window procedure
2264 if *all* the following conditions are met:
2265
2266 * Window belongs to calling thread
2267 * The calling thread is not being hooked for CallWndProc
2268 * Not calling a server side proc:
2269 Desktop, Switch, ScrollBar, Menu, IconTitle, or hWndMessage
2270 */
2271
2272 return IntCallMessageProc(Window, Wnd, Msg, wParam, lParam, TRUE);
2273 }
2274 }
2275
2276 AnsiMsg.hwnd = Wnd;
2277 AnsiMsg.message = Msg;
2278 AnsiMsg.wParam = wParam;
2279 AnsiMsg.lParam = lParam;
2280
2281 if (!MsgiAnsiToUnicodeMessage(Wnd, &UcMsg, &AnsiMsg))
2282 {
2283 return FALSE;
2284 }
2285
2286 if (!MsgiUMToKMMessage(&UcMsg, &KMMsg, FALSE))
2287 {
2288 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
2289 return FALSE;
2290 }
2291
2292 Result = NtUserMessageCall( Wnd,
2293 KMMsg.message,
2294 KMMsg.wParam,
2295 KMMsg.lParam,
2296 (ULONG_PTR)&Result,
2297 FNID_SENDMESSAGE,
2298 TRUE);
2299
2300 MsgiUMToKMCleanup(&UcMsg, &KMMsg);
2301 MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result);
2302
2303 return Result;
2304 }
2305
2306 /*
2307 * @implemented
2308 */
2309 BOOL
2310 WINAPI
2311 SendMessageCallbackA(
2312 HWND hWnd,
2313 UINT Msg,
2314 WPARAM wParam,
2315 LPARAM lParam,
2316 SENDASYNCPROC lpCallBack,
2317 ULONG_PTR dwData)
2318 {
2319 BOOL Result;
2320 MSG AnsiMsg, UcMsg;
2321 CALL_BACK_INFO CallBackInfo;
2322
2323 if (is_pointer_message(Msg))
2324 {
2325 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
2326 return FALSE;
2327 }
2328
2329 CallBackInfo.CallBack = lpCallBack;
2330 CallBackInfo.Context = dwData;
2331
2332 AnsiMsg.hwnd = hWnd;
2333 AnsiMsg.message = Msg;
2334 AnsiMsg.wParam = wParam;
2335 AnsiMsg.lParam = lParam;
2336
2337 if (!MsgiAnsiToUnicodeMessage(hWnd, &UcMsg, &AnsiMsg))
2338 {
2339 return FALSE;
2340 }
2341
2342 Result = NtUserMessageCall( hWnd,
2343 UcMsg.message,
2344 UcMsg.wParam,
2345 UcMsg.lParam,
2346 (ULONG_PTR)&CallBackInfo,
2347 FNID_SENDMESSAGECALLBACK,
2348 TRUE);
2349
2350 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
2351
2352 return Result;
2353 }
2354
2355 /*
2356 * @implemented
2357 */
2358 BOOL
2359 WINAPI
2360 SendMessageCallbackW(
2361 HWND hWnd,
2362 UINT Msg,
2363 WPARAM wParam,
2364 LPARAM lParam,
2365 SENDASYNCPROC lpCallBack,
2366 ULONG_PTR dwData)
2367 {
2368 CALL_BACK_INFO CallBackInfo;
2369
2370 if (is_pointer_message(Msg))
2371 {
2372 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
2373 return FALSE;
2374 }
2375
2376 CallBackInfo.CallBack = lpCallBack;
2377 CallBackInfo.Context = dwData;
2378
2379 return NtUserMessageCall(hWnd,
2380 Msg,
2381 wParam,
2382 lParam,
2383 (ULONG_PTR)&CallBackInfo,
2384 FNID_SENDMESSAGECALLBACK,
2385 FALSE);
2386 }
2387
2388 /*
2389 * @implemented
2390 */
2391 LRESULT
2392 WINAPI
2393 SendMessageTimeoutA(
2394 HWND hWnd,
2395 UINT Msg,
2396 WPARAM wParam,
2397 LPARAM lParam,
2398 UINT fuFlags,
2399 UINT uTimeout,
2400 PDWORD_PTR lpdwResult)
2401 {
2402 MSG AnsiMsg, UcMsg;
2403 LRESULT Result;
2404 DOSENDMESSAGE dsm;
2405 PWND Window;
2406 PTHREADINFO ti = GetW32ThreadInfo();
2407
2408 if ( Msg & ~WM_MAXIMUM || fuFlags & ~(SMTO_NOTIMEOUTIFNOTHUNG|SMTO_ABORTIFHUNG|SMTO_BLOCK))
2409 {
2410 SetLastError( ERROR_INVALID_PARAMETER );
2411 return 0;
2412 }
2413
2414 if (lpdwResult) *lpdwResult = 0;
2415
2416 //// This is due to message system bug.
2417 if (hWnd != HWND_TOPMOST && hWnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
2418 {
2419 Window = ValidateHwnd(hWnd);
2420
2421 if ( Window != NULL &&
2422 Window->head.pti == ti &&
2423 !ISITHOOKED(WH_CALLWNDPROC) &&
2424 !ISITHOOKED(WH_CALLWNDPROCRET) &&
2425 !(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
2426 {
2427 Result = IntCallMessageProc(Window, hWnd, Msg, wParam, lParam, TRUE);
2428 if (lpdwResult) *lpdwResult = Result;
2429 return TRUE;
2430 }
2431 }
2432 ////
2433 SPY_EnterMessage(SPY_SENDMESSAGE, hWnd, Msg, wParam, lParam);
2434
2435 dsm.uFlags = fuFlags;
2436 dsm.uTimeout = uTimeout;
2437
2438 AnsiMsg.hwnd = hWnd;
2439 AnsiMsg.message = Msg;
2440 AnsiMsg.wParam = wParam;
2441 AnsiMsg.lParam = lParam;
2442
2443 if (! MsgiAnsiToUnicodeMessage(hWnd, &UcMsg, &AnsiMsg))
2444 {
2445 return FALSE;
2446 }
2447
2448 Result = NtUserMessageCall( hWnd,
2449 UcMsg.message,
2450 UcMsg.wParam,
2451 UcMsg.lParam,
2452 (ULONG_PTR)&dsm,
2453 FNID_SENDMESSAGEWTOOPTION,
2454 TRUE);
2455
2456 MsgiAnsiToUnicodeReply(&UcMsg, &AnsiMsg, &Result);
2457
2458 if (lpdwResult) *lpdwResult = dsm.Result;
2459
2460 SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
2461
2462 return Result;
2463 }
2464
2465
2466 /*
2467 * @implemented
2468 */
2469 LRESULT
2470 WINAPI
2471 SendMessageTimeoutW(
2472 HWND hWnd,
2473 UINT Msg,
2474 WPARAM wParam,
2475 LPARAM lParam,
2476 UINT fuFlags,
2477 UINT uTimeout,
2478 PDWORD_PTR lpdwResult)
2479 {
2480 LRESULT Result;
2481 DOSENDMESSAGE dsm;
2482 PWND Window;
2483 PTHREADINFO ti = GetW32ThreadInfo();
2484
2485 if ( Msg & ~WM_MAXIMUM || fuFlags & ~(SMTO_NOTIMEOUTIFNOTHUNG|SMTO_ABORTIFHUNG|SMTO_BLOCK))
2486 {
2487 SetLastError( ERROR_INVALID_PARAMETER );
2488 return 0;
2489 }
2490
2491 if (lpdwResult) *lpdwResult = 0;
2492
2493 //// This is due to message system bug.
2494 if (hWnd != HWND_TOPMOST && hWnd != HWND_BROADCAST && (Msg < WM_DDE_FIRST || Msg > WM_DDE_LAST))
2495 {
2496 Window = ValidateHwnd(hWnd);
2497
2498 if ( Window != NULL &&
2499 Window->head.pti == ti &&
2500 !ISITHOOKED(WH_CALLWNDPROC) &&
2501 !ISITHOOKED(WH_CALLWNDPROCRET) &&
2502 !(Window->state & WNDS_SERVERSIDEWINDOWPROC) )
2503 {
2504 Result = IntCallMessageProc(Window, hWnd, Msg, wParam, lParam, FALSE);
2505 if (lpdwResult) *lpdwResult = Result;
2506 return TRUE;
2507 }
2508 }
2509 ////
2510 SPY_EnterMessage(SPY_SENDMESSAGE, hWnd, Msg, wParam, lParam);
2511
2512 dsm.uFlags = fuFlags;
2513 dsm.uTimeout = uTimeout;
2514
2515 Result = NtUserMessageCall( hWnd,
2516 Msg,
2517 wParam,
2518 lParam,
2519 (ULONG_PTR)&dsm,
2520 FNID_SENDMESSAGEWTOOPTION,
2521 FALSE);
2522
2523 if (lpdwResult) *lpdwResult = dsm.Result;
2524
2525 SPY_ExitMessage(SPY_RESULT_OK, hWnd, Msg, Result, wParam, lParam);
2526
2527 return Result;
2528 }
2529
2530 /*
2531 * @implemented
2532 */
2533 BOOL
2534 WINAPI
2535 SendNotifyMessageA(
2536 HWND hWnd,
2537 UINT Msg,
2538 WPARAM wParam,
2539 LPARAM lParam)
2540 {
2541 BOOL Ret;
2542 MSG AnsiMsg, UcMsg;
2543
2544 if (is_pointer_message(Msg))
2545 {
2546 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
2547 return FALSE;
2548 }
2549
2550 AnsiMsg.hwnd = hWnd;
2551 AnsiMsg.message = Msg;
2552 AnsiMsg.wParam = wParam;
2553 AnsiMsg.lParam = lParam;
2554 if (! MsgiAnsiToUnicodeMessage(hWnd, &UcMsg, &AnsiMsg))
2555 {
2556 return FALSE;
2557 }
2558 Ret = SendNotifyMessageW(hWnd, UcMsg.message, UcMsg.wParam, UcMsg.lParam);
2559
2560 MsgiAnsiToUnicodeCleanup(&UcMsg, &AnsiMsg);
2561
2562 return Ret;
2563 }
2564
2565 /*
2566 * @implemented
2567 */
2568 BOOL
2569 WINAPI
2570 SendNotifyMessageW(
2571 HWND hWnd,
2572 UINT Msg,
2573 WPARAM wParam,
2574 LPARAM lParam)
2575 {
2576 MSG UMMsg, KMMsg;
2577 LRESULT Result;
2578
2579 if (is_pointer_message(Msg))
2580 {
2581 SetLastError( ERROR_MESSAGE_SYNC_ONLY );
2582 return FALSE;
2583 }
2584
2585 UMMsg.hwnd = hWnd;
2586 UMMsg.message = Msg;
2587 UMMsg.wParam = wParam;
2588 UMMsg.lParam = lParam;
2589 if (! MsgiUMToKMMessage(&UMMsg, &KMMsg, TRUE))
2590 {
2591 return FALSE;
2592 }
2593 Result = NtUserMessageCall( hWnd,
2594 KMMsg.message,
2595 KMMsg.wParam,
2596 KMMsg.lParam,
2597 0,
2598 FNID_SENDNOTIFYMESSAGE,
2599 FALSE);
2600
2601 MsgiUMToKMCleanup(&UMMsg, &KMMsg);
2602
2603 return Result;
2604 }
2605
2606 /*
2607 * @implemented
2608 */
2609 BOOL WINAPI
2610 TranslateMessageEx(CONST MSG *lpMsg, UINT Flags)
2611 {
2612 switch (lpMsg->message)
2613 {
2614 case WM_KEYDOWN:
2615 case WM_KEYUP:
2616 case WM_SYSKEYDOWN:
2617 case WM_SYSKEYUP:
2618 return(NtUserTranslateMessage((LPMSG)lpMsg, Flags));
2619
2620 default:
2621 if ( lpMsg->message & ~WM_MAXIMUM )
2622 SetLastError(ERROR_INVALID_PARAMETER);
2623 return FALSE;
2624 }
2625 }
2626
2627
2628 /*
2629 * @implemented
2630 */
2631 BOOL WINAPI
2632 TranslateMessage(CONST MSG *lpMsg)
2633 {
2634 BOOL Ret = FALSE;
2635
2636 // Ref: msdn ImmGetVirtualKey:
2637 // http://msdn.microsoft.com/en-us/library/aa912145.aspx
2638 /*
2639 if ( (LOWORD(lpMsg->wParam) != VK_PROCESSKEY) ||
2640 !(Ret = IMM_ImmTranslateMessage( lpMsg->hwnd,
2641 lpMsg->message,
2642 lpMsg->wParam,
2643 lpMsg->lParam)) )*/
2644 {
2645 Ret = TranslateMessageEx((LPMSG)lpMsg, 0);
2646 }
2647 return Ret;
2648 }
2649
2650
2651 /*
2652 * @implemented
2653 */
2654 UINT WINAPI
2655 RegisterWindowMessageA(LPCSTR lpString)
2656 {
2657 UNICODE_STRING String;
2658 BOOLEAN Result;
2659 UINT Atom;
2660
2661 Result = RtlCreateUnicodeStringFromAsciiz(&String, (PCSZ)lpString);
2662 if (!Result)
2663 {
2664 return(0);
2665 }
2666 Atom = NtUserRegisterWindowMessage(&String);
2667 RtlFreeUnicodeString(&String);
2668 return(Atom);
2669 }
2670
2671
2672 /*
2673 * @implemented
2674 */
2675 UINT WINAPI
2676 RegisterWindowMessageW(LPCWSTR lpString)
2677 {
2678 UNICODE_STRING String;
2679
2680 RtlInitUnicodeString(&String, lpString);
2681 return(NtUserRegisterWindowMessage(&String));
2682 }
2683
2684 /*
2685 * @implemented
2686 */
2687 HWND WINAPI
2688 GetCapture(VOID)
2689 {
2690 return (HWND)NtUserGetThreadState(THREADSTATE_CAPTUREWINDOW);
2691 }
2692
2693 /*
2694 * @implemented
2695 */
2696 BOOL WINAPI
2697 ReleaseCapture(VOID)
2698 {
2699 return NtUserxReleaseCapture();
2700 }
2701
2702
2703 /*
2704 * @implemented
2705 */
2706 DWORD
2707 WINAPI
2708 RealGetQueueStatus(UINT flags)
2709 {
2710 #define QS_TEMPALLINPUT 255 // ATM, do not support QS_RAWINPUT
2711 if (flags & ~(QS_SMRESULT|QS_ALLPOSTMESSAGE|QS_TEMPALLINPUT))
2712 {
2713 SetLastError( ERROR_INVALID_FLAGS );
2714 return 0;
2715 }
2716 return NtUserxGetQueueStatus(flags);
2717 }
2718
2719
2720 /*
2721 * @implemented
2722 */
2723 BOOL WINAPI GetInputState(VOID)
2724 {
2725 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
2726
2727 if ((!pcti) || (pcti->fsChangeBits & (QS_KEY|QS_MOUSEBUTTON)))
2728 return (BOOL)NtUserGetThreadState(THREADSTATE_GETINPUTSTATE);
2729
2730 return FALSE;
2731 }
2732
2733
2734 NTSTATUS WINAPI
2735 User32CallWindowProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
2736 {
2737 PWINDOWPROC_CALLBACK_ARGUMENTS CallbackArgs;
2738 MSG KMMsg, UMMsg;
2739 PWND pWnd = NULL;
2740 ULONG_PTR LowLimit;
2741 PCLIENTINFO pci = GetWin32ClientInfo();
2742
2743 /* Make sure we don't try to access mem beyond what we were given */
2744 if (ArgumentLength < sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
2745 {
2746 return STATUS_INFO_LENGTH_MISMATCH;
2747 }
2748
2749 LowLimit = (ULONG_PTR)NtCurrentTeb()->NtTib.StackLimit;
2750 if (((ULONG_PTR)&ArgumentLength - LowLimit) < PAGE_SIZE )
2751 {
2752 ERR("Callback from Win32k Exceeded Stack!\n");
2753 return STATUS_BAD_STACK;
2754 }
2755
2756 CallbackArgs = (PWINDOWPROC_CALLBACK_ARGUMENTS) Arguments;
2757 KMMsg.hwnd = CallbackArgs->Wnd;
2758 KMMsg.message = CallbackArgs->Msg;
2759 KMMsg.wParam = CallbackArgs->wParam;
2760 /* Check if lParam is really a pointer and adjust it if it is */
2761 if (0 <= CallbackArgs->lParamBufferSize)
2762 {
2763 if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS)
2764 + CallbackArgs->lParamBufferSize)
2765 {
2766 return STATUS_INFO_LENGTH_MISMATCH;
2767 }
2768 KMMsg.lParam = (LPARAM) ((char *) CallbackArgs + sizeof(WINDOWPROC_CALLBACK_ARGUMENTS));
2769 }
2770 else
2771 {
2772 if (ArgumentLength != sizeof(WINDOWPROC_CALLBACK_ARGUMENTS))
2773 {
2774 return STATUS_INFO_LENGTH_MISMATCH;
2775 }
2776 KMMsg.lParam = CallbackArgs->lParam;
2777 }
2778
2779 if (WM_NCCALCSIZE == CallbackArgs->Msg && CallbackArgs->wParam)
2780 {
2781 NCCALCSIZE_PARAMS *Params = (NCCALCSIZE_PARAMS *) KMMsg.lParam;
2782 Params->lppos = (PWINDOWPOS) (Params + 1);
2783 }
2784
2785 if (! MsgiKMToUMMessage(&KMMsg, &UMMsg))
2786 {
2787 }
2788
2789 if (pci->CallbackWnd.hWnd == UMMsg.hwnd)
2790 pWnd = pci->CallbackWnd.pWnd;
2791
2792 CallbackArgs->Result = IntCallWindowProcW( CallbackArgs->IsAnsiProc,
2793 CallbackArgs->Proc,
2794 pWnd,
2795 UMMsg.hwnd,
2796 UMMsg.message,
2797 UMMsg.wParam,
2798 UMMsg.lParam);
2799
2800 if (! MsgiKMToUMReply(&KMMsg, &UMMsg, &CallbackArgs->Result))
2801 {
2802 }
2803
2804 return ZwCallbackReturn(CallbackArgs, ArgumentLength, STATUS_SUCCESS);
2805 }
2806
2807 /*
2808 * @implemented
2809 */
2810 BOOL WINAPI SetMessageQueue(int cMessagesMax)
2811 {
2812 /* Function does nothing on 32 bit windows */
2813 return TRUE;
2814 }
2815 typedef DWORD (WINAPI * RealGetQueueStatusProc)(UINT flags);
2816 typedef DWORD (WINAPI * RealMsgWaitForMultipleObjectsExProc)(DWORD nCount, CONST HANDLE *lpHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags);
2817 typedef BOOL (WINAPI * RealInternalGetMessageProc)(LPMSG,HWND,UINT,UINT,UINT,BOOL);
2818 typedef BOOL (WINAPI * RealWaitMessageExProc)(DWORD,UINT);
2819
2820 typedef struct _USER_MESSAGE_PUMP_ADDRESSES {
2821 DWORD cbSize;
2822 RealInternalGetMessageProc NtUserRealInternalGetMessage;
2823 RealWaitMessageExProc NtUserRealWaitMessageEx;
2824 RealGetQueueStatusProc RealGetQueueStatus;
2825 RealMsgWaitForMultipleObjectsExProc RealMsgWaitForMultipleObjectsEx;
2826 } USER_MESSAGE_PUMP_ADDRESSES, * PUSER_MESSAGE_PUMP_ADDRESSES;
2827
2828 DWORD
2829 WINAPI
2830 RealMsgWaitForMultipleObjectsEx(
2831 DWORD nCount,
2832 CONST HANDLE *pHandles,
2833 DWORD dwMilliseconds,
2834 DWORD dwWakeMask,
2835 DWORD dwFlags);
2836
2837 typedef BOOL (WINAPI * MESSAGEPUMPHOOKPROC)(BOOL Unregistering,PUSER_MESSAGE_PUMP_ADDRESSES MessagePumpAddresses);
2838
2839 CRITICAL_SECTION gcsMPH;
2840 MESSAGEPUMPHOOKPROC gpfnInitMPH;
2841 DWORD gcLoadMPH = 0;
2842 USER_MESSAGE_PUMP_ADDRESSES gmph = {sizeof(USER_MESSAGE_PUMP_ADDRESSES),
2843 NtUserRealInternalGetMessage,
2844 NtUserRealWaitMessageEx,
2845 RealGetQueueStatus,
2846 RealMsgWaitForMultipleObjectsEx
2847 };
2848
2849 DWORD gfMessagePumpHook = 0;
2850
2851 BOOL WINAPI IsInsideMessagePumpHook()
2852 { // FF uses this and polls it when Min/Max
2853 PCLIENTTHREADINFO pcti = GetWin32ClientInfo()->pClientThreadInfo;
2854 return (gfMessagePumpHook && pcti && (pcti->dwcPumpHook > 0));
2855 }
2856
2857 void WINAPI ResetMessagePumpHook(PUSER_MESSAGE_PUMP_ADDRESSES Addresses)
2858 {
2859 Addresses->cbSize = sizeof(USER_MESSAGE_PUMP_ADDRESSES);
2860 Addresses->NtUserRealInternalGetMessage = NtUserRealInternalGetMessage;
2861 Addresses->NtUserRealWaitMessageEx = NtUserRealWaitMessageEx;
2862 Addresses->RealGetQueueStatus = RealGetQueueStatus;
2863 Addresses->RealMsgWaitForMultipleObjectsEx = RealMsgWaitForMultipleObjectsEx;
2864 }
2865
2866 BOOL WINAPI RegisterMessagePumpHook(MESSAGEPUMPHOOKPROC Hook)
2867 {
2868 EnterCriticalSection(&gcsMPH);
2869 if(!Hook) {
2870 SetLastError(ERROR_INVALID_PARAMETER);
2871 LeaveCriticalSection(&gcsMPH);
2872 return FALSE;
2873 }
2874 if(!gcLoadMPH) {
2875 USER_MESSAGE_PUMP_ADDRESSES Addresses;
2876 gpfnInitMPH = Hook;
2877 ResetMessagePumpHook(&Addresses);
2878 if(!Hook(FALSE, &Addresses) || !Addresses.cbSize) {
2879 LeaveCriticalSection(&gcsMPH);
2880 return FALSE;
2881 }
2882 memcpy(&gmph, &Addresses, Addresses.cbSize);
2883 } else {
2884 if(gpfnInitMPH != Hook) {
2885 LeaveCriticalSection(&gcsMPH);
2886 return FALSE;
2887 }
2888 }
2889 if(NtUserxInitMessagePump()) {
2890 LeaveCriticalSection(&gcsMPH);
2891 return FALSE;
2892 }
2893 if (!gcLoadMPH++) {
2894 InterlockedExchange((PLONG)&gfMessagePumpHook, 1);
2895 }
2896 LeaveCriticalSection(&gcsMPH);
2897 return TRUE;
2898 }
2899
2900 BOOL WINAPI UnregisterMessagePumpHook(VOID)
2901 {
2902 EnterCriticalSection(&gcsMPH);
2903 if(gcLoadMPH > 0) {
2904 if(NtUserxUnInitMessagePump()) {
2905 gcLoadMPH--;
2906 if(!gcLoadMPH) {
2907 InterlockedExchange((PLONG)&gfMessagePumpHook, 0);
2908 gpfnInitMPH(TRUE, NULL);
2909 ResetMessagePumpHook(&gmph);
2910 gpfnInitMPH = 0;
2911 }
2912 LeaveCriticalSection(&gcsMPH);
2913 return TRUE;
2914 }
2915 }
2916 LeaveCriticalSection(&gcsMPH);
2917 return FALSE;
2918 }
2919
2920 DWORD WINAPI GetQueueStatus(UINT flags)
2921 {
2922 return IsInsideMessagePumpHook() ? gmph.RealGetQueueStatus(flags) : RealGetQueueStatus(flags);
2923 }
2924
2925 /**
2926 * @name RealMsgWaitForMultipleObjectsEx
2927 *
2928 * Wait either for either message arrival or for one of the passed events
2929 * to be signalled.
2930 *
2931 * @param nCount
2932 * Number of handles in the pHandles array.
2933 * @param pHandles
2934 * Handles of events to wait for.
2935 * @param dwMilliseconds
2936 * Timeout interval.
2937 * @param dwWakeMask
2938 * Mask specifying on which message events we should wakeup.
2939 * @param dwFlags
2940 * Wait type (see MWMO_* constants).
2941 *
2942 * @implemented
2943 */
2944
2945 DWORD WINAPI
2946 RealMsgWaitForMultipleObjectsEx(
2947 DWORD nCount,
2948 const HANDLE *pHandles,
2949 DWORD dwMilliseconds,
2950 DWORD dwWakeMask,
2951 DWORD dwFlags)
2952 {
2953 LPHANDLE RealHandles;
2954 HANDLE MessageQueueHandle;
2955 DWORD Result;
2956 PCLIENTINFO pci;
2957 PCLIENTTHREADINFO pcti;
2958
2959 if (dwFlags & ~(MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE))
2960 {
2961 SetLastError(ERROR_INVALID_PARAMETER);
2962 return WAIT_FAILED;
2963 }
2964
2965 pci = GetWin32ClientInfo();
2966 if (!pci) return WAIT_FAILED;
2967
2968 pcti = pci->pClientThreadInfo;
2969 if (pcti && ( !nCount || !(dwFlags & MWMO_WAITALL) ))
2970 {
2971 if ( (pcti->fsChangeBits & LOWORD(dwWakeMask)) ||
2972 ( (dwFlags & MWMO_INPUTAVAILABLE) && (pcti->fsWakeBits & LOWORD(dwWakeMask)) ) )
2973 {
2974 //FIXME("Chg 0x%x Wake 0x%x Mask 0x%x nCnt %d\n",pcti->fsChangeBits, pcti->fsWakeBits, dwWakeMask, nCount);
2975 return nCount;
2976 }
2977 }
2978
2979 MessageQueueHandle = NtUserxMsqSetWakeMask(MAKELONG(dwWakeMask, dwFlags));
2980 if (MessageQueueHandle == NULL)
2981 {
2982 SetLastError(0); /* ? */
2983 return WAIT_FAILED;
2984 }
2985
2986 RealHandles = HeapAlloc(GetProcessHeap(), 0, (nCount + 1) * sizeof(HANDLE));
2987 if (RealHandles == NULL)
2988 {
2989 NtUserxMsqClearWakeMask();
2990 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2991 return WAIT_FAILED;
2992 }
2993
2994 RtlCopyMemory(RealHandles, pHandles, nCount * sizeof(HANDLE));
2995 RealHandles[nCount] = MessageQueueHandle;
2996
2997 Result = WaitForMultipleObjectsEx(nCount + 1, RealHandles,
2998 dwFlags & MWMO_WAITALL,
2999 dwMilliseconds, dwFlags & MWMO_ALERTABLE);
3000
3001 HeapFree(GetProcessHeap(), 0, RealHandles);
3002 NtUserxMsqClearWakeMask();
3003 //FIXME("Result 0X%x\n",Result);
3004 return Result;
3005 }
3006
3007 /*
3008 * @implemented
3009 */
3010 DWORD WINAPI
3011 MsgWaitForMultipleObjectsEx(
3012 DWORD nCount,
3013 CONST HANDLE *lpHandles,
3014 DWORD dwMilliseconds,
3015 DWORD dwWakeMask,
3016 DWORD dwFlags)
3017 {
3018 return IsInsideMessagePumpHook() ? gmph.RealMsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds, dwWakeMask, dwFlags) : RealMsgWaitForMultipleObjectsEx(nCount, lpHandles,dwMilliseconds, dwWakeMask, dwFlags);
3019 }
3020
3021 /*
3022 * @implemented
3023 */
3024 DWORD WINAPI
3025 MsgWaitForMultipleObjects(
3026 DWORD nCount,
3027 CONST HANDLE *lpHandles,
3028 BOOL fWaitAll,
3029 DWORD dwMilliseconds,
3030 DWORD dwWakeMask)
3031 {
3032 return MsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds,
3033 dwWakeMask, fWaitAll ? MWMO_WAITALL : 0);
3034 }
3035
3036
3037 BOOL FASTCALL MessageInit(VOID)
3038 {
3039 InitializeCriticalSection(&DdeCrst);
3040 InitializeCriticalSection(&gcsMPH);
3041
3042 return TRUE;
3043 }
3044
3045 VOID FASTCALL MessageCleanup(VOID)
3046 {
3047 DeleteCriticalSection(&DdeCrst);
3048 DeleteCriticalSection(&gcsMPH);
3049 }
3050
3051 /*
3052 * @implemented
3053 */
3054 BOOL WINAPI
3055 IsDialogMessageA( HWND hwndDlg, LPMSG pmsg )
3056 {
3057 MSG msg = *pmsg;
3058 msg.wParam = map_wparam_AtoW( msg.message, msg.wParam );
3059 return IsDialogMessageW( hwndDlg, &msg );
3060 }
3061
3062 LONG
3063 WINAPI
3064 IntBroadcastSystemMessage(
3065 DWORD dwflags,
3066 LPDWORD lpdwRecipients,
3067 UINT uiMessage,
3068 WPARAM wParam,
3069 LPARAM lParam,
3070 PBSMINFO pBSMInfo,
3071 BOOL Ansi)
3072 {
3073 BROADCASTPARM parm;
3074 DWORD recips = BSM_ALLCOMPONENTS;
3075 BOOL ret = -1; // Set to return fail
3076 static const DWORD all_flags = ( BSF_QUERY | BSF_IGNORECURRENTTASK | BSF_FLUSHDISK | BSF_NOHANG
3077 | BSF_POSTMESSAGE | BSF_FORCEIFHUNG | BSF_NOTIMEOUTIFNOTHUNG
3078 | BSF_ALLOWSFW | BSF_SENDNOTIFYMESSAGE | BSF_RETURNHDESK | BSF_LUID );
3079
3080 if ((dwflags & ~all_flags) ||
3081 (!pBSMInfo && (dwflags & (BSF_RETURNHDESK|BSF_LUID))) )
3082 {
3083 SetLastError(ERROR_INVALID_PARAMETER);
3084 return 0;
3085 }
3086
3087 if(uiMessage >= WM_USER && uiMessage < 0xC000)
3088 {
3089 SetLastError(ERROR_INVALID_PARAMETER);
3090 return 0;
3091 }
3092
3093 if (dwflags & BSF_FORCEIFHUNG) dwflags |= BSF_NOHANG;
3094
3095 if (dwflags & BSF_QUERY) dwflags &= ~BSF_SENDNOTIFYMESSAGE|BSF_POSTMESSAGE;
3096
3097 if (!lpdwRecipients)
3098 lpdwRecipients = &recips;
3099
3100 if (*lpdwRecipients & ~(BSM_APPLICATIONS|BSM_ALLDESKTOPS|BSM_INSTALLABLEDRIVERS|BSM_NETDRIVER|BSM_VXDS))
3101 {
3102 SetLastError(ERROR_INVALID_PARAMETER);
3103 return 0;
3104 }
3105
3106 if ( pBSMInfo && (dwflags & BSF_QUERY) )
3107 {
3108 if (pBSMInfo->cbSize != sizeof(BSMINFO))
3109 {
3110 SetLastError(ERROR_INVALID_PARAMETER);
3111 return 0;
3112 }
3113 }
3114
3115 parm.hDesk = NULL;
3116 parm.hWnd = NULL;
3117 parm.flags = dwflags;
3118 parm.recipients = *lpdwRecipients;
3119
3120 if (dwflags & BSF_LUID) parm.luid = pBSMInfo->luid;
3121
3122 ret = NtUserMessageCall(GetDesktopWindow(),
3123 uiMessage,
3124 wParam,
3125 lParam,
3126 (ULONG_PTR)&parm,
3127 FNID_BROADCASTSYSTEMMESSAGE,
3128 Ansi);
3129
3130 if (!ret)
3131 {
3132 if ( pBSMInfo && (dwflags & BSF_QUERY) )
3133 {
3134 pBSMInfo->hdesk = parm.hDesk;
3135 pBSMInfo->hwnd = parm.hWnd;
3136 }
3137 }
3138 return ret;
3139 }
3140
3141 /*
3142 * @implemented
3143 */
3144 LONG
3145 WINAPI
3146 BroadcastSystemMessageA(
3147 DWORD dwFlags,
3148 LPDWORD lpdwRecipients,
3149 UINT uiMessage,
3150 WPARAM wParam,
3151 LPARAM lParam)
3152 {
3153 return IntBroadcastSystemMessage( dwFlags, lpdwRecipients, uiMessage, wParam, lParam, NULL, TRUE );
3154 }
3155
3156 /*
3157 * @implemented
3158 */
3159 LONG
3160 WINAPI
3161 BroadcastSystemMessageW(
3162 DWORD dwFlags,
3163 LPDWORD lpdwRecipients,
3164 UINT uiMessage,
3165 WPARAM wParam,
3166 LPARAM lParam)
3167 {
3168 return IntBroadcastSystemMessage( dwFlags, lpdwRecipients, uiMessage, wParam, lParam, NULL, FALSE );
3169 }
3170
3171 /*
3172 * @implemented
3173 */
3174 LONG
3175 WINAPI
3176 BroadcastSystemMessageExA(
3177 DWORD dwflags,
3178 LPDWORD lpdwRecipients,
3179 UINT uiMessage,
3180 WPARAM wParam,
3181 LPARAM lParam,
3182 PBSMINFO pBSMInfo)
3183 {
3184 return IntBroadcastSystemMessage( dwflags, lpdwRecipients, uiMessage, wParam, lParam , pBSMInfo, TRUE );
3185 }
3186
3187 /*
3188 * @implemented
3189 */
3190 LONG
3191 WINAPI
3192 BroadcastSystemMessageExW(
3193 DWORD dwflags,
3194 LPDWORD lpdwRecipients,
3195 UINT uiMessage,
3196 WPARAM wParam,
3197 LPARAM lParam,
3198 PBSMINFO pBSMInfo)
3199 {
3200 return IntBroadcastSystemMessage( dwflags, lpdwRecipients, uiMessage, wParam, lParam , pBSMInfo, FALSE );
3201 }
3202