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