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