1 #include <user32.h> 2 3 #include <ndk/cmfuncs.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 PUSER_HANDLE_TABLE gHandleTable = NULL; 31 PUSER_HANDLE_ENTRY gHandleEntries = NULL; 32 PSERVERINFO gpsi = NULL; 33 SHAREDINFO gSharedInfo = {0}; 34 ULONG_PTR g_ulSharedDelta; 35 BOOLEAN gfLogonProcess = FALSE; 36 BOOLEAN gfServerProcess = FALSE; 37 BOOLEAN gfFirstThread = TRUE; 38 HICON hIconSmWindows = NULL, hIconWindows = NULL; 39 40 WCHAR szAppInit[KEY_LENGTH]; 41 42 BOOL 43 GetDllList(VOID) 44 { 45 NTSTATUS Status; 46 OBJECT_ATTRIBUTES Attributes; 47 BOOL bRet = FALSE; 48 BOOL bLoad; 49 HANDLE hKey = NULL; 50 DWORD dwSize; 51 PKEY_VALUE_PARTIAL_INFORMATION kvpInfo = NULL; 52 53 UNICODE_STRING szKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"); 54 UNICODE_STRING szLoadName = RTL_CONSTANT_STRING(L"LoadAppInit_DLLs"); 55 UNICODE_STRING szDllsName = RTL_CONSTANT_STRING(L"AppInit_DLLs"); 56 57 InitializeObjectAttributes(&Attributes, &szKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); 58 Status = NtOpenKey(&hKey, KEY_READ, &Attributes); 59 if (NT_SUCCESS(Status)) 60 { 61 dwSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD); 62 kvpInfo = HeapAlloc(GetProcessHeap(), 0, dwSize); 63 if (!kvpInfo) 64 goto end; 65 66 Status = NtQueryValueKey(hKey, 67 &szLoadName, 68 KeyValuePartialInformation, 69 kvpInfo, 70 dwSize, 71 &dwSize); 72 if (!NT_SUCCESS(Status)) 73 goto end; 74 75 RtlMoveMemory(&bLoad, 76 kvpInfo->Data, 77 kvpInfo->DataLength); 78 79 HeapFree(GetProcessHeap(), 0, kvpInfo); 80 kvpInfo = NULL; 81 82 if (bLoad) 83 { 84 Status = NtQueryValueKey(hKey, 85 &szDllsName, 86 KeyValuePartialInformation, 87 NULL, 88 0, 89 &dwSize); 90 if (Status != STATUS_BUFFER_TOO_SMALL) 91 goto end; 92 93 kvpInfo = HeapAlloc(GetProcessHeap(), 0, dwSize); 94 if (!kvpInfo) 95 goto end; 96 97 Status = NtQueryValueKey(hKey, 98 &szDllsName, 99 KeyValuePartialInformation, 100 kvpInfo, 101 dwSize, 102 &dwSize); 103 if (NT_SUCCESS(Status)) 104 { 105 LPWSTR lpBuffer = (LPWSTR)kvpInfo->Data; 106 if (*lpBuffer != UNICODE_NULL) 107 { 108 INT bytesToCopy, nullPos; 109 110 bytesToCopy = min(kvpInfo->DataLength, KEY_LENGTH * sizeof(WCHAR)); 111 112 if (bytesToCopy != 0) 113 { 114 RtlMoveMemory(szAppInit, 115 kvpInfo->Data, 116 bytesToCopy); 117 118 nullPos = (bytesToCopy / sizeof(WCHAR)) - 1; 119 120 /* ensure string is terminated */ 121 szAppInit[nullPos] = UNICODE_NULL; 122 123 bRet = TRUE; 124 } 125 } 126 } 127 } 128 } 129 130 end: 131 if (hKey) 132 NtClose(hKey); 133 134 if (kvpInfo) 135 HeapFree(GetProcessHeap(), 0, kvpInfo); 136 137 return bRet; 138 } 139 140 141 VOID 142 LoadAppInitDlls(VOID) 143 { 144 szAppInit[0] = UNICODE_NULL; 145 146 if (GetDllList()) 147 { 148 WCHAR buffer[KEY_LENGTH]; 149 LPWSTR ptr; 150 size_t i; 151 152 RtlCopyMemory(buffer, szAppInit, KEY_LENGTH * sizeof(WCHAR) ); 153 154 for (i = 0; i < KEY_LENGTH; ++ i) 155 { 156 if(buffer[i] == L' ' || buffer[i] == L',') 157 buffer[i] = 0; 158 } 159 160 for (i = 0; i < KEY_LENGTH; ) 161 { 162 if(buffer[i] == 0) 163 ++ i; 164 else 165 { 166 ptr = buffer + i; 167 i += wcslen(ptr); 168 LoadLibraryW(ptr); 169 } 170 } 171 } 172 } 173 174 VOID 175 UnloadAppInitDlls(VOID) 176 { 177 if (szAppInit[0] != UNICODE_NULL) 178 { 179 WCHAR buffer[KEY_LENGTH]; 180 HMODULE hModule; 181 LPWSTR ptr; 182 size_t i; 183 184 RtlCopyMemory(buffer, szAppInit, KEY_LENGTH * sizeof(WCHAR)); 185 186 for (i = 0; i < KEY_LENGTH; ++ i) 187 { 188 if(buffer[i] == L' ' || buffer[i] == L',') 189 buffer[i] = 0; 190 } 191 192 for (i = 0; i < KEY_LENGTH; ) 193 { 194 if(buffer[i] == 0) 195 ++ i; 196 else 197 { 198 ptr = buffer + i; 199 i += wcslen(ptr); 200 hModule = GetModuleHandleW(ptr); 201 FreeLibrary(hModule); 202 } 203 } 204 } 205 } 206 207 PVOID apfnDispatch[USER32_CALLBACK_MAXIMUM + 1] = 208 { 209 User32CallWindowProcFromKernel, 210 User32CallSendAsyncProcForKernel, 211 User32LoadSysMenuTemplateForKernel, 212 User32SetupDefaultCursors, 213 User32CallHookProcFromKernel, 214 User32CallEventProcFromKernel, 215 User32CallLoadMenuFromKernel, 216 User32CallClientThreadSetupFromKernel, 217 User32CallClientLoadLibraryFromKernel, 218 User32CallGetCharsetInfo, 219 User32CallCopyImageFromKernel, 220 User32CallSetWndIconsFromKernel, 221 User32DeliverUserAPC, 222 User32CallDDEPostFromKernel, 223 User32CallDDEGetFromKernel, 224 User32CallOBMFromKernel, 225 User32CallLPKFromKernel, 226 User32CallUMPDFromKernel, 227 }; 228 229 230 231 VOID 232 WINAPI 233 GdiProcessSetup(VOID); 234 235 BOOL 236 WINAPI 237 ClientThreadSetupHelper(BOOL IsCallback) 238 { 239 /* 240 * Normally we are called by win32k so the win32 thread pointers 241 * should be valid as they are set in win32k::InitThreadCallback. 242 */ 243 PCLIENTINFO ClientInfo = GetWin32ClientInfo(); 244 BOOLEAN IsFirstThread = _InterlockedExchange8((PCHAR)&gfFirstThread, FALSE); 245 246 TRACE("In ClientThreadSetup(IsCallback == %s, gfServerProcess = %s, IsFirstThread = %s)\n", 247 IsCallback ? "TRUE" : "FALSE", gfServerProcess ? "TRUE" : "FALSE", IsFirstThread ? "TRUE" : "FALSE"); 248 249 if (IsFirstThread) 250 GdiProcessSetup(); 251 252 /* Check for already initialized thread, and bail out if so */ 253 if (ClientInfo->CI_flags & CI_INITTHREAD) 254 { 255 ERR("ClientThreadSetup: Thread already initialized.\n"); 256 return FALSE; 257 } 258 259 /* 260 * CSRSS couldn't use user32::DllMain CSR server-to-server call to connect 261 * to win32k. So it is delayed to a manually-call to ClientThreadSetup. 262 * Also this needs to be done only for the first thread (since the connection 263 * is per-process). 264 */ 265 if (gfServerProcess && IsFirstThread) 266 { 267 NTSTATUS Status; 268 USERCONNECT UserCon; 269 270 RtlZeroMemory(&UserCon, sizeof(UserCon)); 271 272 /* Minimal setup of the connect info structure */ 273 UserCon.ulVersion = USER_VERSION; 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 g_ulSharedDelta = UserCon.siClient.ulSharedDelta; 284 gpsi = SharedPtrToUser(UserCon.siClient.psi); 285 gHandleTable = SharedPtrToUser(UserCon.siClient.aheList); 286 gHandleEntries = SharedPtrToUser(gHandleTable->handles); 287 gSharedInfo = UserCon.siClient; 288 289 // ERR("1 SI 0x%x : HT 0x%x : D 0x%x\n", UserCon.siClient.psi, UserCon.siClient.aheList, g_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 422 TRACE("HACK: Hackish NtUserProcessConnect call!!\n"); 423 /* Connect to win32k */ 424 Status = NtUserProcessConnect(NtCurrentProcess(), 425 UserCon, 426 sizeof(*UserCon)); 427 if (!NT_SUCCESS(Status)) return FALSE; 428 } 429 430 // 431 // We continue as we should do normally... 432 // 433 434 /* Retrieve data */ 435 g_ppi = GetWin32ClientInfo()->ppi; // Snapshot PI, used as pointer only! 436 g_ulSharedDelta = UserCon->siClient.ulSharedDelta; 437 gpsi = SharedPtrToUser(UserCon->siClient.psi); 438 gHandleTable = SharedPtrToUser(UserCon->siClient.aheList); 439 gHandleEntries = SharedPtrToUser(gHandleTable->handles); 440 gSharedInfo = UserCon->siClient; 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 #if WIN32K_ISNT_BROKEN 548 InitializeImmEntryTable(); 549 #else 550 /* imm32 takes a refcount and prevents us from unloading */ 551 LoadLibraryW(L"user32"); 552 #endif 553 // 554 // Wine is stub and throws an exception so save this for real Imm32.dll testing!!!! 555 // 556 //gImmApiEntries.pImmRegisterClient(&gSharedInfo, ghImm32); 557 } 558 559 break; 560 } 561 562 case DLL_PROCESS_DETACH: 563 { 564 if (ghImm32) 565 FreeLibrary(ghImm32); 566 567 Cleanup(); 568 break; 569 } 570 } 571 572 /* Finally, initialize GDI */ 573 return GdiDllInitialize(hInstanceDll, dwReason, reserved); 574 } 575 576 NTSTATUS 577 WINAPI 578 User32CallClientThreadSetupFromKernel(PVOID Arguments, ULONG ArgumentLength) 579 { 580 TRACE("User32CallClientThreadSetupFromKernel -->\n"); 581 // FIXME: Disabling this call is a HACK!! See also ClientThreadSetup... 582 // ClientThreadSetupHelper(TRUE); 583 TRACE("<-- User32CallClientThreadSetupFromKernel\n"); 584 return ZwCallbackReturn(NULL, 0, STATUS_SUCCESS); 585 } 586 587 NTSTATUS 588 WINAPI 589 User32CallGetCharsetInfo(PVOID Arguments, ULONG ArgumentLength) 590 { 591 BOOL Ret; 592 PGET_CHARSET_INFO pgci = (PGET_CHARSET_INFO)Arguments; 593 594 TRACE("GetCharsetInfo\n"); 595 596 Ret = TranslateCharsetInfo((DWORD *)(ULONG_PTR)pgci->Locale, &pgci->Cs, TCI_SRCLOCALE); 597 598 return ZwCallbackReturn(Arguments, ArgumentLength, Ret ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); 599 } 600 601 NTSTATUS 602 WINAPI 603 User32CallSetWndIconsFromKernel(PVOID Arguments, ULONG ArgumentLength) 604 { 605 PSETWNDICONS_CALLBACK_ARGUMENTS Common = Arguments; 606 607 if (!gpsi->hIconSmWindows) 608 { 609 Common->hIconSample = LoadImageW(0, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); 610 Common->hIconHand = LoadImageW(0, IDI_HAND, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); 611 Common->hIconQuestion = LoadImageW(0, IDI_QUESTION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); 612 Common->hIconBang = LoadImageW(0, IDI_EXCLAMATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); 613 Common->hIconNote = LoadImageW(0, IDI_ASTERISK, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); 614 Common->hIconWindows = LoadImageW(0, IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); 615 Common->hIconSmWindows = LoadImageW(0, IDI_WINLOGO, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); 616 hIconWindows = Common->hIconWindows; 617 hIconSmWindows = Common->hIconSmWindows; 618 } 619 ERR("hIconSmWindows %p hIconWindows %p \n",hIconSmWindows,hIconWindows); 620 return ZwCallbackReturn(Arguments, ArgumentLength, STATUS_SUCCESS); 621 } 622 623 NTSTATUS 624 WINAPI 625 User32DeliverUserAPC(PVOID Arguments, ULONG ArgumentLength) 626 { 627 return ZwCallbackReturn(0, 0, STATUS_SUCCESS); 628 } 629 630 NTSTATUS 631 WINAPI 632 User32CallOBMFromKernel(PVOID Arguments, ULONG ArgumentLength) 633 { 634 BITMAP bmp; 635 PSETOBM_CALLBACK_ARGUMENTS Common = Arguments; 636 637 GetObjectW(LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE)), sizeof(bmp), &bmp); 638 Common->oembmi[OBI_CLOSE].cx = bmp.bmWidth; 639 Common->oembmi[OBI_CLOSE].cy = bmp.bmHeight; 640 641 GetObjectW(LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW)), sizeof(bmp), &bmp); 642 Common->oembmi[OBI_MNARROW].cx = bmp.bmWidth; 643 Common->oembmi[OBI_MNARROW].cy = bmp.bmHeight; 644 645 GetObjectW(LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW)), sizeof(bmp), &bmp); 646 Common->oembmi[OBI_DNARROW].cx = bmp.bmWidth; 647 Common->oembmi[OBI_DNARROW].cy = bmp.bmHeight; 648 649 GetObjectW(LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI)), sizeof(bmp), &bmp); 650 Common->oembmi[OBI_DNARROWI].cx = bmp.bmWidth; 651 Common->oembmi[OBI_DNARROWI].cy = bmp.bmHeight; 652 653 GetObjectW(LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW)), sizeof(bmp), &bmp); 654 Common->oembmi[OBI_UPARROW].cx = bmp.bmWidth; 655 Common->oembmi[OBI_UPARROW].cy = bmp.bmHeight; 656 657 GetObjectW(LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI)), sizeof(bmp), &bmp); 658 Common->oembmi[OBI_UPARROWI].cx = bmp.bmWidth; 659 Common->oembmi[OBI_UPARROWI].cy = bmp.bmHeight; 660 661 return ZwCallbackReturn(Arguments, ArgumentLength, STATUS_SUCCESS); 662 } 663 664 NTSTATUS WINAPI User32CallLPKFromKernel(PVOID Arguments, ULONG ArgumentLength) 665 { 666 BOOL bResult; 667 PLPK_CALLBACK_ARGUMENTS Argument; 668 669 Argument = (PLPK_CALLBACK_ARGUMENTS)Arguments; 670 671 Argument->lpString = (LPWSTR)((ULONG_PTR)Argument->lpString + (ULONG_PTR)Argument); 672 673 bResult = ExtTextOutW(Argument->hdc, 674 Argument->x, 675 Argument->y, 676 Argument->flags, 677 (Argument->bRect) ? &Argument->rect : NULL, 678 Argument->lpString, 679 Argument->count, 680 NULL); 681 682 return ZwCallbackReturn(&bResult, sizeof(BOOL), STATUS_SUCCESS); 683 } 684 685 NTSTATUS WINAPI User32CallUMPDFromKernel(PVOID Arguments, ULONG ArgumentLength) 686 { 687 DWORD Buffer[MAX_USER_MODE_DRV_BUFFER]; 688 INT cbSize = 0; 689 NTSTATUS Status = STATUS_SUCCESS; 690 PUMPDPKTHEAD pkt, pktOut = NULL; 691 692 pkt = (PUMPDPKTHEAD)Arguments; 693 694 if ( pkt->RetSize <= sizeof(Buffer) ) 695 { 696 pktOut = (PUMPDPKTHEAD)Buffer; 697 698 if ( (GdiPrinterThunk( pkt, pktOut, pkt->RetSize ) == GDI_ERROR) ) 699 { 700 pktOut = NULL; 701 Status = STATUS_UNSUCCESSFUL; 702 } 703 else 704 { 705 cbSize = pkt->RetSize; 706 } 707 } 708 else 709 { 710 Status = STATUS_NO_MEMORY; 711 } 712 return ZwCallbackReturn( pktOut, cbSize, Status ); 713 } 714