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