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