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