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