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