Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

desktop.c

Go to the documentation of this file.
00001 /***************************** Module Header ******************************\ 00002 * Module Name: desktop.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module contains everything related to the desktop support. 00007 * 00008 * History: 00009 * 23-Oct-1990 DarrinM Created. 00010 * 01-Feb-1991 JimA Added new API stubs. 00011 * 11-Feb-1991 JimA Added access checks. 00012 \***************************************************************************/ 00013 00014 #include "precomp.h" 00015 #pragma hdrstop 00016 00017 typedef struct _DESKTOP_CONTEXT { 00018 PUNICODE_STRING pstrDevice; 00019 LPDEVMODE lpDevMode; 00020 DWORD dwFlags; 00021 } DESKTOP_CONTEXT, *PDESKTOP_CONTEXT; 00022 00023 extern BOOL fGdiEnabled; 00024 00025 /* 00026 * We use these to protect a handle we're currently using from being closed. 00027 */ 00028 PEPROCESS gProcessInUse; 00029 HANDLE gHandleInUse; 00030 00031 /* 00032 * Debug Related Info. 00033 */ 00034 #if DBG 00035 DWORD gDesktopsBusy; // diagnostic 00036 #endif 00037 00038 VOID FreeView( 00039 PEPROCESS Process, 00040 PDESKTOP pdesk); 00041 00042 #ifdef POOL_INSTR 00043 extern FAST_MUTEX* gpAllocFastMutex; // mutex to syncronize pool allocations 00044 #endif // POOL_INSTR 00045 00046 00047 PVOID DesktopAlloc( 00048 PDESKTOP pdesk, 00049 UINT uSize, 00050 DWORD tag) 00051 { 00052 if (pdesk->dwDTFlags & DF_DESTROYED) { 00053 RIPMSG2(RIP_ERROR, 00054 "DesktopAlloc: tag %d pdesk %#p is destroyed", 00055 tag, 00056 pdesk); 00057 return NULL; 00058 } 00059 00060 return Win32HeapAlloc(pdesk->pheapDesktop, uSize, tag, 0); 00061 } 00062 00063 #if DBG 00064 00065 WCHAR s_strName[64]; 00066 WCHAR s_strNameNull[] = L"null"; 00067 00068 /***************************************************************************\ 00069 * GetDesktopName 00070 * 00071 * This is for debug purposes. 00072 * 00073 * Dec-10-1997 CLUPU Created. 00074 \***************************************************************************/ 00075 PWCHAR GetDesktopName( 00076 PDESKTOP pdesk) 00077 { 00078 POBJECT_HEADER pHead; 00079 POBJECT_HEADER_NAME_INFO pNameInfo; 00080 00081 if (pdesk == NULL) { 00082 return s_strNameNull; 00083 } 00084 pHead = OBJECT_TO_OBJECT_HEADER(pdesk); 00085 pNameInfo = (POBJECT_HEADER_NAME_INFO)((char*)pHead - pHead->NameInfoOffset); 00086 00087 UserAssert(pNameInfo->Name.Length < sizeof(s_strName)); 00088 00089 RtlCopyMemory(s_strName, pNameInfo->Name.Buffer, pNameInfo->Name.Length); 00090 s_strName[pNameInfo->Name.Length / sizeof(WCHAR)] = 0; 00091 00092 return s_strName; 00093 } 00094 00095 #endif // DBG 00096 00097 /***************************************************************************\ 00098 * xxxDesktopThread 00099 * 00100 * This thread owns all desktops windows on a windowstation. 00101 * While waiting for messages, it moves the mouse cursor without entering the 00102 * USER critical section. The RIT does the rest of the mouse input processing. 00103 * 00104 * History: 00105 * 03-Dec-1993 JimA Created. 00106 \***************************************************************************/ 00107 00108 #ifdef LOCK_MOUSE_CODE 00109 #pragma alloc_text(MOUSE, xxxDesktopThread) 00110 #endif 00111 00112 #define OBJECTS_COUNT 4 00113 00114 VOID xxxDesktopThread( 00115 PTERMINAL pTerm) 00116 { 00117 KPRIORITY Priority; 00118 PTHREADINFO ptiCurrent; 00119 PQ pqOriginal; 00120 UNICODE_STRING strThreadName; 00121 PKEVENT *apRITEvents; 00122 PKEVENT pEvent; 00123 MSGWAITCALLBACK pfnHidChangeRoutine = NULL; 00124 DWORD nEvents = 0; 00125 UINT idMouseInput; 00126 UINT idDesktopDestroy; 00127 UINT idPumpMessages; 00128 UINT idHungThread; 00129 PKWAIT_BLOCK WaitBlockArray; 00130 00131 UserAssert(pTerm != NULL); 00132 00133 /* 00134 * Set the desktop thread's priority to low realtime. 00135 */ 00136 Priority = LOW_REALTIME_PRIORITY; 00137 ZwSetInformationThread(NtCurrentThread(), 00138 ThreadPriority, 00139 &Priority, 00140 sizeof(KPRIORITY)); 00141 00142 /* 00143 * There are just two TERMINAL structures. One is for the 00144 * interactive windowstation and the other is for all the 00145 * non-interactive windowstations. 00146 */ 00147 if (pTerm->dwTERMF_Flags & TERMF_NOIO) { 00148 RtlInitUnicodeString(&strThreadName, L"NOIO_DT"); 00149 } else { 00150 RtlInitUnicodeString(&strThreadName, L"IO_DT"); 00151 } 00152 00153 if (!NT_SUCCESS(InitSystemThread(&strThreadName))) { 00154 pTerm->dwTERMF_Flags |= TERMF_DTINITFAILED; 00155 KeSetEvent(pTerm->pEventTermInit, EVENT_INCREMENT, FALSE); 00156 RIPMSG0(RIP_ERROR, "Fail to create the desktop thread"); 00157 return; 00158 } 00159 00160 ptiCurrent = PtiCurrentShared(); 00161 00162 pTerm->ptiDesktop = ptiCurrent; 00163 pTerm->pqDesktop = pqOriginal = ptiCurrent->pq; 00164 00165 (pqOriginal->cLockCount)++; 00166 ptiCurrent->pDeskInfo = &diStatic; 00167 00168 /* 00169 * Set the winsta to NULL. It will be set to the right 00170 * windowstation in xxxCreateDesktop before pEventInputReady 00171 * is set. 00172 */ 00173 ptiCurrent->pwinsta = NULL; 00174 00175 /* 00176 * Allocate non-paged array. Include an extra entry for 00177 * the thread's input event. 00178 */ 00179 apRITEvents = UserAllocPoolNonPaged((OBJECTS_COUNT * sizeof(PKEVENT)), 00180 TAG_SYSTEM); 00181 00182 if (apRITEvents == NULL) { 00183 pTerm->dwTERMF_Flags |= TERMF_DTINITFAILED; 00184 KeSetEvent(pTerm->pEventTermInit, EVENT_INCREMENT, FALSE); 00185 return; 00186 } 00187 00188 WaitBlockArray = UserAllocPoolNonPaged((OBJECTS_COUNT * sizeof(KWAIT_BLOCK)), 00189 TAG_SYSTEM); 00190 if (WaitBlockArray == NULL) { 00191 pTerm->dwTERMF_Flags |= TERMF_DTINITFAILED; 00192 KeSetEvent(pTerm->pEventTermInit, EVENT_INCREMENT, FALSE); 00193 UserFreePool(apRITEvents); 00194 return; 00195 } 00196 00197 idMouseInput = 0xFFFF; 00198 idDesktopDestroy = 0xFFFF; 00199 idHungThread = 0xFFFF; 00200 00201 /* 00202 * Reference the mouse input event. The system terminal doesn't 00203 * wait for any mouse input. 00204 */ 00205 if (!(pTerm->dwTERMF_Flags & TERMF_NOIO)) { 00206 pfnHidChangeRoutine = (MSGWAITCALLBACK)ProcessDeviceChanges; 00207 idMouseInput = nEvents++; 00208 UserAssert(aDeviceTemplate[DEVICE_TYPE_MOUSE].pkeHidChange); 00209 apRITEvents[idMouseInput] = aDeviceTemplate[DEVICE_TYPE_MOUSE].pkeHidChange; 00210 } 00211 00212 /* 00213 * Create the desktop destruction event. 00214 */ 00215 idDesktopDestroy = nEvents++; 00216 apRITEvents[idDesktopDestroy] = CreateKernelEvent(SynchronizationEvent, FALSE); 00217 if (apRITEvents[idDesktopDestroy] == NULL) { 00218 pTerm->dwTERMF_Flags |= TERMF_DTINITFAILED; 00219 KeSetEvent(pTerm->pEventTermInit, EVENT_INCREMENT, FALSE); 00220 UserFreePool(apRITEvents); 00221 UserFreePool(WaitBlockArray); 00222 return; 00223 } 00224 pTerm->pEventDestroyDesktop = apRITEvents[idDesktopDestroy]; 00225 00226 /* 00227 * Hung thread not needed for noninteractive windowstations. 00228 */ 00229 if (!(pTerm->dwTERMF_Flags & TERMF_NOIO)) { 00230 idHungThread = nEvents++; 00231 apRITEvents[idHungThread] = CreateKernelEvent(SynchronizationEvent, FALSE); 00232 if (apRITEvents[idHungThread] == NULL) { 00233 pTerm->dwTERMF_Flags |= TERMF_DTINITFAILED; 00234 KeSetEvent(pTerm->pEventTermInit, EVENT_INCREMENT, FALSE); 00235 FreeKernelEvent(&apRITEvents[idDesktopDestroy]); 00236 UserFreePool(apRITEvents); 00237 UserFreePool(WaitBlockArray); 00238 return; 00239 } 00240 00241 gpEventHungThread = apRITEvents[idHungThread]; 00242 } 00243 00244 EnterCrit(); 00245 UserAssert(IsWinEventNotifyDeferredOK()); 00246 00247 /* 00248 * Set the event that tells the initialization of desktop 00249 * thread is done. 00250 */ 00251 pTerm->dwTERMF_Flags |= TERMF_DTINITSUCCESS; 00252 KeSetEvent(pTerm->pEventTermInit, EVENT_INCREMENT, FALSE); 00253 00254 /* 00255 * Prepare to wait on input ready event. 00256 */ 00257 pEvent = pTerm->pEventInputReady; 00258 ObReferenceObjectByPointer(pEvent, 00259 EVENT_ALL_ACCESS, 00260 *ExEventObjectType, 00261 KernelMode); 00262 00263 LeaveCrit(); 00264 00265 KeWaitForSingleObject(pEvent, WrUserRequest, KernelMode, FALSE, NULL); 00266 ObDereferenceObject(pEvent); 00267 00268 EnterCrit(); 00269 00270 /* 00271 * Adjust the event ids 00272 */ 00273 idMouseInput += WAIT_OBJECT_0; 00274 idDesktopDestroy += WAIT_OBJECT_0; 00275 idHungThread += WAIT_OBJECT_0; 00276 idPumpMessages = WAIT_OBJECT_0 + nEvents; 00277 00278 /* 00279 * message loop lasts until we get a WM_QUIT message 00280 * upon which we shall return from the function 00281 */ 00282 while (TRUE) { 00283 DWORD result; 00284 00285 /* 00286 * Wait for any message sent or posted to this queue, while calling 00287 * ProcessDeviceChanges whenever the mouse change event (pkeHidChange) 00288 * is set. 00289 */ 00290 result = xxxMsgWaitForMultipleObjects(nEvents, 00291 apRITEvents, 00292 pfnHidChangeRoutine, 00293 WaitBlockArray); 00294 00295 #if DBG 00296 gDesktopsBusy++; // diagnostic 00297 if (gDesktopsBusy >= 2) { 00298 RIPMSG0(RIP_WARNING, "2 or more desktop threads busy"); 00299 } 00300 #endif 00301 00302 /* 00303 * result tells us the type of event we have: 00304 * a message or a signalled handle 00305 * 00306 * if there are one or more messages in the queue ... 00307 */ 00308 if (result == (DWORD)idPumpMessages) { 00309 00310 /* 00311 * block-local variable 00312 */ 00313 MSG msg ; 00314 00315 CheckCritIn(); 00316 00317 /* 00318 * read all of the messages in this next loop 00319 * removing each message as we read it 00320 */ 00321 while (xxxPeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { 00322 00323 /* 00324 * if it's a quit message we're out of here 00325 */ 00326 if (msg.message == WM_QUIT && ptiCurrent->cWindows == 1) { 00327 00328 TRACE_DESKTOP(("WM_QUIT: Destroying the desktop thread. cWindows %d\n", 00329 ptiCurrent->cWindows)); 00330 00331 /* 00332 * The window station is gone, so 00333 * 00334 * DON'T USE PWINSTA ANYMORE 00335 */ 00336 00337 /* 00338 * We could have received a mouse message in between the 00339 * desktop destroy event and the WM_QUIT message in which 00340 * case we may need to clear spwndTrack again to make sure 00341 * that a window (gotta be the desktop) isn't locked in. 00342 */ 00343 Unlock(&ptiCurrent->rpdesk->spwndTrack); 00344 00345 /* 00346 * If we're running on the last interactive desktop, 00347 * then we never unlocked pdesk->pDeskInfo->spwnd. 00348 * However, it seems to me that the system stops 00349 * running before we make it here; otherwise, (or 00350 * for a Hydra-like thing) we need to unlock that 00351 * window here..... 00352 */ 00353 UserAssert(ptiCurrent->rpdesk != NULL && 00354 ptiCurrent->rpdesk->pDeskInfo != NULL && 00355 ptiCurrent->rpdesk->pDeskInfo->spwnd != NULL); 00356 00357 Unlock(&ptiCurrent->rpdesk->pDeskInfo->spwnd); 00358 00359 /* 00360 * Because there is no desktop, we need to fake a 00361 * desktop info structure so that the IsHooked() 00362 * macro can test a "valid" fsHooks value. 00363 */ 00364 ptiCurrent->pDeskInfo = &diStatic; 00365 00366 /* 00367 * The desktop window is all that's left, so 00368 * let's exit. The thread cleanup code will 00369 * handle destruction of the window. 00370 */ 00371 00372 /* 00373 * If the thread is not using the original queue, 00374 * destroy it. 00375 */ 00376 UserAssert(pqOriginal->cLockCount); 00377 (pqOriginal->cLockCount)--; 00378 if (ptiCurrent->pq != pqOriginal) { 00379 zzzDestroyQueue(pqOriginal, ptiCurrent); // DeferWinEventNotify() ?? IANJA ?? 00380 } 00381 00382 #if DBG 00383 gDesktopsBusy--; // diagnostic 00384 #endif 00385 00386 LeaveCrit(); 00387 00388 /* 00389 * Deref the events now that we're done with them. 00390 * Also free the wait array. 00391 */ 00392 if (!(pTerm->dwTERMF_Flags & TERMF_NOIO)) { 00393 FreeKernelEvent(&gpEventHungThread); 00394 } 00395 FreeKernelEvent(&apRITEvents[idDesktopDestroy]); 00396 UserFreePool(apRITEvents); 00397 UserFreePool(WaitBlockArray); 00398 00399 /* 00400 * Terminate the thread. This will call the 00401 * Win32k thread cleanup code. 00402 */ 00403 TRACE_DESKTOP(("call PsTerminateSystemThread\n")); 00404 00405 pTerm->ptiDesktop = NULL; 00406 pTerm->pqDesktop = NULL; 00407 00408 pTerm->dwTERMF_Flags &= TERMF_DTDESTROYED; 00409 00410 PsTerminateSystemThread(0); 00411 } 00412 00413 UserAssert(msg.message != WM_QUIT); 00414 00415 /* 00416 * otherwise dispatch it 00417 */ 00418 xxxDispatchMessage(&msg); 00419 00420 } // end of PeekMessage while loop 00421 00422 } else if (result == idDesktopDestroy) { 00423 00424 PDESKTOP *ppdesk; 00425 PDESKTOP pdesk; 00426 PWND pwnd; 00427 PMENU pmenu; 00428 TL tlpwinsta; 00429 PWINDOWSTATION pwinsta; 00430 TL tlpdesk; 00431 TL tlpwnd; 00432 PDESKTOP pdeskTemp; 00433 HDESK hdeskTemp; 00434 TL tlpdeskTemp; 00435 00436 /* 00437 * Destroy desktops on the destruction list. 00438 */ 00439 for (ppdesk = &pTerm->rpdeskDestroy; *ppdesk != NULL; ) { 00440 /* 00441 * Unlink from the list. 00442 */ 00443 pdesk = *ppdesk; 00444 00445 TRACE_DESKTOP(("Destroying desktop '%ws' %#p ...\n", 00446 GetDesktopName(pdesk), pdesk)); 00447 00448 UserAssert(!(pdesk->dwDTFlags & DF_DYING)); 00449 00450 ThreadLockDesktop(ptiCurrent, pdesk, &tlpdesk, LDLT_FN_DESKTOPTHREAD_DESK); 00451 pwinsta = pdesk->rpwinstaParent; 00452 ThreadLockWinSta(ptiCurrent, pdesk->rpwinstaParent, &tlpwinsta); 00453 00454 LockDesktop(ppdesk, pdesk->rpdeskNext, LDL_TERM_DESKDESTROY1, (ULONG_PTR)pTerm); 00455 UnlockDesktop(&pdesk->rpdeskNext, LDU_DESK_DESKNEXT, 0); 00456 00457 /* 00458 * !!! If this is the current desktop, switch to another one. 00459 */ 00460 if (pdesk == grpdeskRitInput) { 00461 PDESKTOP pdeskNew; 00462 00463 TRACE_DESKTOP(("Destroying the current active desktop\n")); 00464 00465 if (pwinsta->dwWSF_Flags & WSF_SWITCHLOCK) { 00466 00467 TRACE_DESKTOP(("The windowstation is locked\n")); 00468 00469 /* 00470 * this should be the interactive windowstation 00471 */ 00472 UserAssert(!(pwinsta->dwWSF_Flags & WSF_NOIO)); 00473 00474 /* 00475 * Switch to the disconnected desktop if the logon desktop 00476 * is being destroyed, or there is no logon desktop, or 00477 * if the logon desktop has already been destroyed. 00478 */ 00479 if (gbRemoteSession && gspdeskDisconnect && 00480 (pdesk == grpdeskLogon || 00481 grpdeskLogon == NULL || 00482 (grpdeskLogon->dwDTFlags & DF_DESKWNDDESTROYED))) { 00483 TRACE_DESKTOP(("disable the screen and switch to the disconnect desktop\n")); 00484 RemoteDisableScreen(); 00485 goto skip; 00486 00487 } else { 00488 TRACE_DESKTOP(("Switch to the logon desktop '%ws' %#p ...\n", 00489 GetDesktopName(grpdeskLogon), grpdeskLogon)); 00490 00491 pdeskNew = grpdeskLogon; 00492 } 00493 } else { 00494 pdeskNew = pwinsta->rpdeskList; 00495 if (pdeskNew == pdesk) 00496 pdeskNew = pdesk->rpdeskNext; 00497 00498 /* 00499 * You can hit this assert if you exit winlogon before 00500 * logging in. I.E. all desktop's close so there is 00501 * no "next" one to switch to. I'm assuming that there 00502 * is a check for a NULL desktop in xxxSwitchDesktop(). 00503 * 00504 * You can't switch to a NULL desktop. But this means 00505 * there isn't any input desktop so clear it manually. 00506 */ 00507 if (gbRemoteSession) { 00508 if (pdeskNew == NULL) { 00509 00510 TRACE_DESKTOP(("NO INPUT FOR DT FROM THIS POINT ON ...\n")); 00511 00512 ClearWakeBit(ptiCurrent, QS_INPUT | QS_EVENT | QS_MOUSEMOVE, FALSE); 00513 } 00514 } else { 00515 UserAssert(pdeskNew); 00516 } 00517 } 00518 00519 TRACE_DESKTOP(("Switch to desktop '%ws' %#p\n", 00520 GetDesktopName(pdeskNew), pdeskNew)); 00521 00522 xxxSwitchDesktop(pwinsta, pdeskNew, FALSE); 00523 } 00524 skip: 00525 00526 /* 00527 * Close the display if this desktop did not use 00528 * the global display. 00529 */ 00530 if ((pdesk->pDispInfo->hDev != NULL) && 00531 (pdesk->pDispInfo->hDev != gpDispInfo->hDev)) { 00532 00533 TRACE_DESKTOP(("Destroy MDEV\n")); 00534 00535 DrvDestroyMDEV(pdesk->pDispInfo->pmdev); 00536 GreFreePool(pdesk->pDispInfo->pmdev); 00537 pdesk->pDispInfo->pmdev = NULL; 00538 } 00539 00540 if (pdesk->pDispInfo != gpDispInfo) { 00541 UserAssert(pdesk->pDispInfo->pMonitorFirst == NULL); 00542 UserFreePool(pdesk->pDispInfo); 00543 pdesk->pDispInfo = NULL; 00544 } 00545 00546 /* 00547 * Destroy desktop and menu windows. 00548 */ 00549 pdeskTemp = ptiCurrent->rpdesk; // save current desktop 00550 hdeskTemp = ptiCurrent->hdesk; 00551 ThreadLockDesktop(ptiCurrent, pdeskTemp, &tlpdeskTemp, LDLT_FN_DESKTOPTHREAD_DESKTEMP); 00552 xxxSetThreadDesktop(NULL, pdesk); 00553 Unlock(&pdesk->spwndForeground); 00554 Unlock(&pdesk->spwndTray); 00555 00556 Unlock(&pdesk->spwndTrack); 00557 pdesk->dwDTFlags &= ~DF_MOUSEMOVETRK; 00558 00559 if (pdesk->spmenuSys != NULL) { 00560 pmenu = pdesk->spmenuSys; 00561 if (UnlockDesktopSysMenu(&pdesk->spmenuSys)) 00562 _DestroyMenu(pmenu); 00563 } 00564 00565 if (pdesk->spmenuDialogSys != NULL) { 00566 pmenu = pdesk->spmenuDialogSys; 00567 if (UnlockDesktopSysMenu(&pdesk->spmenuDialogSys)) 00568 _DestroyMenu(pmenu); 00569 } 00570 00571 if (pdesk->spmenuHScroll != NULL) { 00572 pmenu = pdesk->spmenuHScroll; 00573 if (UnlockDesktopMenu(&pdesk->spmenuHScroll)) 00574 _DestroyMenu(pmenu); 00575 } 00576 00577 if (pdesk->spmenuVScroll != NULL) { 00578 pmenu = pdesk->spmenuVScroll; 00579 if (UnlockDesktopMenu(&pdesk->spmenuVScroll)) 00580 _DestroyMenu(pmenu); 00581 } 00582 00583 /* 00584 * If this desktop doesn't have a pDeskInfo, then 00585 * something is wrong. All desktops should have 00586 * this until the object is freed. 00587 */ 00588 if (pdesk->pDeskInfo == NULL) { 00589 RIPMSG0(RIP_ERROR, 00590 "xxxDesktopThread: There is no pDeskInfo for this desktop"); 00591 } 00592 00593 if (pdesk->pDeskInfo) { 00594 if (pdesk->pDeskInfo->spwnd == gspwndFullScreen) 00595 Unlock(&gspwndFullScreen); 00596 00597 if (pdesk->pDeskInfo->spwndShell) 00598 Unlock(&pdesk->pDeskInfo->spwndShell); 00599 00600 if (pdesk->pDeskInfo->spwndBkGnd) 00601 Unlock(&pdesk->pDeskInfo->spwndBkGnd); 00602 00603 if (pdesk->pDeskInfo->spwndTaskman) 00604 Unlock(&pdesk->pDeskInfo->spwndTaskman); 00605 00606 if (pdesk->pDeskInfo->spwndProgman) 00607 Unlock(&pdesk->pDeskInfo->spwndProgman); 00608 } 00609 00610 UserAssert(!(pdesk->dwDTFlags & DF_DYING)); 00611 00612 if (pdesk->spwndMenu != NULL) { 00613 00614 pwnd = pdesk->spwndMenu; 00615 00616 /* 00617 * Hide this window without activating anyone else. 00618 */ 00619 if (TestWF(pwnd, WFVISIBLE)) { 00620 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd); 00621 xxxSetWindowPos(pwnd, 00622 NULL, 00623 0, 00624 0, 00625 0, 00626 0, 00627 SWP_HIDEWINDOW | SWP_NOACTIVATE | 00628 SWP_NOMOVE | SWP_NOSIZE | 00629 SWP_NOZORDER | SWP_NOREDRAW | 00630 SWP_NOSENDCHANGING); 00631 00632 ThreadUnlock(&tlpwnd); 00633 } 00634 00635 /* 00636 * Reset the flag in the popupmenu structure that tells this 00637 * popup menu belongs to the pdesk->spwndMenu so it can go away. 00638 */ 00639 ((PMENUWND)pwnd)->ppopupmenu->fDesktopMenu = FALSE; 00640 ((PMENUWND)pwnd)->ppopupmenu->fDelayedFree = FALSE; 00641 #if DBG 00642 /* We used to zero out this popup when closing the menu. 00643 * now we zero it out when about to re-use it. 00644 * So make ValidatepPopupMenu happy by clearing the 00645 * leftover ppopupmenuRoot, if any. 00646 */ 00647 ((PMENUWND)pwnd)->ppopupmenu->ppopupmenuRoot = NULL; 00648 #endif 00649 00650 if (Unlock(&pdesk->spwndMenu)) { 00651 xxxDestroyWindow(pwnd); 00652 } 00653 } 00654 00655 if (pdesk->spwndMessage != NULL) { 00656 00657 pwnd = pdesk->spwndMessage; 00658 00659 if (Unlock(&pdesk->spwndMessage)) { 00660 xxxDestroyWindow(pwnd); 00661 } 00662 } 00663 00664 if (pdesk->spwndTooltip != NULL) { 00665 00666 pwnd = pdesk->spwndTooltip; 00667 00668 if (Unlock(&pdesk->spwndTooltip)) { 00669 xxxDestroyWindow(pwnd); 00670 } 00671 UserAssert(!(pdesk->dwDTFlags & DF_TOOLTIPSHOWING)); 00672 } 00673 00674 UserAssert(!(pdesk->dwDTFlags & DF_DYING)); 00675 00676 /* 00677 * If the dying desktop is the owner of the desktop 00678 * owner window, reassign it to the first available 00679 * desktop. This is needed to ensure that 00680 * xxxSetWindowPos will work on desktop windows. 00681 */ 00682 if (pTerm->spwndDesktopOwner != NULL && 00683 pTerm->spwndDesktopOwner->head.rpdesk == pdesk) { 00684 00685 PDESKTOP pdeskR; 00686 00687 /* 00688 * Find out to what desktop the mother desktop window 00689 * should go. Careful with the NOIO case where there 00690 * might be several windowstations using the same 00691 * mother desktop window 00692 */ 00693 if (pTerm->dwTERMF_Flags & TERMF_NOIO) { 00694 00695 PWINDOWSTATION pwinstaW; 00696 00697 UserAssert(grpWinStaList != NULL); 00698 00699 pwinstaW = grpWinStaList->rpwinstaNext; 00700 00701 pdeskR = NULL; 00702 00703 while (pwinstaW != NULL) { 00704 if (pwinstaW->rpdeskList != NULL) { 00705 pdeskR = pwinstaW->rpdeskList; 00706 break; 00707 } 00708 pwinstaW = pwinstaW->rpwinstaNext; 00709 } 00710 } else { 00711 pdeskR = pwinsta->rpdeskList; 00712 } 00713 00714 if (pdeskR == NULL) { 00715 00716 PWND pwnd; 00717 00718 TRACE_DESKTOP(("DESTROYING THE MOTHER DESKTOP WINDOW %#p\n", 00719 pTerm->spwndDesktopOwner)); 00720 00721 pwnd = pTerm->spwndDesktopOwner; 00722 00723 /* 00724 * Hide it first 00725 */ 00726 SetVisible(pwnd, SV_UNSET); 00727 00728 Unlock(&(pTerm->spwndDesktopOwner)); 00729 00730 xxxDestroyWindow(pwnd); 00731 00732 } else { 00733 TRACE_DESKTOP(("MOVING THE MOTHER DESKTOP WINDOW %#p to pdesk %#p '%ws'\n", 00734 pTerm->spwndDesktopOwner, pdeskR, GetDesktopName(pdeskR))); 00735 00736 LockDesktop(&(pTerm->spwndDesktopOwner->head.rpdesk), 00737 pdeskR, LDL_MOTHERDESK_DESK1, (ULONG_PTR)(pTerm->spwndDesktopOwner)); 00738 } 00739 } 00740 00741 if (pdesk->pDeskInfo && (pdesk->pDeskInfo->spwnd != NULL)) { 00742 00743 UserAssert(!(pdesk->dwDTFlags & DF_DESKWNDDESTROYED)); 00744 00745 pwnd = pdesk->pDeskInfo->spwnd; 00746 00747 /* 00748 * Hide this window without activating anyone else. 00749 */ 00750 if (TestWF(pwnd, WFVISIBLE)) { 00751 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd); 00752 xxxSetWindowPos(pwnd, 00753 NULL, 00754 0, 00755 0, 00756 0, 00757 0, 00758 SWP_HIDEWINDOW | SWP_NOACTIVATE | 00759 SWP_NOMOVE | SWP_NOSIZE | 00760 SWP_NOZORDER | SWP_NOREDRAW | 00761 SWP_NOSENDCHANGING); 00762 00763 ThreadUnlock(&tlpwnd); 00764 } 00765 00766 /* 00767 * A lot of pwnd related code assumes that we 00768 * always have a valid desktop window. So we call 00769 * xxxDestroyWindow first to clean up and then 00770 * we unlock it to free it (now or eventually). 00771 * However, if we're destroying the last destkop, then 00772 * we don't unlock the window since we're are forced 00773 * to continue running on that desktop. 00774 */ 00775 00776 TRACE_DESKTOP(("Destroying the desktop window\n")); 00777 00778 xxxDestroyWindow(pdesk->pDeskInfo->spwnd); 00779 if (pdesk != grpdeskRitInput) { 00780 Unlock(&pdesk->pDeskInfo->spwnd); 00781 } else { 00782 00783 /* 00784 * unlock the gspwndShouldBeForeground window 00785 */ 00786 if (ISTS() && gspwndShouldBeForeground != NULL) { 00787 Unlock(&gspwndShouldBeForeground); 00788 } 00789 00790 /* 00791 * This is hit in HYDRA when the last desktop does away 00792 */ 00793 RIPMSG1(RIP_WARNING, "xxxDesktopThread: Running on zombie desk:%#p", pdesk); 00794 } 00795 pdesk->dwDTFlags |= DF_DESKWNDDESTROYED; 00796 } 00797 00798 /* 00799 * Restore the previous desktop 00800 */ 00801 xxxSetThreadDesktop(hdeskTemp, pdeskTemp); 00802 00803 00804 ThreadUnlockDesktop(ptiCurrent, &tlpdeskTemp, LDUT_FN_DESKTOPTHREAD_DESKTEMP); 00805 ThreadUnlockWinSta(ptiCurrent, &tlpwinsta); 00806 ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_DESKTOPTHREAD_DESK); 00807 } 00808 00809 if (gbRemoteSession) { 00810 /* 00811 * Wakeup ntinput thread for exit processing 00812 */ 00813 TRACE_DESKTOP(("Wakeup ntinput thread for exit processing\n")); 00814 00815 UserAssert(gpevtDesktopDestroyed != NULL); 00816 00817 KeSetEvent(gpevtDesktopDestroyed, EVENT_INCREMENT, FALSE); 00818 } 00819 00820 } else if (result == idHungThread) { 00821 /* 00822 * By using gspwndMouseOwner this code relies on this event being 00823 * received before another click may occur. In the worst case we 00824 * may "lose" a click and only react to the latest one. 00825 */ 00826 PWND pwnd = gspwndMouseOwner; 00827 if (pwnd != NULL && FHungApp(GETPTI(pwnd), CMSHUNGAPPTIMEOUT)) { 00828 00829 int ht = FindNCHit(pwnd, POINTTOPOINTS(glinp.ptLastClick)); 00830 00831 if (ht == HTCLOSE) { 00832 /* 00833 * Note -- this is private, and does not go to the hook, 00834 * only the posted ones from the shell. 00835 */ 00836 00837 PostShellHookMessages(HSHELL_ENDTASK, (LPARAM)HWq(pwnd)); 00838 } else if (ht == HTMINBUTTON) { 00839 TL tlpwnd; 00840 00841 ThreadLockAlways(pwnd, &tlpwnd); 00842 xxxMinimizeHungWindow(pwnd); 00843 ThreadUnlock(&tlpwnd); 00844 } 00845 } 00846 00847 } else { 00848 RIPMSG0(RIP_WARNING, "Desktop woke up for what?"); 00849 } 00850 00851 #if DBG 00852 gDesktopsBusy--; // diagnostic 00853 #endif 00854 } 00855 } 00856 00857 /***************************************************************************\ 00858 * xxxRealizeDesktop 00859 * 00860 * 4/28/97 vadimg created 00861 \***************************************************************************/ 00862 00863 VOID xxxRealizeDesktop(PWND pwnd) 00864 { 00865 CheckLock(pwnd); 00866 UserAssert(GETFNID(pwnd) == FNID_DESKTOP); 00867 00868 if (ghpalWallpaper) { 00869 HDC hdc = _GetDC(pwnd); 00870 xxxInternalPaintDesktop(pwnd, hdc, FALSE); 00871 _ReleaseDC(hdc); 00872 } 00873 } 00874 00875 /***************************************************************************\ 00876 * xxxDesktopWndProc 00877 * 00878 * History: 00879 * 23-Oct-1990 DarrinM Ported from Win 3.0 sources. 00880 * 08-Aug-1996 jparsons 51725 - added fix to prevent crash on WM_SETICON 00881 \***************************************************************************/ 00882 00883 LRESULT xxxDesktopWndProc( 00884 PWND pwnd, 00885 UINT message, 00886 WPARAM wParam, 00887 LPARAM lParam) 00888 { 00889 PTHREADINFO ptiCurrent = PtiCurrent(); 00890 HDC hdcT; 00891 PAINTSTRUCT ps; 00892 PWINDOWPOS pwp; 00893 00894 00895 CheckLock(pwnd); 00896 UserAssert(IsWinEventNotifyDeferredOK()); 00897 00898 VALIDATECLASSANDSIZE(pwnd, message, wParam, lParam, FNID_DESKTOP, WM_CREATE); 00899 00900 00901 if (pwnd->spwndParent == NULL) { 00902 switch (message) { 00903 00904 case WM_SETICON: 00905 /* 00906 * cannot allow this as it will cause a callback to user mode from the 00907 * desktop system thread. 00908 */ 00909 RIPMSG0(RIP_WARNING, "WM_ICON sent to desktop window was discarded.\n") ; 00910 return 0L ; 00911 00912 default: 00913 break; 00914 } /* switch */ 00915 00916 return xxxDefWindowProc(pwnd, message, wParam, lParam); 00917 } 00918 00919 switch (message) { 00920 00921 case WM_WINDOWPOSCHANGING: 00922 00923 /* 00924 * We receive this when switch desktop is called. Just 00925 * to be consistent, set the rit desktop as this 00926 * thread's desktop. 00927 */ 00928 pwp = (PWINDOWPOS)lParam; 00929 if (!(pwp->flags & SWP_NOZORDER) && pwp->hwndInsertAfter == HWND_TOP) { 00930 00931 xxxSetThreadDesktop(NULL, grpdeskRitInput); 00932 00933 /* 00934 * If some app has taken over the system-palette, we should make 00935 * sure the system is restored. Otherwise, if this is the logon 00936 * desktop, we might not be able to view the dialog correctly. 00937 */ 00938 if (GreGetSystemPaletteUse(gpDispInfo->hdcScreen) != SYSPAL_STATIC) 00939 GreRealizeDefaultPalette(gpDispInfo->hdcScreen, TRUE); 00940 00941 /* 00942 * Let everyone know if the palette has changed 00943 */ 00944 if (grpdeskRitInput->dwDTFlags & DTF_NEEDSPALETTECHANGED) { 00945 xxxSendNotifyMessage(PWND_BROADCAST, 00946 WM_PALETTECHANGED, 00947 (WPARAM)HWq(pwnd), 00948 0); 00949 grpdeskRitInput->dwDTFlags &= ~DTF_NEEDSPALETTECHANGED; 00950 } 00951 } 00952 break; 00953 00954 case WM_FULLSCREEN: { 00955 TL tlpwndT; 00956 00957 ThreadLockWithPti(ptiCurrent, grpdeskRitInput->pDeskInfo->spwnd, &tlpwndT); 00958 xxxMakeWindowForegroundWithState( 00959 grpdeskRitInput->pDeskInfo->spwnd, GDIFULLSCREEN); 00960 ThreadUnlock(&tlpwndT); 00961 00962 /* 00963 * We have to tell the switch window to repaint if we switched 00964 * modes 00965 */ 00966 if (gspwndAltTab != NULL) { 00967 ThreadLockAlwaysWithPti(ptiCurrent, gspwndAltTab, &tlpwndT); 00968 xxxSendMessage(gspwndAltTab, WM_FULLSCREEN, 0, 0); 00969 ThreadUnlock(&tlpwndT); 00970 } 00971 00972 break; 00973 } 00974 00975 case WM_CLOSE: 00976 00977 /* 00978 * Make sure nobody sends this window a WM_CLOSE and causes it to 00979 * destroy itself. 00980 */ 00981 break; 00982 00983 case WM_SETICON: 00984 /* 00985 * cannot allow this as it will cause a callback to user mode from the 00986 * desktop system thread. 00987 */ 00988 RIPMSG0(RIP_WARNING, "WM_ICON sent to desktop window was discarded.\n") ; 00989 break; 00990 00991 case WM_CREATE: { 00992 TL tlName; 00993 PUNICODE_STRING pProfileUserName = CreateProfileUserName(&tlName); 00994 /* 00995 * Is there a desktop pattern, or bitmap name in WIN.INI? 00996 */ 00997 xxxSetDeskPattern(pProfileUserName, (LPWSTR)-1, TRUE); 00998 00999 FreeProfileUserName(pProfileUserName, &tlName); 01000 /* 01001 * Initialize the system colors before we show the desktop window. 01002 */ 01003 xxxSendNotifyMessage(pwnd, WM_SYSCOLORCHANGE, 0, 0L); 01004 01005 hdcT = _GetDC(pwnd); 01006 xxxInternalPaintDesktop(pwnd, hdcT, FALSE); // use "normal" HDC so SelectPalette() will work 01007 _ReleaseDC(hdcT); 01008 01009 /* 01010 * Save process and thread ids. 01011 */ 01012 xxxSetWindowLong(pwnd, 01013 0, 01014 HandleToUlong(PsGetCurrentThread()->Cid.UniqueProcess), 01015 FALSE); 01016 01017 xxxSetWindowLong(pwnd, 01018 4, 01019 HandleToUlong(PsGetCurrentThread()->Cid.UniqueThread), 01020 FALSE); 01021 break; 01022 } 01023 case WM_PALETTECHANGED: 01024 if (HWq(pwnd) == (HWND)wParam) 01025 break; 01026 01027 // FALL THROUGH 01028 01029 case WM_QUERYNEWPALETTE: 01030 xxxRealizeDesktop(pwnd); 01031 break; 01032 01033 case WM_SYSCOLORCHANGE: 01034 01035 /* 01036 * We do the redrawing if someone has changed the sys-colors from 01037 * another desktop and we need to redraw. This is appearent with 01038 * the MATROX card which requires OGL applications to take over 01039 * the entire sys-colors for drawing. When switching desktops, we 01040 * never broadcast the WM_SYSCOLORCHANGE event to tell us to redraw 01041 * This is only a DAYTONA related fix, and should be removed once 01042 * we move the SYSMETS to a per-desktop state. 01043 * 01044 * 05-03-95 : ChrisWil. 01045 */ 01046 xxxRedrawWindow(pwnd, 01047 NULL, 01048 NULL, 01049 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE); 01050 break; 01051 01052 case WM_ERASEBKGND: 01053 hdcT = (HDC)wParam; 01054 xxxInternalPaintDesktop(pwnd, hdcT, TRUE); 01055 return TRUE; 01056 01057 case WM_PAINT: 01058 xxxBeginPaint(pwnd, (LPPAINTSTRUCT)&ps); 01059 xxxEndPaint(pwnd, (LPPAINTSTRUCT)&ps); 01060 break; 01061 01062 #ifdef HUNGAPP_GHOSTING 01063 case WM_HUNGTHREAD: 01064 { 01065 PWND pwnd = RevalidateHwnd((HWND)lParam); 01066 01067 if (pwnd != NULL && FHungApp(GETPTI(pwnd), CMSHUNGAPPTIMEOUT)) { 01068 TL tlpwnd; 01069 01070 pwnd = GetTopLevelWindow(pwnd); 01071 01072 ThreadLockAlways(pwnd, &tlpwnd); 01073 xxxCreateGhost(pwnd); 01074 ThreadUnlock(&tlpwnd); 01075 } 01076 break; 01077 } 01078 #endif // HUNGAPP_GHOSTING 01079 01080 case WM_LBUTTONDBLCLK: 01081 message = WM_SYSCOMMAND; 01082 wParam = SC_TASKLIST; 01083 01084 /* 01085 *** FALL THRU ** 01086 */ 01087 01088 default: 01089 return xxxDefWindowProc(pwnd, message, wParam, lParam); 01090 } 01091 01092 return 0L; 01093 } 01094 01095 /***************************************************************************\ 01096 * SetDeskPattern 01097 * 01098 * NOTE: the lpszPattern parameter is new for Win 3.1. 01099 * 01100 * History: 01101 * 23-Oct-1990 DarrinM Created stub. 01102 * 22-Apr-1991 DarrinM Ported code from Win 3.1 sources. 01103 \***************************************************************************/ 01104 01105 BOOL xxxSetDeskPattern(PUNICODE_STRING pProfileUserName, 01106 LPWSTR lpszPattern, 01107 BOOL fCreation) 01108 { 01109 LPWSTR p; 01110 int i; 01111 UINT val; 01112 WCHAR wszNone[20]; 01113 WCHAR wchValue[MAX_PATH]; 01114 WORD rgBits[CXYDESKPATTERN]; 01115 HBRUSH hBrushTemp; 01116 01117 CheckCritIn(); 01118 01119 /* 01120 * Get rid of the old bitmap (if any). 01121 */ 01122 if (ghbmDesktop != NULL) { 01123 GreDeleteObject(ghbmDesktop); 01124 ghbmDesktop = NULL; 01125 } 01126 01127 /* 01128 * Check if a pattern is passed via lpszPattern. 01129 */ 01130 if (lpszPattern != (LPWSTR)LongToPtr( (LONG)-1 )) { 01131 01132 /* 01133 * Yes! Then use that pattern; 01134 */ 01135 p = lpszPattern; 01136 goto GotThePattern; 01137 } 01138 01139 /* 01140 * Else, pickup the pattern selected in WIN.INI. 01141 * Get the "DeskPattern" string from WIN.INI's [Desktop] section. 01142 */ 01143 if (!FastGetProfileStringFromIDW(pProfileUserName, 01144 PMAP_DESKTOP, 01145 STR_DESKPATTERN, 01146 TEXT(""), 01147 wchValue, 01148 sizeof(wchValue)/sizeof(WCHAR) 01149 )) { 01150 return FALSE; 01151 } 01152 01153 ServerLoadString(hModuleWin, 01154 STR_NONE, 01155 wszNone, 01156 sizeof(wszNone)/sizeof(WCHAR)); 01157 01158 p = wchValue; 01159 01160 GotThePattern: 01161 01162 /* 01163 * Was a Desk Pattern selected? 01164 */ 01165 if (*p == TEXT('\0') || _wcsicmp(p, wszNone) == 0) { 01166 hBrushTemp = GreCreateSolidBrush(SYSRGB(DESKTOP)); 01167 if (hBrushTemp != NULL) { 01168 if (SYSHBR(DESKTOP)) { 01169 GreMarkDeletableBrush(SYSHBR(DESKTOP)); 01170 GreDeleteObject(SYSHBR(DESKTOP)); 01171 } 01172 GreMarkUndeletableBrush(hBrushTemp); 01173 SYSHBR(DESKTOP) = hBrushTemp; 01174 } 01175 GreSetBrushOwnerPublic(hBrushTemp); 01176 goto SDPExit; 01177 } 01178 01179 /* 01180 * Get eight groups of numbers seprated by non-numeric characters. 01181 */ 01182 for (i = 0; i < CXYDESKPATTERN; i++) { 01183 val = 0; 01184 01185 /* 01186 * Skip over any non-numeric characters, check for null EVERY time. 01187 */ 01188 while (*p && !(*p >= TEXT('0') && *p <= TEXT('9'))) 01189 p++; 01190 01191 /* 01192 * Get the next series of digits. 01193 */ 01194 while (*p >= TEXT('0') && *p <= TEXT('9')) 01195 val = val * (UINT)10 + (UINT)(*p++ - TEXT('0')); 01196 01197 rgBits[i] = (WORD)val; 01198 } 01199 01200 ghbmDesktop = GreCreateBitmap(CXYDESKPATTERN, 01201 CXYDESKPATTERN, 01202 1, 01203 1, 01204 (LPBYTE)rgBits); 01205 01206 if (ghbmDesktop == NULL) 01207 return FALSE; 01208 01209 GreSetBitmapOwner(ghbmDesktop, OBJECT_OWNER_PUBLIC); 01210 01211 RecolorDeskPattern(); 01212 01213 SDPExit: 01214 if (!fCreation) { 01215 01216 /* 01217 * Notify everyone that the colors have changed. 01218 */ 01219 xxxSendNotifyMessage(PWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0L); 01220 01221 /* 01222 * Update the entire screen. If this is creation, don't update: the 01223 * screen hasn't drawn, and also there are some things that aren't 01224 * initialized yet. 01225 */ 01226 xxxRedrawScreen(); 01227 } 01228 01229 return TRUE; 01230 } 01231 01232 /***************************************************************************\ 01233 * RecolorDeskPattern 01234 * 01235 * Remakes the desktop pattern (if it exists) so that it uses the new 01236 * system colors. 01237 * 01238 * History: 01239 * 22-Apr-1991 DarrinM Ported from Win 3.1 sources. 01240 \***************************************************************************/ 01241 01242 VOID RecolorDeskPattern(VOID) 01243 { 01244 HBITMAP hbmOldDesk; 01245 HBITMAP hbmOldMem; 01246 HBITMAP hbmMem; 01247 HBRUSH hBrushTemp; 01248 if (ghbmDesktop == NULL) 01249 return; 01250 01251 /* 01252 * Redo the desktop pattern in the new colors. 01253 */ 01254 01255 if (hbmOldDesk = GreSelectBitmap(ghdcMem, ghbmDesktop)) { 01256 01257 if (!SYSMET(SAMEDISPLAYFORMAT)) { 01258 01259 BYTE bmi[sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*2]; 01260 PBITMAPINFO pbmi = (PBITMAPINFO) &bmi; 01261 01262 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 01263 pbmi->bmiHeader.biWidth = CXYDESKPATTERN; 01264 pbmi->bmiHeader.biHeight = CXYDESKPATTERN; 01265 pbmi->bmiHeader.biPlanes = 1; 01266 pbmi->bmiHeader.biBitCount = 1; 01267 pbmi->bmiHeader.biCompression = BI_RGB; 01268 pbmi->bmiHeader.biSizeImage = 0; 01269 pbmi->bmiHeader.biXPelsPerMeter = 0; 01270 pbmi->bmiHeader.biYPelsPerMeter = 0; 01271 pbmi->bmiHeader.biClrUsed = 2; 01272 pbmi->bmiHeader.biClrImportant = 2; 01273 01274 pbmi->bmiColors[0].rgbBlue = (BYTE)((SYSRGB(DESKTOP) >> 16) & 0xff); 01275 pbmi->bmiColors[0].rgbGreen = (BYTE)((SYSRGB(DESKTOP) >> 8) & 0xff); 01276 pbmi->bmiColors[0].rgbRed = (BYTE)((SYSRGB(DESKTOP) ) & 0xff); 01277 01278 pbmi->bmiColors[1].rgbBlue = (BYTE)((SYSRGB(WINDOWTEXT) >> 16) & 0xff); 01279 pbmi->bmiColors[1].rgbGreen = (BYTE)((SYSRGB(WINDOWTEXT) >> 8) & 0xff); 01280 pbmi->bmiColors[1].rgbRed = (BYTE)((SYSRGB(WINDOWTEXT) ) & 0xff); 01281 01282 hbmMem = GreCreateDIBitmapReal( 01283 HDCBITS(), 0, NULL, 01284 pbmi,DIB_RGB_COLORS,sizeof(bmi),0, 01285 NULL,0,NULL,0,0); 01286 01287 } else { 01288 01289 hbmMem = GreCreateCompatibleBitmap( 01290 HDCBITS(), CXYDESKPATTERN, CXYDESKPATTERN); 01291 } 01292 01293 if (hbmMem) { 01294 01295 if (hbmOldMem = GreSelectBitmap(ghdcMem2, hbmMem)) { 01296 01297 GreSetTextColor(ghdcMem2, SYSRGB(DESKTOP)); 01298 GreSetBkColor(ghdcMem2, SYSRGB(WINDOWTEXT)); 01299 01300 GreBitBlt(ghdcMem2, 01301 0, 01302 0, 01303 CXYDESKPATTERN, 01304 CXYDESKPATTERN, 01305 ghdcMem, 01306 0, 01307 0, 01308 SRCCOPY, 01309 0); 01310 01311 if (hBrushTemp = GreCreatePatternBrush(hbmMem)) { 01312 01313 if (SYSHBR(DESKTOP) != NULL) { 01314 GreMarkDeletableBrush(SYSHBR(DESKTOP)); 01315 GreDeleteObject(SYSHBR(DESKTOP)); 01316 } 01317 01318 GreMarkUndeletableBrush(hBrushTemp); 01319 SYSHBR(DESKTOP) = hBrushTemp; 01320 } 01321 01322 GreSetBrushOwnerPublic(hBrushTemp); 01323 GreSelectBitmap(ghdcMem2, hbmOldMem); 01324 } 01325 01326 GreDeleteObject(hbmMem); 01327 } 01328 01329 GreSelectBitmap(ghdcMem, hbmOldDesk); 01330 } 01331 } 01332 01333 /***************************************************************************\ 01334 * xxxCreateDesktop (API) 01335 * 01336 * Create a new desktop object 01337 * 01338 * History: 01339 * 16-Jan-1991 JimA Created scaffold code. 01340 * 11-Feb-1991 JimA Added access checks. 01341 \***************************************************************************/ 01342 01343 NTSTATUS xxxCreateDesktop2( 01344 PWINDOWSTATION pwinsta, 01345 PACCESS_STATE pAccessState, 01346 KPROCESSOR_MODE AccessMode, 01347 PUNICODE_STRING pstrName, 01348 PDESKTOP_CONTEXT Context, 01349 PVOID *pObject) 01350 { 01351 LUID luidCaller; 01352 OBJECT_ATTRIBUTES ObjectAttributes; 01353 PEPROCESS Process; 01354 PDESKTOP pdesk; 01355 PDESKTOPINFO pdi; 01356 ULONG ulHeapSize; 01357 NTSTATUS Status; 01358 01359 CheckCritIn(); 01360 01361 /* 01362 * If this is a desktop creation, make sure 01363 * that the windowstation grants create access. 01364 */ 01365 if (!ObCheckCreateObjectAccess( 01366 pwinsta, 01367 WINSTA_CREATEDESKTOP, 01368 pAccessState, 01369 pstrName, 01370 TRUE, 01371 AccessMode, 01372 &Status)) { 01373 01374 return Status; 01375 } 01376 /* 01377 * Fail if the windowstation is locked 01378 */ 01379 Process = PsGetCurrentProcess(); 01380 01381 if (pwinsta->dwWSF_Flags & WSF_OPENLOCK && 01382 Process->UniqueProcessId != gpidLogon) { 01383 01384 /* 01385 * If logoff is occuring and the caller does not 01386 * belong to the session that is ending, allow the 01387 * open to proceed. 01388 */ 01389 Status = GetProcessLuid(NULL, &luidCaller); 01390 01391 if (!NT_SUCCESS(Status) || 01392 !(pwinsta->dwWSF_Flags & WSF_SHUTDOWN) || 01393 RtlEqualLuid(&luidCaller, &pwinsta->luidEndSession)) { 01394 return STATUS_DEVICE_BUSY; 01395 } 01396 } 01397 01398 /* 01399 * If a devmode has been specified, we also must be able 01400 * to switch desktops. 01401 */ 01402 if (Context->lpDevMode != NULL && (pwinsta->dwWSF_Flags & WSF_OPENLOCK) && 01403 Process->UniqueProcessId != gpidLogon) { 01404 return STATUS_DEVICE_BUSY; 01405 } 01406 01407 /* 01408 * Allocate the new object 01409 */ 01410 InitializeObjectAttributes(&ObjectAttributes, pstrName, 0, NULL, NULL); 01411 Status = ObCreateObject( 01412 KernelMode, 01413 *ExDesktopObjectType, 01414 &ObjectAttributes, 01415 UserMode, 01416 NULL, 01417 sizeof(DESKTOP), 01418 0, 01419 0, 01420 &pdesk); 01421 if (!NT_SUCCESS(Status)) { 01422 RIPMSG1(RIP_WARNING, "xxxCreateDesktop2: ObCreateObject failed with Status 0x%x", 01423 Status); 01424 return Status; 01425 } 01426 RtlZeroMemory(pdesk, sizeof(DESKTOP)); 01427 01428 /* 01429 * Store the session id of the session who created the desktop 01430 */ 01431 pdesk->dwSessionId = gSessionId; 01432 01433 /* 01434 * Create security descriptor 01435 */ 01436 Status = ObAssignSecurity( 01437 pAccessState, 01438 OBJECT_TO_OBJECT_HEADER(pwinsta)->SecurityDescriptor, 01439 pdesk, 01440 *ExDesktopObjectType); 01441 01442 if (!NT_SUCCESS(Status)) 01443 goto Error; 01444 01445 /* 01446 * Set up desktop heap. The first desktop (logon desktop) uses a 01447 * small heap (128). 01448 */ 01449 if (!(pwinsta->dwWSF_Flags & WSF_NOIO) && (pwinsta->rpdeskList == NULL)) { 01450 #ifdef _WIN64 01451 /* 01452 * Temporary fix. When winlogon starts creating processes on the right 01453 * desktop, we'll have to figure out what this size should really be. 01454 */ 01455 ulHeapSize = gdwDesktopSectionSize; 01456 #else 01457 ulHeapSize = 128; 01458 #endif 01459 } else { 01460 if (pwinsta->dwWSF_Flags & WSF_NOIO) { 01461 ulHeapSize = gdwNOIOSectionSize; 01462 } else { 01463 01464 /* 01465 * The disconnected desktop should be small also. 01466 */ 01467 if (gbRemoteSession && gspdeskDisconnect == NULL) 01468 ulHeapSize = 64; 01469 else 01470 ulHeapSize = gdwDesktopSectionSize; 01471 } 01472 } 01473 01474 ulHeapSize *= 1024; 01475 /* 01476 * Create the desktop heap. 01477 */ 01478 pdesk->hsectionDesktop = CreateDesktopHeap(&pdesk->pheapDesktop, ulHeapSize); 01479 if (pdesk->hsectionDesktop == NULL) { 01480 RIPMSG1(RIP_WARNING, "xxxCreateDesktop: CreateDesktopHeap failed for pdesk %#p", 01481 pdesk); 01482 goto ErrorOutOfMemory; 01483 } 01484 01485 if (pwinsta->rpdeskList == NULL || (pwinsta->dwWSF_Flags & WSF_NOIO)) { 01486 01487 /* 01488 * The first desktop or invisible desktops must also 01489 * use the default settings. This is because specifying 01490 * the devmode causes a desktop switch, which must be 01491 * avoided in this case. 01492 */ 01493 Context->lpDevMode = NULL; 01494 } 01495 01496 /* 01497 * Allocate desktopinfo 01498 */ 01499 pdi = (PDESKTOPINFO)DesktopAlloc(pdesk, sizeof(DESKTOPINFO), DTAG_DESKTOPINFO); 01500 if (pdi == NULL) { 01501 RIPMSG0(RIP_WARNING, "xxxCreateDesktop: failed DeskInfo Alloc"); 01502 goto ErrorOutOfMemory; 01503 } 01504 01505 /* 01506 * Initialize everything. 01507 */ 01508 pdesk->pDeskInfo = pdi; 01509 InitializeListHead(&pdesk->PtiList); 01510 01511 /* 01512 * If a DEVMODE or another device name is passed in, then use that 01513 * information. 01514 * Otherwise use the default information (gpDispInfo). 01515 */ 01516 01517 if (Context->lpDevMode) { 01518 01519 BOOL bDisabled = FALSE; 01520 PMDEV pmdev = NULL; 01521 LONG ChangeStat = GRE_DISP_CHANGE_FAILED; 01522 01523 /* 01524 * Allocate a display-info for this device. 01525 */ 01526 pdesk->pDispInfo = (PDISPLAYINFO)UserAllocPoolZInit( 01527 sizeof(DISPLAYINFO), TAG_DISPLAYINFO); 01528 01529 if (!pdesk->pDispInfo) { 01530 RIPMSG1(RIP_WARNING, "xxxCreateDesktop: failed to allocate pDispInfo for pdesk %#p", 01531 pdesk); 01532 goto ErrorOutOfMemory; 01533 } 01534 01535 if ((bDisabled = DrvDisableMDEV(gpDispInfo->pmdev, TRUE)) == TRUE) { 01536 01537 ChangeStat = DrvChangeDisplaySettings(Context->pstrDevice, 01538 NULL, 01539 Context->lpDevMode, 01540 LongToPtr( gdwDesktopId ), 01541 UserMode, 01542 FALSE, 01543 TRUE, 01544 NULL, 01545 &pmdev, 01546 GRE_DEFAULT, 01547 FALSE); 01548 } 01549 01550 if (ChangeStat != GRE_DISP_CHANGE_SUCCESSFUL) { 01551 01552 if (bDisabled) { 01553 DrvEnableMDEV(gpDispInfo->pmdev, TRUE); 01554 } 01555 01556 // 01557 // If there is a failure, then repaint the whole screen. 01558 // 01559 01560 RIPMSG1(RIP_WARNING, "xxxCreateDesktop2 callback for pdesk %#p !", 01561 pdesk); 01562 01563 xxxUserResetDisplayDevice(); 01564 01565 Status = STATUS_UNSUCCESSFUL; 01566 goto Error; 01567 } 01568 01569 pdesk->pDispInfo->hDev = pmdev->hdevParent; 01570 pdesk->pDispInfo->pmdev = pmdev; 01571 pdesk->dwDesktopId = gdwDesktopId++; 01572 01573 CopyRect(&pdesk->pDispInfo->rcScreen, &gpDispInfo->rcScreen); 01574 pdesk->pDispInfo->dmLogPixels = gpDispInfo->dmLogPixels; 01575 01576 pdesk->pDispInfo->pMonitorFirst = NULL; 01577 pdesk->pDispInfo->pMonitorPrimary = NULL; 01578 01579 } else { 01580 01581 pdesk->pDispInfo = gpDispInfo; 01582 pdesk->dwDesktopId = GW_DESKTOP_ID; 01583 01584 } 01585 01586 /* 01587 * Heap is HEAP_ZERO_MEMORY, so we should be zero-initialized already. 01588 */ 01589 UserAssert(pdi->pvwplShellHook == NULL); 01590 01591 pdi->pvDesktopBase = Win32HeapGetHandle(pdesk->pheapDesktop); 01592 pdi->pvDesktopLimit = (PBYTE)pdi->pvDesktopBase + ulHeapSize; 01593 01594 /* 01595 * Reference the parent windowstation 01596 */ 01597 LockWinSta(&(pdesk->rpwinstaParent), pwinsta); 01598 01599 /* 01600 * Link the desktop into the windowstation list 01601 */ 01602 if (pwinsta->rpdeskList == NULL) { 01603 01604 if (!(pwinsta->dwWSF_Flags & WSF_NOIO)) 01605 LockDesktop(&grpdeskLogon, pdesk, LDL_DESKLOGON, 0); 01606 /* 01607 * Make the first desktop the "owner" of the top 01608 * desktop window. This is needed to ensure that 01609 * xxxSetWindowPos will work on desktop windows. 01610 */ 01611 LockDesktop(&(pwinsta->pTerm->spwndDesktopOwner->head.rpdesk), 01612 pdesk, LDL_MOTHERDESK_DESK2, (ULONG_PTR)(pwinsta->pTerm->spwndDesktopOwner)); 01613 } 01614 01615 01616 LockDesktop(&pdesk->rpdeskNext, pwinsta->rpdeskList, LDL_DESK_DESKNEXT1, (ULONG_PTR)pwinsta); 01617 LockDesktop(&pwinsta->rpdeskList, pdesk, LDL_WINSTA_DESKLIST1, (ULONG_PTR)pwinsta); 01618 01619 /* 01620 * Mask off invalid access bits 01621 */ 01622 if (pAccessState->RemainingDesiredAccess & MAXIMUM_ALLOWED) { 01623 pAccessState->RemainingDesiredAccess &= ~MAXIMUM_ALLOWED; 01624 pAccessState->RemainingDesiredAccess |= GENERIC_ALL; 01625 } 01626 01627 RtlMapGenericMask( &pAccessState->RemainingDesiredAccess, (PGENERIC_MAPPING)&DesktopMapping); 01628 pAccessState->RemainingDesiredAccess &= 01629 (DesktopMapping.GenericAll | ACCESS_SYSTEM_SECURITY); 01630 01631 *pObject = pdesk; 01632 01633 /* 01634 * Add the desktop to the global list of desktops in this win32k. 01635 * This is HYDRA only 01636 */ 01637 DbgTrackAddDesktop(pdesk); 01638 01639 return STATUS_SUCCESS; 01640 01641 ErrorOutOfMemory: 01642 Status = STATUS_NO_MEMORY; 01643 // fall-through 01644 01645 Error: 01646 LogDesktop(pdesk, LD_DEREF_FN_2CREATEDESKTOP, FALSE, 0); 01647 ObDereferenceObject(pdesk); 01648 01649 UserAssert(!NT_SUCCESS(Status)); 01650 01651 return Status; 01652 } 01653 01654 BOOL xxxCreateDisconnectDesktop( 01655 HWINSTA hwinsta, 01656 PWINDOWSTATION pwinsta) 01657 { 01658 UNICODE_STRING strDesktop; 01659 OBJECT_ATTRIBUTES oa; 01660 HDESK hdeskDisconnect; 01661 HRGN hrgn; 01662 NTSTATUS Status; 01663 01664 /* 01665 * If not created yet, then create the Disconnected desktop 01666 * (used when WinStation is disconnected), and lock the desktop 01667 * and desktop window to ensure they never get deleted. 01668 */ 01669 RtlInitUnicodeString(&strDesktop, TEXT("Disconnect")); 01670 InitializeObjectAttributes(&oa, &strDesktop, 01671 OBJ_OPENIF | OBJ_CASE_INSENSITIVE, hwinsta, NULL); 01672 01673 hdeskDisconnect = xxxCreateDesktop(&oa, KernelMode, 01674 NULL, NULL, 0, MAXIMUM_ALLOWED); 01675 01676 if (hdeskDisconnect == NULL) { 01677 RIPMSG0(RIP_WARNING, "Could not create Disconnect desktop"); 01678 return FALSE; 01679 } 01680 01681 /* 01682 * Keep around an extra reference to the disconnect desktop from 01683 * the CSR so it will stay around even if winlogon exits. 01684 */ 01685 Status = ObReferenceObjectByHandle(hdeskDisconnect, 01686 0, 01687 NULL, 01688 KernelMode, 01689 &gspdeskDisconnect, 01690 NULL); 01691 if (!NT_SUCCESS(Status)) { 01692 01693 RIPMSG1(RIP_WARNING, "Disconnect Desktop reference failed 0x%x", Status); 01694 01695 xxxCloseDesktop(hdeskDisconnect, KernelMode); 01696 gspdeskDisconnect = NULL; 01697 return FALSE; 01698 } 01699 01700 LogDesktop(gspdeskDisconnect, LDL_DESKDISCONNECT, TRUE, 0); 01701 01702 /* 01703 * Set the region of the desktop window to be (0, 0, 0, 0) so 01704 * that there is no hittesting going on the 'disconnect' desktop 01705 */ 01706 hrgn = CreateEmptyRgn(); 01707 01708 UserAssert(gspdeskDisconnect->pDeskInfo != NULL); 01709 01710 SelectWindowRgn(gspdeskDisconnect->pDeskInfo->spwnd, hrgn); 01711 01712 KeAttachProcess(&gpepCSRSS->Pcb); 01713 01714 Status = ObOpenObjectByPointer( 01715 gspdeskDisconnect, 01716 0, 01717 NULL, 01718 EVENT_ALL_ACCESS, 01719 NULL, 01720 KernelMode, 01721 &ghDisconnectDesk); 01722 01723 if (NT_SUCCESS(Status)) { 01724 01725 Status = ObOpenObjectByPointer( 01726 pwinsta, 01727 0, 01728 NULL, 01729 EVENT_ALL_ACCESS, 01730 NULL, 01731 KernelMode, 01732 &ghDisconnectWinSta); 01733 } 01734 01735 KeDetachProcess(); 01736 01737 if (!NT_SUCCESS(Status)) { 01738 01739 RIPMSG0(RIP_WARNING, "Could not create Disconnect desktop"); 01740 01741 if (ghDisconnectDesk != NULL) { 01742 CloseProtectedHandle(ghDisconnectDesk); 01743 ghDisconnectDesk = NULL; 01744 } 01745 01746 xxxCloseDesktop(hdeskDisconnect, KernelMode); 01747 return FALSE; 01748 } 01749 01750 /* 01751 * Don't want to do alot of paints if we disconnected before this. 01752 */ 01753 if (!gbConnected) { 01754 RIPMSG0(RIP_WARNING, 01755 "RemoteDisconnect was issued during CreateDesktop(\"Winlogon\"..."); 01756 } 01757 01758 return TRUE; 01759 } 01760 01761 VOID CleanupDirtyDesktops( 01762 VOID) 01763 { 01764 PWINDOWSTATION pwinsta; 01765 PDESKTOP* ppdesk; 01766 01767 CheckCritIn(); 01768 01769 for (pwinsta = grpWinStaList; pwinsta != NULL; pwinsta = pwinsta->rpwinstaNext) { 01770 01771 ppdesk = &pwinsta->rpdeskList; 01772 01773 while (*ppdesk != NULL) { 01774 01775 if (!((*ppdesk)->dwDTFlags & DF_DESKCREATED)) { 01776 RIPMSG1(RIP_WARNING, "Desktop %#p in a dirty state", *ppdesk); 01777 01778 if (grpdeskLogon == *ppdesk) { 01779 UnlockDesktop(&grpdeskLogon, LDU_DESKLOGON, 0); 01780 } 01781 01782 if (pwinsta->pTerm->spwndDesktopOwner && 01783 pwinsta->pTerm->spwndDesktopOwner->head.rpdesk == *ppdesk) { 01784 01785 UnlockDesktop(&(pwinsta->pTerm->spwndDesktopOwner->head.rpdesk), 01786 LDU_MOTHERDESK_DESK, (ULONG_PTR)(pwinsta->pTerm->spwndDesktopOwner)); 01787 } 01788 01789 LockDesktop(ppdesk, (*ppdesk)->rpdeskNext, LDL_WINSTA_DESKLIST1, (ULONG_PTR)pwinsta); 01790 } else { 01791 ppdesk = &(*ppdesk)->rpdeskNext; 01792 } 01793 } 01794 } 01795 } 01796 01797 HDESK xxxCreateDesktop( 01798 POBJECT_ATTRIBUTES ccxObjectAttributes, 01799 KPROCESSOR_MODE ProbeMode, 01800 PUNICODE_STRING ccxpstrDevice, 01801 LPDEVMODE ccxlpdevmode, 01802 DWORD dwFlags, 01803 DWORD dwDesiredAccess) 01804 { 01805 HWINSTA hwinsta; 01806 HDESK hdesk; 01807 DESKTOP_CONTEXT Context; 01808 PDESKTOP pdesk; 01809 PDESKTOPINFO pdi; 01810 PWINDOWSTATION pwinsta; 01811 PDESKTOP pdeskTemp; 01812 HDESK hdeskTemp; 01813 PWND pwndDesktop = NULL; 01814 PWND pwndMessage = NULL; 01815 PWND pwndTooltip = NULL; 01816 PWND pwndMenu = NULL; 01817 TL tlpwnd; 01818 PTHREADINFO ptiCurrent = PtiCurrent(); 01819 BOOL fWasNull; 01820 BOOL bSuccess; 01821 PPROCESSINFO ppi; 01822 PPROCESSINFO ppiSave; 01823 PTERMINAL pTerm; 01824 NTSTATUS Status; 01825 DWORD dwDisableHooks; 01826 01827 #if DBG 01828 /* 01829 * Too many jumps in this function to use BEGIN/ENDATOMICHCECK 01830 */ 01831 DWORD dwCritSecUseSave = gdwCritSecUseCount; 01832 #endif 01833 01834 CheckCritIn(); 01835 01836 UserAssert(IsWinEventNotifyDeferredOK()); 01837 01838 /* 01839 * Capture directory handle and check for create access. 01840 */ 01841 try { 01842 hwinsta = ccxObjectAttributes->RootDirectory; 01843 } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { 01844 return NULL; 01845 } 01846 if (hwinsta != NULL) { 01847 Status = ObReferenceObjectByHandle( 01848 hwinsta, 01849 WINSTA_CREATEDESKTOP, 01850 *ExWindowStationObjectType, 01851 ProbeMode, 01852 &pwinsta, 01853 NULL); 01854 if (NT_SUCCESS(Status)) { 01855 ObDereferenceObject(pwinsta); 01856 } else { 01857 RIPNTERR0(Status, RIP_VERBOSE, "ObReferenceObjectByHandle Failed"); 01858 return NULL; 01859 } 01860 } 01861 01862 /* 01863 * Set up creation context 01864 */ 01865 Context.lpDevMode = ccxlpdevmode; 01866 Context.pstrDevice = ccxpstrDevice; 01867 Context.dwFlags = dwFlags; 01868 01869 /* 01870 * Create the desktop -- the object manager uses try blocks 01871 */ 01872 Status = ObOpenObjectByName( 01873 ccxObjectAttributes, 01874 *ExDesktopObjectType, 01875 ProbeMode, 01876 NULL, 01877 dwDesiredAccess, 01878 &Context, 01879 &hdesk); 01880 01881 if (!NT_SUCCESS(Status)) { 01882 01883 RIPNTERR1(Status, 01884 RIP_WARNING, 01885 "xxxCreateDesktop: ObOpenObjectByName failed with Status 0x%x", 01886 Status); 01887 01888 /* 01889 * Cleanup desktop objects that were created in xxxCreateDesktop2 01890 * but later on the Ob manager failed the creation for other 01891 * reasons (ex: no quota) 01892 */ 01893 CleanupDirtyDesktops(); 01894 01895 return NULL; 01896 } 01897 01898 /* 01899 * If the desktop already exists, we're done. This will only happen 01900 * if OBJ_OPENIF was specified. 01901 */ 01902 if (Status == STATUS_OBJECT_NAME_EXISTS) { 01903 SetHandleFlag(hdesk, HF_PROTECTED, TRUE); 01904 RIPMSG0(RIP_WARNING, "xxxCreateDesktop: Object name exists"); 01905 return hdesk; 01906 } 01907 01908 /* 01909 * Reference the desktop to finish initialization 01910 */ 01911 Status = ObReferenceObjectByHandle( 01912 hdesk, 01913 0, 01914 *ExDesktopObjectType, 01915 KernelMode, 01916 &pdesk, 01917 NULL); 01918 if (!NT_SUCCESS(Status)) { 01919 RIPNTERR0(Status, RIP_VERBOSE, ""); 01920 CloseProtectedHandle(hdesk); 01921 return NULL; 01922 } 01923 01924 pdesk->dwDTFlags |= DF_DESKCREATED; 01925 01926 LogDesktop(pdesk, LD_REF_FN_CREATEDESKTOP, TRUE, (ULONG_PTR)PtiCurrent()); 01927 01928 pwinsta = pdesk->rpwinstaParent; 01929 pTerm = pwinsta->pTerm; 01930 pdi = pdesk->pDeskInfo; 01931 01932 pdi->ppiShellProcess = NULL; 01933 01934 /* 01935 * If the desktop was not mapped in as a result of the open, 01936 * fail. 01937 */ 01938 ppi = PpiCurrent(); 01939 if (GetDesktopView(ppi, pdesk) == NULL) { 01940 01941 /* 01942 * Desktop mapping failed. 01943 */ 01944 CloseProtectedHandle(hdesk); 01945 01946 LogDesktop(pdesk, LD_DEREF_FN_CREATEDESKTOP1, FALSE, (ULONG_PTR)PtiCurrent()); 01947 01948 ObDereferenceObject(pdesk); 01949 RIPNTERR0(STATUS_ACCESS_DENIED, RIP_WARNING, "Desktop mapping failed"); 01950 return NULL; 01951 } 01952 01953 if (gpepCSRSS != NULL) { 01954 /* 01955 * Map the desktop into CSRSS to ensure that the 01956 * hard error handler can get access. 01957 */ 01958 try { 01959 MapDesktop(ObOpenHandle, gpepCSRSS, pdesk, 0, 1); 01960 } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { 01961 01962 /* 01963 * Desktop mapping failed. 01964 */ 01965 CloseProtectedHandle(hdesk); 01966 01967 LogDesktop(pdesk, LD_DEREF_FN_CREATEDESKTOP2, FALSE, (ULONG_PTR)PtiCurrent()); 01968 01969 ObDereferenceObject(pdesk); 01970 RIPNTERR0(STATUS_ACCESS_DENIED, RIP_WARNING, "Desktop mapping failed (2)"); 01971 return NULL; 01972 } 01973 01974 UserAssert(GetDesktopView(PpiFromProcess(gpepCSRSS), pdesk) != NULL); 01975 } 01976 01977 /* 01978 * Set hook flags 01979 */ 01980 SetHandleFlag(hdesk, HF_DESKTOPHOOK, dwFlags & DF_ALLOWOTHERACCOUNTHOOK); 01981 01982 /* 01983 * Set up to create the desktop window. 01984 */ 01985 fWasNull = (ptiCurrent->ppi->rpdeskStartup == NULL); 01986 pdeskTemp = ptiCurrent->rpdesk; // save current desktop 01987 hdeskTemp = ptiCurrent->hdesk; 01988 01989 /* 01990 * Switch ppi values so window will be created using the 01991 * system's desktop window class. 01992 */ 01993 ppiSave = ptiCurrent->ppi; 01994 ptiCurrent->ppi = pTerm->ptiDesktop->ppi; 01995 01996 DeferWinEventNotify(); 01997 BeginAtomicCheck(); 01998 01999 zzzSetDesktop(ptiCurrent, pdesk, hdesk); 02000 02001 /* 02002 * Create the desktop window 02003 */ 02004 /* 02005 * HACK HACK HACK!!! (adams) In order to create the desktop window 02006 * with the correct desktop, we set the desktop of the current thread 02007 * to the new desktop. But in so doing we allow hooks on the current 02008 * thread to also hook this new desktop. This is bad, because we don't 02009 * want the desktop window to be hooked while it is created. So we 02010 * temporarily disable hooks of the current thread and its desktop, 02011 * and reenable them after switching back to the original desktop. 02012 */ 02013 02014 dwDisableHooks = ptiCurrent->TIF_flags & TIF_DISABLEHOOKS; 02015 ptiCurrent->TIF_flags |= TIF_DISABLEHOOKS; 02016 02017 pwndDesktop = xxxCreateWindowEx( 02018 (DWORD)0, 02019 (PLARGE_STRING)DESKTOPCLASS, 02020 NULL, 02021 (WS_POPUP | WS_CLIPCHILDREN), 02022 pdesk->pDispInfo->rcScreen.left, 02023 pdesk->pDispInfo->rcScreen.top, 02024 pdesk->pDispInfo->rcScreen.right - pdesk->pDispInfo->rcScreen.left, 02025 pdesk->pDispInfo->rcScreen.bottom - pdesk->pDispInfo->rcScreen.top, 02026 NULL, 02027 NULL, 02028 hModuleWin, 02029 NULL, 02030 VER31); 02031 02032 if (pwndDesktop == NULL) { 02033 RIPMSG1(RIP_WARNING, 02034 "xxxCreateDesktop: Failed to create the desktop window for pdesk %#p", 02035 pdesk); 02036 goto Error; 02037 } 02038 02039 /* 02040 * NOTE: In order for the message window to be created without 02041 * the desktop as it's owner, it needs to be created before 02042 * setting pdi->spwnd to the desktop window. This is a complete 02043 * hack and should be fixed. 02044 */ 02045 pwndMessage = xxxCreateWindowEx( 02046 (DWORD)0, 02047 (PLARGE_STRING)gatomMessage, 02048 NULL, 02049 (WS_POPUP | WS_CLIPCHILDREN), 02050 0, 02051 0, 02052 100, 02053 100, 02054 NULL, 02055 NULL, 02056 hModuleWin, 02057 NULL, 02058 VER31); 02059 02060 if (pwndMessage == NULL) { 02061 RIPMSG0(RIP_WARNING, "xxxCreateDesktop: Failed to create the message window"); 02062 goto Error; 02063 } 02064 02065 UserAssert(pdi->spwnd == NULL); 02066 02067 Lock(&(pdi->spwnd), pwndDesktop); 02068 02069 SetFullScreen(pwndDesktop, GDIFULLSCREEN); 02070 02071 /* 02072 * set this windows to the fullscreen window if we don't have one yet 02073 */ 02074 02075 /* 02076 * LATER mikeke 02077 * this can be a problem if a desktop is created while we are in 02078 * FullScreenCleanup() 02079 */ 02080 02081 /* 02082 * Don't set gspwndFullScreen if fGdiEnabled has been cleared 02083 * (we may be in the middle of a disconnect). 02084 */ 02085 UserAssert(fGdiEnabled == TRUE); 02086 02087 if (gspwndFullScreen == NULL && !(pwinsta->dwWSF_Flags & WSF_NOIO)) { 02088 Lock(&(gspwndFullScreen), pwndDesktop); 02089 } 02090 02091 /* 02092 * NT Bug 388747: Link the message window to the mother desktop window 02093 * so that it properly has a parent. We will do this before we link the 02094 * desktop window just so the initial message window appears after the 02095 * initial desktop window (a minor optimization, but not necessary). 02096 */ 02097 Lock(&pwndMessage->spwndParent, pTerm->spwndDesktopOwner); 02098 LinkWindow(pwndMessage, NULL, pTerm->spwndDesktopOwner); 02099 Lock(&pdesk->spwndMessage, pwndMessage); 02100 Unlock(&pwndMessage->spwndOwner); 02101 02102 /* 02103 * Link it as a child but don't use WS_CHILD style 02104 */ 02105 LinkWindow(pwndDesktop, NULL, pTerm->spwndDesktopOwner); 02106 Lock(&pwndDesktop->spwndParent, pTerm->spwndDesktopOwner); 02107 Unlock(&pwndDesktop->spwndOwner); 02108 02109 /* 02110 * Make it regional if it's display configuration is regional. 02111 */ 02112 if (!pdesk->pDispInfo->fDesktopIsRect) { 02113 pwndDesktop->hrgnClip = pdesk->pDispInfo->hrgnScreen; 02114 } 02115 02116 /* 02117 * Create shared menu window and tooltip window 02118 */ 02119 ThreadLock(pdesk->spwndMessage, &tlpwnd); 02120 02121 /* 02122 * Create the tooltip window only for desktops in 02123 * interactive windowstations. 02124 */ 02125 if (!(pwinsta->dwWSF_Flags & WSF_NOIO)) { 02126 pwndTooltip = xxxCreateWindowEx( 02127 WS_EX_TOOLWINDOW | WS_EX_TOPMOST, 02128 (PLARGE_STRING)TOOLTIPCLASS, 02129 NULL, 02130 WS_POPUP | WS_BORDER, 02131 0, 02132 0, 02133 100, 02134 100, 02135 pdesk->spwndMessage, 02136 NULL, 02137 hModuleWin, 02138 NULL, 02139 VER31); 02140 02141 02142 if (pwndTooltip == NULL) { 02143 ThreadUnlock(&tlpwnd); 02144 RIPMSG0(RIP_WARNING, "xxxCreateDesktop: Failed to create the tooltip window"); 02145 goto Error; 02146 } 02147 02148 Lock(&pdesk->spwndTooltip, pwndTooltip); 02149 } 02150 02151 pwndMenu = xxxCreateWindowEx( 02152 WS_EX_TOOLWINDOW | WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE, 02153 (PLARGE_STRING)MENUCLASS, 02154 NULL, 02155 WS_POPUP | WS_BORDER, 02156 0, 02157 0, 02158 100, 02159 100, 02160 pdesk->spwndMessage, 02161 NULL, 02162 hModuleWin, 02163 NULL, 02164 WINVER); 02165 02166 ThreadUnlock(&tlpwnd); 02167 02168 if (pwndMenu == NULL) { 02169 RIPMSG0(RIP_WARNING, "xxxCreateDesktop: Failed to create the menu window"); 02170 goto Error; 02171 } 02172 02173 Lock(&(pdesk->spwndMenu), pwndMenu); 02174 02175 /* 02176 * Set the flag in the popupmenu structure that tells this 02177 * popup menu belongs to the pdesk->spwndMenu 02178 */ 02179 ((PMENUWND)pdesk->spwndMenu)->ppopupmenu->fDesktopMenu = TRUE; 02180 /* 02181 * Unlock spwndPopupMenu since the menu is not in use but mainly 02182 * so we won't have to special case this later when the menu is used. 02183 */ 02184 Unlock(&((PMENUWND)pdesk->spwndMenu)->ppopupmenu->spwndPopupMenu); 02185 02186 HMChangeOwnerThread(pdi->spwnd, pTerm->ptiDesktop); 02187 HMChangeOwnerThread(pwndMessage, pTerm->ptiDesktop); 02188 HMChangeOwnerThread(pdesk->spwndMenu, pTerm->ptiDesktop); 02189 02190 if (!(pwinsta->dwWSF_Flags & WSF_NOIO)) { 02191 HMChangeOwnerThread(pwndTooltip, pTerm->ptiDesktop); 02192 } 02193 02194 /* 02195 * Restore caller's ppi 02196 */ 02197 PtiCurrent()->ppi = ppiSave; 02198 02199 /* 02200 * HACK HACK HACK (adams): Renable hooks. 02201 */ 02202 UserAssert(ptiCurrent->TIF_flags & TIF_DISABLEHOOKS); 02203 ptiCurrent->TIF_flags = (ptiCurrent->TIF_flags & ~TIF_DISABLEHOOKS) | dwDisableHooks; 02204 02205 /* 02206 * Restore the previous desktop 02207 */ 02208 zzzSetDesktop(ptiCurrent, pdeskTemp, hdeskTemp); 02209 02210 EndAtomicCheck(); 02211 UserAssert(dwCritSecUseSave == gdwCritSecUseCount); 02212 zzzEndDeferWinEventNotify(); 02213 02214 /* 02215 * If this is the first desktop, let the worker threads run now 02216 * that there is someplace to send input to. Reassign the event 02217 * to handle desktop destruction. 02218 */ 02219 if (pTerm->pEventInputReady != NULL) { 02220 02221 /* 02222 * Set the windowstation for RIT and desktop thread 02223 * so when EventInputReady is signaled the RIT and the desktop 02224 * will have a windowstation. 02225 */ 02226 if (!(pTerm->dwTERMF_Flags & TERMF_NOIO)) { 02227 gptiRit->pwinsta = pwinsta; 02228 } else { 02229 /* 02230 * let the desktop thread of the system terminal have 02231 * a rpdesk. 02232 */ 02233 zzzSetDesktop(pTerm->ptiDesktop, pdesk, NULL); 02234 } 02235 02236 pTerm->ptiDesktop->pwinsta = pwinsta; 02237 02238 KeSetEvent(pTerm->pEventInputReady, EVENT_INCREMENT, FALSE); 02239 02240 if (!(pTerm->dwTERMF_Flags & TERMF_NOIO)) { 02241 02242 LeaveCrit(); 02243 while (grpdeskRitInput == NULL) { 02244 UserSleep(20); 02245 RIPMSG0(RIP_WARNING, "Waiting for grpdeskRitInput to be set ..."); 02246 } 02247 EnterCrit(); 02248 } 02249 02250 ObDereferenceObject(pTerm->pEventInputReady); 02251 pTerm->pEventInputReady = NULL; 02252 } 02253 02254 02255 /* 02256 * HACK HACK: 02257 * LATER 02258 * 02259 * If we have a devmode passed in, then switch desktops ... 02260 */ 02261 02262 if (ccxlpdevmode) { 02263 02264 TRACE_INIT(("xxxCreateDesktop: about to call switch desktop\n")); 02265 02266 bSuccess = xxxSwitchDesktop(pwinsta, pdesk, TRUE); 02267 if (!bSuccess) { 02268 RIPMSG0(RIP_ERROR, "Failed to switch desktop on Create\n"); 02269 } 02270 02271 } else if (pTerm == &gTermIO){ 02272 02273 UserAssert(grpdeskRitInput != NULL); 02274 02275 /* 02276 * Force the window to the bottom of the z-order if there 02277 * is an active desktop so any drawing done on the desktop 02278 * window will not be seen. This will also allow 02279 * IsWindowVisible to work for apps on invisible 02280 * desktops. 02281 */ 02282 ThreadLockWithPti(ptiCurrent, pwndDesktop, &tlpwnd); 02283 xxxSetWindowPos(pwndDesktop, PWND_BOTTOM, 0, 0, 0, 0, 02284 SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | 02285 SWP_NOREDRAW | SWP_NOSIZE | SWP_NOSENDCHANGING); 02286 ThreadUnlock(&tlpwnd); 02287 } 02288 02289 /* 02290 * If it was null when we came in, make it null going out, or else 02291 * we'll have the wrong desktop selected into this. 02292 */ 02293 if (fWasNull) 02294 UnlockDesktop(&ptiCurrent->ppi->rpdeskStartup, 02295 LDU_PPI_DESKSTARTUP1, (ULONG_PTR)(ptiCurrent->ppi)); 02296 02297 if (gbRemoteSession && 02298 gspdeskDisconnect == NULL && 02299 pdesk == grpdeskLogon) { 02300 02301 UserAssert(hdesk != NULL); 02302 02303 /* 02304 * Create the 'disconnect' desktop 02305 */ 02306 if (!xxxCreateDisconnectDesktop(hwinsta, pwinsta)) { 02307 RIPMSG0(RIP_WARNING, "Failed to create the 'disconnect' desktop"); 02308 02309 LogDesktop(pdesk, LD_DEREF_FN_CREATEDESKTOP3, FALSE, (ULONG_PTR)PtiCurrent()); 02310 ObDereferenceObject(pdesk); 02311 02312 xxxCloseDesktop(hdesk, KernelMode); 02313 02314 return NULL; 02315 } 02316 02317 /* 02318 * Signal that the disconnect desktop got created. 02319 */ 02320 KeSetEvent(gpEventDiconnectDesktop, EVENT_INCREMENT, FALSE); 02321 02322 HYDRA_HINT(HH_DISCONNECTDESKTOP); 02323 } 02324 02325 Cleanup: 02326 02327 LogDesktop(pdesk, LD_DEREF_FN_CREATEDESKTOP3, FALSE, (ULONG_PTR)PtiCurrent()); 02328 ObDereferenceObject(pdesk); 02329 02330 TRACE_INIT(("xxxCreateDesktop: Leaving\n")); 02331 02332 if (hdesk != NULL) { 02333 SetHandleFlag(hdesk, HF_PROTECTED, TRUE); 02334 } 02335 return hdesk; 02336 02337 Error: 02338 02339 EndAtomicCheck(); 02340 UserAssert(dwCritSecUseSave == gdwCritSecUseCount); 02341 zzzEndDeferWinEventNotify(); 02342 02343 UserAssert(pwndMenu == NULL); 02344 02345 if (pwndTooltip != NULL) { 02346 xxxDestroyWindow(pwndTooltip); 02347 Unlock(&pdesk->spwndTooltip); 02348 } 02349 if (pwndMessage != NULL) { 02350 xxxDestroyWindow(pwndMessage); 02351 Unlock(&pdesk->spwndMessage); 02352 } 02353 if (pwndDesktop != NULL) { 02354 xxxDestroyWindow(pwndDesktop); 02355 Unlock(&pdi->spwnd); 02356 Unlock(&gspwndFullScreen); 02357 } 02358 /* 02359 * Restore caller's ppi 02360 */ 02361 PtiCurrent()->ppi = ppiSave; 02362 02363 UserAssert(ptiCurrent->TIF_flags & TIF_DISABLEHOOKS); 02364 ptiCurrent->TIF_flags = (ptiCurrent->TIF_flags & ~TIF_DISABLEHOOKS) | dwDisableHooks; 02365 zzzSetDesktop(ptiCurrent, pdeskTemp, hdeskTemp); 02366 02367 CloseProtectedHandle(hdesk); 02368 hdesk = NULL; 02369 02370 /* 02371 * If it was null when we came in, make it null going out, or else 02372 * we'll have the wrong desktop selected into this. 02373 */ 02374 if (fWasNull) 02375 UnlockDesktop(&ptiCurrent->ppi->rpdeskStartup, 02376 LDU_PPI_DESKSTARTUP1, (ULONG_PTR)(ptiCurrent->ppi)); 02377 02378 goto Cleanup; 02379 02380 } 02381 02382 /***************************************************************************\ 02383 * ParseDesktop 02384 * 02385 * Parse a desktop path. 02386 * 02387 * History: 02388 * 14-Jun-1995 JimA Created. 02389 \***************************************************************************/ 02390 02391 NTSTATUS ParseDesktop( 02392 PVOID pContainerObject, 02393 POBJECT_TYPE pObjectType, 02394 PACCESS_STATE pAccessState, 02395 KPROCESSOR_MODE AccessMode, 02396 ULONG Attributes, 02397 PUNICODE_STRING pstrCompleteName, 02398 PUNICODE_STRING pstrRemainingName, 02399 PVOID Context, 02400 PSECURITY_QUALITY_OF_SERVICE pqos, 02401 PVOID *pObject) 02402 { 02403 PWINDOWSTATION pwinsta = pContainerObject; 02404 PDESKTOP pdesk; 02405 PUNICODE_STRING pstrName; 02406 NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND; 02407 02408 *pObject = NULL; 02409 02410 BEGIN_REENTERCRIT(); 02411 02412 UserAssert(OBJECT_TO_OBJECT_HEADER(pContainerObject)->Type == *ExWindowStationObjectType); 02413 UserAssert(pObjectType == *ExDesktopObjectType); 02414 02415 /* 02416 * See if the desktop exists 02417 */ 02418 for (pdesk = pwinsta->rpdeskList; pdesk != NULL; pdesk = pdesk->rpdeskNext) { 02419 pstrName = POBJECT_NAME(pdesk); 02420 if (pstrName && RtlEqualUnicodeString(pstrRemainingName, pstrName, 02421 (BOOLEAN)((Attributes & OBJ_CASE_INSENSITIVE) != 0))) { 02422 if (Context != NULL) { 02423 if (!(Attributes & OBJ_OPENIF)) { 02424 02425 /* 02426 * We are attempting to create a desktop and one 02427 * already exists. 02428 */ 02429 Status = STATUS_OBJECT_NAME_COLLISION; 02430 goto Exit; 02431 02432 } else { 02433 Status = STATUS_OBJECT_NAME_EXISTS; 02434 } 02435 } else { 02436 Status = STATUS_SUCCESS; 02437 } 02438 02439 ObReferenceObject(pdesk); 02440 02441 *pObject = pdesk; 02442 goto Exit; 02443 } 02444 } 02445 02446 /* 02447 * Handle creation request 02448 */ 02449 if (Context != NULL) { 02450 Status = xxxCreateDesktop2(pContainerObject, 02451 pAccessState, 02452 AccessMode, 02453 pstrRemainingName, 02454 Context, 02455 pObject); 02456 } 02457 02458 Exit: 02459 END_REENTERCRIT(); 02460 02461 return Status; 02462 02463 UNREFERENCED_PARAMETER(pObjectType); 02464 UNREFERENCED_PARAMETER(pstrCompleteName); 02465 UNREFERENCED_PARAMETER(pqos); 02466 } 02467 02468 /***************************************************************************\ 02469 * DestroyDesktop 02470 * 02471 * Called upon last close of a desktop to remove the desktop from the 02472 * desktop list and free all desktop resources. 02473 * 02474 * History: 02475 * 08-Dec-1993 JimA Created. 02476 \***************************************************************************/ 02477 02478 BOOL DestroyDesktop( 02479 PDESKTOP pdesk) 02480 { 02481 PWINDOWSTATION pwinsta = pdesk->rpwinstaParent; 02482 PTERMINAL pTerm; 02483 PDESKTOP *ppdesk; 02484 02485 if (pdesk->dwDTFlags & DF_DESTROYED) { 02486 RIPMSG1(RIP_WARNING, "DestroyDesktop: Already destroyed:%#p", pdesk); 02487 return FALSE; 02488 } 02489 02490 /* 02491 * Unlink the desktop, if it has not yet been unlinked. 02492 */ 02493 if (pwinsta != NULL) { 02494 02495 ppdesk = &pwinsta->rpdeskList; 02496 while (*ppdesk != NULL && *ppdesk != pdesk) { 02497 ppdesk = &((*ppdesk)->rpdeskNext); 02498 } 02499 02500 if (*ppdesk != NULL) { 02501 02502 /* 02503 * remove desktop from the list 02504 */ 02505 LockDesktop(ppdesk, pdesk->rpdeskNext, LDL_WINSTA_DESKLIST2, (ULONG_PTR)pwinsta); 02506 UnlockDesktop(&pdesk->rpdeskNext, LDU_DESK_DESKNEXT, (ULONG_PTR)pwinsta); 02507 } 02508 } 02509 02510 /* 02511 * Link it into the destruction list and signal the desktop thread. 02512 */ 02513 pTerm = pwinsta->pTerm; 02514 02515 LockDesktop(&pdesk->rpdeskNext, pTerm->rpdeskDestroy, LDL_DESK_DESKNEXT2, 0); 02516 LockDesktop(&pTerm->rpdeskDestroy, pdesk, LDL_TERM_DESKDESTROY2, (ULONG_PTR)pTerm); 02517 KeSetEvent(pTerm->pEventDestroyDesktop, EVENT_INCREMENT, FALSE); 02518 02519 pdesk->dwDTFlags |= DF_DESTROYED; 02520 02521 TRACE_DESKTOP(("pdesk %#p '%ws' marked as destroyed\n", pdesk, GetDesktopName(pdesk))); 02522 02523 return TRUE; 02524 } 02525 02526 /***************************************************************************\ 02527 * FreeDesktop 02528 * 02529 * Called to free desktop object and section when last lock is released. 02530 * 02531 * History: 02532 * 08-Dec-1993 JimA Created. 02533 \***************************************************************************/ 02534 02535 VOID FreeDesktop( 02536 PVOID pobj) 02537 { 02538 PDESKTOP pdesk = (PDESKTOP)pobj; 02539 NTSTATUS Status; 02540 02541 BEGIN_REENTERCRIT(); 02542 02543 UserAssert(OBJECT_TO_OBJECT_HEADER(pobj)->Type == *ExDesktopObjectType); 02544 02545 #ifdef LOGDESKTOPLOCKS 02546 02547 if (pdesk->pLog != NULL) { 02548 02549 /* 02550 * By the time we get here the lock count for lock/unlock 02551 * tracking code should be 0 02552 */ 02553 if (pdesk->nLockCount != 0) { 02554 RIPMSG3(RIP_WARNING, 02555 "FreeDesktop pdesk %#p, pLog %#p, nLockCount %d should be 0", 02556 pdesk, pdesk->pLog, pdesk->nLockCount); 02557 } 02558 UserFreePool(pdesk->pLog); 02559 pdesk->pLog = NULL; 02560 } 02561 #endif // LOGDESKTOPLOCKS 02562 02563 #if DBG 02564 if (pdesk->pDeskInfo && (pdesk->pDeskInfo->spwnd != NULL)) { 02565 02566 /* 02567 * assert if the desktop has a desktop window but the flag 02568 * that says the window is destroyed is not set 02569 */ 02570 UserAssert(pdesk->dwDTFlags & DF_DESKWNDDESTROYED); 02571 } 02572 #endif // DBG 02573 02574 /* 02575 * Mark the desktop as dying. Make sure we aren't recursing. 02576 */ 02577 UserAssert(!(pdesk->dwDTFlags & DF_DYING)); 02578 pdesk->dwDTFlags |= DF_DYING; 02579 02580 #ifdef DEBUG_DESK 02581 { 02582 /* 02583 * Verify that the desktop has been cleaned out. 02584 */ 02585 #if 0 02586 PPROCESSINFO ppi; 02587 PCLS pcls, pclsClone; 02588 #endif 02589 PHE pheT, pheMax; 02590 BOOL fDirty = FALSE; 02591 02592 #if 0 02593 for (ppi = gppiFirst; ppi != NULL; ppi = ppi->ppiNext) { 02594 for (pcls = ppi->pclsPrivateList; pcls != NULL; pcls = pcls->pclsNext) { 02595 if (pcls->pheapDesktop == pdesk->pheapDesktop) { 02596 DbgPrint("ppi %08x private class at %08x exists\n", ppi, pcls); 02597 fDirty = TRUE; 02598 } 02599 for (pclsClone = pcls->pclsClone; pclsClone != NULL; 02600 pclsClone = pclsClone->pclsNext) { 02601 if (pclsClone->pheapDesktop == pdesk->pheapDesktop) { 02602 DbgPrint("ppi %08x private class clone at %08x exists\n", ppi, pclsClone); 02603 fDirty = TRUE; 02604 } 02605 } 02606 } 02607 for (pcls = ppi->pclsPublicList; pcls != NULL; pcls = pcls->pclsNext) { 02608 if (pcls->pheapDesktop == pdesk->pheapDesktop) { 02609 DbgPrint("ppi %08x public class at %08x exists\n", ppi, pcls); 02610 fDirty = TRUE; 02611 } 02612 for (pclsClone = pcls->pclsClone; pclsClone != NULL; 02613 pclsClone = pclsClone->pclsNext) { 02614 if (pclsClone->pheapDesktop == pdesk->pheapDesktop) { 02615 DbgPrint("ppi %08x public class clone at %08x exists\n", ppi, pclsClone); 02616 fDirty = TRUE; 02617 } 02618 } 02619 } 02620 } 02621 #endif 02622 02623 pheMax = &gSharedInfo.aheList[giheLast]; 02624 for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) { 02625 switch (pheT->bType) { 02626 case TYPE_WINDOW: 02627 if (((PWND)pheT->phead)->head.rpdesk == pdesk) { 02628 DbgPrint("Window at %08x exists\n", pheT->phead); 02629 break; 02630 } 02631 continue; 02632 case TYPE_MENU: 02633 if (((PMENU)pheT->phead)->head.rpdesk == pdesk) { 02634 DbgPrint("Menu at %08x exists\n", pheT->phead); 02635 break; 02636 } 02637 continue; 02638 case TYPE_CALLPROC: 02639 if (((PCALLPROCDATA)pheT->phead)->head.rpdesk == pdesk) { 02640 DbgPrint("Callproc at %08x exists\n", pheT->phead); 02641 break; 02642 } 02643 continue; 02644 case TYPE_HOOK: 02645 if (((PHOOK)pheT->phead)->head.rpdesk == pdesk) { 02646 DbgPrint("Hook at %08x exists\n", pheT->phead); 02647 break; 02648 } 02649 continue; 02650 default: 02651 continue; 02652 } 02653 fDirty = TRUE; 02654 } 02655 if (fDirty) { 02656 RIPMSG0(RIP_ERROR,"Desktop cleanup failed\n"); 02657 } 02658 } 02659 #endif 02660 02661 /* 02662 * If the desktop is mapped into CSR, unmap it. Note the 02663 * handle count values passed in will cause the desktop 02664 * to be unmapped and skip the desktop destruction tests. 02665 */ 02666 FreeView(gpepCSRSS, pdesk); 02667 02668 if (pdesk->pheapDesktop != NULL) { 02669 02670 PVOID hheap = Win32HeapGetHandle(pdesk->pheapDesktop); 02671 02672 Win32HeapDestroy(pdesk->pheapDesktop); 02673 02674 Status = Win32UnmapViewInSessionSpace(hheap); 02675 02676 UserAssert(NT_SUCCESS(Status)); 02677 Win32DestroySection(pdesk->hsectionDesktop); 02678 } 02679 02680 UnlockWinSta(&pdesk->rpwinstaParent); 02681 02682 DbgTrackRemoveDesktop(pdesk); 02683 02684 END_REENTERCRIT(); 02685 } 02686 02687 /***************************************************************************\ 02688 * CreateDesktopHeap 02689 * 02690 * Create a new desktop heap 02691 * 02692 * History: 02693 * 27-Jul-1992 JimA Created. 02694 \***************************************************************************/ 02695 02696 HANDLE CreateDesktopHeap( 02697 PWIN32HEAP* ppheapRet, 02698 ULONG ulHeapSize) 02699 { 02700 HANDLE hsection; 02701 LARGE_INTEGER SectionSize; 02702 SIZE_T ulViewSize; 02703 NTSTATUS Status; 02704 PWIN32HEAP pheap; 02705 PVOID pHeapBase; 02706 02707 /* 02708 * Create desktop heap section and map it into the kernel 02709 */ 02710 SectionSize.QuadPart = ulHeapSize; 02711 02712 Status = Win32CreateSection(&hsection, 02713 SECTION_ALL_ACCESS, 02714 (POBJECT_ATTRIBUTES)NULL, 02715 &SectionSize, 02716 PAGE_EXECUTE_READWRITE, 02717 SEC_RESERVE, 02718 (HANDLE)NULL, 02719 NULL, 02720 TAG_SECTION_DESKTOP); 02721 02722 if (!NT_SUCCESS( Status )) { 02723 RIPNTERR0(Status, RIP_WARNING, "Can't create section for desktop heap."); 02724 return NULL; 02725 } 02726 02727 ulViewSize = ulHeapSize; 02728 pHeapBase = NULL; 02729 02730 Status = Win32MapViewInSessionSpace(hsection, &pHeapBase, &ulViewSize); 02731 02732 if (!NT_SUCCESS(Status)) { 02733 RIPNTERR0(Status, 02734 RIP_WARNING, 02735 "Can't map section for desktop heap into system space."); 02736 goto Error; 02737 } 02738 02739 /* 02740 * Create desktop heap. 02741 */ 02742 if ((pheap = UserCreateHeap( 02743 hsection, 02744 0, 02745 pHeapBase, 02746 ulHeapSize, 02747 UserCommitDesktopMemory)) == NULL) { 02748 02749 RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "Can't create Desktop heap."); 02750 02751 Win32UnmapViewInSessionSpace(pHeapBase); 02752 Error: 02753 Win32DestroySection(hsection); 02754 *ppheapRet = NULL; 02755 return NULL; 02756 } 02757 02758 UserAssert(Win32HeapGetHandle(pheap) == pHeapBase); 02759 *ppheapRet = pheap; 02760 02761 return hsection; 02762 } 02763 02764 /***************************************************************************\ 02765 * GetDesktopView 02766 * 02767 * Determines if a desktop has already been mapped into a process. 02768 * 02769 * History: 02770 * 10-Apr-1995 JimA Created. 02771 \***************************************************************************/ 02772 02773 PDESKTOPVIEW GetDesktopView( 02774 PPROCESSINFO ppi, 02775 PDESKTOP pdesk) 02776 { 02777 PDESKTOPVIEW pdv; 02778 02779 if(ppi->Process != gpepCSRSS && pdesk == NULL) { 02780 RIPMSG1(RIP_WARNING, "Process %#p isn't CSRSS but pdesk is NULL in GetDesktopView", ppi); 02781 } 02782 02783 for (pdv = ppi->pdvList; pdv != NULL; pdv = pdv->pdvNext) 02784 if (pdv->pdesk == pdesk) 02785 break; 02786 return pdv; 02787 } 02788 02789 /***************************************************************************\ 02790 * _MapDesktopObject 02791 * 02792 * Maps a desktop object into the client's address space 02793 * 02794 * History: 02795 * 11-Apr-1995 JimA Created. 02796 \***************************************************************************/ 02797 02798 PVOID _MapDesktopObject( 02799 HANDLE h) 02800 { 02801 PDESKOBJHEAD pobj; 02802 PDESKTOPVIEW pdv; 02803 02804 /* 02805 * Validate the handle 02806 */ 02807 pobj = HMValidateHandle(h, TYPE_GENERIC); 02808 if (pobj == NULL) 02809 return NULL; 02810 02811 UserAssert(HMObjectFlags(pobj) & OCF_DESKTOPHEAP); 02812 02813 /* 02814 * Locate the client's view of the desktop. Realistically, 02815 * this should never fail for valid objects. 02816 */ 02817 pdv = GetDesktopView(PpiCurrent(), pobj->rpdesk); 02818 if (pdv == NULL) { 02819 RIPMSG1(RIP_WARNING, "MapDesktopObject: can not map handle %#p", h); 02820 return NULL; 02821 } 02822 02823 UserAssert(pdv->ulClientDelta != 0); 02824 return (PVOID)((PBYTE)pobj - pdv->ulClientDelta); 02825 } 02826 02827 /***************************************************************************\ 02828 * MapDesktop 02829 * 02830 * Attempts to map a desktop heap into a process. 02831 * 02832 * History: 02833 * 20-Oct-1994 JimA Created. 02834 \***************************************************************************/ 02835 02836 VOID MapDesktop( 02837 OB_OPEN_REASON OpenReason, 02838 PEPROCESS Process, 02839 PVOID pobj, 02840 ACCESS_MASK amGranted, 02841 ULONG cHandles) 02842 { 02843 PPROCESSINFO ppi; 02844 PDESKTOP pdesk = (PDESKTOP)pobj; 02845 NTSTATUS Status; 02846 SIZE_T ulViewSize; 02847 LARGE_INTEGER liOffset; 02848 PDESKTOPVIEW pdvNew; 02849 PBYTE pClientBase; 02850 BOOL bFailed = FALSE; 02851 02852 UserAssert(OBJECT_TO_OBJECT_HEADER(pobj)->Type == *ExDesktopObjectType); 02853 02854 /* 02855 * Ignore handle inheritance because MmMapViewOfSection 02856 * cannot be called during process creation. 02857 */ 02858 if (OpenReason == ObInheritHandle) 02859 return; 02860 02861 /* 02862 * If there is no ppi, we can't map the desktop 02863 */ 02864 ppi = PpiFromProcess(Process); 02865 if (ppi == NULL) 02866 return; 02867 02868 /* 02869 * If the desktop has already been mapped we're done. 02870 */ 02871 if (GetDesktopView(ppi, pdesk) != NULL) 02872 return; 02873 02874 /* 02875 * Allocate a view of the desktop 02876 */ 02877 pdvNew = UserAllocPoolWithQuota(sizeof(*pdvNew), TAG_PROCESSINFO); 02878 if (pdvNew == NULL) { 02879 RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_VERBOSE, ""); 02880 02881 /* 02882 * Raise an exception so that the object manager 02883 * knows OpenProcedure wasn't successful 02884 */ 02885 ExRaiseStatus(STATUS_NO_MEMORY); 02886 return; 02887 } 02888 02889 BEGIN_REENTERCRIT(); 02890 02891 /* 02892 * Read/write access has been granted. Map the desktop 02893 * memory into the client process. 02894 */ 02895 ulViewSize = 0; 02896 liOffset.QuadPart = 0; 02897 pClientBase = NULL; 02898 02899 Status = MmMapViewOfSection(pdesk->hsectionDesktop, 02900 Process, 02901 &pClientBase, 02902 0, 02903 0, 02904 &liOffset, 02905 &ulViewSize, 02906 ViewUnmap, 02907 SEC_NO_CHANGE, 02908 PAGE_EXECUTE_READ); 02909 02910 if (!NT_SUCCESS(Status)) { 02911 #if DBG 02912 if ( Status != STATUS_NO_MEMORY && 02913 Status != STATUS_PROCESS_IS_TERMINATING && 02914 Status != STATUS_COMMITMENT_LIMIT) { 02915 RIPMSG1(RIP_WARNING, "MapDesktop - failed to map to client process (status == %lX). Contact ChrisWil",Status); 02916 } 02917 #endif 02918 02919 RIPNTERR0(Status, RIP_VERBOSE, ""); 02920 UserFreePool(pdvNew); 02921 bFailed = TRUE; 02922 goto Exit; 02923 } 02924 02925 /* 02926 * Link the view into the ppi 02927 */ 02928 pdvNew->pdesk = pdesk; 02929 pdvNew->ulClientDelta = (ULONG_PTR)((PBYTE)Win32HeapGetHandle(pdesk->pheapDesktop) - pClientBase); 02930 pdvNew->pdvNext = ppi->pdvList; 02931 ppi->pdvList = pdvNew; 02932 02933 Exit: 02934 END_REENTERCRIT(); 02935 02936 /* 02937 * If something failed raise an exception so that the object manager 02938 * knows OpenProcedure wasn't successful 02939 */ 02940 if (bFailed) { 02941 ExRaiseStatus(STATUS_NO_MEMORY); 02942 } 02943 02944 UNREFERENCED_PARAMETER(cHandles); 02945 UNREFERENCED_PARAMETER(amGranted); 02946 } 02947 02948 02949 VOID FreeView( 02950 PEPROCESS Process, 02951 PDESKTOP pdesk) 02952 { 02953 PPROCESSINFO ppi; 02954 NTSTATUS Status; 02955 PDESKTOPVIEW pdv; 02956 PDESKTOPVIEW *ppdv; 02957 02958 /* 02959 * Bug 277291: gpepCSRSS can be NULL when FreeView is 02960 * called from FreeDesktop. 02961 */ 02962 if (Process == NULL) { 02963 return; 02964 } 02965 02966 ppi = PpiFromProcess(Process); 02967 02968 /* 02969 * If there is no ppi, then the process is gone and nothing 02970 * needs to be unmapped. 02971 */ 02972 if (ppi != NULL) { 02973 pdv = GetDesktopView(ppi, pdesk); 02974 02975 /* 02976 * Because mapping cannot be done when a handle is 02977 * inherited, there may not be a view of the desktop. 02978 * Only unmap if there is a view. 02979 */ 02980 if (pdv != NULL) { 02981 Status = MmUnmapViewOfSection(Process, 02982 (PBYTE)Win32HeapGetHandle(pdesk->pheapDesktop) - pdv->ulClientDelta); 02983 UserAssert(NT_SUCCESS(Status) || Status == STATUS_PROCESS_IS_TERMINATING); 02984 if (!NT_SUCCESS(Status)) { 02985 RIPMSG1(RIP_WARNING, "FreeView unmap status = 0x%#lx", Status); 02986 } 02987 02988 /* 02989 * Unlink and delete the view. 02990 */ 02991 for (ppdv = &ppi->pdvList; *ppdv && *ppdv != pdv; 02992 ppdv = &(*ppdv)->pdvNext) 02993 ; 02994 UserAssert(*ppdv); 02995 *ppdv = pdv->pdvNext; 02996 UserFreePool(pdv); 02997 } 02998 02999 #if DBG 03000 /* 03001 * No thread in this process should be on this desktop 03002 */ 03003 { 03004 PTHREADINFO pti = ppi->ptiList; 03005 while (pti != NULL) { 03006 if (pti->rpdesk == pdesk) { 03007 RIPMSG2(RIP_ERROR, "FreeView: pti %#p still on pdesk %#p", pti, pdesk); 03008 } 03009 pti = pti->ptiSibling; 03010 } 03011 } 03012 #endif 03013 } 03014 } 03015 03016 03017 VOID UnmapDesktop( 03018 PEPROCESS Process, 03019 PVOID pobj, 03020 ACCESS_MASK amGranted, 03021 ULONG cProcessHandles, 03022 ULONG cSystemHandles) 03023 { 03024 PDESKTOP pdesk = (PDESKTOP)pobj; 03025 03026 BEGIN_REENTERCRIT(); 03027 03028 UserAssert(OBJECT_TO_OBJECT_HEADER(pobj)->Type == *ExDesktopObjectType); 03029 03030 /* 03031 * Update cSystemHandles with the correct information 03032 */ 03033 cSystemHandles = OBJECT_TO_OBJECT_HEADER(pobj)->HandleCount + 1; 03034 03035 /* 03036 * Only unmap the desktop if this is the last process handle and 03037 * the process is not CSR. 03038 */ 03039 if (cProcessHandles == 1 && Process != gpepCSRSS) { 03040 FreeView(Process, pdesk); 03041 } 03042 03043 if (cSystemHandles > 2) 03044 goto Exit; 03045 03046 if (cSystemHandles == 2 && pdesk->dwConsoleThreadId != 0) { 03047 03048 /* 03049 * If a console thread exists and we're down to two handles, 03050 * it means that the last application handle to the 03051 * desktop is being closed. Terminate the console 03052 * thread so the desktop can be freed. 03053 */ 03054 TerminateConsole(pdesk); 03055 } else if (cSystemHandles == 1) { 03056 03057 /* 03058 * If this is the last handle to this desktop in the system, 03059 * destroy the desktop. 03060 */ 03061 03062 /* 03063 * No pti should be linked to this desktop. 03064 */ 03065 if ((&pdesk->PtiList != pdesk->PtiList.Flink) 03066 || (&pdesk->PtiList != pdesk->PtiList.Blink)) { 03067 03068 RIPMSG1(RIP_WARNING, "UnmapDesktop: PtiList not Empty. pdesk:%#p", pdesk); 03069 } 03070 03071 DestroyDesktop(pdesk); 03072 } 03073 03074 Exit: 03075 END_REENTERCRIT(); 03076 03077 UNREFERENCED_PARAMETER(amGranted); 03078 } 03079 03080 /***************************************************************************\ 03081 * OkayToCloseDesktop 03082 * 03083 * We can only close desktop handles if they're not in use. 03084 * 03085 * History: 03086 * 08-Feb-1999 JerrySh Created. 03087 \***************************************************************************/ 03088 03089 BOOLEAN OkayToCloseDesktop( 03090 PEPROCESS Process OPTIONAL, 03091 PVOID Object, 03092 HANDLE Handle) 03093 { 03094 PDESKTOP pdesk = (PDESKTOP)Object; 03095 03096 UNREFERENCED_PARAMETER(Process); 03097 03098 UserAssert(OBJECT_TO_OBJECT_HEADER(Object)->Type == *ExDesktopObjectType); 03099 03100 /* 03101 * Kernel mode code can close anything. 03102 */ 03103 if (KeGetPreviousMode() == KernelMode) { 03104 return TRUE; 03105 } 03106 03107 /* 03108 * We can't close the desktop if we're still initializing it. 03109 */ 03110 if (!(pdesk->dwDTFlags & DF_DESKCREATED)) { 03111 RIPMSG1(RIP_WARNING, "Trying to close desktop %#p during initialization", pdesk); 03112 return FALSE; 03113 } 03114 03115 /* 03116 * We can't close a desktop that's being used. 03117 */ 03118 if (CheckHandleInUse(Handle) || CheckHandleFlag(Handle, HF_PROTECTED)) { 03119 RIPMSG1(RIP_WARNING, "Trying to close desktop %#p while still in use", pdesk); 03120 return FALSE; 03121 } 03122 03123 return TRUE; 03124 } 03125 03126 /***************************************************************************\ 03127 * xxxUserResetDisplayDevice 03128 * 03129 * Called to reset the display device after a switch to another device. 03130 * Used when opening a new device, or when switching back to an old desktop 03131 * 03132 * History: 03133 * 31-May-1994 AndreVa Created. 03134 \***************************************************************************/ 03135 03136 VOID xxxUserResetDisplayDevice() 03137 { 03138 TL tlpwnd; 03139 TRACE_INIT(("xxxUserResetDisplayDevice: about to reset the device\n")); 03140 03141 /* 03142 * Handle early system initialization gracefully. 03143 */ 03144 if (grpdeskRitInput != NULL) { 03145 ThreadLock(grpdeskRitInput->pDeskInfo->spwnd, &tlpwnd); 03146 #if 0 03147 // what should we do here to notify the display applet ? 03148 // AndreVa 03149 03150 /* 03151 * Broadcast that the display has changed resolution. We are going 03152 * to specify the desktop for the changing-desktop. That way we 03153 * don't get confused as to what desktop to broadcast to. 03154 */ 03155 xxxBroadcastMessage(grpdeskRitInput->pDeskInfo->spwnd, 03156 WM_DISPLAYCHANGE, 03157 gpsi->BitCount, 03158 MAKELONG(SYSMET(CXSCREEN), SYSMET(CYSCREEN)), 03159 BMSG_SENDNOTIFYMSG, 03160 NULL); 03161 #endif 03162 xxxRedrawWindow(grpdeskRitInput->pDeskInfo->spwnd, 03163 NULL, 03164 NULL, 03165 RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW | 03166 RDW_ALLCHILDREN); 03167 gpqCursor = NULL; 03168 03169 /* 03170 * No need to DeferWinEventNotify() - we just made an xxx call above 03171 */ 03172 zzzInternalSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y); 03173 03174 SetPointer(TRUE); 03175 03176 ThreadUnlock(&tlpwnd); 03177 } 03178 03179 TRACE_INIT(("xxxUserResetDisplayDevice: complete\n")); 03180 03181 } 03182 03183 /***************************************************************************\ 03184 * OpenDesktopCompletion 03185 * 03186 * Verifies that a given desktop has successfully opened. 03187 * 03188 * History: 03189 * 03-Oct-1995 JimA Created. 03190 \***************************************************************************/ 03191 03192 BOOL OpenDesktopCompletion( 03193 PDESKTOP pdesk, 03194 HDESK hdesk, 03195 DWORD dwFlags, 03196 BOOL* pbShutDown) 03197 { 03198 PPROCESSINFO ppi = PpiCurrent(); 03199 PWINDOWSTATION pwinsta; 03200 BOOL fMapped; 03201 03202 /* 03203 * If the desktop was not mapped in as a result of the open, 03204 * fail. 03205 */ 03206 fMapped = (GetDesktopView(ppi, pdesk) != NULL); 03207 if (!fMapped) { 03208 03209 RIPMSG0(RIP_WARNING, "OpenDesktopCompletion failed." 03210 " The desktop is not mapped"); 03211 03212 /* 03213 * Desktop mapping failed. Status is set by MapDesktop 03214 */ 03215 return FALSE; 03216 } else { 03217 03218 /* 03219 * Fail if the windowstation is locked 03220 */ 03221 pwinsta = pdesk->rpwinstaParent; 03222 if (pwinsta->dwWSF_Flags & WSF_OPENLOCK && 03223 ppi->Process->UniqueProcessId != gpidLogon) { 03224 LUID luidCaller; 03225 NTSTATUS Status; 03226 03227 /* 03228 * If logoff is occuring and the caller does not 03229 * belong to the session that is ending, allow the 03230 * open to proceed. 03231 */ 03232 Status = GetProcessLuid(NULL, &luidCaller); 03233 03234 if (!NT_SUCCESS(Status) || 03235 (pwinsta->dwWSF_Flags & WSF_REALSHUTDOWN) || 03236 RtlEqualLuid(&luidCaller, &pwinsta->luidEndSession)) { 03237 03238 RIPERR0(ERROR_BUSY, RIP_WARNING, "OpenDesktopCompletion failed"); 03239 03240 /* 03241 * Set the shut down flag 03242 */ 03243 *pbShutDown = TRUE; 03244 return FALSE; 03245 } 03246 } 03247 } 03248 03249 SetHandleFlag(hdesk, HF_DESKTOPHOOK, dwFlags & DF_ALLOWOTHERACCOUNTHOOK); 03250 03251 return TRUE; 03252 } 03253 03254 /***************************************************************************\ 03255 * xxxOpenDesktop (API) 03256 * 03257 * Open a desktop object. This is an 'xxx' function because it leaves the 03258 * critical section while waiting for the windowstation desktop open lock 03259 * to be available. 03260 * 03261 * History: 03262 * 16-Jan-1991 JimA Created scaffold code. 03263 \***************************************************************************/ 03264 03265 HDESK xxxOpenDesktop( 03266 POBJECT_ATTRIBUTES ccxObjA, 03267 KPROCESSOR_MODE AccessMode, 03268 DWORD dwFlags, 03269 DWORD dwDesiredAccess, 03270 BOOL* pbShutDown) 03271 { 03272 HDESK hdesk; 03273 PDESKTOP pdesk; 03274 NTSTATUS Status; 03275 03276 /* 03277 * Require read/write access 03278 */ 03279 dwDesiredAccess |= DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS; 03280 03281 /* 03282 * Open the desktop -- Ob routines capture Obj attributes. 03283 */ 03284 Status = ObOpenObjectByName( 03285 ccxObjA, 03286 *ExDesktopObjectType, 03287 AccessMode, 03288 NULL, 03289 dwDesiredAccess, 03290 NULL, 03291 &hdesk); 03292 if (!NT_SUCCESS(Status)) { 03293 RIPNTERR0(Status, RIP_VERBOSE, ""); 03294 return NULL; 03295 } 03296 03297 /* 03298 * Reference the desktop 03299 */ 03300 ObReferenceObjectByHandle( 03301 hdesk, 03302 0, 03303 *ExDesktopObjectType, 03304 KernelMode, 03305 &pdesk, 03306 NULL); 03307 if (!NT_SUCCESS(Status)) { 03308 RIPNTERR0(Status, RIP_VERBOSE, ""); 03309 03310 Error: 03311 CloseProtectedHandle(hdesk); 03312 return NULL; 03313 } 03314 03315 if (pdesk->dwSessionId != gSessionId) { 03316 RIPNTERR1(STATUS_INVALID_HANDLE, RIP_WARNING, 03317 "xxxOpenDesktop pdesk %#p belongs to a different session", 03318 pdesk); 03319 ObDereferenceObject(pdesk); 03320 goto Error; 03321 } 03322 03323 LogDesktop(pdesk, LD_REF_FN_OPENDESKTOP, TRUE, (ULONG_PTR)PtiCurrent()); 03324 03325 /* 03326 * Complete the desktop open 03327 */ 03328 if (!OpenDesktopCompletion(pdesk, hdesk, dwFlags, pbShutDown)) { 03329 CloseProtectedHandle(hdesk); 03330 hdesk = NULL; 03331 } 03332 03333 TRACE_INIT(("xxxOpenDesktop: Leaving\n")); 03334 03335 LogDesktop(pdesk, LD_DEREF_FN_OPENDESKTOP, FALSE, (ULONG_PTR)PtiCurrent()); 03336 ObDereferenceObject(pdesk); 03337 03338 if (hdesk != NULL) { 03339 SetHandleFlag(hdesk, HF_PROTECTED, TRUE); 03340 } 03341 03342 return hdesk; 03343 } 03344 03345 /***************************************************************************\ 03346 * xxxSwitchDesktop (API) 03347 * 03348 * Switch input focus to another desktop and bring it to the top of the 03349 * desktops 03350 * 03351 * bCreateNew is set when a new desktop has been created on the device, and 03352 * when we do not want to send another enable\disable 03353 * 03354 * History: 03355 * 16-Jan-1991 JimA Created scaffold code. 03356 \***************************************************************************/ 03357 03358 BOOL xxxSwitchDesktop( 03359 PWINDOWSTATION pwinsta, 03360 PDESKTOP pdesk, 03361 BOOL bCreateNew) 03362 { 03363 PETHREAD Thread; 03364 PWND pwndSetForeground; 03365 TL tlpwndChild; 03366 TL tlpwnd; 03367 TL tlhdesk; 03368 PQ pq; 03369 BOOL bUpdateCursor = FALSE; 03370 PLIST_ENTRY pHead, pEntry; 03371 PTHREADINFO pti; 03372 PTHREADINFO ptiCurrent = PtiCurrent(); 03373 PTERMINAL pTerm; 03374 NTSTATUS Status; 03375 HDESK hdesk; 03376 03377 CheckCritIn(); 03378 03379 UserAssert(IsWinEventNotifyDeferredOK()); 03380 03381 if (pdesk == NULL) { 03382 return FALSE; 03383 } 03384 03385 if (pdesk == grpdeskRitInput) { 03386 return TRUE; 03387 } 03388 03389 if (pdesk->dwDTFlags & DF_DESTROYED) { 03390 RIPMSG1(RIP_ERROR, "xxxSwitchDesktop: destroyed:%#p", pdesk); 03391 return FALSE; 03392 } 03393 03394 UserAssert(!(pdesk->dwDTFlags & (DF_DESKWNDDESTROYED | DF_DYING))); 03395 03396 if (pwinsta == NULL) 03397 pwinsta = pdesk->rpwinstaParent; 03398 03399 /* 03400 * Get the windowstation, and assert if this process doesn't have one. 03401 */ 03402 UserAssert(pwinsta); 03403 if (pwinsta == NULL) { 03404 RIPMSG1(RIP_WARNING, 03405 "xxxSwitchDesktop: failed for pwinsta NULL pdesk %#p", pdesk); 03406 return FALSE; 03407 } 03408 03409 /* 03410 * Don't allow invisible desktops to become active 03411 */ 03412 if (pwinsta->dwWSF_Flags & WSF_NOIO) { 03413 RIPMSG1(RIP_VERBOSE, 03414 "xxxSwitchDesktop: failed for NOIO pdesk %#p", pdesk); 03415 return FALSE; 03416 } 03417 03418 pTerm = pwinsta->pTerm; 03419 03420 UserAssert(grpdeskRitInput == pwinsta->pdeskCurrent); 03421 03422 /* 03423 * Do tracing only if compiled in. 03424 */ 03425 TRACE_INIT(("xxxSwitchDesktop: Entering, desktop = %ws, createdNew = %01lx\n", POBJECT_NAME(pdesk), (DWORD)bCreateNew)); 03426 if (grpdeskRitInput) { 03427 TRACE_INIT((" coming from desktop = %ws\n", POBJECT_NAME(grpdeskRitInput))); 03428 } 03429 03430 /* 03431 * Wait if the logon has the windowstation locked 03432 */ 03433 Thread = PsGetCurrentThread(); 03434 03435 /* 03436 * Allow switches to the disconnected desktop 03437 */ 03438 if (pdesk != gspdeskDisconnect) 03439 if (!IS_SYSTEM_THREAD(Thread) && pwinsta->dwWSF_Flags & WSF_SWITCHLOCK && 03440 pdesk != grpdeskLogon && 03441 Thread->Cid.UniqueProcess != gpidLogon) 03442 return FALSE; 03443 03444 /* 03445 * We don't allow switching away from the disconnect desktop. 03446 */ 03447 if (gbDesktopLocked && ((!gspdeskDisconnect) || (pdesk != gspdeskDisconnect))) { 03448 TRACE_DESKTOP(("Attempt to switch away from the disconnect desktop\n")); 03449 03450 /* 03451 * we should not lock this global !!! clupu 03452 */ 03453 LockDesktop(&gspdeskShouldBeForeground, pdesk, LDL_DESKSHOULDBEFOREGROUND1, 0); 03454 return TRUE; 03455 } 03456 03457 /* 03458 * HACKHACK LATER !!! 03459 * Where should we really switch the desktop ... 03460 * And we need to send repaint messages to everyone... 03461 * 03462 */ 03463 03464 UserAssert(grpdeskRitInput == pwinsta->pdeskCurrent); 03465 03466 if (!bCreateNew && grpdeskRitInput && 03467 (grpdeskRitInput->pDispInfo->hDev != pdesk->pDispInfo->hDev)) { 03468 03469 if (!DrvDisableMDEV(grpdeskRitInput->pDispInfo->pmdev, TRUE)) { 03470 RIPMSG1(RIP_WARNING, "xxxSwitchDesktop: DrvDisableMDEV failed for pdesk %#p", 03471 grpdeskRitInput); 03472 return FALSE; 03473 } 03474 DrvEnableMDEV(pdesk->pDispInfo->pmdev, TRUE); 03475 bUpdateCursor = TRUE; 03476 03477 } 03478 03479 /* 03480 * Grab a handle to the pdesk 03481 */ 03482 Status = ObOpenObjectByPointer(pdesk, 03483 0, 03484 NULL, 03485 EVENT_ALL_ACCESS, 03486 NULL, 03487 KernelMode, 03488 &hdesk); 03489 if (!NT_SUCCESS(Status)) { 03490 03491 RIPMSG2(RIP_ERROR, "Could not get a handle for pdesk %#p Status %x", 03492 pdesk, Status); 03493 return FALSE; 03494 } 03495 03496 ThreadLockDesktopHandle(ptiCurrent, &tlhdesk, hdesk); 03497 03498 #if DBG 03499 /* 03500 * The current desktop is now the new desktop. 03501 */ 03502 pwinsta->pdeskCurrent = pdesk; 03503 #endif // DBG 03504 03505 /* 03506 * Kill any journalling that is occuring. If an app is journaling to 03507 * the CoolSwitch window, zzzCancelJournalling() will kill the window. 03508 */ 03509 if (ptiCurrent->rpdesk != NULL) 03510 zzzCancelJournalling(); 03511 03512 /* 03513 * Remove the cool switch window if it's on the RIT. Sending the message 03514 * is OK because the destination is the RIT, which should never block. 03515 */ 03516 if (gspwndAltTab != NULL) { 03517 03518 TL tlpwndT; 03519 03520 ThreadLockWithPti(ptiCurrent, gspwndAltTab, &tlpwndT); 03521 xxxSendMessage(gspwndAltTab, WM_CLOSE, 0, 0); 03522 ThreadUnlock(&tlpwndT); 03523 } 03524 03525 /* 03526 * Remove all trace of previous active window. 03527 */ 03528 if (grpdeskRitInput != NULL) { 03529 03530 UserAssert(grpdeskRitInput->spwndForeground == NULL); 03531 03532 if (grpdeskRitInput->pDeskInfo->spwnd != NULL) { 03533 if (gpqForeground != NULL) { 03534 03535 Lock(&grpdeskRitInput->spwndForeground, 03536 gpqForeground->spwndActive); 03537 03538 /* 03539 * This is an API so ptiCurrent can pretty much be on any 03540 * state; it might not be in grpdeskRitInput (current) or 03541 * pdesk (the one we're switching to). It can be sharing its 03542 * queue with other threads from another desktop. 03543 * This is tricky because we're calling xxxSetForegroundWindow 03544 * and xxxSetWindowPos but PtiCurrent might be on whatever 03545 * desktop. We cannot cleanly switch ptiCurrent to the proper 03546 * desktop because it might be sharing its queue with other 03547 * threads, own windows, hooks, etc. So this is kind of broken. 03548 * 03549 * Old Comment: 03550 * Fixup the current-thread (system) desktop. This 03551 * could be needed in case the xxxSetForegroundWindow() 03552 * calls xxxDeactivate(). There is logic in their which 03553 * requires the desktop. This is only needed temporarily 03554 * for this case. 03555 * 03556 * We would only go into xxxDeactivate if 03557 * ptiCurrent->pq == qpqForeground; but if this is the case, 03558 * then ptiCurrent must be in grpdeskRitInput already. So 03559 * I don't think we need this at all. Let's find out. 03560 * Note that we might switch queues while processing the 03561 * xxxSetForegroundWindow call. That should be fine as long 03562 * as we don't switch desktops..... 03563 */ 03564 UserAssert((ptiCurrent->pq != gpqForeground) 03565 || (ptiCurrent->rpdesk == grpdeskRitInput)); 03566 03567 /* 03568 * The SetForegroundWindow call must succed here, so we call 03569 * xxxSetForegroundWindow2() directly 03570 */ 03571 xxxSetForegroundWindow2(NULL, ptiCurrent, 0); // WHAT KEEPS pdesk LOCKED - IANJA ??? 03572 03573 } 03574 } 03575 } 03576 03577 /* 03578 * Post update events to all queues sending input to the desktop 03579 * that is becoming inactive. This keeps the queues in sync up 03580 * to the desktop switch. 03581 */ 03582 if (grpdeskRitInput != NULL) { 03583 03584 pHead = &grpdeskRitInput->PtiList; 03585 03586 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) { 03587 03588 pti = CONTAINING_RECORD(pEntry, THREADINFO, PtiLink); 03589 pq = pti->pq; 03590 03591 if (pq->QF_flags & QF_UPDATEKEYSTATE) 03592 PostUpdateKeyStateEvent(pq); 03593 03594 /* 03595 * Clear the reset bit to ensure that we can properly 03596 * reset the key state when this desktop again becomes 03597 * active. 03598 */ 03599 pq->QF_flags &= ~QF_KEYSTATERESET; 03600 } 03601 } 03602 03603 /* 03604 * Send the RIT input to the desktop. We do this before any window 03605 * management since DoPaint() uses grpdeskRitInput to go looking for 03606 * windows with update regions. 03607 */ 03608 LockDesktop(&grpdeskRitInput, pdesk, LDL_DESKRITINPUT, 0); 03609 03610 /* 03611 * Free any spbs that are only valid for the previous desktop. 03612 */ 03613 FreeAllSpbs(); 03614 03615 /* 03616 * Lock it into the RIT thread (we could use this desktop rather than 03617 * the global grpdeskRitInput to direct input!) 03618 */ 03619 zzzSetDesktop(gptiRit, pdesk, NULL); // DeferWinEventNotify() ?? IANJA ?? 03620 03621 /* 03622 * Lock the desktop into the desktop thread. Be sure 03623 * that the thread is using an unattached queue before 03624 * setting the desktop. This is needed to ensure that 03625 * the thread does not using a shared journal queue 03626 * for the old desktop. 03627 */ 03628 if (pTerm->ptiDesktop->pq != pTerm->pqDesktop) { 03629 UserAssert(pTerm->pqDesktop->cThreads == 0); 03630 AllocQueue(NULL, pTerm->pqDesktop); 03631 pTerm->pqDesktop->cThreads++; 03632 zzzAttachToQueue(pTerm->ptiDesktop, pTerm->pqDesktop, NULL, FALSE); 03633 } 03634 zzzSetDesktop(pTerm->ptiDesktop, pdesk, NULL); // DeferWinEventNotify() ?? IANJA ?? 03635 03636 /* 03637 * Bring the desktop window to the top and invalidate 03638 * everything. 03639 */ 03640 ThreadLockWithPti(ptiCurrent, pdesk->pDeskInfo->spwnd, &tlpwnd); 03641 03642 03643 /* 03644 * Suspend DirectDraw before we bring up the desktop window, so we make 03645 * sure that everything is repainted properly once DirectDraw is disabled. 03646 */ 03647 03648 GreSuspendDirectDraw(pdesk->pDispInfo->hDev, TRUE); 03649 03650 xxxSetWindowPos(pdesk->pDeskInfo->spwnd, // WHAT KEEPS pdesk LOCKED - IANJA ??? 03651 NULL, 03652 0, 03653 0, 03654 0, 03655 0, 03656 SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOCOPYBITS); 03657 03658 /* 03659 * At this point, my understanding is that the new desktop window has been 03660 * brought to the front, and therefore the vis-region of any app on any 03661 * other desktop is now NULL. 03662 * 03663 * So this is the appropriate time to resume DirectDraw, which will 03664 * ensure the DirectDraw app can not draw anything in the future. 03665 * 03666 * If this is not the case, then this code needs to be moved to a more 03667 * appropriate location. 03668 * 03669 * [andreva] 6-26-96 03670 */ 03671 03672 GreResumeDirectDraw(pdesk->pDispInfo->hDev, TRUE); 03673 03674 /* 03675 * Find the first visible top-level window. 03676 */ 03677 pwndSetForeground = pdesk->spwndForeground; 03678 if (pwndSetForeground == NULL || HMIsMarkDestroy(pwndSetForeground)) { 03679 03680 pwndSetForeground = pdesk->pDeskInfo->spwnd->spwndChild; 03681 03682 while ((pwndSetForeground != NULL) && 03683 !TestWF(pwndSetForeground, WFVISIBLE)) { 03684 03685 pwndSetForeground = pwndSetForeground->spwndNext; 03686 } 03687 } 03688 Unlock(&pdesk->spwndForeground); 03689 03690 /* 03691 * Now set it to the foreground. 03692 */ 03693 03694 if (pwndSetForeground == NULL) { 03695 xxxSetForegroundWindow2(NULL, NULL, 0); 03696 } else { 03697 03698 UserAssert(GETPTI(pwndSetForeground)->rpdesk == grpdeskRitInput); 03699 /* 03700 * If the new foreground window is a minimized fullscreen app, 03701 * make it fullscreen. 03702 */ 03703 if (GetFullScreen(pwndSetForeground) == FULLSCREENMIN) { 03704 SetFullScreen(pwndSetForeground, FULLSCREEN); 03705 } 03706 03707 ThreadLockAlwaysWithPti(ptiCurrent, pwndSetForeground, &tlpwndChild); 03708 /* 03709 * The SetForegroundWindow call must succed here, so we call 03710 * xxxSetForegroundWindow2() directly 03711 */ 03712 xxxSetForegroundWindow2(pwndSetForeground, ptiCurrent, 0); 03713 ThreadUnlock(&tlpwndChild); 03714 } 03715 03716 03717 ThreadUnlock(&tlpwnd); 03718 03719 /* 03720 * Overwrite key state of all queues sending input to the new 03721 * active desktop with the current async key state. This 03722 * prevents apps on inactive desktops from spying on active 03723 * desktops. This blows away anything set with SetKeyState, 03724 * but there is no way of preserving this without giving 03725 * away information about what keys were hit on other 03726 * desktops. 03727 */ 03728 pHead = &grpdeskRitInput->PtiList; 03729 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) { 03730 03731 pti = CONTAINING_RECORD(pEntry, THREADINFO, PtiLink); 03732 pq = pti->pq; 03733 03734 if (!(pq->QF_flags & QF_KEYSTATERESET)) { 03735 pq->QF_flags |= QF_UPDATEKEYSTATE | QF_KEYSTATERESET; 03736 RtlFillMemory(pq->afKeyRecentDown, CBKEYSTATERECENTDOWN, 0xff); 03737 PostUpdateKeyStateEvent(pq); 03738 } 03739 } 03740 03741 /* 03742 * If there is a hard-error popup up, nuke it and notify the 03743 * hard error thread that it needs to pop it up again. 03744 */ 03745 if (gHardErrorHandler.pti) { 03746 IPostQuitMessage(gHardErrorHandler.pti, 0); 03747 } 03748 03749 /* 03750 * Notify anyone waiting for a desktop switch. 03751 */ 03752 UserAssert(!(pdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO)); 03753 03754 KePulseEvent(gpEventSwitchDesktop, EVENT_INCREMENT, FALSE); 03755 03756 /* 03757 * reset the cursor when we come back from another pdev 03758 */ 03759 if (bUpdateCursor == TRUE) { 03760 03761 gpqCursor = NULL; 03762 zzzInternalSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y); 03763 03764 SetPointer(TRUE); 03765 } 03766 03767 /* 03768 * Make sure we come back to the right mode when this is all done, because 03769 * the device may be left in an interesting state if we were running 03770 * DirectDraw. 03771 */ 03772 03773 { 03774 /* 03775 * Don't check the return code right now since there is nothing 03776 * we can do if we can not reset the mode ... 03777 */ 03778 03779 // BUGBUG 03780 // DONT_CHECKIN 03781 03782 //UserChangeDisplaySettings(pdesk->pDispInfo->hDevInfo, 03783 // pdesk->pDesktopDevmode, 03784 // _GetDesktopWindow(), 03785 // pdesk, 03786 // 0, 03787 // NULL, 03788 // TRUE); 03789 } 03790 03791 03792 /* 03793 * If this desktop was not active during last display settings change 03794 * let's now bradcast the settings change to its windows. This 03795 * code is copied from xxxResetDisplayDevice(). 03796 */ 03797 03798 03799 if ((pdesk->dwDTFlags & DF_NEWDISPLAYSETTINGS) && pdesk->pDeskInfo && pdesk->pDeskInfo->spwnd ){ 03800 03801 pdesk->dwDTFlags &= ~DF_NEWDISPLAYSETTINGS; 03802 xxxBroadcastDisplaySettingsChange(pdesk, TRUE); 03803 03804 03805 } 03806 03807 ThreadUnlockDesktopHandle(&tlhdesk); 03808 03809 TRACE_INIT(("xxxSwitchDesktop: Leaving\n")); 03810 03811 return TRUE; 03812 } 03813 03814 /***************************************************************************\ 03815 * zzzSetDesktop 03816 * 03817 * Set desktop and desktop info in the specified pti. 03818 * 03819 * History: 03820 * 23-Dec-1993 JimA Created. 03821 \***************************************************************************/ 03822 03823 VOID zzzSetDesktop( 03824 PTHREADINFO pti, 03825 PDESKTOP pdesk, 03826 HDESK hdesk) 03827 { 03828 PTEB pteb; 03829 OBJECT_HANDLE_INFORMATION ohi; 03830 PDESKTOP pdeskRef; 03831 PDESKTOP pdeskOld; 03832 PCLIENTTHREADINFO pctiOld; 03833 TL tlpdesk; 03834 PTHREADINFO ptiCurrent = PtiCurrent(); 03835 03836 if (pti == NULL) { 03837 UserAssert(pti); 03838 return; 03839 } 03840 03841 /* 03842 * A handle without an object pointer is bad news. 03843 */ 03844 UserAssert(pdesk != NULL || hdesk == NULL); 03845 03846 /* 03847 * This desktop must not be destroyed 03848 */ 03849 if (pdesk != NULL && (pdesk->dwDTFlags & (DF_DESKWNDDESTROYED | DF_DYING)) && 03850 pdesk != pti->rpdesk) { 03851 RIPMSG2(RIP_ERROR, "Assigning pti %#p to a dying desktop %#p", 03852 pti, pdesk); 03853 return; 03854 } 03855 03856 #if DBG 03857 /* 03858 * Catch reset of important desktops 03859 */ 03860 if (pti->rpdesk && pti->rpdesk->dwConsoleThreadId == TIDq(pti) && 03861 pti->cWindows != 0) { 03862 RIPMSG0(RIP_ERROR, "Reset of console desktop"); 03863 } 03864 #endif 03865 03866 /* 03867 * Clear hook flag 03868 */ 03869 pti->TIF_flags &= ~TIF_ALLOWOTHERACCOUNTHOOK; 03870 03871 /* 03872 * Get granted access 03873 */ 03874 pti->hdesk = hdesk; 03875 if (hdesk != NULL) { 03876 if (NT_SUCCESS(ObReferenceObjectByHandle(hdesk, 03877 0, 03878 *ExDesktopObjectType, 03879 KernelMode, 03880 &pdeskRef, 03881 &ohi))) { 03882 03883 UserAssert(pdesk->dwSessionId == gSessionId); 03884 03885 LogDesktop(pdeskRef, LD_REF_FN_SETDESKTOP, TRUE, (ULONG_PTR)PtiCurrent()); 03886 03887 UserAssert(pdeskRef == pdesk); 03888 LogDesktop(pdesk, LD_DEREF_FN_SETDESKTOP, FALSE, (ULONG_PTR)PtiCurrent()); 03889 ObDereferenceObject(pdeskRef); 03890 pti->amdesk = ohi.GrantedAccess; 03891 if (CheckHandleFlag(hdesk, HF_DESKTOPHOOK)) 03892 pti->TIF_flags |= TIF_ALLOWOTHERACCOUNTHOOK; 03893 03894 SetHandleFlag(hdesk, HF_PROTECTED, TRUE); 03895 03896 } else { 03897 pti->amdesk = 0; 03898 } 03899 03900 } else { 03901 pti->amdesk = 0; 03902 } 03903 03904 /* 03905 * Do nothing else if the thread has initialized and the desktop 03906 * is not changing. 03907 */ 03908 if ((pdesk != NULL) && (pdesk == pti->rpdesk)) 03909 return; 03910 03911 /* 03912 * Save old pointers for later. Locking the old desktop ensures 03913 * that we will be able to free the CLIENTTHREADINFO structure. 03914 */ 03915 pdeskOld = pti->rpdesk; 03916 ThreadLockDesktop(ptiCurrent, pdeskOld, &tlpdesk, LDLT_FN_SETDESKTOP); 03917 pctiOld = pti->pcti; 03918 03919 /* 03920 * Remove the pti from the current desktop. 03921 */ 03922 if (pti->rpdesk) { 03923 UserAssert(ISATOMICCHECK() || pti->pq == NULL || pti->pq->cThreads == 1); 03924 RemoveEntryList(&pti->PtiLink); 03925 } 03926 03927 LockDesktop(&pti->rpdesk, pdesk, LDL_PTI_DESK, (ULONG_PTR)pti); 03928 03929 03930 /* 03931 * If there is no desktop, we need to fake a desktop info 03932 * structure so that the IsHooked() macro can test a "valid" 03933 * fsHooks value. Also link the pti to the desktop. 03934 */ 03935 if (pdesk != NULL) { 03936 pti->pDeskInfo = pdesk->pDeskInfo; 03937 InsertHeadList(&pdesk->PtiList, &pti->PtiLink); 03938 } else { 03939 pti->pDeskInfo = &diStatic; 03940 } 03941 03942 // UserAssert((pti->ppi != NULL) || (pti->ppi == PpiCurrent())); // can't access TEB/pClientInfo of other process 03943 03944 pteb = pti->pEThread->Tcb.Teb; 03945 if (pteb) { 03946 PDESKTOPVIEW pdv; 03947 if (pdesk && (pdv = GetDesktopView(pti->ppi, pdesk))) { 03948 03949 pti->pClientInfo->pDeskInfo = 03950 (PDESKTOPINFO)((PBYTE)pti->pDeskInfo - pdv->ulClientDelta); 03951 03952 pti->pClientInfo->ulClientDelta = pdv->ulClientDelta; 03953 03954 } else { 03955 03956 pti->pClientInfo->pDeskInfo = NULL; 03957 pti->pClientInfo->ulClientDelta = 0; 03958 03959 /* 03960 * Reset the cursor level to its orginal state. 03961 */ 03962 pti->iCursorLevel = TEST_GTERMF(GTERMF_MOUSE) ? 0 : -1; 03963 if (pti->pq) 03964 pti->pq->iCursorLevel = pti->iCursorLevel; 03965 } 03966 } 03967 03968 /* 03969 * Allocate thread information visible from client, then copy and free 03970 * any old info we have lying around. 03971 */ 03972 if (pdesk != NULL) { 03973 03974 /* 03975 * Do not use DesktopAlloc here because the desktop might 03976 * have DF_DESTROYED set. 03977 */ 03978 pti->pcti = DesktopAllocAlways(pdesk, 03979 sizeof(CLIENTTHREADINFO), 03980 DTAG_CLIENTTHREADINFO); 03981 } 03982 03983 if (pdesk == NULL || pti->pcti == NULL) { 03984 pti->pcti = &(pti->cti); 03985 pti->pClientInfo->pClientThreadInfo = NULL; 03986 } else { 03987 pti->pClientInfo->pClientThreadInfo = 03988 (PCLIENTTHREADINFO)((PBYTE)pti->pcti - pti->pClientInfo->ulClientDelta); 03989 } 03990 03991 if (pctiOld != NULL) { 03992 03993 if (pctiOld != pti->pcti) { 03994 RtlCopyMemory(pti->pcti, pctiOld, sizeof(CLIENTTHREADINFO)); 03995 } 03996 03997 if (pctiOld != &(pti->cti)) { 03998 DesktopFree(pdeskOld, pctiOld); 03999 } 04000 04001 } else { 04002 RtlZeroMemory(pti->pcti, sizeof(CLIENTTHREADINFO)); 04003 } 04004 04005 /* 04006 * If journalling is occuring on the new desktop, attach to 04007 * the journal queue. 04008 * Assert that the pti and the pdesk point to the same deskinfo 04009 * if not, we will check the wrong hooks. 04010 */ 04011 UserAssert((pdesk == NULL ) || (pti->pDeskInfo == pdesk->pDeskInfo)); 04012 UserAssert(pti->rpdesk == pdesk); 04013 if (pti->pq != NULL) { 04014 PQ pq = GetJournallingQueue(pti); 04015 if (pq != NULL) { 04016 pq->cThreads++; 04017 zzzAttachToQueue(pti, pq, NULL, FALSE); 04018 } 04019 } 04020 04021 ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_SETDESKTOP); 04022 } 04023 04024 /***************************************************************************\ 04025 * xxxSetThreadDesktop (API) 04026 * 04027 * Associate the current thread with a desktop. 04028 * 04029 * History: 04030 * 16-Jan-1991 JimA Created stub. 04031 \***************************************************************************/ 04032 04033 BOOL xxxSetThreadDesktop( 04034 HDESK hdesk, 04035 PDESKTOP pdesk) 04036 { 04037 PTHREADINFO ptiCurrent; 04038 PPROCESSINFO ppiCurrent; 04039 PQ pqAttach; 04040 04041 ptiCurrent = PtiCurrent(); 04042 ppiCurrent = ptiCurrent->ppi; 04043 04044 04045 /* 04046 * If the handle has not been mapped in, do it now. 04047 */ 04048 if (pdesk != NULL) { 04049 try { 04050 MapDesktop(ObOpenHandle, ppiCurrent->Process, pdesk, 0, 1); 04051 } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { 04052 return FALSE; 04053 } 04054 04055 UserAssert(GetDesktopView(ppiCurrent, pdesk) != NULL); 04056 } 04057 04058 /* 04059 * Check non-system thread status 04060 */ 04061 if (ptiCurrent->pEThread->ThreadsProcess != gpepCSRSS) { 04062 04063 /* 04064 * Fail if the non-system thread has any windows or thread hooks. 04065 */ 04066 if (ptiCurrent->cWindows != 0 || ptiCurrent->fsHooks) { 04067 RIPERR0(ERROR_BUSY, RIP_WARNING, "Thread has windows or hooks"); 04068 return FALSE; 04069 } 04070 04071 /* 04072 * If this is the first desktop assigned to the process, 04073 * make it the startup desktop. 04074 */ 04075 if (ppiCurrent->rpdeskStartup == NULL && hdesk != NULL) { 04076 LockDesktop(&ppiCurrent->rpdeskStartup, pdesk, LDL_PPI_DESKSTARTUP1, (ULONG_PTR)ppiCurrent); 04077 ppiCurrent->hdeskStartup = hdesk; 04078 } 04079 } 04080 04081 04082 /* 04083 * If the desktop is changing and the thread is sharing a queue, 04084 * detach the thread. This will ensure that threads sharing 04085 * queues are all on the same desktop. This will prevent 04086 * zzzDestroyQueue from getting confused and setting ptiKeyboard 04087 * and ptiMouse to NULL when a thread detachs. 04088 */ 04089 if (ptiCurrent->rpdesk != pdesk) { 04090 if (ptiCurrent->pq->cThreads > 1) { 04091 pqAttach = AllocQueue(NULL, NULL); 04092 if (pqAttach != NULL) { 04093 pqAttach->cThreads++; 04094 zzzAttachToQueue(ptiCurrent, pqAttach, NULL, FALSE); 04095 } else { 04096 RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "Thread could not be detached"); 04097 return FALSE; 04098 } 04099 } else if (ptiCurrent->pq == gpqForeground) { 04100 /* 04101 * This thread doesn't own any windows, still it's attached to qpgForeground and 04102 * it's the only thread attached to it. 04103 * Since any threads attached to qpgForeground must be in grpdeskRitInput, 04104 * we must set qpgForeground to NULL here because this thread is going to another 04105 * desktop. 04106 */ 04107 UserAssert(ptiCurrent->pq->spwndActive == NULL); 04108 UserAssert(ptiCurrent->pq->spwndCapture == NULL); 04109 UserAssert(ptiCurrent->pq->spwndFocus == NULL); 04110 UserAssert(ptiCurrent->pq->spwndActivePrev == NULL); 04111 xxxSetForegroundWindow2(NULL, ptiCurrent, 0); 04112 } else if (ptiCurrent->rpdesk == NULL) { 04113 /* 04114 * We need to initialize iCursorLevel. 04115 */ 04116 ptiCurrent->iCursorLevel = TEST_GTERMF(GTERMF_MOUSE) ? 0 : -1; 04117 ptiCurrent->pq->iCursorLevel = ptiCurrent->iCursorLevel; 04118 } 04119 04120 UserAssert(ptiCurrent->pq != gpqForeground); 04121 04122 } 04123 04124 zzzSetDesktop(ptiCurrent, pdesk, hdesk); 04125 04126 return TRUE; 04127 } 04128 /***************************************************************************\ 04129 * xxxDuplicateObject 04130 * 04131 * ZwDuplicateObject grabs ObpInitKillMutant so we have to leave our 04132 * critical section. 04133 * 04134 * 04-24-96 GerardoB Created 04135 \***************************************************************************/ 04136 NTSTATUS 04137 xxxUserDuplicateObject( 04138 IN HANDLE SourceProcessHandle, 04139 IN HANDLE SourceHandle, 04140 IN HANDLE TargetProcessHandle OPTIONAL, 04141 OUT PHANDLE TargetHandle OPTIONAL, 04142 IN ACCESS_MASK DesiredAccess, 04143 IN ULONG HandleAttributes, 04144 IN ULONG Options 04145 ) 04146 04147 { 04148 NTSTATUS Status; 04149 04150 CheckCritIn(); 04151 04152 LeaveCrit(); 04153 04154 Status = ZwDuplicateObject(SourceProcessHandle, SourceHandle, TargetProcessHandle, 04155 TargetHandle, DesiredAccess, HandleAttributes, Options); 04156 04157 EnterCrit(); 04158 04159 return Status; 04160 } 04161 /***************************************************************************\ 04162 * xxxUserFindHandleForObject 04163 * 04164 * ObFindHandleForObject grabs ObpInitKillMutant so we have to leave our 04165 * critical section. 04166 * 04167 * 04-24-96 GerardoB Created 04168 \***************************************************************************/ 04169 04170 BOOLEAN 04171 xxxUserFindHandleForObject( 04172 IN PEPROCESS Process, 04173 IN PVOID Object OPTIONAL, 04174 IN POBJECT_TYPE ObjectType OPTIONAL, 04175 IN POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL, 04176 OUT PHANDLE Handle 04177 ) 04178 { 04179 BOOLEAN fRet; 04180 BOOL fExclusive, fShared; 04181 04182 fExclusive = ExIsResourceAcquiredExclusiveLite(gpresUser); 04183 if (!fExclusive) { 04184 fShared = ExIsResourceAcquiredSharedLite(gpresUser); 04185 } 04186 04187 if (fExclusive || fShared) { 04188 LeaveCrit(); 04189 } 04190 04191 fRet = ObFindHandleForObject(Process, Object, ObjectType, HandleInformation, Handle); 04192 04193 if (fExclusive) { 04194 EnterCrit(); 04195 } else if (fShared) { 04196 EnterSharedCrit(); 04197 } 04198 04199 return fRet; 04200 } 04201 04202 /***************************************************************************\ 04203 * xxxGetThreadDesktop (API) 04204 * 04205 * Return a handle to the desktop assigned to the specified thread. 04206 * 04207 * History: 04208 * 16-Jan-1991 JimA Created stub. 04209 \***************************************************************************/ 04210 04211 HDESK xxxGetThreadDesktop( 04212 DWORD dwThread, 04213 HDESK hdeskConsole, 04214 KPROCESSOR_MODE AccessMode) 04215 { 04216 PTHREADINFO pti = PtiFromThreadId(dwThread); 04217 PPROCESSINFO ppiThread; 04218 HDESK hdesk; 04219 NTSTATUS Status; 04220 04221 if (pti == NULL) { 04222 04223 /* 04224 * If the thread has a console use that desktop. If 04225 * not, then the thread is either invalid or not 04226 * a Win32 thread. 04227 */ 04228 if (hdeskConsole == NULL) { 04229 RIPERR1(ERROR_INVALID_PARAMETER, RIP_VERBOSE, 04230 "xxxGetThreadDesktop: invalid threadId 0x%x", 04231 dwThread); 04232 return NULL; 04233 } 04234 04235 hdesk = hdeskConsole; 04236 ppiThread = PpiFromProcess(gpepCSRSS); 04237 } else { 04238 hdesk = pti->hdesk; 04239 ppiThread = pti->ppi; 04240 } 04241 04242 /* 04243 * If there is no desktop, return NULL with no error 04244 */ 04245 if (hdesk != NULL) { 04246 04247 /* 04248 * If the thread belongs to this process, return the 04249 * handle. Otherwise, enumerate the handle table of 04250 * this process to find a handle with the same 04251 * attributes. 04252 */ 04253 if (ppiThread != PpiCurrent()) { 04254 PVOID pobj; 04255 OBJECT_HANDLE_INFORMATION ohi; 04256 04257 RIPMSG4(RIP_VERBOSE, "[%x.%x] %s called xxxGetThreadDesktop for pti %#p\n", 04258 PsGetCurrentThread()->Cid.UniqueProcess, 04259 PsGetCurrentThread()->Cid.UniqueThread, 04260 PsGetCurrentProcess()->ImageFileName, 04261 pti); 04262 04263 KeAttachProcess(&ppiThread->Process->Pcb); 04264 Status = ObReferenceObjectByHandle(hdesk, 04265 0, 04266 *ExDesktopObjectType, 04267 AccessMode, 04268 &pobj, 04269 &ohi); 04270 KeDetachProcess(); 04271 if (!NT_SUCCESS(Status) || 04272 !xxxUserFindHandleForObject(PsGetCurrentProcess(), pobj, NULL, &ohi, &hdesk)) { 04273 04274 RIPMSG0(RIP_VERBOSE, "Cannot find hdesk for current process"); 04275 04276 hdesk = NULL; 04277 04278 } else { 04279 LogDesktop(pobj, LD_REF_FN_GETTHREADDESKTOP, TRUE, (ULONG_PTR)PtiCurrent()); 04280 } 04281 if (NT_SUCCESS(Status)) { 04282 LogDesktop(pobj, LD_DEREF_FN_GETTHREADDESKTOP, FALSE, (ULONG_PTR)PtiCurrent()); 04283 ObDereferenceObject(pobj); 04284 } 04285 } 04286 04287 if (hdesk == NULL) { 04288 RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "xxxGetThreadDesktop: hdesk is null"); 04289 } else { 04290 SetHandleFlag(hdesk, HF_PROTECTED, TRUE); 04291 } 04292 } 04293 04294 return hdesk; 04295 } 04296 04297 04298 /***************************************************************************\ 04299 * xxxGetInputDesktop (API) 04300 * 04301 * Obsolete - kept for compatibility only. Return a handle to the 04302 * desktop currently receiving input. Returns the first handle to 04303 * the input desktop found. 04304 * 04305 * History: 04306 * 16-Jan-1991 JimA Created scaffold code. 04307 \***************************************************************************/ 04308 04309 HDESK xxxGetInputDesktop(VOID) 04310 { 04311 HDESK hdesk; 04312 04313 if (xxxUserFindHandleForObject(PsGetCurrentProcess(), grpdeskRitInput, NULL, NULL, &hdesk)) { 04314 SetHandleFlag(hdesk, HF_PROTECTED, TRUE); 04315 return hdesk; 04316 } else { 04317 return NULL; 04318 } 04319 } 04320 04321 /***************************************************************************\ 04322 * xxxCloseDesktop (API) 04323 * 04324 * Close a reference to a desktop and destroy the desktop if it is no 04325 * longer referenced. 04326 * 04327 * History: 04328 * 16-Jan-1991 JimA Created scaffold code. 04329 * 11-Feb-1991 JimA Added access checks. 04330 \***************************************************************************/ 04331 04332 BOOL xxxCloseDesktop( 04333 HDESK hdesk, 04334 KPROCESSOR_MODE AccessMode) 04335 { 04336 PDESKTOP pdesk; 04337 PTHREADINFO ptiT; 04338 PPROCESSINFO ppi; 04339 NTSTATUS Status; 04340 04341 ppi = PpiCurrent(); 04342 04343 /* 04344 * Get a pointer to the desktop. 04345 */ 04346 Status = ObReferenceObjectByHandle( 04347 hdesk, 04348 0, 04349 *ExDesktopObjectType, 04350 AccessMode, 04351 &pdesk, 04352 NULL); 04353 if (!NT_SUCCESS(Status)) { 04354 RIPNTERR0(Status, RIP_VERBOSE, ""); 04355 return FALSE; 04356 } 04357 04358 UserAssert(pdesk->dwSessionId == gSessionId); 04359 04360 LogDesktop(pdesk, LD_REF_FN_CLOSEDESKTOP, TRUE, (ULONG_PTR)PtiCurrent()); 04361 04362 if (ppi->Process != gpepCSRSS) { 04363 04364 /* 04365 * Disallow closing of the desktop if the handle is in use by 04366 * any threads in the process. 04367 */ 04368 for (ptiT = ppi->ptiList; ptiT != NULL; ptiT = ptiT->ptiSibling) { 04369 if (ptiT->hdesk == hdesk) { 04370 RIPERR2(ERROR_BUSY, RIP_WARNING, 04371 "CloseDesktop: Desktop %#p still in use by thread %#p", 04372 pdesk, ptiT); 04373 LogDesktop(pdesk, LD_DEREF_FN_CLOSEDESKTOP1, FALSE, (ULONG_PTR)PtiCurrent()); 04374 ObDereferenceObject(pdesk); 04375 return FALSE; 04376 } 04377 } 04378 04379 /* 04380 * If this is the startup desktop, unlock it 04381 */ 04382 /* 04383 * Bug 41394. Make sure that hdesk == ppi->hdeskStartup. We might 04384 * be getting a handle to the desktop object that is different 04385 * from ppi->hdeskStartup but we still end up 04386 * setting ppi->hdeskStartup to NULL. 04387 */ 04388 if ((pdesk == ppi->rpdeskStartup) && (hdesk == ppi->hdeskStartup)) { 04389 UnlockDesktop(&ppi->rpdeskStartup, LDU_PPI_DESKSTARTUP2, (ULONG_PTR)ppi); 04390 ppi->hdeskStartup = NULL; 04391 } 04392 } 04393 04394 /* 04395 * Clear hook flag 04396 */ 04397 SetHandleFlag(hdesk, HF_DESKTOPHOOK, FALSE); 04398 04399 /* 04400 * Close the handle 04401 */ 04402 Status = CloseProtectedHandle(hdesk); 04403 04404 LogDesktop(pdesk, LD_DEREF_FN_CLOSEDESKTOP2, FALSE, (ULONG_PTR)PtiCurrent()); 04405 ObDereferenceObject(pdesk); 04406 UserAssert(NT_SUCCESS(Status)); 04407 04408 return TRUE; 04409 } 04410 04411 /***************************************************************************\ 04412 * TerminateConsole 04413 * 04414 * Post a quit message to a console thread and wait for it to terminate. 04415 * 04416 * History: 04417 * 08-May-1995 JimA Created. 04418 \***************************************************************************/ 04419 04420 VOID TerminateConsole( 04421 PDESKTOP pdesk) 04422 { 04423 NTSTATUS Status; 04424 PETHREAD Thread; 04425 PTHREADINFO pti; 04426 04427 if (pdesk->dwConsoleThreadId == 0) 04428 return; 04429 04430 /* 04431 * Locate the console thread. 04432 */ 04433 Status = LockThreadByClientId((HANDLE)LongToHandle( pdesk->dwConsoleThreadId ), &Thread); 04434 if (!NT_SUCCESS(Status)) 04435 return; 04436 04437 /* 04438 * Post a quit message to the console. 04439 */ 04440 pti = PtiFromThread(Thread); 04441 UserAssert(pti != NULL); 04442 if (pti != NULL) { 04443 _PostThreadMessage(pti, WM_QUIT, 0, 0); 04444 } 04445 04446 /* 04447 * Clear thread id so we don't post twice 04448 */ 04449 pdesk->dwConsoleThreadId = 0; 04450 04451 UnlockThread(Thread); 04452 } 04453 04454 /***************************************************************************\ 04455 * CheckHandleFlag 04456 * 04457 * Returns TRUE if the desktop handle allows other accounts 04458 * to hook this process. 04459 * 04460 * History: 04461 * 07-13-95 JimA Created. 04462 \***************************************************************************/ 04463 04464 BOOL CheckHandleFlag( 04465 HANDLE hObject, 04466 DWORD dwFlag) 04467 { 04468 PPROCESSINFO ppi; 04469 ULONG Index = ((PEXHANDLE)&hObject)->Index * HF_LIMIT + dwFlag; 04470 BOOL fRet = FALSE; 04471 04472 EnterHandleFlagsCrit(); 04473 04474 if ((ppi = PpiCurrent()) != NULL) { 04475 fRet = (Index < ppi->bmHandleFlags.SizeOfBitMap && 04476 RtlCheckBit(&ppi->bmHandleFlags, Index)); 04477 } 04478 04479 LeaveHandleFlagsCrit(); 04480 04481 return fRet; 04482 } 04483 04484 /***************************************************************************\ 04485 * SetHandleFlag 04486 * 04487 * Sets and clears the ability of a desktop handle to allow 04488 * other accounts to hook this process. 04489 * 04490 * History: 04491 * 07-13-95 JimA Created. 04492 \***************************************************************************/ 04493 04494 BOOL SetHandleFlag( 04495 HANDLE hObject, 04496 DWORD dwFlag, 04497 BOOL fSet) 04498 { 04499 PPROCESSINFO ppi; 04500 ULONG Index = ((PEXHANDLE)&hObject)->Index * HF_LIMIT + dwFlag; 04501 PRTL_BITMAP pbm; 04502 ULONG cBits; 04503 PULONG Buffer; 04504 BOOL fRet = TRUE; 04505 04506 UserAssert(dwFlag < HF_LIMIT); 04507 04508 EnterHandleFlagsCrit(); 04509 04510 if ((ppi = PpiCurrent()) != NULL) { 04511 pbm = &ppi->bmHandleFlags; 04512 if (fSet) { 04513 04514 /* 04515 * Expand the bitmap if needed 04516 */ 04517 if (Index >= pbm->SizeOfBitMap) { 04518 /* 04519 * Index is zero-based - cBits is an exact number of dwords 04520 */ 04521 cBits = ((Index + 1) + 0x1F) & ~0x1F; 04522 Buffer = UserAllocPoolWithQuotaZInit(cBits / 8, TAG_PROCESSINFO); 04523 if (Buffer == NULL) { 04524 fRet = FALSE; 04525 goto Exit; 04526 } 04527 if (pbm->Buffer) { 04528 RtlCopyMemory(Buffer, pbm->Buffer, pbm->SizeOfBitMap / 8); 04529 UserFreePool(pbm->Buffer); 04530 } 04531 04532 RtlInitializeBitMap(pbm, Buffer, cBits); 04533 } 04534 04535 RtlSetBits(pbm, Index, 1); 04536 } else if (Index < pbm->SizeOfBitMap) { 04537 RtlClearBits(pbm, Index, 1); 04538 } 04539 } 04540 04541 Exit: 04542 LeaveHandleFlagsCrit(); 04543 04544 return fRet; 04545 } 04546 04547 04548 /***************************************************************************\ 04549 * CheckHandleInUse 04550 * 04551 * Returns TRUE if the handle is currently in use. 04552 * 04553 * History: 04554 * 02-Jun-1999 JerrySh Created. 04555 \***************************************************************************/ 04556 04557 BOOL CheckHandleInUse( 04558 HANDLE hObject) 04559 { 04560 BOOL fRet; 04561 04562 EnterHandleFlagsCrit(); 04563 fRet = ((gProcessInUse == PsGetCurrentProcess()) && 04564 (gHandleInUse == hObject)); 04565 LeaveHandleFlagsCrit(); 04566 04567 return fRet; 04568 } 04569 04570 /***************************************************************************\ 04571 * SetHandleInUse 04572 * 04573 * Mark the handle as in use. 04574 * 04575 * History: 04576 * 02-Jun-1999 JerrySh Created. 04577 \***************************************************************************/ 04578 04579 VOID SetHandleInUse( 04580 HANDLE hObject) 04581 { 04582 EnterHandleFlagsCrit(); 04583 gProcessInUse = PsGetCurrentProcess(); 04584 gHandleInUse = hObject; 04585 LeaveHandleFlagsCrit(); 04586 } 04587 04588 NTSTATUS xxxResolveDesktopForWOW ( 04589 IN OUT PUNICODE_STRING pstrDesktop) 04590 { 04591 NTSTATUS Status; 04592 UNICODE_STRING strDesktop, strWinSta, strStatic; 04593 LPWSTR pszDesktop; 04594 BOOL fWinStaDefaulted; 04595 BOOL fDesktopDefaulted; 04596 HWINSTA hwinsta; 04597 HDESK hdesk; 04598 OBJECT_ATTRIBUTES ObjA; 04599 PUNICODE_STRING pstrStatic; 04600 POBJECT_ATTRIBUTES pObjA = NULL; 04601 SIZE_T cbObjA; 04602 BOOL bShutDown = FALSE; 04603 PTEB pteb = NtCurrentTeb(); 04604 04605 UserAssert(pteb); 04606 04607 /* 04608 * Determine windowstation and desktop names. 04609 */ 04610 04611 04612 if (pstrDesktop == NULL) { 04613 return STATUS_INVALID_PARAMETER; 04614 } 04615 04616 strStatic.Length = 0; 04617 strStatic.MaximumLength = STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR); 04618 04619 /* 04620 * Use the StaticUnicodeBuffer on the TEB as the buffer for the object name. 04621 * Even if this is client side and we pass KernelMode to the Ob call in 04622 * _OpenWindowStation this is safe because the TEB is not going to go away 04623 * during this call. The worst it can happen is to have the buffer in the TEB 04624 * trashed. 04625 */ 04626 strStatic.Buffer = pteb->StaticUnicodeBuffer; 04627 04628 UserAssert(pteb->StaticUnicodeBuffer == pteb->StaticUnicodeString.Buffer); 04629 UserAssert(pteb->StaticUnicodeString.MaximumLength ==STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR)); 04630 04631 if (pstrDesktop->Length == 0) { 04632 RtlInitUnicodeString(&strDesktop, TEXT("Default")); 04633 fWinStaDefaulted = fDesktopDefaulted = TRUE; 04634 } else { 04635 USHORT cch; 04636 /* 04637 * The name be of the form windowstation\desktop. Parse 04638 * the string to separate out the names. 04639 */ 04640 strWinSta = *pstrDesktop; 04641 cch = strWinSta.Length / sizeof(WCHAR); 04642 pszDesktop = strWinSta.Buffer; 04643 while (cch && *pszDesktop != L'\\') { 04644 cch--; 04645 pszDesktop++; 04646 } 04647 fDesktopDefaulted = FALSE; 04648 04649 if (cch == 0) { 04650 04651 /* 04652 * No windowstation name was specified, only the desktop. 04653 */ 04654 strDesktop = strWinSta; 04655 fWinStaDefaulted = TRUE; 04656 } else { 04657 /* 04658 * Both names were in the string. 04659 */ 04660 strDesktop.Buffer = pszDesktop + 1; 04661 strDesktop.Length = strDesktop.MaximumLength = (cch - 1) * sizeof(WCHAR); 04662 strWinSta.Length = (USHORT)(pszDesktop - strWinSta.Buffer) * sizeof(WCHAR); 04663 04664 /* 04665 * zero terminate the strWinSta buffer so the rebuild of the desktop 04666 * name at the end of the function works. 04667 */ 04668 *pszDesktop = (WCHAR)0; 04669 04670 fWinStaDefaulted = FALSE; 04671 04672 RtlAppendUnicodeToString(&strStatic, (PWSTR)szWindowStationDirectory); 04673 RtlAppendUnicodeToString(&strStatic, L"\\"); 04674 RtlAppendUnicodeStringToString(&strStatic, &strWinSta); 04675 04676 } 04677 } 04678 04679 if (fWinStaDefaulted) { 04680 04681 //Default Window Station 04682 RtlInitUnicodeString(&strWinSta, L"WinSta0"); 04683 04684 RtlAppendUnicodeToString(&strStatic, (PWSTR)szWindowStationDirectory); 04685 RtlAppendUnicodeToString(&strStatic, L"\\"); 04686 RtlAppendUnicodeStringToString(&strStatic, &strWinSta); 04687 04688 } 04689 04690 /* 04691 * Open the computed windowstation. This will also do an access check 04692 */ 04693 if (gbSecureDesktop) { 04694 /* 04695 * Allocate an object attributes structure in user address space. 04696 */ 04697 cbObjA = sizeof(*pObjA) + sizeof(*pstrStatic); 04698 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 04699 &pObjA, 0, &cbObjA, MEM_COMMIT, PAGE_READWRITE); 04700 pstrStatic = (PUNICODE_STRING)((PBYTE)pObjA + sizeof(*pObjA)); 04701 04702 if (NT_SUCCESS(Status)) { 04703 /* 04704 * Note -- the string must be in client-space or the 04705 * address validation in OpenWindowStation will fail. 04706 */ 04707 try { 04708 *pstrStatic = strStatic; 04709 InitializeObjectAttributes( pObjA, 04710 pstrStatic, 04711 OBJ_CASE_INSENSITIVE, 04712 NULL, 04713 NULL 04714 ); 04715 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 04716 Status = GetExceptionCode(); 04717 } 04718 04719 if (NT_SUCCESS(Status)) { 04720 hwinsta = _OpenWindowStation(pObjA, MAXIMUM_ALLOWED, UserMode); 04721 } else { 04722 hwinsta = NULL; 04723 } 04724 if (!hwinsta) { 04725 ZwFreeVirtualMemory(NtCurrentProcess(), &pObjA, &cbObjA, 04726 MEM_RELEASE); 04727 return STATUS_ACCESS_DENIED; 04728 } 04729 } else { 04730 return STATUS_NO_MEMORY; 04731 } 04732 } else { 04733 InitializeObjectAttributes( &ObjA, 04734 &strStatic, 04735 OBJ_CASE_INSENSITIVE, 04736 NULL, 04737 NULL 04738 ); 04739 hwinsta = _OpenWindowStation(&ObjA, MAXIMUM_ALLOWED, KernelMode); 04740 if (!hwinsta) { 04741 return STATUS_ACCESS_DENIED; 04742 } 04743 } 04744 04745 /* 04746 * Do an access check on the desktop by opening it 04747 */ 04748 04749 RtlCopyUnicodeString(&strStatic, &strDesktop); 04750 04751 if (gbSecureDesktop) { 04752 /* 04753 * Note -- the string must be in client-space or the 04754 * address validation in OpenDesktop will fail. 04755 */ 04756 try { 04757 *pstrStatic = strStatic; 04758 InitializeObjectAttributes( pObjA, 04759 pstrStatic, 04760 OBJ_CASE_INSENSITIVE, 04761 hwinsta, 04762 NULL 04763 ); 04764 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 04765 Status = GetExceptionCode(); 04766 } 04767 04768 if (NT_SUCCESS(Status)) { 04769 hdesk = xxxOpenDesktop(pObjA, 04770 UserMode, 04771 0, 04772 MAXIMUM_ALLOWED, 04773 &bShutDown); 04774 } else { 04775 hdesk = NULL; 04776 } 04777 04778 ZwFreeVirtualMemory(NtCurrentProcess(), &pObjA, &cbObjA, 04779 MEM_RELEASE); 04780 } else { 04781 InitializeObjectAttributes( &ObjA, 04782 &strStatic, 04783 OBJ_CASE_INSENSITIVE, 04784 hwinsta, 04785 NULL 04786 ); 04787 hdesk = xxxOpenDesktop(&ObjA, 04788 KernelMode, 04789 0, 04790 MAXIMUM_ALLOWED, 04791 &bShutDown); 04792 } 04793 04794 if (!hdesk) { 04795 UserVerify(NT_SUCCESS(ZwClose(hwinsta))); 04796 return STATUS_ACCESS_DENIED; 04797 } 04798 04799 CloseProtectedHandle(hdesk); 04800 UserVerify(NT_SUCCESS(ZwClose(hwinsta))); 04801 04802 /* 04803 * Copy the final Computed String 04804 */ 04805 RtlCopyUnicodeString(pstrDesktop, &strWinSta); 04806 RtlAppendUnicodeToString(pstrDesktop, L"\\"); 04807 RtlAppendUnicodeStringToString(pstrDesktop, &strDesktop); 04808 04809 return STATUS_SUCCESS; 04810 } 04811 /***************************************************************************\ 04812 * xxxResolveDesktop 04813 * 04814 * Attempts to return handles to a windowstation and desktop associated 04815 * with the logon session. 04816 * 04817 * History: 04818 * 25-Apr-1994 JimA Created. 04819 \***************************************************************************/ 04820 04821 HDESK xxxResolveDesktop( 04822 HANDLE hProcess, 04823 PUNICODE_STRING pstrDesktop, 04824 HWINSTA *phwinsta, 04825 BOOL fInherit, 04826 BOOL* pbShutDown) 04827 { 04828 PEPROCESS Process; 04829 PPROCESSINFO ppi; 04830 HWINSTA hwinsta; 04831 HDESK hdesk; 04832 PDESKTOP pdesk; 04833 PWINDOWSTATION pwinsta; 04834 BOOL fInteractive; 04835 UNICODE_STRING strDesktop; 04836 UNICODE_STRING strWinSta, strStatic; 04837 OBJECT_ATTRIBUTES ObjA; 04838 PUNICODE_STRING pstrStatic; 04839 POBJECT_ATTRIBUTES pObjA = NULL; 04840 SIZE_T cbObjA; 04841 LPWSTR pszDesktop; 04842 WCHAR awchName[sizeof(L"Service-0x0000-0000$") / sizeof(WCHAR)]; 04843 BOOL fWinStaDefaulted; 04844 BOOL fDesktopDefaulted; 04845 LUID luidService; 04846 NTSTATUS Status; 04847 HWINSTA hwinstaDup; 04848 PTEB pteb = NtCurrentTeb(); 04849 04850 CheckCritIn(); 04851 04852 UserAssert(pteb); 04853 04854 Status = ObReferenceObjectByHandle(hProcess, 04855 PROCESS_QUERY_INFORMATION, 04856 *PsProcessType, 04857 UserMode, 04858 &Process, 04859 NULL); 04860 if (!NT_SUCCESS(Status)) { 04861 RIPMSG1(RIP_WARNING, "ResolveDesktop: Could not reference process handle (0x%X)", hProcess); 04862 return NULL; 04863 } 04864 04865 strStatic.Length = 0; 04866 strStatic.MaximumLength = STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR); 04867 04868 /* 04869 * Use the StaticUnicodeBuffer on the TEB as the buffer for the object name. 04870 * Even if this is client side and we pass KernelMode to the Ob call in 04871 * _OpenWindowStation this is safe because the TEB is not going to go away 04872 * during this call. The worst it can happen is to have the buffer in the TEB 04873 * trashed. 04874 */ 04875 strStatic.Buffer = pteb->StaticUnicodeBuffer; 04876 04877 UserAssert(pteb->StaticUnicodeBuffer == pteb->StaticUnicodeString.Buffer); 04878 UserAssert(pteb->StaticUnicodeString.MaximumLength ==STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR)); 04879 /* 04880 * The static unicode buffer in the teb 04881 /* 04882 * If the process already has a windowstation and a startup desktop, 04883 * return them. 04884 */ 04885 hwinsta = NULL; 04886 hwinstaDup = NULL; 04887 hdesk = NULL; 04888 ppi = PpiFromProcess(Process); 04889 04890 /* 04891 * Make sure the process has not been destroyed. Bug 214643 04892 */ 04893 if (ppi != NULL) { 04894 04895 if (ppi->W32PF_Flags & W32PF_TERMINATED) { 04896 04897 ObDereferenceObject(Process); 04898 04899 RIPMSG1(RIP_WARNING, "xxxResolveDesktop: ppi %#p has been destroyed", ppi); 04900 return NULL; 04901 } 04902 04903 if (ppi->hwinsta != NULL && ppi->hdeskStartup != NULL) { 04904 04905 /* 04906 * If the target process is the current process, simply 04907 * return the handles. Otherwise, open the objects. 04908 */ 04909 if (Process == PsGetCurrentProcess()) { 04910 hwinsta = ppi->hwinsta; 04911 hdesk = ppi->hdeskStartup; 04912 } else { 04913 Status = ObOpenObjectByPointer( 04914 ppi->rpwinsta, 04915 0, 04916 NULL, 04917 MAXIMUM_ALLOWED, 04918 *ExWindowStationObjectType, 04919 (KPROCESSOR_MODE)(gbSecureDesktop ? UserMode : KernelMode), 04920 &hwinsta); 04921 if (NT_SUCCESS(Status)) { 04922 Status = ObOpenObjectByPointer( 04923 ppi->rpdeskStartup, 04924 0, 04925 NULL, 04926 MAXIMUM_ALLOWED, 04927 *ExDesktopObjectType, 04928 (KPROCESSOR_MODE)(gbSecureDesktop ? UserMode : KernelMode), 04929 &hdesk); 04930 if (!NT_SUCCESS(Status)) { 04931 UserVerify(NT_SUCCESS(ZwClose(hwinsta))); 04932 hwinsta = NULL; 04933 } 04934 } 04935 if (!NT_SUCCESS(Status)) { 04936 RIPNTERR2( 04937 Status, 04938 RIP_WARNING, 04939 "ResolveDesktop: Could not reference winsta=%#p and/or desk=%#p", 04940 ppi->rpwinsta, ppi->rpdeskStartup); 04941 } 04942 } 04943 04944 RIPMSG2(RIP_VERBOSE, 04945 "ResolveDesktop: to hwinsta=%#p desktop=%#p", 04946 hwinsta, hdesk); 04947 04948 ObDereferenceObject(Process); 04949 *phwinsta = hwinsta; 04950 return hdesk; 04951 } 04952 } 04953 04954 /* 04955 * Determine windowstation and desktop names. 04956 */ 04957 if (pstrDesktop == NULL || pstrDesktop->Length == 0) { 04958 RtlInitUnicodeString(&strDesktop, TEXT("Default")); 04959 fWinStaDefaulted = fDesktopDefaulted = TRUE; 04960 } else { 04961 USHORT cch; 04962 /* 04963 * The name be of the form windowstation\desktop. Parse 04964 * the string to separate out the names. 04965 */ 04966 strWinSta = *pstrDesktop; 04967 cch = strWinSta.Length / sizeof(WCHAR); 04968 pszDesktop = strWinSta.Buffer; 04969 while (cch && *pszDesktop != L'\\') { 04970 cch--; 04971 pszDesktop++; 04972 } 04973 fDesktopDefaulted = FALSE; 04974 04975 if (cch == 0) { 04976 04977 /* 04978 * No windowstation name was specified, only the desktop. 04979 */ 04980 strDesktop = strWinSta; 04981 fWinStaDefaulted = TRUE; 04982 } else { 04983 /* 04984 * Both names were in the string. 04985 */ 04986 strDesktop.Buffer = pszDesktop + 1; 04987 strDesktop.Length = strDesktop.MaximumLength = (cch - 1) * sizeof(WCHAR); 04988 strWinSta.Length = (USHORT)(pszDesktop - strWinSta.Buffer) * sizeof(WCHAR); 04989 fWinStaDefaulted = FALSE; 04990 04991 RtlAppendUnicodeToString(&strStatic, (PWSTR)szWindowStationDirectory); 04992 RtlAppendUnicodeToString(&strStatic, L"\\"); 04993 RtlAppendUnicodeStringToString(&strStatic, &strWinSta); 04994 04995 if (!NT_SUCCESS(Status = _UserTestForWinStaAccess(&strStatic,TRUE))) { 04996 if (strStatic.MaximumLength > strStatic.Length) 04997 strStatic.Buffer[strStatic.Length/sizeof(WCHAR)] = 0; 04998 else 04999 strStatic.Buffer[(strStatic.Length - sizeof(WCHAR))/sizeof(WCHAR)] = 0; 05000 RIPMSG2(RIP_WARNING, 05001 "ResolveDesktop: Error (0x%X) resolving to WinSta='%ws'", 05002 Status, strStatic.Buffer); 05003 ObDereferenceObject(Process); 05004 *phwinsta = NULL; 05005 return NULL; 05006 } 05007 05008 } 05009 } 05010 05011 /* 05012 * If the desktop name is defaulted, make the handles 05013 * not inheritable. 05014 */ 05015 if (fDesktopDefaulted) 05016 fInherit = FALSE; 05017 05018 /* 05019 * If a windowstation has not been assigned to this process yet and 05020 * there are existing windowstations, attempt an open. 05021 */ 05022 if (hwinsta == NULL && grpWinStaList) { 05023 05024 /* 05025 * If the windowstation name was defaulted, create a name 05026 * based on the session. 05027 */ 05028 if (fWinStaDefaulted) { 05029 //Default Window Station 05030 RtlInitUnicodeString(&strWinSta, L"WinSta0"); 05031 05032 RtlAppendUnicodeToString(&strStatic, (PWSTR)szWindowStationDirectory); 05033 RtlAppendUnicodeToString(&strStatic, L"\\"); 05034 RtlAppendUnicodeStringToString(&strStatic, &strWinSta); 05035 05036 if (gbRemoteSession) { 05037 /* 05038 * Fake this out if it's an non-interactive winstation startup. 05039 * We don't want an extra winsta. 05040 */ 05041 fInteractive = NT_SUCCESS(_UserTestForWinStaAccess(&strStatic, TRUE)); 05042 } else { 05043 fInteractive = NT_SUCCESS(_UserTestForWinStaAccess(&strStatic,fInherit)); 05044 } 05045 05046 if (!fInteractive) { 05047 GetProcessLuid(NULL, &luidService); 05048 swprintf(awchName, L"Service-0x%x-%x$", 05049 luidService.HighPart, luidService.LowPart); 05050 RtlInitUnicodeString(&strWinSta, awchName); 05051 } 05052 } 05053 05054 /* 05055 * If no windowstation name was passed in and a windowstation 05056 * handle was inherited, assign it. 05057 */ 05058 if (fWinStaDefaulted) { 05059 if (xxxUserFindHandleForObject(Process, NULL, *ExWindowStationObjectType, 05060 NULL, &hwinsta)) { 05061 05062 /* 05063 * If the handle belongs to another process, 05064 * dup it into this one 05065 */ 05066 if (Process != PsGetCurrentProcess()) { 05067 05068 Status = xxxUserDuplicateObject( 05069 hProcess, 05070 hwinsta, 05071 NtCurrentProcess(), 05072 &hwinstaDup, 05073 0, 05074 0, 05075 DUPLICATE_SAME_ACCESS); 05076 if (!NT_SUCCESS(Status)) { 05077 hwinsta = NULL; 05078 } else { 05079 hwinsta = hwinstaDup; 05080 } 05081 } 05082 } 05083 } 05084 05085 /* 05086 * If we were assigned to a windowstation, make sure 05087 * it matches our fInteractive flag 05088 */ 05089 if (hwinsta != NULL) { 05090 Status = ObReferenceObjectByHandle(hwinsta, 05091 0, 05092 *ExWindowStationObjectType, 05093 KernelMode, 05094 &pwinsta, 05095 NULL); 05096 if (NT_SUCCESS(Status)) { 05097 BOOL fIO = (pwinsta->dwWSF_Flags & WSF_NOIO) ? FALSE : TRUE; 05098 if (fIO != fInteractive) { 05099 if (hwinstaDup) { 05100 CloseProtectedHandle(hwinsta); 05101 } 05102 hwinsta = NULL; 05103 } 05104 ObDereferenceObject(pwinsta); 05105 } 05106 } 05107 05108 /* 05109 * If not, open the computed windowstation. 05110 */ 05111 if (NT_SUCCESS(Status) && hwinsta == NULL) { 05112 05113 /* 05114 * Fill in the path to the windowstation 05115 */ 05116 strStatic.Length = 0; 05117 RtlAppendUnicodeToString(&strStatic, (PWSTR)szWindowStationDirectory); 05118 RtlAppendUnicodeToString(&strStatic, L"\\"); 05119 RtlAppendUnicodeStringToString(&strStatic, &strWinSta); 05120 05121 if (gbSecureDesktop) { 05122 /* 05123 * Allocate an object attributes structure in user address space. 05124 */ 05125 cbObjA = sizeof(*pObjA) + sizeof(*pstrStatic); 05126 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 05127 &pObjA, 0, &cbObjA, MEM_COMMIT, PAGE_READWRITE); 05128 pstrStatic = (PUNICODE_STRING)((PBYTE)pObjA + sizeof(*pObjA)); 05129 05130 if (NT_SUCCESS(Status)) { 05131 /* 05132 * Note -- the string must be in client-space or the 05133 * address validation in OpenWindowStation will fail. 05134 */ 05135 try { 05136 *pstrStatic = strStatic; 05137 InitializeObjectAttributes( pObjA, 05138 pstrStatic, 05139 OBJ_CASE_INSENSITIVE, 05140 NULL, 05141 NULL 05142 ); 05143 if (fInherit) 05144 pObjA->Attributes |= OBJ_INHERIT; 05145 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 05146 Status = GetExceptionCode(); 05147 } 05148 05149 if (NT_SUCCESS(Status)) { 05150 hwinsta = _OpenWindowStation(pObjA, MAXIMUM_ALLOWED, UserMode); 05151 } 05152 } 05153 } else { 05154 InitializeObjectAttributes( &ObjA, 05155 &strStatic, 05156 OBJ_CASE_INSENSITIVE, 05157 NULL, 05158 NULL 05159 ); 05160 if (fInherit) 05161 ObjA.Attributes |= OBJ_INHERIT; 05162 hwinsta = _OpenWindowStation(&ObjA, MAXIMUM_ALLOWED, KernelMode); 05163 } 05164 } 05165 05166 /* 05167 * Only allow service logons at the console. I don't think our 05168 * win32k exit routines cope with more than one windowstation. 05169 */ 05170 /* 05171 * If the open failed and the process is in a non-interactive 05172 * logon session, attempt to create a windowstation and 05173 * desktop for that session. Note that the desktop handle 05174 * will be closed after the desktop has been assigned. 05175 */ 05176 if (!gbRemoteSession && NT_SUCCESS(Status) && 05177 hwinsta == NULL && !fInteractive && fWinStaDefaulted) { 05178 05179 *phwinsta = xxxConnectService( 05180 &strStatic, 05181 &hdesk); 05182 05183 /* 05184 * Clean up and leave. 05185 */ 05186 if (pObjA != NULL) { 05187 ZwFreeVirtualMemory(NtCurrentProcess(), &pObjA, &cbObjA, 05188 MEM_RELEASE); 05189 } 05190 ObDereferenceObject(Process); 05191 05192 RIPMSG2(RIP_VERBOSE, 05193 "ResolveDesktop: xxxConnectService was called\n" 05194 "to hwinsta=%#p desktop=%#p", 05195 *phwinsta, hdesk); 05196 05197 return hdesk; 05198 } 05199 } 05200 05201 /* 05202 * Attempt to assign a desktop. 05203 */ 05204 if (hwinsta != NULL) { 05205 05206 /* 05207 * Every gui thread needs an associated desktop. We'll use the default 05208 * to start with and the application can override it if it wants. 05209 */ 05210 if (hdesk == NULL) { 05211 05212 /* 05213 * If no desktop name was passed in and a desktop 05214 * handle was inherited, assign it. 05215 */ 05216 if (fDesktopDefaulted) { 05217 if (xxxUserFindHandleForObject(Process, NULL, *ExDesktopObjectType, 05218 NULL, &hdesk)) { 05219 05220 /* 05221 * If the handle belongs to another process, 05222 * dup it into this one 05223 */ 05224 if (Process != PsGetCurrentProcess()) { 05225 HDESK hdeskDup; 05226 05227 Status = xxxUserDuplicateObject( 05228 hProcess, 05229 hdesk, 05230 NtCurrentProcess(), 05231 &hdeskDup, 05232 0, 05233 0, 05234 DUPLICATE_SAME_ACCESS); 05235 if (!NT_SUCCESS(Status)) { 05236 CloseProtectedHandle(hdesk); 05237 hdesk = NULL; 05238 } else { 05239 hdesk = hdeskDup; 05240 } 05241 } 05242 05243 /* 05244 * Map the desktop into the process. 05245 */ 05246 if (hdesk != NULL && ppi != NULL) { 05247 Status = ObReferenceObjectByHandle(hdesk, 05248 0, 05249 *ExDesktopObjectType, 05250 KernelMode, 05251 &pdesk, 05252 NULL); 05253 if (NT_SUCCESS(Status)) { 05254 05255 LogDesktop(pdesk, LD_REF_FN_RESOLVEDESKTOP, TRUE, (ULONG_PTR)PtiCurrent()); 05256 05257 try { 05258 MapDesktop(ObOpenHandle, Process, pdesk, 0, 1); 05259 } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { 05260 Status = STATUS_NO_MEMORY; 05261 CloseProtectedHandle(hdesk); 05262 hdesk = NULL; 05263 } 05264 #if DBG 05265 if (hdesk != NULL) { 05266 UserAssert(GetDesktopView(ppi, pdesk) != NULL); 05267 } 05268 #endif // DBG 05269 LogDesktop(pdesk, LD_DEREF_FN_RESOLVEDESKTOP, FALSE, (ULONG_PTR)PtiCurrent()); 05270 ObDereferenceObject(pdesk); 05271 } else { 05272 CloseProtectedHandle(hdesk); 05273 hdesk = NULL; 05274 } 05275 } 05276 } 05277 } 05278 05279 /* 05280 * If not, open the desktop. 05281 */ 05282 if (NT_SUCCESS(Status) && hdesk == NULL) { 05283 RtlCopyUnicodeString(&strStatic, &strDesktop); 05284 05285 if (gbSecureDesktop) { 05286 if (pObjA == NULL) { 05287 /* 05288 * Allocate an object attributes structure in user address space. 05289 */ 05290 cbObjA = sizeof(*pObjA) + sizeof(*pstrStatic); 05291 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 05292 &pObjA, 0, &cbObjA, MEM_COMMIT, PAGE_READWRITE); 05293 pstrStatic = (PUNICODE_STRING)((PBYTE)pObjA + sizeof(*pObjA)); 05294 } 05295 05296 if (NT_SUCCESS(Status)) { 05297 /* 05298 * Note -- the string must be in client-space or the 05299 * address validation in OpenDesktop will fail. 05300 */ 05301 try { 05302 *pstrStatic = strStatic; 05303 InitializeObjectAttributes( pObjA, 05304 pstrStatic, 05305 OBJ_CASE_INSENSITIVE, 05306 hwinsta, 05307 NULL 05308 ); 05309 if (fInherit) 05310 pObjA->Attributes |= OBJ_INHERIT; 05311 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 05312 Status = GetExceptionCode(); 05313 } 05314 05315 if (NT_SUCCESS(Status)) { 05316 hdesk = xxxOpenDesktop(pObjA, 05317 UserMode, 05318 0, 05319 MAXIMUM_ALLOWED, 05320 pbShutDown); 05321 } 05322 } 05323 } else { 05324 InitializeObjectAttributes( &ObjA, 05325 &strStatic, 05326 OBJ_CASE_INSENSITIVE, 05327 hwinsta, 05328 NULL 05329 ); 05330 if (fInherit) 05331 ObjA.Attributes |= OBJ_INHERIT; 05332 hdesk = xxxOpenDesktop(&ObjA, 05333 KernelMode, 05334 0, 05335 MAXIMUM_ALLOWED, 05336 pbShutDown); 05337 } 05338 } 05339 } 05340 if (hdesk == NULL) { 05341 UserVerify(NT_SUCCESS(ZwClose(hwinsta))); 05342 hwinsta = NULL; 05343 } 05344 } 05345 05346 ObDereferenceObject(Process); 05347 05348 if (pObjA != NULL) { 05349 ZwFreeVirtualMemory(NtCurrentProcess(), &pObjA, &cbObjA, 05350 MEM_RELEASE); 05351 } 05352 05353 *phwinsta = hwinsta; 05354 05355 RIPMSG2(RIP_VERBOSE, 05356 "ResolveDesktop: to hwinsta=%#p desktop=%#p", 05357 *phwinsta, hdesk); 05358 05359 return hdesk; 05360 }

Generated on Sat May 15 19:39:40 2004 for test by doxygen 1.3.7