1 #include <user32.h> 2 #include <ndk/cmfuncs.h> 3 #include <strsafe.h> 4 5 #define MAX_USER_MODE_DRV_BUFFER 526 6 7 // 8 // UMPD Packet Header should match win32ss/include/ntumpd.h 9 // 10 typedef struct _UMPDPKTHEAD 11 { 12 INT Size; 13 INT Index; 14 INT RetSize; 15 DWORD Reserved; 16 HUMPD humpd; 17 ULONG_PTR Buffer[]; 18 } UMPDPKTHEAD, *PUMPDPKTHEAD; 19 20 INT WINAPI GdiPrinterThunk(PUMPDPKTHEAD,PVOID,INT); 21 22 WINE_DEFAULT_DEBUG_CHANNEL(user32); 23 24 #define KEY_LENGTH 1024 25 26 static ULONG User32TlsIndex; 27 HINSTANCE User32Instance; 28 29 PPROCESSINFO g_ppi = NULL; 30 SHAREDINFO gSharedInfo = {0}; 31 PSERVERINFO gpsi = NULL; 32 PUSER_HANDLE_TABLE gHandleTable = NULL; 33 PUSER_HANDLE_ENTRY gHandleEntries = NULL; 34 BOOLEAN gfLogonProcess = FALSE; 35 BOOLEAN gfServerProcess = FALSE; 36 BOOLEAN gfFirstThread = TRUE; 37 HICON hIconSmWindows = NULL, hIconWindows = NULL; 38 39 WCHAR szAppInit[KEY_LENGTH]; 40 41 BOOL 42 GetDllList(VOID) 43 { 44 NTSTATUS Status; 45 OBJECT_ATTRIBUTES Attributes; 46 BOOL bRet = FALSE; 47 BOOL bLoad; 48 HANDLE hKey = NULL; 49 DWORD dwSize; 50 PKEY_VALUE_PARTIAL_INFORMATION kvpInfo = NULL; 51 52 UNICODE_STRING szKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"); 53 UNICODE_STRING szLoadName = RTL_CONSTANT_STRING(L"LoadAppInit_DLLs"); 54 UNICODE_STRING szDllsName = RTL_CONSTANT_STRING(L"AppInit_DLLs"); 55 56 InitializeObjectAttributes(&Attributes, &szKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); 57 Status = NtOpenKey(&hKey, KEY_READ, &Attributes); 58 if (NT_SUCCESS(Status)) 59 { 60 dwSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD); 61 kvpInfo = HeapAlloc(GetProcessHeap(), 0, dwSize); 62 if (!kvpInfo) 63 goto end; 64 65 Status = NtQueryValueKey(hKey, 66 &szLoadName, 67 KeyValuePartialInformation, 68 kvpInfo, 69 dwSize, 70 &dwSize); 71 if (!NT_SUCCESS(Status)) 72 goto end; 73 74 RtlMoveMemory(&bLoad, 75 kvpInfo->Data, 76 kvpInfo->DataLength); 77 78 HeapFree(GetProcessHeap(), 0, kvpInfo); 79 kvpInfo = NULL; 80 81 if (bLoad) 82 { 83 Status = NtQueryValueKey(hKey, 84 &szDllsName, 85 KeyValuePartialInformation, 86 NULL, 87 0, 88 &dwSize); 89 if (Status != STATUS_BUFFER_TOO_SMALL) 90 goto end; 91 92 kvpInfo = HeapAlloc(GetProcessHeap(), 0, dwSize); 93 if (!kvpInfo) 94 goto end; 95 96 Status = NtQueryValueKey(hKey, 97 &szDllsName, 98 KeyValuePartialInformation, 99 kvpInfo, 100 dwSize, 101 &dwSize); 102 if (NT_SUCCESS(Status)) 103 { 104 LPWSTR lpBuffer = (LPWSTR)kvpInfo->Data; 105 if (*lpBuffer != UNICODE_NULL) 106 { 107 INT bytesToCopy, nullPos; 108 109 bytesToCopy = min(kvpInfo->DataLength, KEY_LENGTH * sizeof(WCHAR)); 110 111 if (bytesToCopy != 0) 112 { 113 RtlMoveMemory(szAppInit, 114 kvpInfo->Data, 115 bytesToCopy); 116 117 nullPos = (bytesToCopy / sizeof(WCHAR)) - 1; 118 119 /* ensure string is terminated */ 120 szAppInit[nullPos] = UNICODE_NULL; 121 122 bRet = TRUE; 123 } 124 } 125 } 126 } 127 } 128 129 end: 130 if (hKey) 131 NtClose(hKey); 132 133 if (kvpInfo) 134 HeapFree(GetProcessHeap(), 0, kvpInfo); 135 136 return bRet; 137 } 138 139 140 VOID 141 LoadAppInitDlls(VOID) 142 { 143 szAppInit[0] = UNICODE_NULL; 144 145 if (GetDllList()) 146 { 147 WCHAR buffer[KEY_LENGTH]; 148 LPWSTR ptr; 149 size_t i; 150 151 RtlCopyMemory(buffer, szAppInit, KEY_LENGTH * sizeof(WCHAR) ); 152 153 for (i = 0; i < KEY_LENGTH; ++ i) 154 { 155 if(buffer[i] == L' ' || buffer[i] == L',') 156 buffer[i] = 0; 157 } 158 159 for (i = 0; i < KEY_LENGTH; ) 160 { 161 if(buffer[i] == 0) 162 ++ i; 163 else 164 { 165 ptr = buffer + i; 166 i += wcslen(ptr); 167 LoadLibraryW(ptr); 168 } 169 } 170 } 171 } 172 173 VOID 174 UnloadAppInitDlls(VOID) 175 { 176 if (szAppInit[0] != UNICODE_NULL) 177 { 178 WCHAR buffer[KEY_LENGTH]; 179 HMODULE hModule; 180 LPWSTR ptr; 181 size_t i; 182 183 RtlCopyMemory(buffer, szAppInit, KEY_LENGTH * sizeof(WCHAR)); 184 185 for (i = 0; i < KEY_LENGTH; ++ i) 186 { 187 if(buffer[i] == L' ' || buffer[i] == L',') 188 buffer[i] = 0; 189 } 190 191 for (i = 0; i < KEY_LENGTH; ) 192 { 193 if(buffer[i] == 0) 194 ++ i; 195 else 196 { 197 ptr = buffer + i; 198 i += wcslen(ptr); 199 hModule = GetModuleHandleW(ptr); 200 FreeLibrary(hModule); 201 } 202 } 203 } 204 } 205 206 PVOID apfnDispatch[USER32_CALLBACK_MAXIMUM + 1] = 207 { 208 User32CallWindowProcFromKernel, 209 User32CallSendAsyncProcForKernel, 210 User32LoadSysMenuTemplateForKernel, 211 User32SetupDefaultCursors, 212 User32CallHookProcFromKernel, 213 User32CallEventProcFromKernel, 214 User32CallLoadMenuFromKernel, 215 User32CallClientThreadSetupFromKernel, 216 User32CallClientLoadLibraryFromKernel, 217 User32CallGetCharsetInfo, 218 User32CallCopyImageFromKernel, 219 User32CallSetWndIconsFromKernel, 220 User32DeliverUserAPC, 221 User32CallDDEPostFromKernel, 222 User32CallDDEGetFromKernel, 223 User32CallOBMFromKernel, 224 User32CallLPKFromKernel, 225 User32CallUMPDFromKernel, 226 }; 227 228 229 230 VOID 231 WINAPI 232 GdiProcessSetup(VOID); 233 234 BOOL 235 WINAPI 236 ClientThreadSetupHelper(BOOL IsCallback) 237 { 238 /* 239 * Normally we are called by win32k so the win32 thread pointers 240 * should be valid as they are set in win32k::InitThreadCallback. 241 */ 242 PCLIENTINFO ClientInfo = GetWin32ClientInfo(); 243 BOOLEAN IsFirstThread = _InterlockedExchange8((PCHAR)&gfFirstThread, FALSE); 244 245 TRACE("In ClientThreadSetup(IsCallback == %s, gfServerProcess = %s, IsFirstThread = %s)\n", 246 IsCallback ? "TRUE" : "FALSE", gfServerProcess ? "TRUE" : "FALSE", IsFirstThread ? "TRUE" : "FALSE"); 247 248 if (IsFirstThread) 249 GdiProcessSetup(); 250 251 /* Check for already initialized thread, and bail out if so */ 252 if (ClientInfo->CI_flags & CI_INITTHREAD) 253 { 254 ERR("ClientThreadSetup: Thread already initialized.\n"); 255 return FALSE; 256 } 257 258 /* 259 * CSRSS couldn't use user32::DllMain CSR server-to-server call to connect 260 * to win32k. So it is delayed to a manually-call to ClientThreadSetup. 261 * Also this needs to be done only for the first thread (since the connection 262 * is per-process). 263 */ 264 if (gfServerProcess && IsFirstThread) 265 { 266 NTSTATUS Status; 267 USERCONNECT UserCon; 268 269 RtlZeroMemory(&UserCon, sizeof(UserCon)); 270 271 /* Minimal setup of the connect info structure */ 272 UserCon.ulVersion = USER_VERSION; 273 // UserCon.dwDispatchCount; 274 275 /* Connect to win32k */ 276 Status = NtUserProcessConnect(NtCurrentProcess(), 277 &UserCon, 278 sizeof(UserCon)); 279 if (!NT_SUCCESS(Status)) return FALSE; 280 281 /* Retrieve data */ 282 g_ppi = ClientInfo->ppi; // Snapshot PI, used as pointer only! 283 gSharedInfo = UserCon.siClient; 284 gpsi = gSharedInfo.psi; 285 gHandleTable = gSharedInfo.aheList; 286 /* ReactOS-Specific! */ gHandleEntries = SharedPtrToUser(gHandleTable->handles); 287 288 // ERR("1 SI 0x%x : HT 0x%x : D 0x%x\n", 289 // gSharedInfo.psi, gSharedInfo.aheList, gSharedInfo.ulSharedDelta); 290 } 291 292 TRACE("Checkpoint (register PFN)\n"); 293 if (!RegisterClientPFN()) 294 { 295 ERR("RegisterClientPFN failed\n"); 296 return FALSE; 297 } 298 299 /* Mark this thread as initialized */ 300 ClientInfo->CI_flags |= CI_INITTHREAD; 301 302 /* Initialization that should be done once per process */ 303 if (IsFirstThread) 304 { 305 TRACE("Checkpoint (Allocating TLS)\n"); 306 307 /* Allocate an index for user32 thread local data */ 308 User32TlsIndex = TlsAlloc(); 309 if (User32TlsIndex == TLS_OUT_OF_INDEXES) 310 return FALSE; 311 312 // HAAAAAAAAAACK!!!!!! 313 // ASSERT(gpsi); 314 if (!gpsi) ERR("AAAAAAAAAAAHHHHHHHHHHHHHH!!!!!!!! gpsi == NULL !!!!\n"); 315 if (gpsi) 316 { 317 TRACE("Checkpoint (MessageInit)\n"); 318 319 if (MessageInit()) 320 { 321 TRACE("Checkpoint (MenuInit)\n"); 322 if (MenuInit()) 323 { 324 TRACE("Checkpoint initialization done OK\n"); 325 InitializeCriticalSection(&U32AccelCacheLock); 326 LoadAppInitDlls(); 327 return TRUE; 328 } 329 MessageCleanup(); 330 } 331 332 TlsFree(User32TlsIndex); 333 return FALSE; 334 } 335 } 336 337 return TRUE; 338 } 339 340 /* 341 * @implemented 342 */ 343 BOOL 344 WINAPI 345 ClientThreadSetup(VOID) 346 { 347 // 348 // This routine, in Windows, does a lot of what Init does, but in a radically 349 // different way. 350 // 351 // In Windows, because CSRSS's threads have TIF_CSRSSTHREAD set (we have this 352 // flag in ROS but not sure if we use it), the xxxClientThreadSetup callback 353 // isn't made when CSRSS first loads WINSRV.DLL (which loads USER32.DLL). 354 // 355 // However, all the other calls are made as normal, and WINSRV.DLL loads 356 // USER32.dll, the DllMain runs, and eventually the first NtUser system call is 357 // made which initializes Win32k (and initializes the thread, but as mentioned 358 // above, the thread is marked as TIF_CSRSSTHREAD). 359 // 360 // In the DllMain of User32, there is also a CsrClientConnectToServer call to 361 // server 2 (winsrv). When this is done from CSRSS, the "InServer" flag is set, 362 // so user32 will remember that it's running inside of CSRSS. Also, another 363 // flag, called "FirstThread" is manually set by DllMain. 364 // 365 // Then, WINSRV finishes loading, and CSRSRV starts the API thread/loop. This 366 // code then calls CsrConnectToUser, which calls... ClientThreadStartup. Now 367 // this routine detects that it's in the server process, which means it's CSRSS 368 // and that the callback never happened. It does some first-time-Win32k connection 369 // initialization and caches a bunch of things -- if it's the first thread. It also 370 // acquires a critical section to initialize GDI -- and then resets the first thread 371 // flag. 372 // 373 // For now, we'll do none of this, but to support Windows' CSRSRV.DLL which calls 374 // CsrConnectToUser, we'll pretend we "did something" here. Then the rest will 375 // continue as normal. 376 // 377 378 // FIXME: Disabling this call is a HACK!! See also User32CallClientThreadSetupFromKernel... 379 // return ClientThreadSetupHelper(FALSE); 380 TRACE("ClientThreadSetup is not implemented\n"); 381 return TRUE; 382 } 383 384 BOOL 385 Init(PUSERCONNECT UserCon /*PUSERSRV_API_CONNECTINFO*/) 386 { 387 NTSTATUS Status = STATUS_SUCCESS; 388 389 TRACE("user32::Init(0x%p) -->\n", UserCon); 390 391 RtlInitializeCriticalSection(&gcsUserApiHook); 392 393 /* Initialize callback table in PEB data */ 394 NtCurrentPeb()->KernelCallbackTable = apfnDispatch; 395 NtCurrentPeb()->PostProcessInitRoutine = NULL; 396 397 // This is a HACK!! // 398 gfServerProcess = FALSE; 399 gfFirstThread = TRUE; 400 //// End of HACK!! /// 401 402 /* 403 * Retrieve data from the connect info structure if the initializing 404 * process is not CSRSS. In case it is, this will be done from inside 405 * ClientThreadSetup. 406 */ 407 if (!gfServerProcess) 408 { 409 // FIXME: HACK!! We should fixup for the NtUserProcessConnect fixups 410 // because it was made in the context of CSRSS process and not ours!! 411 // So... as long as we don't fix that, we need to redo again a call 412 // to NtUserProcessConnect... How perverse is that?! 413 // 414 // HACK(2): This call is necessary since we disabled 415 // the CSR call in DllMain... 416 { 417 RtlZeroMemory(UserCon, sizeof(*UserCon)); 418 419 /* Minimal setup of the connect info structure */ 420 UserCon->ulVersion = USER_VERSION; 421 // UserCon->dwDispatchCount; 422 423 TRACE("HACK: Hackish NtUserProcessConnect call!!\n"); 424 /* Connect to win32k */ 425 Status = NtUserProcessConnect(NtCurrentProcess(), 426 UserCon, 427 sizeof(*UserCon)); 428 if (!NT_SUCCESS(Status)) return FALSE; 429 } 430 431 // 432 // We continue as we should do normally... 433 // 434 435 /* Retrieve data */ 436 g_ppi = GetWin32ClientInfo()->ppi; // Snapshot PI, used as pointer only! 437 gSharedInfo = UserCon->siClient; 438 gpsi = gSharedInfo.psi; 439 gHandleTable = gSharedInfo.aheList; 440 /* ReactOS-Specific! */ gHandleEntries = SharedPtrToUser(gHandleTable->handles); 441 } 442 443 // FIXME: Yet another hack... This call should normally not be done here, but 444 // instead in ClientThreadSetup, and in User32CallClientThreadSetupFromKernel as well. 445 TRACE("HACK: Using Init-ClientThreadSetupHelper hack!!\n"); 446 if (!ClientThreadSetupHelper(FALSE)) 447 { 448 TRACE("Init-ClientThreadSetupHelper hack failed!\n"); 449 return FALSE; 450 } 451 452 TRACE("<-- user32::Init()\n"); 453 454 return NT_SUCCESS(Status); 455 } 456 457 VOID 458 Cleanup(VOID) 459 { 460 UnloadAppInitDlls(); 461 DeleteCriticalSection(&U32AccelCacheLock); 462 MenuCleanup(); 463 MessageCleanup(); 464 TlsFree(User32TlsIndex); 465 DeleteFrameBrushes(); 466 } 467 468 INT WINAPI 469 DllMain( 470 IN PVOID hInstanceDll, 471 IN ULONG dwReason, 472 IN PVOID reserved) 473 { 474 switch (dwReason) 475 { 476 case DLL_PROCESS_ATTACH: 477 { 478 479 #define WIN_OBJ_DIR L"\\Windows" 480 #define SESSION_DIR L"\\Sessions" 481 482 USERSRV_API_CONNECTINFO ConnectInfo; // USERCONNECT 483 484 #if 0 // Disabling this code is a BIG HACK!! 485 486 NTSTATUS Status; 487 ULONG ConnectInfoSize = sizeof(ConnectInfo); 488 WCHAR SessionDir[256]; 489 490 /* Cache the PEB and Session ID */ 491 PPEB Peb = NtCurrentPeb(); 492 ULONG SessionId = Peb->SessionId; // gSessionId 493 494 TRACE("user32::DllMain\n"); 495 496 /* Don't bother us for each thread */ 497 DisableThreadLibraryCalls(hInstanceDll); 498 499 RtlZeroMemory(&ConnectInfo, sizeof(ConnectInfo)); 500 501 /* Minimal setup of the connect info structure */ 502 ConnectInfo.ulVersion = USER_VERSION; 503 504 /* Setup the Object Directory path */ 505 if (!SessionId) 506 { 507 /* Use the raw path */ 508 wcscpy(SessionDir, WIN_OBJ_DIR); 509 } 510 else 511 { 512 /* Use the session path */ 513 swprintf(SessionDir, 514 L"%ws\\%ld%ws", 515 SESSION_DIR, 516 SessionId, 517 WIN_OBJ_DIR); 518 } 519 520 TRACE("Checkpoint (call CSR)\n"); 521 522 /* Connect to the USER Server */ 523 Status = CsrClientConnectToServer(SessionDir, 524 USERSRV_SERVERDLL_INDEX, 525 &ConnectInfo, 526 &ConnectInfoSize, 527 &gfServerProcess); 528 if (!NT_SUCCESS(Status)) 529 { 530 ERR("Failed to connect to CSR (Status %lx)\n", Status); 531 return FALSE; 532 } 533 534 TRACE("Checkpoint (CSR called)\n"); 535 536 #endif 537 538 User32Instance = hInstanceDll; 539 540 /* Finish initialization */ 541 TRACE("Checkpoint (call Init)\n"); 542 if (!Init(&ConnectInfo)) 543 return FALSE; 544 545 if (!gfServerProcess) 546 { 547 HINSTANCE hImm32 = NULL; 548 549 if (gpsi && (gpsi->dwSRVIFlags & SRVINFO_IMM32)) 550 { 551 WCHAR szImmFile[MAX_PATH]; 552 InitializeImmEntryTable(); 553 GetImmFileName(szImmFile, _countof(szImmFile)); 554 hImm32 = GetModuleHandleW(szImmFile); 555 } 556 557 if (!IMM_FN(ImmRegisterClient)(&gSharedInfo, hImm32)) 558 return FALSE; 559 } 560 break; 561 } 562 563 case DLL_PROCESS_DETACH: 564 { 565 if (ghImm32) 566 FreeLibrary(ghImm32); 567 568 Cleanup(); 569 break; 570 } 571 } 572 573 /* Finally, initialize GDI */ 574 return GdiDllInitialize(hInstanceDll, dwReason, reserved); 575 } 576 577 NTSTATUS 578 WINAPI 579 User32CallClientThreadSetupFromKernel(PVOID Arguments, ULONG ArgumentLength) 580 { 581 TRACE("User32CallClientThreadSetupFromKernel -->\n"); 582 // FIXME: Disabling this call is a HACK!! See also ClientThreadSetup... 583 // ClientThreadSetupHelper(TRUE); 584 TRACE("<-- User32CallClientThreadSetupFromKernel\n"); 585 return ZwCallbackReturn(NULL, 0, STATUS_SUCCESS); 586 } 587 588 NTSTATUS 589 WINAPI 590 User32CallGetCharsetInfo(PVOID Arguments, ULONG ArgumentLength) 591 { 592 BOOL Ret; 593 PGET_CHARSET_INFO pgci = (PGET_CHARSET_INFO)Arguments; 594 595 TRACE("GetCharsetInfo\n"); 596 597 Ret = TranslateCharsetInfo((DWORD *)(ULONG_PTR)pgci->Locale, &pgci->Cs, TCI_SRCLOCALE); 598 599 return ZwCallbackReturn(Arguments, ArgumentLength, Ret ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); 600 } 601 602 NTSTATUS 603 WINAPI 604 User32CallSetWndIconsFromKernel(PVOID Arguments, ULONG ArgumentLength) 605 { 606 PSETWNDICONS_CALLBACK_ARGUMENTS Common = Arguments; 607 608 if (!gpsi->hIconSmWindows) 609 { 610 Common->hIconSample = LoadImageW(0, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); 611 Common->hIconHand = LoadImageW(0, IDI_HAND, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); 612 Common->hIconQuestion = LoadImageW(0, IDI_QUESTION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); 613 Common->hIconBang = LoadImageW(0, IDI_EXCLAMATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); 614 Common->hIconNote = LoadImageW(0, IDI_ASTERISK, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); 615 Common->hIconWindows = LoadImageW(0, IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); 616 Common->hIconSmWindows = LoadImageW(0, IDI_WINLOGO, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); 617 hIconWindows = Common->hIconWindows; 618 hIconSmWindows = Common->hIconSmWindows; 619 } 620 ERR("hIconSmWindows %p hIconWindows %p \n",hIconSmWindows,hIconWindows); 621 return ZwCallbackReturn(Arguments, ArgumentLength, STATUS_SUCCESS); 622 } 623 624 NTSTATUS 625 WINAPI 626 User32DeliverUserAPC(PVOID Arguments, ULONG ArgumentLength) 627 { 628 return ZwCallbackReturn(0, 0, STATUS_SUCCESS); 629 } 630 631 NTSTATUS 632 WINAPI 633 User32CallOBMFromKernel(PVOID Arguments, ULONG ArgumentLength) 634 { 635 BITMAP bmp; 636 PSETOBM_CALLBACK_ARGUMENTS Common = Arguments; 637 638 GetObjectW(LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE)), sizeof(bmp), &bmp); 639 Common->oembmi[OBI_CLOSE].cx = bmp.bmWidth; 640 Common->oembmi[OBI_CLOSE].cy = bmp.bmHeight; 641 642 GetObjectW(LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW)), sizeof(bmp), &bmp); 643 Common->oembmi[OBI_MNARROW].cx = bmp.bmWidth; 644 Common->oembmi[OBI_MNARROW].cy = bmp.bmHeight; 645 646 GetObjectW(LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW)), sizeof(bmp), &bmp); 647 Common->oembmi[OBI_DNARROW].cx = bmp.bmWidth; 648 Common->oembmi[OBI_DNARROW].cy = bmp.bmHeight; 649 650 GetObjectW(LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI)), sizeof(bmp), &bmp); 651 Common->oembmi[OBI_DNARROWI].cx = bmp.bmWidth; 652 Common->oembmi[OBI_DNARROWI].cy = bmp.bmHeight; 653 654 GetObjectW(LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW)), sizeof(bmp), &bmp); 655 Common->oembmi[OBI_UPARROW].cx = bmp.bmWidth; 656 Common->oembmi[OBI_UPARROW].cy = bmp.bmHeight; 657 658 GetObjectW(LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI)), sizeof(bmp), &bmp); 659 Common->oembmi[OBI_UPARROWI].cx = bmp.bmWidth; 660 Common->oembmi[OBI_UPARROWI].cy = bmp.bmHeight; 661 662 return ZwCallbackReturn(Arguments, ArgumentLength, STATUS_SUCCESS); 663 } 664 665 NTSTATUS WINAPI User32CallLPKFromKernel(PVOID Arguments, ULONG ArgumentLength) 666 { 667 BOOL bResult; 668 PLPK_CALLBACK_ARGUMENTS Argument; 669 670 Argument = (PLPK_CALLBACK_ARGUMENTS)Arguments; 671 672 Argument->lpString = (LPWSTR)((ULONG_PTR)Argument->lpString + (ULONG_PTR)Argument); 673 674 bResult = ExtTextOutW(Argument->hdc, 675 Argument->x, 676 Argument->y, 677 Argument->flags, 678 (Argument->bRect) ? &Argument->rect : NULL, 679 Argument->lpString, 680 Argument->count, 681 NULL); 682 683 return ZwCallbackReturn(&bResult, sizeof(BOOL), STATUS_SUCCESS); 684 } 685 686 NTSTATUS WINAPI User32CallUMPDFromKernel(PVOID Arguments, ULONG ArgumentLength) 687 { 688 DWORD Buffer[MAX_USER_MODE_DRV_BUFFER]; 689 INT cbSize = 0; 690 NTSTATUS Status = STATUS_SUCCESS; 691 PUMPDPKTHEAD pkt, pktOut = NULL; 692 693 pkt = (PUMPDPKTHEAD)Arguments; 694 695 if ( pkt->RetSize <= sizeof(Buffer) ) 696 { 697 pktOut = (PUMPDPKTHEAD)Buffer; 698 699 if ( (GdiPrinterThunk( pkt, pktOut, pkt->RetSize ) == GDI_ERROR) ) 700 { 701 pktOut = NULL; 702 Status = STATUS_UNSUCCESSFUL; 703 } 704 else 705 { 706 cbSize = pkt->RetSize; 707 } 708 } 709 else 710 { 711 Status = STATUS_NO_MEMORY; 712 } 713 return ZwCallbackReturn( pktOut, cbSize, Status ); 714 } 715