Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5791 lines
184 KiB

  1. /***************************** Module Header ******************************\
  2. * Module Name: desktop.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains everything related to the desktop support.
  7. *
  8. * History:
  9. * 23-Oct-1990 DarrinM Created.
  10. * 01-Feb-1991 JimA Added new API stubs.
  11. * 11-Feb-1991 JimA Added access checks.
  12. \***************************************************************************/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. typedef struct _DESKTOP_CONTEXT {
  16. PUNICODE_STRING pstrDevice;
  17. LPDEVMODE lpDevMode;
  18. DWORD dwFlags;
  19. DWORD dwCallerSessionId;
  20. } DESKTOP_CONTEXT, *PDESKTOP_CONTEXT;
  21. extern BOOL gfGdiEnabled;
  22. /*
  23. * We use these to protect a handle we're currently using from being closed.
  24. */
  25. PEPROCESS gProcessInUse;
  26. HANDLE gHandleInUse;
  27. /*
  28. * Debug Related Info.
  29. */
  30. #if DBG
  31. DWORD gDesktopsBusy; // diagnostic
  32. #endif
  33. #ifdef DEBUG_DESK
  34. VOID ValidateDesktop(PDESKTOP pdesk);
  35. #endif
  36. VOID DbgCheckForThreadsOnDesktop(PPROCESSINFO ppi, PDESKTOP pdesk);
  37. VOID FreeView(
  38. PEPROCESS Process,
  39. PDESKTOP pdesk);
  40. NTSTATUS
  41. SetDisconnectDesktopSecurity(
  42. IN HDESK hdeskDisconnect);
  43. #ifdef POOL_INSTR
  44. extern FAST_MUTEX* gpAllocFastMutex; // mutex to syncronize pool allocations
  45. #endif
  46. PVOID DesktopAlloc(
  47. PDESKTOP pdesk,
  48. UINT uSize,
  49. DWORD tag)
  50. {
  51. PVOID ptr;
  52. if (pdesk->dwDTFlags & DF_DESTROYED) {
  53. RIPMSG2(RIP_ERROR,
  54. "DesktopAlloc: tag %d pdesk %#p is destroyed",
  55. tag,
  56. pdesk);
  57. return NULL;
  58. }
  59. ptr = Win32HeapAlloc(pdesk->pheapDesktop, uSize, tag, 0);
  60. if (ptr == NULL && TEST_SRVIF(SRVIF_LOGDESKTOPHEAPFAILURE)) {
  61. /*
  62. * This will be logged at most once per-session so as to avoid
  63. * flooding the event log.
  64. */
  65. CLEAR_SRVIF(SRVIF_LOGDESKTOPHEAPFAILURE);
  66. UserLogError(NULL, 0, WARNING_DESKTOP_HEAP_ALLOC_FAIL);
  67. }
  68. return ptr;
  69. }
  70. #if DBG
  71. WCHAR s_strName[100];
  72. CONST WCHAR s_strNameNull[] = L"null";
  73. /***************************************************************************\
  74. * GetDesktopName
  75. *
  76. * This is for debug purposes.
  77. *
  78. * Dec-10-1997 CLupu Created.
  79. \***************************************************************************/
  80. LPCWSTR GetDesktopName(
  81. PDESKTOP pdesk)
  82. {
  83. POBJECT_NAME_INFORMATION DesktopObjectName = (POBJECT_NAME_INFORMATION)s_strName;
  84. ULONG DesktopObjectNameLength = sizeof(s_strName) - sizeof(WCHAR);
  85. NTSTATUS Status;
  86. if (pdesk == NULL) {
  87. return s_strNameNull;
  88. }
  89. Status = ObQueryNameString(pdesk,
  90. DesktopObjectName,
  91. DesktopObjectNameLength,
  92. &DesktopObjectNameLength);
  93. if (!NT_SUCCESS(Status)) {
  94. return s_strNameNull;
  95. }
  96. UserAssert(DesktopObjectNameLength + sizeof(WCHAR) < sizeof(s_strName));
  97. DesktopObjectName->Name.Buffer[DesktopObjectName->Name.Length / sizeof(WCHAR)] = 0;
  98. return (LPCWSTR)DesktopObjectName->Name.Buffer;
  99. }
  100. #endif
  101. typedef struct _CST_THREADS {
  102. PVOID pParam;
  103. HANDLE UniqueProcessId;
  104. UINT uID;
  105. } CST_THREADS, *PCST_THREADS;
  106. CST_THREADS gCSTParam[CST_MAX_THREADS];
  107. CST_THREADS gCSTRemoteParam[CST_MAX_THREADS];
  108. /***************************************************************************\
  109. * CSTPop
  110. *
  111. * Pops the first available pointer and ID in gCSTParam or gCSTRemoteParam.
  112. *
  113. * History:
  114. * 31-Mar-00 MHamid Created.
  115. \***************************************************************************/
  116. BOOL CSTPop(
  117. PUINT pThreadID,
  118. PVOID *pParam,
  119. PHANDLE pUniqueProcessId,
  120. BOOL bRemoteThreadStack)
  121. {
  122. UINT i = 0;
  123. PCST_THREADS pCSTParam = bRemoteThreadStack ? gCSTRemoteParam : gCSTParam;
  124. CheckCritIn();
  125. while (i < CST_MAX_THREADS) {
  126. if (pCSTParam[i].pParam) {
  127. *pParam = pCSTParam[i].pParam;
  128. if (NULL != pUniqueProcessId) {
  129. *pUniqueProcessId = pCSTParam[i].UniqueProcessId;
  130. }
  131. *pThreadID = pCSTParam[i].uID;
  132. pCSTParam[i].pParam = NULL;
  133. pCSTParam[i].uID = 0;
  134. return TRUE;
  135. }
  136. i++;
  137. }
  138. return FALSE;
  139. }
  140. /***************************************************************************\
  141. * CSTPush
  142. *
  143. * Push pointer (pParam) and ID in the first empty spot in gCSTParam or
  144. * gCSTRemoteParam.
  145. *
  146. * History:
  147. * 31-Mar-00 MHamid Created.
  148. \***************************************************************************/
  149. BOOL CSTPush(
  150. UINT uThreadID,
  151. PVOID pParam,
  152. HANDLE UniqueProcessId,
  153. BOOL bRemoteThreadStack)
  154. {
  155. UINT i = 0;
  156. PCST_THREADS pCSTParam = bRemoteThreadStack ? gCSTRemoteParam : gCSTParam;
  157. CheckCritIn();
  158. while (i < CST_MAX_THREADS) {
  159. if (!pCSTParam[i].pParam) {
  160. pCSTParam[i].pParam = pParam;
  161. pCSTParam[i].UniqueProcessId = UniqueProcessId;
  162. pCSTParam[i].uID = uThreadID;
  163. return TRUE;
  164. }
  165. i++;
  166. }
  167. return FALSE;
  168. }
  169. /***************************************************************************\
  170. * CSTCleanupStack
  171. *
  172. * Clean up any items left on gCSTParam or gCSTRemoteParam.
  173. *
  174. * History:
  175. * 20-Aug-00 MSadek Created.
  176. \***************************************************************************/
  177. VOID CSTCleanupStack(
  178. BOOL bRemoteThreadStack)
  179. {
  180. UINT uThreadID;
  181. PVOID pObj;
  182. while(CSTPop(&uThreadID, &pObj, NULL, bRemoteThreadStack)) {
  183. switch(uThreadID) {
  184. case CST_RIT:
  185. if (((PRIT_INIT)pObj)->pRitReadyEvent) {
  186. FreeKernelEvent(&((PRIT_INIT)pObj)->pRitReadyEvent);
  187. }
  188. break;
  189. case CST_POWER:
  190. if (((PPOWER_INIT)pObj)->pPowerReadyEvent) {
  191. FreeKernelEvent(&((PPOWER_INIT)pObj)->pPowerReadyEvent);
  192. }
  193. break;
  194. }
  195. }
  196. }
  197. /***************************************************************************\
  198. * GetRemoteProcessId
  199. *
  200. * Return handle to a remote process where a system thread would be created
  201. * (currently, only for ghost thread).
  202. *
  203. * History:
  204. * 20-Aug-00 MSadek Created.
  205. \***************************************************************************/
  206. HANDLE GetRemoteProcessId(
  207. VOID)
  208. {
  209. UINT uThreadID;
  210. PVOID pInitData;
  211. HANDLE UniqueProcessId;
  212. if (!CSTPop(&uThreadID, &pInitData, &UniqueProcessId, TRUE)) {
  213. return NULL;
  214. }
  215. /*
  216. * We should be here only for ghost thread.
  217. */
  218. UserAssert(uThreadID == CST_GHOST);
  219. CSTPush(uThreadID, pInitData, UniqueProcessId, TRUE);
  220. return UniqueProcessId;
  221. }
  222. /***************************************************************************\
  223. * HandleSystemThreadCreationFailure
  224. *
  225. * Handles the System thread creation failure
  226. *
  227. * History:
  228. * 1-Oct-00 MSadek Created.
  229. \***************************************************************************/
  230. VOID HandleSystemThreadCreationFailure(
  231. BOOL bRemoteThread)
  232. {
  233. UINT uThreadID;
  234. PVOID pObj;
  235. /*
  236. * Should be called only in the context of CSRSS.
  237. */
  238. if (!ISCSRSS()) {
  239. return;
  240. }
  241. if (!CSTPop(&uThreadID, &pObj, NULL, bRemoteThread)) {
  242. return;
  243. }
  244. if (uThreadID == CST_POWER) {
  245. if (((PPOWER_INIT)pObj)->pPowerReadyEvent) {
  246. KeSetEvent(((PPOWER_INIT)pObj)->pPowerReadyEvent, EVENT_INCREMENT, FALSE);
  247. }
  248. }
  249. }
  250. /***************************************************************************\
  251. * xxxCreateSystemThreads
  252. *
  253. * Call the right thread routine (depending on uThreadID),
  254. * which will wait for its own desired messages.
  255. *
  256. * History:
  257. * 15-Mar-00 MHamid Created.
  258. \***************************************************************************/
  259. VOID xxxCreateSystemThreads(
  260. BOOL bRemoteThread)
  261. {
  262. UINT uThreadID;
  263. PVOID pObj;
  264. /*
  265. * Do not allow any process other than CSRSS to call this function. The
  266. * only exception is the case of the ghost thread since we now allow it
  267. * to launch in the context of the shell process.
  268. */
  269. if (!bRemoteThread && !ISCSRSS()) {
  270. RIPMSG0(RIP_WARNING,
  271. "xxxCreateSystemThreads get called from a Process other than CSRSS");
  272. return;
  273. }
  274. if (!CSTPop(&uThreadID, &pObj, NULL, bRemoteThread)) {
  275. return;
  276. }
  277. LeaveCrit();
  278. switch (uThreadID) {
  279. case CST_DESKTOP:
  280. xxxDesktopThread(pObj);
  281. break;
  282. case CST_RIT:
  283. RawInputThread(pObj);
  284. break;
  285. case CST_GHOST:
  286. GhostThread(pObj);
  287. break;
  288. case CST_POWER:
  289. VideoPortCalloutThread(pObj);
  290. break;
  291. }
  292. EnterCrit();
  293. }
  294. /***************************************************************************\
  295. * xxxDesktopThread
  296. *
  297. * This thread owns all desktops windows on a windowstation. While waiting
  298. * for messages, it moves the mouse cursor without entering the USER critical
  299. * section. The RIT does the rest of the mouse input processing.
  300. *
  301. * History:
  302. * 03-Dec-1993 JimA Created.
  303. \***************************************************************************/
  304. #define OBJECTS_COUNT 3
  305. VOID xxxDesktopThread(
  306. PTERMINAL pTerm)
  307. {
  308. KPRIORITY Priority;
  309. NTSTATUS Status;
  310. PTHREADINFO ptiCurrent;
  311. PQ pqOriginal;
  312. UNICODE_STRING strThreadName;
  313. PKEVENT *apRITEvents;
  314. HANDLE hevtShutDown;
  315. PKEVENT pEvents[2];
  316. USHORT cEvents = 1;
  317. MSGWAITCALLBACK pfnHidChangeRoutine = NULL;
  318. DWORD nEvents = 0;
  319. UINT idMouseInput;
  320. UINT idDesktopDestroy;
  321. UINT idPumpMessages;
  322. UserAssert(pTerm != NULL);
  323. /*
  324. * Set the desktop thread's priority to low realtime.
  325. */
  326. #ifdef W2K_COMPAT_PRIORITY
  327. Priority = LOW_REALTIME_PRIORITY;
  328. #else
  329. Priority = LOW_REALTIME_PRIORITY - 4;
  330. #endif
  331. ZwSetInformationThread(NtCurrentThread(),
  332. ThreadPriority,
  333. &Priority,
  334. sizeof(KPRIORITY));
  335. /*
  336. * There are just two TERMINAL structures. One is for the
  337. * interactive windowstation and the other is for all the
  338. * non-interactive windowstations.
  339. */
  340. if (pTerm->dwTERMF_Flags & TERMF_NOIO) {
  341. RtlInitUnicodeString(&strThreadName, L"NOIO_DT");
  342. } else {
  343. RtlInitUnicodeString(&strThreadName, L"IO_DT");
  344. }
  345. if (!NT_SUCCESS(InitSystemThread(&strThreadName))) {
  346. pTerm->dwTERMF_Flags |= TERMF_DTINITFAILED;
  347. KeSetEvent(pTerm->pEventTermInit, EVENT_INCREMENT, FALSE);
  348. RIPMSG0(RIP_ERROR, "Fail to create the desktop thread");
  349. return;
  350. }
  351. ptiCurrent = PtiCurrentShared();
  352. pTerm->ptiDesktop = ptiCurrent;
  353. pTerm->pqDesktop = pqOriginal = ptiCurrent->pq;
  354. (pqOriginal->cLockCount)++;
  355. ptiCurrent->pDeskInfo = &diStatic;
  356. /*
  357. * Set the winsta to NULL. It will be set to the right windowstation in
  358. * xxxCreateDesktop before pEventInputReady is set.
  359. */
  360. ptiCurrent->pwinsta = NULL;
  361. /*
  362. * Allocate non-paged array. Include an extra entry for the thread's
  363. * input event.
  364. */
  365. apRITEvents = UserAllocPoolNonPagedNS((OBJECTS_COUNT * sizeof(PKEVENT)),
  366. TAG_SYSTEM);
  367. if (apRITEvents == NULL) {
  368. pTerm->dwTERMF_Flags |= TERMF_DTINITFAILED;
  369. KeSetEvent(pTerm->pEventTermInit, EVENT_INCREMENT, FALSE);
  370. return;
  371. }
  372. idMouseInput = 0xFFFF;
  373. idDesktopDestroy = 0xFFFF;
  374. /*
  375. * Reference the mouse input event. The system terminal doesn't
  376. * wait for any mouse input.
  377. */
  378. if (!(pTerm->dwTERMF_Flags & TERMF_NOIO)) {
  379. pfnHidChangeRoutine = (MSGWAITCALLBACK)ProcessDeviceChanges;
  380. idMouseInput = nEvents++;
  381. UserAssert(aDeviceTemplate[DEVICE_TYPE_MOUSE].pkeHidChange);
  382. apRITEvents[idMouseInput] = aDeviceTemplate[DEVICE_TYPE_MOUSE].pkeHidChange;
  383. }
  384. /*
  385. * Create the desktop destruction event.
  386. */
  387. idDesktopDestroy = nEvents++;
  388. apRITEvents[idDesktopDestroy] = CreateKernelEvent(SynchronizationEvent, FALSE);
  389. if (apRITEvents[idDesktopDestroy] == NULL) {
  390. pTerm->dwTERMF_Flags |= TERMF_DTINITFAILED;
  391. KeSetEvent(pTerm->pEventTermInit, EVENT_INCREMENT, FALSE);
  392. UserFreePool(apRITEvents);
  393. return;
  394. }
  395. pTerm->pEventDestroyDesktop = apRITEvents[idDesktopDestroy];
  396. EnterCrit();
  397. UserAssert(IsWinEventNotifyDeferredOK());
  398. /*
  399. * Set the event that tells the initialization of desktop
  400. * thread is done.
  401. */
  402. pTerm->dwTERMF_Flags |= TERMF_DTINITSUCCESS;
  403. KeSetEvent(pTerm->pEventTermInit, EVENT_INCREMENT, FALSE);
  404. if (gbRemoteSession) {
  405. WCHAR szName[MAX_SESSION_PATH];
  406. UNICODE_STRING ustrName;
  407. OBJECT_ATTRIBUTES obja;
  408. /*
  409. * Open the shutdown event. This event will be signaled
  410. * from W32WinStationTerminate.
  411. * This is a named event opend by CSR to signal that win32k should
  412. * go away. It's used in ntuser\server\api.c
  413. */
  414. swprintf(szName,
  415. L"\\Sessions\\%ld\\BaseNamedObjects\\EventShutDownCSRSS",
  416. gSessionId);
  417. RtlInitUnicodeString(&ustrName, szName);
  418. InitializeObjectAttributes(&obja,
  419. &ustrName,
  420. OBJ_CASE_INSENSITIVE,
  421. NULL,
  422. NULL);
  423. Status = ZwOpenEvent(&hevtShutDown,
  424. EVENT_ALL_ACCESS,
  425. &obja);
  426. if (!NT_SUCCESS(Status)) {
  427. pTerm->dwTERMF_Flags |= TERMF_DTINITFAILED;
  428. if(pTerm->pEventTermInit) {
  429. KeSetEvent(pTerm->pEventTermInit, EVENT_INCREMENT, FALSE);
  430. }
  431. FreeKernelEvent(&apRITEvents[idDesktopDestroy]);
  432. UserFreePool(apRITEvents);
  433. return;
  434. }
  435. ObReferenceObjectByHandle(hevtShutDown,
  436. EVENT_ALL_ACCESS,
  437. *ExEventObjectType,
  438. KernelMode,
  439. &pEvents[1],
  440. NULL);
  441. cEvents++;
  442. }
  443. /*
  444. * Prepare to wait on input ready event.
  445. */
  446. pEvents[0] = pTerm->pEventInputReady;
  447. ObReferenceObjectByPointer(pEvents[0],
  448. EVENT_ALL_ACCESS,
  449. *ExEventObjectType,
  450. KernelMode);
  451. LeaveCrit();
  452. Status = KeWaitForMultipleObjects(cEvents,
  453. pEvents,
  454. WaitAny,
  455. WrUserRequest,
  456. KernelMode,
  457. FALSE,
  458. NULL,
  459. NULL);
  460. EnterCrit();
  461. ObDereferenceObject(pEvents[0]);
  462. if (cEvents > 1) {
  463. ObDereferenceObject(pEvents[1]);
  464. }
  465. if (Status == WAIT_OBJECT_0 + 1) {
  466. pTerm->dwTERMF_Flags |= TERMF_DTINITFAILED;
  467. if (pTerm->spwndDesktopOwner != NULL) {
  468. xxxCleanupMotherDesktopWindow(pTerm);
  469. }
  470. if (pTerm->pEventTermInit) {
  471. KeSetEvent(pTerm->pEventTermInit, EVENT_INCREMENT, FALSE);
  472. }
  473. FreeKernelEvent(&apRITEvents[idDesktopDestroy]);
  474. UserFreePool(apRITEvents);
  475. if (hevtShutDown) {
  476. ZwClose(hevtShutDown);
  477. }
  478. pqOriginal->cLockCount--;
  479. pTerm->ptiDesktop = NULL;
  480. pTerm->pqDesktop = NULL;
  481. LeaveCrit();
  482. return;
  483. }
  484. /*
  485. * Adjust the event ids
  486. */
  487. idMouseInput += WAIT_OBJECT_0;
  488. idDesktopDestroy += WAIT_OBJECT_0;
  489. idPumpMessages = WAIT_OBJECT_0 + nEvents;
  490. /*
  491. * message loop lasts until we get a WM_QUIT message
  492. * upon which we shall return from the function
  493. */
  494. while (TRUE) {
  495. DWORD result;
  496. /*
  497. * Wait for any message sent or posted to this queue, while calling
  498. * ProcessDeviceChanges whenever the mouse change event (pkeHidChange)
  499. * is set.
  500. */
  501. result = xxxMsgWaitForMultipleObjects(nEvents,
  502. apRITEvents,
  503. pfnHidChangeRoutine,
  504. NULL);
  505. #if DBG
  506. gDesktopsBusy++;
  507. if (gDesktopsBusy >= 2) {
  508. RIPMSG0(RIP_WARNING, "2 or more desktop threads busy");
  509. }
  510. #endif
  511. /*
  512. * result tells us the type of event we have:
  513. * a message or a signalled handle
  514. *
  515. * if there are one or more messages in the queue ...
  516. */
  517. if (result == (DWORD)idPumpMessages) {
  518. MSG msg;
  519. CheckCritIn();
  520. /*
  521. * read all of the messages in this next loop
  522. * removing each message as we read it
  523. */
  524. while (xxxPeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  525. /*
  526. * Instrumentation to catch Windows Bug #210358.
  527. */
  528. if (msg.message == WM_QUIT && ptiCurrent->cWindows > 1) {
  529. FRE_RIPMSG2(RIP_ERROR, "xxxDesktopThread: WM_QUIT received when %d windows around for pti=%p",
  530. ptiCurrent->cWindows, ptiCurrent);
  531. }
  532. /*
  533. * If it's a quit message we're out of here.
  534. */
  535. if (msg.message == WM_QUIT && ptiCurrent->cWindows <= 1) {
  536. TRACE_DESKTOP(("WM_QUIT: Destroying the desktop thread. cWindows %d\n",
  537. ptiCurrent->cWindows));
  538. HYDRA_HINT(HH_DTQUITRECEIVED);
  539. /*
  540. * The window station is gone, so
  541. *
  542. * DON'T USE PWINSTA ANYMORE
  543. */
  544. /*
  545. * We could have received a mouse message in between the
  546. * desktop destroy event and the WM_QUIT message in which
  547. * case we may need to clear spwndTrack again to make sure
  548. * that a window (gotta be the desktop) isn't locked in.
  549. */
  550. Unlock(&ptiCurrent->rpdesk->spwndTrack);
  551. /*
  552. * If we're running on the last interactive desktop,
  553. * then we never unlocked pdesk->pDeskInfo->spwnd.
  554. * However, it seems to me that the system stops
  555. * running before we make it here; otherwise, (or
  556. * for a Hydra-like thing) we need to unlock that
  557. * window here.....
  558. */
  559. UserAssert(ptiCurrent->rpdesk != NULL &&
  560. ptiCurrent->rpdesk->pDeskInfo != NULL);
  561. if (ptiCurrent->rpdesk->pDeskInfo->spwnd != NULL) {
  562. Unlock(&ptiCurrent->rpdesk->pDeskInfo->spwnd);
  563. ptiCurrent->rpdesk->dwDTFlags |= DF_QUITUNLOCK;
  564. }
  565. /*
  566. * Because there is no desktop, we need to fake a
  567. * desktop info structure so that the IsHooked()
  568. * macro can test a "valid" fsHooks value.
  569. */
  570. ptiCurrent->pDeskInfo = &diStatic;
  571. /*
  572. * The desktop window is all that's left, so
  573. * let's exit. The thread cleanup code will
  574. * handle destruction of the window.
  575. */
  576. /*
  577. * If the thread is not using the original queue,
  578. * destroy it.
  579. */
  580. UserAssert(pqOriginal->cLockCount);
  581. (pqOriginal->cLockCount)--;
  582. if (ptiCurrent->pq != pqOriginal) {
  583. zzzDestroyQueue(pqOriginal, ptiCurrent);
  584. }
  585. #if DBG
  586. gDesktopsBusy--;
  587. #endif
  588. LeaveCrit();
  589. /*
  590. * Deref the events now that we're done with them.
  591. * Also free the wait array.
  592. */
  593. FreeKernelEvent(&apRITEvents[idDesktopDestroy]);
  594. UserFreePool(apRITEvents);
  595. pTerm->ptiDesktop = NULL;
  596. pTerm->pqDesktop = NULL;
  597. pTerm->dwTERMF_Flags |= TERMF_DTDESTROYED;
  598. /*
  599. * Terminate the thread by just returning, since we are
  600. * now a user thread.
  601. */
  602. return;
  603. } else if (msg.message == WM_DESKTOPNOTIFY) {
  604. switch(msg.wParam) {
  605. case DESKTOP_RELOADWALLPAPER:
  606. {
  607. TL tlName;
  608. PUNICODE_STRING pProfileUserName = CreateProfileUserName(&tlName);
  609. xxxSetDeskWallpaper(pProfileUserName, SETWALLPAPER_METRICS);
  610. FreeProfileUserName(pProfileUserName, &tlName);
  611. }
  612. break;
  613. default:
  614. RIPMSG1(RIP_WARNING, "WM_DESKTOPNOTIFY received with unrecognized wParam 0x%x", msg.wParam);
  615. break;
  616. }
  617. continue;
  618. }
  619. UserAssert(msg.message != WM_QUIT);
  620. /*
  621. * Otherwise dispatch it.
  622. */
  623. xxxDispatchMessage(&msg);
  624. }
  625. } else if (result == idDesktopDestroy) {
  626. PDESKTOP *ppdesk;
  627. PDESKTOP pdesk;
  628. PWND pwnd;
  629. PMENU pmenu;
  630. TL tlpwinsta;
  631. PWINDOWSTATION pwinsta;
  632. TL tlpdesk;
  633. TL tlpwnd;
  634. PDESKTOP pdeskTemp;
  635. HDESK hdeskTemp;
  636. TL tlpdeskTemp;
  637. /*
  638. * Destroy desktops on the destruction list.
  639. */
  640. for (ppdesk = &pTerm->rpdeskDestroy; *ppdesk != NULL;) {
  641. /*
  642. * Unlink from the list.
  643. */
  644. pdesk = *ppdesk;
  645. TRACE_DESKTOP(("Destroying desktop '%ws' %#p ...\n",
  646. GetDesktopName(pdesk), pdesk));
  647. UserAssert(!(pdesk->dwDTFlags & DF_DYING));
  648. ThreadLockDesktop(ptiCurrent, pdesk, &tlpdesk, LDLT_FN_DESKTOPTHREAD_DESK);
  649. pwinsta = pdesk->rpwinstaParent;
  650. ThreadLockWinSta(ptiCurrent, pdesk->rpwinstaParent, &tlpwinsta);
  651. LockDesktop(ppdesk, pdesk->rpdeskNext, LDL_TERM_DESKDESTROY1, (ULONG_PTR)pTerm);
  652. UnlockDesktop(&pdesk->rpdeskNext, LDU_DESK_DESKNEXT, 0);
  653. /*
  654. * !!! If this is the current desktop, switch to another one.
  655. */
  656. if (pdesk == grpdeskRitInput) {
  657. PDESKTOP pdeskNew;
  658. TRACE_DESKTOP(("Destroying the current active desktop\n"));
  659. pdesk->dwDTFlags |= DF_ACTIVEONDESTROY;
  660. if (pwinsta->dwWSF_Flags & WSF_SWITCHLOCK) {
  661. TRACE_DESKTOP(("The windowstation is locked\n"));
  662. /*
  663. * this should be the interactive windowstation
  664. */
  665. if (pwinsta->dwWSF_Flags & WSF_NOIO) {
  666. FRE_RIPMSG1(RIP_ERROR, "xxxDesktopThread: grpdeskRitInput on non-IO windowstation = %p", grpdeskRitInput);
  667. }
  668. /*
  669. * Switch to the disconnected desktop if the logon desktop
  670. * is being destroyed, or there is no logon desktop, or
  671. * if the logon desktop has already been destroyed.
  672. */
  673. if (gspdeskDisconnect &&
  674. (pdesk == grpdeskLogon ||
  675. grpdeskLogon == NULL ||
  676. (grpdeskLogon->dwDTFlags & DF_DESKWNDDESTROYED))) {
  677. TRACE_DESKTOP(("disable the screen and switch to the disconnect desktop\n"));
  678. pdesk->dwDTFlags |= DF_SKIPSWITCHDESKTOP;
  679. RemoteDisableScreen();
  680. goto skip;
  681. } else {
  682. TRACE_DESKTOP(("Switch to the logon desktop '%ws' %#p ...\n",
  683. GetDesktopName(grpdeskLogon), grpdeskLogon));
  684. pdeskNew = grpdeskLogon;
  685. }
  686. } else {
  687. pdeskNew = pwinsta->rpdeskList;
  688. if (pdeskNew == pdesk)
  689. pdeskNew = pdesk->rpdeskNext;
  690. /*
  691. * You can hit this if you exit winlogon before
  692. * logging in. I.E. all desktop's close so there is
  693. * no "next" one to switch to. I'm assuming that there
  694. * is a check for a NULL desktop in xxxSwitchDesktop().
  695. *
  696. * You can't switch to a NULL desktop. But this means
  697. * there isn't any input desktop so clear it manually.
  698. */
  699. if (pdeskNew == NULL) {
  700. TRACE_DESKTOP(("NO INPUT FOR DT FROM THIS POINT ON ...\n"));
  701. ClearWakeBit(ptiCurrent, QS_INPUT | QS_EVENT | QS_MOUSEMOVE, FALSE);
  702. pdesk->dwDTFlags |= DF_DTNONEWDESKTOP;
  703. }
  704. }
  705. TRACE_DESKTOP(("Switch to desktop '%ws' %#p\n",
  706. GetDesktopName(pdeskNew), pdeskNew));
  707. xxxSwitchDesktop(pwinsta, pdeskNew, 0);
  708. }
  709. skip:
  710. /*
  711. * Close the display if this desktop did not use the global
  712. * display.
  713. */
  714. if ((pdesk->pDispInfo->hDev != NULL) &&
  715. (pdesk->pDispInfo->hDev != gpDispInfo->hDev)) {
  716. TRACE_DESKTOP(("Destroy MDEV\n"));
  717. DrvDestroyMDEV(pdesk->pDispInfo->pmdev);
  718. GreFreePool(pdesk->pDispInfo->pmdev);
  719. pdesk->pDispInfo->pmdev = NULL;
  720. }
  721. if (pdesk->pDispInfo != gpDispInfo) {
  722. UserAssert(pdesk->pDispInfo->pMonitorFirst == NULL);
  723. UserFreePool(pdesk->pDispInfo);
  724. pdesk->pDispInfo = NULL;
  725. }
  726. /*
  727. * Makes sure the IO desktop thread is running on the active destkop.
  728. */
  729. if (!(pTerm->dwTERMF_Flags & TERMF_NOIO) && (ptiCurrent->rpdesk != grpdeskRitInput)) {
  730. FRE_RIPMSG0(RIP_ERROR, "xxxDesktopThread: desktop thread not originally on grpdeskRitInput");
  731. }
  732. pdeskTemp = ptiCurrent->rpdesk; // save current desktop
  733. hdeskTemp = ptiCurrent->hdesk;
  734. ThreadLockDesktop(ptiCurrent, pdeskTemp, &tlpdeskTemp, LDLT_FN_DESKTOPTHREAD_DESKTEMP);
  735. xxxSetThreadDesktop(NULL, pdesk);
  736. Unlock(&pdesk->spwndForeground);
  737. Unlock(&pdesk->spwndTray);
  738. /*
  739. * Destroy desktop and menu windows.
  740. */
  741. Unlock(&pdesk->spwndTrack);
  742. pdesk->dwDTFlags &= ~DF_MOUSEMOVETRK;
  743. if (pdesk->spmenuSys != NULL) {
  744. pmenu = pdesk->spmenuSys;
  745. if (UnlockDesktopSysMenu(&pdesk->spmenuSys)) {
  746. _DestroyMenu(pmenu);
  747. }
  748. }
  749. if (pdesk->spmenuDialogSys != NULL) {
  750. pmenu = pdesk->spmenuDialogSys;
  751. if (UnlockDesktopSysMenu(&pdesk->spmenuDialogSys)) {
  752. _DestroyMenu(pmenu);
  753. }
  754. }
  755. if (pdesk->spmenuHScroll != NULL) {
  756. pmenu = pdesk->spmenuHScroll;
  757. if (UnlockDesktopMenu(&pdesk->spmenuHScroll)) {
  758. _DestroyMenu(pmenu);
  759. }
  760. }
  761. if (pdesk->spmenuVScroll != NULL) {
  762. pmenu = pdesk->spmenuVScroll;
  763. if (UnlockDesktopMenu(&pdesk->spmenuVScroll)) {
  764. _DestroyMenu(pmenu);
  765. }
  766. }
  767. /*
  768. * If this desktop doesn't have a pDeskInfo, then something
  769. * is wrong. All desktops should have this until the object
  770. * is freed.
  771. */
  772. UserAssert(pdesk->pDeskInfo != NULL);
  773. if (pdesk->pDeskInfo) {
  774. if (pdesk->pDeskInfo->spwnd == gspwndFullScreen) {
  775. Unlock(&gspwndFullScreen);
  776. }
  777. if (pdesk->pDeskInfo->spwndShell) {
  778. Unlock(&pdesk->pDeskInfo->spwndShell);
  779. }
  780. if (pdesk->pDeskInfo->spwndBkGnd) {
  781. Unlock(&pdesk->pDeskInfo->spwndBkGnd);
  782. }
  783. if (pdesk->pDeskInfo->spwndTaskman) {
  784. Unlock(&pdesk->pDeskInfo->spwndTaskman);
  785. }
  786. if (pdesk->pDeskInfo->spwndProgman) {
  787. Unlock(&pdesk->pDeskInfo->spwndProgman);
  788. }
  789. }
  790. UserAssert(!(pdesk->dwDTFlags & DF_DYING));
  791. if (pdesk->spwndMessage != NULL) {
  792. pwnd = pdesk->spwndMessage;
  793. if (Unlock(&pdesk->spwndMessage)) {
  794. xxxDestroyWindow(pwnd);
  795. }
  796. }
  797. if (pdesk->spwndTooltip != NULL) {
  798. pwnd = pdesk->spwndTooltip;
  799. if (Unlock(&pdesk->spwndTooltip)) {
  800. xxxDestroyWindow(pwnd);
  801. }
  802. UserAssert(!(pdesk->dwDTFlags & DF_TOOLTIPSHOWING));
  803. }
  804. UserAssert(!(pdesk->dwDTFlags & DF_DYING));
  805. /*
  806. * If the dying desktop is the owner of the desktop owner
  807. * window, reassign it to the first available desktop. This
  808. * is needed to ensure that xxxSetWindowPos will work on
  809. * desktop windows.
  810. */
  811. if (pTerm->spwndDesktopOwner != NULL &&
  812. pTerm->spwndDesktopOwner->head.rpdesk == pdesk) {
  813. PDESKTOP pdeskR;
  814. /*
  815. * Find out to what desktop the mother desktop window
  816. * should go. Careful with the NOIO case where there
  817. * might be several windowstations using the same
  818. * mother desktop window
  819. */
  820. if (pTerm->dwTERMF_Flags & TERMF_NOIO) {
  821. PWINDOWSTATION pwinstaW;
  822. pdeskR = NULL;
  823. CheckCritIn();
  824. if (grpWinStaList) {
  825. pwinstaW = grpWinStaList->rpwinstaNext;
  826. while (pwinstaW != NULL) {
  827. if (pwinstaW->rpdeskList != NULL) {
  828. pdeskR = pwinstaW->rpdeskList;
  829. break;
  830. }
  831. pwinstaW = pwinstaW->rpwinstaNext;
  832. }
  833. }
  834. } else {
  835. pdeskR = pwinsta->rpdeskList;
  836. }
  837. if (pdeskR == NULL) {
  838. TRACE_DESKTOP(("DESTROYING THE MOTHER DESKTOP WINDOW %#p\n",
  839. pTerm->spwndDesktopOwner));
  840. xxxCleanupMotherDesktopWindow(pTerm);
  841. } else {
  842. TRACE_DESKTOP(("MOVING THE MOTHER DESKTOP WINDOW %#p to pdesk %#p '%ws'\n",
  843. pTerm->spwndDesktopOwner, pdeskR, GetDesktopName(pdeskR)));
  844. LockDesktop(&(pTerm->spwndDesktopOwner->head.rpdesk),
  845. pdeskR, LDL_MOTHERDESK_DESK1, (ULONG_PTR)(pTerm->spwndDesktopOwner));
  846. }
  847. }
  848. if (pdesk->pDeskInfo && (pdesk->pDeskInfo->spwnd != NULL)) {
  849. UserAssert(!(pdesk->dwDTFlags & DF_DESKWNDDESTROYED));
  850. pwnd = pdesk->pDeskInfo->spwnd;
  851. /*
  852. * Hide this window without activating anyone else.
  853. */
  854. if (TestWF(pwnd, WFVISIBLE)) {
  855. ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd);
  856. xxxSetWindowPos(pwnd,
  857. NULL,
  858. 0,
  859. 0,
  860. 0,
  861. 0,
  862. SWP_HIDEWINDOW | SWP_NOACTIVATE |
  863. SWP_NOMOVE | SWP_NOSIZE |
  864. SWP_NOZORDER | SWP_NOREDRAW |
  865. SWP_NOSENDCHANGING);
  866. ThreadUnlock(&tlpwnd);
  867. }
  868. /*
  869. * A lot of pwnd related code assumes that we always
  870. * have a valid desktop window. So we call
  871. * xxxDestroyWindow first to clean up and then we unlock
  872. * it to free it (now or eventually). However, if we're
  873. * destroying the last destkop, then we don't unlock the
  874. * window since we're are forced to continue running on
  875. * that desktop.
  876. */
  877. TRACE_DESKTOP(("Destroying the desktop window\n"));
  878. xxxDestroyWindow(pdesk->pDeskInfo->spwnd);
  879. if (pdesk != grpdeskRitInput) {
  880. Unlock(&pdesk->pDeskInfo->spwnd);
  881. pdesk->dwDTFlags |= DF_NOTRITUNLOCK;
  882. } else {
  883. pdesk->dwDTFlags |= DF_ZOMBIE;
  884. /*
  885. * unlock the gspwndShouldBeForeground window
  886. */
  887. if (ISTS() && gspwndShouldBeForeground != NULL) {
  888. Unlock(&gspwndShouldBeForeground);
  889. }
  890. /*
  891. * This is hit in HYDRA when the last desktop does away
  892. */
  893. RIPMSG1(RIP_WARNING, "xxxDesktopThread: Running on zombie desk:%#p", pdesk);
  894. }
  895. pdesk->dwDTFlags |= DF_DESKWNDDESTROYED;
  896. }
  897. /*
  898. * Restore the previous desktop.
  899. *
  900. * In NOIO sessions, if pdeskTemp is destroyed, don't bother switching
  901. * back to it since it'll fail (and assert) latter in zzzSetDesktop
  902. */
  903. if (!(pTerm->dwTERMF_Flags & TERMF_NOIO) ||
  904. !(pdeskTemp->dwDTFlags & (DF_DESKWNDDESTROYED | DF_DYING))) {
  905. xxxSetThreadDesktop(hdeskTemp, pdeskTemp);
  906. }
  907. /*
  908. * Makes sure the IO desktop thread is running on the active destkop.
  909. */
  910. if (!(pTerm->dwTERMF_Flags & TERMF_NOIO) && (ptiCurrent->rpdesk != grpdeskRitInput)) {
  911. FRE_RIPMSG0(RIP_ERROR, "xxxDesktopThread: desktop thread not back on grpdeskRitInput");
  912. }
  913. ThreadUnlockDesktop(ptiCurrent, &tlpdeskTemp, LDUT_FN_DESKTOPTHREAD_DESKTEMP);
  914. ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
  915. ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_DESKTOPTHREAD_DESK);
  916. }
  917. /*
  918. * Wakeup ntinput thread for exit processing
  919. */
  920. TRACE_DESKTOP(("Wakeup ntinput thread for exit processing\n"));
  921. UserAssert(gpevtDesktopDestroyed != NULL);
  922. KeSetEvent(gpevtDesktopDestroyed, EVENT_INCREMENT, FALSE);
  923. } else if ((NTSTATUS)result == STATUS_USER_APC) {
  924. /*
  925. * Instrumentation to catch Windows Bug #210358.
  926. */
  927. FRE_RIPMSG1(RIP_ERROR, "xxxDesktopThread: received STATUS_USER_APC for pti=%p", ptiCurrent);
  928. /*
  929. * Perhaps we should repost WM_QUIT to myself?
  930. */
  931. } else {
  932. RIPMSG1(RIP_ERROR, "Desktop woke up for what? status=%08x", result);
  933. }
  934. #if DBG
  935. gDesktopsBusy--;
  936. #endif
  937. }
  938. }
  939. /***************************************************************************\
  940. * xxxRealizeDesktop
  941. *
  942. * 4/28/97 vadimg created
  943. \***************************************************************************/
  944. VOID xxxRealizeDesktop(PWND pwnd)
  945. {
  946. CheckLock(pwnd);
  947. UserAssert(GETFNID(pwnd) == FNID_DESKTOP);
  948. if (ghpalWallpaper) {
  949. HDC hdc = _GetDC(pwnd);
  950. xxxInternalPaintDesktop(pwnd, hdc, FALSE);
  951. _ReleaseDC(hdc);
  952. }
  953. }
  954. /***************************************************************************\
  955. * xxxDesktopWndProc
  956. *
  957. * History:
  958. * 23-Oct-1990 DarrinM Ported from Win 3.0 sources.
  959. * 08-Aug-1996 jparsons 51725 - added fix to prevent crash on WM_SETICON
  960. \***************************************************************************/
  961. LRESULT xxxDesktopWndProc(
  962. PWND pwnd,
  963. UINT message,
  964. WPARAM wParam,
  965. LPARAM lParam)
  966. {
  967. PTHREADINFO ptiCurrent = PtiCurrent();
  968. HDC hdcT;
  969. PAINTSTRUCT ps;
  970. PWINDOWPOS pwp;
  971. CheckLock(pwnd);
  972. UserAssert(IsWinEventNotifyDeferredOK());
  973. VALIDATECLASSANDSIZE(pwnd, message, wParam, lParam, FNID_DESKTOP, WM_CREATE);
  974. if (pwnd->spwndParent == NULL) {
  975. switch (message) {
  976. case WM_SETICON:
  977. /*
  978. * Cannot allow this as it will cause a callback to user mode
  979. * from the desktop system thread.
  980. */
  981. RIPMSG0(RIP_WARNING, "Discarding WM_SETICON sent to desktop.");
  982. return 0L;
  983. default:
  984. break;
  985. }
  986. return xxxDefWindowProc(pwnd, message, wParam, lParam);
  987. }
  988. switch (message) {
  989. case WM_WINDOWPOSCHANGING:
  990. /*
  991. * We receive this when switch desktop is called. Just to be
  992. * consistent, set the rit desktop as this thread's desktop.
  993. */
  994. pwp = (PWINDOWPOS)lParam;
  995. if (!(pwp->flags & SWP_NOZORDER) && pwp->hwndInsertAfter == HWND_TOP) {
  996. xxxSetThreadDesktop(NULL, grpdeskRitInput);
  997. /*
  998. * If some app has taken over the system-palette, we should make
  999. * sure the system is restored. Otherwise, if this is the logon
  1000. * desktop, we might not be able to view the dialog correctly.
  1001. */
  1002. if (GreGetSystemPaletteUse(gpDispInfo->hdcScreen) != SYSPAL_STATIC) {
  1003. GreRealizeDefaultPalette(gpDispInfo->hdcScreen, TRUE);
  1004. }
  1005. /*
  1006. * Let everyone know if the palette has changed.
  1007. */
  1008. if (grpdeskRitInput->dwDTFlags & DTF_NEEDSPALETTECHANGED) {
  1009. xxxSendNotifyMessage(PWND_BROADCAST,
  1010. WM_PALETTECHANGED,
  1011. (WPARAM)HWq(pwnd),
  1012. 0);
  1013. grpdeskRitInput->dwDTFlags &= ~DTF_NEEDSPALETTECHANGED;
  1014. }
  1015. }
  1016. break;
  1017. case WM_FULLSCREEN: {
  1018. TL tlpwndT;
  1019. ThreadLockWithPti(ptiCurrent, grpdeskRitInput->pDeskInfo->spwnd, &tlpwndT);
  1020. xxxMakeWindowForegroundWithState(grpdeskRitInput->pDeskInfo->spwnd,
  1021. GDIFULLSCREEN);
  1022. ThreadUnlock(&tlpwndT);
  1023. /*
  1024. * We have to tell the switch window to repaint if we switched
  1025. * modes
  1026. */
  1027. if (gspwndAltTab != NULL) {
  1028. ThreadLockAlwaysWithPti(ptiCurrent, gspwndAltTab, &tlpwndT);
  1029. xxxSendMessage(gspwndAltTab, WM_FULLSCREEN, 0, 0);
  1030. ThreadUnlock(&tlpwndT);
  1031. }
  1032. break;
  1033. }
  1034. case WM_CLOSE:
  1035. /*
  1036. * Make sure nobody sends this window a WM_CLOSE and causes it to
  1037. * destroy itself.
  1038. */
  1039. break;
  1040. case WM_SETICON:
  1041. /*
  1042. * cannot allow this as it will cause a callback to user mode from the
  1043. * desktop system thread.
  1044. */
  1045. RIPMSG0(RIP_WARNING, "WM_SETICON sent to desktop window was discarded.");
  1046. break;
  1047. case WM_CREATE: {
  1048. TL tlName;
  1049. PUNICODE_STRING pProfileUserName = CreateProfileUserName(&tlName);
  1050. /*
  1051. * Is there a desktop pattern, or bitmap name in WIN.INI?
  1052. */
  1053. xxxSetDeskPattern(pProfileUserName, (LPWSTR)-1, TRUE);
  1054. FreeProfileUserName(pProfileUserName, &tlName);
  1055. /*
  1056. * Initialize the system colors before we show the desktop window.
  1057. */
  1058. xxxSendNotifyMessage(pwnd, WM_SYSCOLORCHANGE, 0, 0L);
  1059. hdcT = _GetDC(pwnd);
  1060. xxxInternalPaintDesktop(pwnd, hdcT, FALSE); // use "normal" HDC so SelectPalette() will work
  1061. _ReleaseDC(hdcT);
  1062. /*
  1063. * Save process and thread ids.
  1064. */
  1065. xxxSetWindowLong(pwnd,
  1066. 0,
  1067. HandleToUlong(PsGetCurrentProcessId()),
  1068. FALSE);
  1069. xxxSetWindowLong(pwnd,
  1070. 4,
  1071. HandleToUlong(PsGetCurrentThreadId()),
  1072. FALSE);
  1073. break;
  1074. }
  1075. case WM_PALETTECHANGED:
  1076. if (HWq(pwnd) == (HWND)wParam) {
  1077. break;
  1078. }
  1079. // FALL THROUGH
  1080. case WM_QUERYNEWPALETTE:
  1081. xxxRealizeDesktop(pwnd);
  1082. break;
  1083. case WM_SYSCOLORCHANGE:
  1084. /*
  1085. * We do the redrawing if someone has changed the sys-colors from
  1086. * another desktop and we need to redraw. This is appearent with
  1087. * the MATROX card which requires OGL applications to take over
  1088. * the entire sys-colors for drawing. When switching desktops, we
  1089. * never broadcast the WM_SYSCOLORCHANGE event to tell us to redraw
  1090. * This is only a DAYTONA related fix, and should be removed once
  1091. * we move the SYSMETS to a per-desktop state.
  1092. *
  1093. * 05-03-95 : ChrisWil.
  1094. */
  1095. xxxRedrawWindow(pwnd,
  1096. NULL,
  1097. NULL,
  1098. RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE);
  1099. break;
  1100. case WM_ERASEBKGND:
  1101. hdcT = (HDC)wParam;
  1102. xxxInternalPaintDesktop(pwnd, hdcT, TRUE);
  1103. return TRUE;
  1104. case WM_PAINT:
  1105. xxxBeginPaint(pwnd, (LPPAINTSTRUCT)&ps);
  1106. xxxEndPaint(pwnd, (LPPAINTSTRUCT)&ps);
  1107. break;
  1108. #ifdef HUNGAPP_GHOSTING
  1109. case WM_HUNGTHREAD:
  1110. {
  1111. PWND pwndT = RevalidateHwnd((HWND)lParam);
  1112. if (pwndT != NULL && FHungApp(GETPTI(pwndT), CMSHUNGAPPTIMEOUT)) {
  1113. TL tlpwnd;
  1114. pwndT = GetTopLevelWindow(pwndT);
  1115. ThreadLockAlways(pwndT, &tlpwnd);
  1116. xxxCreateGhost(pwndT);
  1117. ThreadUnlock(&tlpwnd);
  1118. }
  1119. break;
  1120. }
  1121. case WM_SCANGHOST:
  1122. if (gpEventScanGhosts) {
  1123. KeSetEvent(gpEventScanGhosts, EVENT_INCREMENT, FALSE);
  1124. }
  1125. break;
  1126. #endif
  1127. case WM_CREATETRAILTIMER:
  1128. if (GETMOUSETRAILS() && !gtmridMouseTrails) {
  1129. gtmridMouseTrails = InternalSetTimer(NULL,
  1130. gtmridMouseTrails,
  1131. 1000 / MOUSE_TRAILS_FREQ,
  1132. HideMouseTrails,
  1133. TMRF_RIT);
  1134. }
  1135. break;
  1136. case WM_LBUTTONDBLCLK:
  1137. message = WM_SYSCOMMAND;
  1138. wParam = SC_TASKLIST;
  1139. /*
  1140. *** FALL THRU **
  1141. */
  1142. default:
  1143. return xxxDefWindowProc(pwnd, message, wParam, lParam);
  1144. }
  1145. return 0L;
  1146. }
  1147. /***************************************************************************\
  1148. * SetDeskPattern
  1149. *
  1150. * NOTE: the lpszPattern parameter is new for Win 3.1.
  1151. *
  1152. * History:
  1153. * 23-Oct-1990 DarrinM Created stub.
  1154. * 22-Apr-1991 DarrinM Ported code from Win 3.1 sources.
  1155. \***************************************************************************/
  1156. BOOL xxxSetDeskPattern(PUNICODE_STRING pProfileUserName,
  1157. LPWSTR lpszPattern,
  1158. BOOL fCreation)
  1159. {
  1160. LPWSTR p;
  1161. int i;
  1162. UINT val;
  1163. WCHAR wszNone[20];
  1164. WCHAR wchValue[MAX_PATH];
  1165. WORD rgBits[CXYDESKPATTERN];
  1166. HBRUSH hBrushTemp;
  1167. CheckCritIn();
  1168. /*
  1169. * Get rid of the old bitmap (if any).
  1170. */
  1171. if (ghbmDesktop != NULL) {
  1172. GreDeleteObject(ghbmDesktop);
  1173. ghbmDesktop = NULL;
  1174. }
  1175. /*
  1176. * Check if a pattern is passed via lpszPattern.
  1177. */
  1178. if (lpszPattern != (LPWSTR)LongToPtr(-1)) {
  1179. /*
  1180. * Yes! Then use that pattern;
  1181. */
  1182. p = lpszPattern;
  1183. goto GotThePattern;
  1184. }
  1185. /*
  1186. * Else, pickup the pattern selected in WIN.INI.
  1187. * Get the "DeskPattern" string from WIN.INI's [Desktop] section.
  1188. */
  1189. if (!FastGetProfileStringFromIDW(pProfileUserName,
  1190. PMAP_DESKTOP,
  1191. STR_DESKPATTERN,
  1192. L"",
  1193. wchValue,
  1194. sizeof(wchValue)/sizeof(WCHAR),
  1195. 0)) {
  1196. return FALSE;
  1197. }
  1198. ServerLoadString(hModuleWin,
  1199. STR_NONE,
  1200. wszNone,
  1201. sizeof(wszNone)/sizeof(WCHAR));
  1202. p = wchValue;
  1203. GotThePattern:
  1204. /*
  1205. * Was a Desk Pattern selected?
  1206. */
  1207. if (*p == L'\0' || _wcsicmp(p, wszNone) == 0) {
  1208. hBrushTemp = GreCreateSolidBrush(SYSRGB(DESKTOP));
  1209. if (hBrushTemp != NULL) {
  1210. if (SYSHBR(DESKTOP)) {
  1211. GreMarkDeletableBrush(SYSHBR(DESKTOP));
  1212. GreDeleteObject(SYSHBR(DESKTOP));
  1213. }
  1214. GreMarkUndeletableBrush(hBrushTemp);
  1215. SYSHBR(DESKTOP) = hBrushTemp;
  1216. }
  1217. GreSetBrushOwnerPublic(hBrushTemp);
  1218. goto SDPExit;
  1219. }
  1220. /*
  1221. * Get eight groups of numbers seprated by non-numeric characters.
  1222. */
  1223. for (i = 0; i < CXYDESKPATTERN; i++) {
  1224. val = 0;
  1225. /*
  1226. * Skip over any non-numeric characters, check for null EVERY time.
  1227. */
  1228. while (*p && !(*p >= L'0' && *p <= L'9')) {
  1229. p++;
  1230. }
  1231. /*
  1232. * Get the next series of digits.
  1233. */
  1234. while (*p >= L'0' && *p <= L'9') {
  1235. val = val * (UINT)10 + (UINT)(*p++ - L'0');
  1236. }
  1237. rgBits[i] = (WORD)val;
  1238. }
  1239. ghbmDesktop = GreCreateBitmap(CXYDESKPATTERN,
  1240. CXYDESKPATTERN,
  1241. 1,
  1242. 1,
  1243. (LPBYTE)rgBits);
  1244. if (ghbmDesktop == NULL) {
  1245. return FALSE;
  1246. }
  1247. GreSetBitmapOwner(ghbmDesktop, OBJECT_OWNER_PUBLIC);
  1248. RecolorDeskPattern();
  1249. SDPExit:
  1250. if (!fCreation) {
  1251. /*
  1252. * Notify everyone that the colors have changed.
  1253. */
  1254. xxxSendNotifyMessage(PWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0L);
  1255. /*
  1256. * Update the entire screen. If this is creation, don't update: the
  1257. * screen hasn't drawn, and also there are some things that aren't
  1258. * initialized yet.
  1259. */
  1260. xxxRedrawScreen();
  1261. }
  1262. return TRUE;
  1263. }
  1264. /***************************************************************************\
  1265. * RecolorDeskPattern
  1266. *
  1267. * Remakes the desktop pattern (if it exists) so that it uses the new system
  1268. * colors.
  1269. *
  1270. * History:
  1271. * 22-Apr-1991 DarrinM Ported from Win 3.1 sources.
  1272. \***************************************************************************/
  1273. VOID RecolorDeskPattern(
  1274. VOID)
  1275. {
  1276. HBITMAP hbmOldDesk;
  1277. HBITMAP hbmOldMem;
  1278. HBITMAP hbmMem;
  1279. HBRUSH hBrushTemp;
  1280. if (ghbmDesktop == NULL) {
  1281. return;
  1282. }
  1283. /*
  1284. * Redo the desktop pattern in the new colors.
  1285. */
  1286. if (hbmOldDesk = GreSelectBitmap(ghdcMem, ghbmDesktop)) {
  1287. if (!SYSMET(SAMEDISPLAYFORMAT)) {
  1288. BYTE bmi[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2];
  1289. PBITMAPINFO pbmi = (PBITMAPINFO)bmi;
  1290. pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1291. pbmi->bmiHeader.biWidth = CXYDESKPATTERN;
  1292. pbmi->bmiHeader.biHeight = CXYDESKPATTERN;
  1293. pbmi->bmiHeader.biPlanes = 1;
  1294. pbmi->bmiHeader.biBitCount = 1;
  1295. pbmi->bmiHeader.biCompression = BI_RGB;
  1296. pbmi->bmiHeader.biSizeImage = 0;
  1297. pbmi->bmiHeader.biXPelsPerMeter = 0;
  1298. pbmi->bmiHeader.biYPelsPerMeter = 0;
  1299. pbmi->bmiHeader.biClrUsed = 2;
  1300. pbmi->bmiHeader.biClrImportant = 2;
  1301. pbmi->bmiColors[0].rgbBlue = (BYTE)((SYSRGB(DESKTOP) >> 16) & 0xff);
  1302. pbmi->bmiColors[0].rgbGreen = (BYTE)((SYSRGB(DESKTOP) >> 8) & 0xff);
  1303. pbmi->bmiColors[0].rgbRed = (BYTE)((SYSRGB(DESKTOP)) & 0xff);
  1304. pbmi->bmiColors[1].rgbBlue = (BYTE)((SYSRGB(WINDOWTEXT) >> 16) & 0xff);
  1305. pbmi->bmiColors[1].rgbGreen = (BYTE)((SYSRGB(WINDOWTEXT) >> 8) & 0xff);
  1306. pbmi->bmiColors[1].rgbRed = (BYTE)((SYSRGB(WINDOWTEXT)) & 0xff);
  1307. hbmMem = GreCreateDIBitmapReal(HDCBITS(),
  1308. 0,
  1309. NULL,
  1310. pbmi,
  1311. DIB_RGB_COLORS,
  1312. sizeof(bmi),
  1313. 0,
  1314. NULL,
  1315. 0,
  1316. NULL,
  1317. 0,
  1318. 0,
  1319. NULL);
  1320. } else {
  1321. hbmMem = GreCreateCompatibleBitmap(HDCBITS(),
  1322. CXYDESKPATTERN,
  1323. CXYDESKPATTERN);
  1324. }
  1325. if (hbmMem) {
  1326. if (hbmOldMem = GreSelectBitmap(ghdcMem2, hbmMem)) {
  1327. GreSetTextColor(ghdcMem2, SYSRGB(DESKTOP));
  1328. GreSetBkColor(ghdcMem2, SYSRGB(WINDOWTEXT));
  1329. GreBitBlt(ghdcMem2,
  1330. 0,
  1331. 0,
  1332. CXYDESKPATTERN,
  1333. CXYDESKPATTERN,
  1334. ghdcMem,
  1335. 0,
  1336. 0,
  1337. SRCCOPY,
  1338. 0);
  1339. if (hBrushTemp = GreCreatePatternBrush(hbmMem)) {
  1340. if (SYSHBR(DESKTOP) != NULL) {
  1341. GreMarkDeletableBrush(SYSHBR(DESKTOP));
  1342. GreDeleteObject(SYSHBR(DESKTOP));
  1343. }
  1344. GreMarkUndeletableBrush(hBrushTemp);
  1345. SYSHBR(DESKTOP) = hBrushTemp;
  1346. }
  1347. GreSetBrushOwnerPublic(hBrushTemp);
  1348. GreSelectBitmap(ghdcMem2, hbmOldMem);
  1349. }
  1350. GreDeleteObject(hbmMem);
  1351. }
  1352. GreSelectBitmap(ghdcMem, hbmOldDesk);
  1353. }
  1354. }
  1355. /***************************************************************************\
  1356. * GetDesktopHeapSize()
  1357. *
  1358. * Calculate the desktop heap size
  1359. *
  1360. * History:
  1361. * 27-Nov-2001 Msadek Created it.
  1362. \***************************************************************************/
  1363. ULONG GetDesktopHeapSize(
  1364. USHORT usFlags)
  1365. {
  1366. ULONG ulHeapSize;
  1367. switch (usFlags) {
  1368. case DHS_LOGON:
  1369. ulHeapSize = USR_LOGONSECT_SIZE;
  1370. #ifdef _WIN64
  1371. /*
  1372. * Increase heap size 50% for Win64 to allow for larger structures.
  1373. */
  1374. ulHeapSize = (ulHeapSize * 3) / 2;
  1375. #endif
  1376. break;
  1377. case DHS_DISCONNECT:
  1378. ulHeapSize = USR_DISCONNECTSECT_SIZE;
  1379. #ifdef _WIN64
  1380. /*
  1381. * Increase heap size 50% for Win64 to allow for larger structures.
  1382. */
  1383. ulHeapSize = (ulHeapSize * 3) / 2;
  1384. #endif
  1385. break;
  1386. case DHS_NOIO:
  1387. ulHeapSize = gdwNOIOSectionSize;
  1388. break;
  1389. default:
  1390. ulHeapSize = gdwDesktopSectionSize;
  1391. }
  1392. return ulHeapSize * 1024;
  1393. }
  1394. /***************************************************************************\
  1395. * xxxCreateDesktop (API)
  1396. *
  1397. * Create a new desktop object.
  1398. *
  1399. * History:
  1400. * 16-Jan-1991 JimA Created scaffold code.
  1401. * 11-Feb-1991 JimA Added access checks.
  1402. \***************************************************************************/
  1403. NTSTATUS xxxCreateDesktop2(
  1404. PWINDOWSTATION pwinsta,
  1405. PACCESS_STATE pAccessState,
  1406. KPROCESSOR_MODE AccessMode,
  1407. PUNICODE_STRING pstrName,
  1408. PDESKTOP_CONTEXT Context,
  1409. PVOID *pObject)
  1410. {
  1411. LUID luidCaller;
  1412. OBJECT_ATTRIBUTES ObjectAttributes;
  1413. PEPROCESS Process;
  1414. PDESKTOP pdesk;
  1415. PDESKTOPINFO pdi;
  1416. ULONG ulHeapSize;
  1417. USHORT usSizeFlags = 0;
  1418. NTSTATUS Status;
  1419. BOOLEAN MemoryAllocated;
  1420. PSECURITY_DESCRIPTOR SecurityDescriptor;
  1421. CheckCritIn();
  1422. /*
  1423. * If this is a desktop creation, make sure that the windowstation
  1424. * grants create access.
  1425. */
  1426. if (!ObCheckCreateObjectAccess(
  1427. pwinsta,
  1428. WINSTA_CREATEDESKTOP,
  1429. pAccessState,
  1430. pstrName,
  1431. TRUE,
  1432. AccessMode,
  1433. &Status)) {
  1434. return Status;
  1435. }
  1436. /*
  1437. * Fail if the windowstation is locked.
  1438. */
  1439. Process = PsGetCurrentProcess();
  1440. if (pwinsta->dwWSF_Flags & WSF_OPENLOCK &&
  1441. PsGetProcessId(Process) != gpidLogon) {
  1442. /*
  1443. * If logoff is occuring and the caller does not
  1444. * belong to the session that is ending, allow the
  1445. * open to proceed.
  1446. */
  1447. Status = GetProcessLuid(NULL, &luidCaller);
  1448. if (!NT_SUCCESS(Status) ||
  1449. !(pwinsta->dwWSF_Flags & WSF_SHUTDOWN) ||
  1450. RtlEqualLuid(&luidCaller, &pwinsta->luidEndSession)) {
  1451. return STATUS_DEVICE_BUSY;
  1452. }
  1453. }
  1454. /*
  1455. * If a devmode has been specified, we also must be able
  1456. * to switch desktops.
  1457. */
  1458. if (Context->lpDevMode != NULL && (pwinsta->dwWSF_Flags & WSF_OPENLOCK) &&
  1459. PsGetProcessId(Process) != gpidLogon) {
  1460. return STATUS_DEVICE_BUSY;
  1461. }
  1462. /*
  1463. * Allocate the new object
  1464. */
  1465. InitializeObjectAttributes(&ObjectAttributes, pstrName, 0, NULL, NULL);
  1466. Status = ObCreateObject(
  1467. KernelMode,
  1468. *ExDesktopObjectType,
  1469. &ObjectAttributes,
  1470. UserMode,
  1471. NULL,
  1472. sizeof(DESKTOP),
  1473. 0,
  1474. 0,
  1475. &pdesk);
  1476. if (!NT_SUCCESS(Status)) {
  1477. RIPMSG1(RIP_WARNING,
  1478. "xxxCreateDesktop2: ObCreateObject failed with Status 0x%x",
  1479. Status);
  1480. return Status;
  1481. }
  1482. RtlZeroMemory(pdesk, sizeof(DESKTOP));
  1483. /*
  1484. * Store the session id of the session who created the desktop
  1485. */
  1486. pdesk->dwSessionId = gSessionId;
  1487. /*
  1488. * Fetch the parents security descriptor
  1489. */
  1490. Status = ObGetObjectSecurity(pwinsta,
  1491. &SecurityDescriptor,
  1492. &MemoryAllocated);
  1493. if (!NT_SUCCESS(Status)) {
  1494. goto Error;
  1495. }
  1496. /*
  1497. * Create security descriptor.
  1498. */
  1499. Status = ObAssignSecurity(pAccessState,
  1500. SecurityDescriptor,
  1501. pdesk,
  1502. *ExDesktopObjectType);
  1503. ObReleaseObjectSecurity(SecurityDescriptor, MemoryAllocated);
  1504. if (!NT_SUCCESS(Status)) {
  1505. goto Error;
  1506. }
  1507. /*
  1508. * Set up desktop heap. The first desktop (logon desktop) uses a
  1509. * small heap (128).
  1510. */
  1511. if (!(pwinsta->dwWSF_Flags & WSF_NOIO) && (pwinsta->rpdeskList == NULL)) {
  1512. usSizeFlags = DHS_LOGON;
  1513. } else {
  1514. if (pwinsta->dwWSF_Flags & WSF_NOIO) {
  1515. usSizeFlags = DHS_NOIO;
  1516. } else {
  1517. /*
  1518. * The disconnected desktop should be small also.
  1519. */
  1520. if (gspdeskDisconnect == NULL) {
  1521. usSizeFlags = DHS_DISCONNECT;
  1522. }
  1523. }
  1524. }
  1525. ulHeapSize = GetDesktopHeapSize(usSizeFlags);
  1526. /*
  1527. * Create the desktop heap.
  1528. */
  1529. pdesk->hsectionDesktop = CreateDesktopHeap(&pdesk->pheapDesktop, ulHeapSize);
  1530. if (pdesk->hsectionDesktop == NULL) {
  1531. RIPMSGF1(RIP_WARNING,
  1532. "CreateDesktopHeap failed for pdesk 0x%p",
  1533. pdesk);
  1534. /*
  1535. * If we fail to create a desktop due to being out of desktop heap,
  1536. * write an entry to the event log.
  1537. */
  1538. if (TEST_SRVIF(SRVIF_LOGDESKTOPHEAPFAILURE)) {
  1539. CLEAR_SRVIF(SRVIF_LOGDESKTOPHEAPFAILURE);
  1540. UserLogError(NULL, 0, WARNING_DESKTOP_CREATION_FAILED);
  1541. }
  1542. goto ErrorOutOfMemory;
  1543. }
  1544. if (pwinsta->rpdeskList == NULL || (pwinsta->dwWSF_Flags & WSF_NOIO)) {
  1545. /*
  1546. * The first desktop or invisible desktops must also use the default
  1547. * settings. This is because specifying the devmode causes a desktop
  1548. * switch, which must be avoided in this case.
  1549. */
  1550. Context->lpDevMode = NULL;
  1551. }
  1552. /*
  1553. * Allocate desktopinfo
  1554. */
  1555. pdi = (PDESKTOPINFO)DesktopAlloc(pdesk, sizeof(DESKTOPINFO), DTAG_DESKTOPINFO);
  1556. if (pdi == NULL) {
  1557. RIPMSG0(RIP_WARNING, "xxxCreateDesktop: failed DeskInfo Alloc");
  1558. goto ErrorOutOfMemory;
  1559. }
  1560. /*
  1561. * Initialize everything.
  1562. */
  1563. pdesk->pDeskInfo = pdi;
  1564. InitializeListHead(&pdesk->PtiList);
  1565. /*
  1566. * If a DEVMODE or another device name is passed in, then use that
  1567. * information. Otherwise use the default information (gpDispInfo).
  1568. */
  1569. if (Context->lpDevMode) {
  1570. BOOL bDisabled = FALSE;
  1571. PMDEV pmdev = NULL;
  1572. LONG ChangeStat = GRE_DISP_CHANGE_FAILED;
  1573. /*
  1574. * Allocate a display-info for this device.
  1575. */
  1576. pdesk->pDispInfo = (PDISPLAYINFO)UserAllocPoolZInit(
  1577. sizeof(DISPLAYINFO), TAG_DISPLAYINFO);
  1578. if (!pdesk->pDispInfo) {
  1579. RIPMSGF1(RIP_WARNING,
  1580. "Failed to allocate pDispInfo for pdesk 0x%p",
  1581. pdesk);
  1582. goto ErrorOutOfMemory;
  1583. }
  1584. if ((bDisabled = SafeDisableMDEV()) == TRUE) {
  1585. ChangeStat = DrvChangeDisplaySettings(Context->pstrDevice,
  1586. NULL,
  1587. Context->lpDevMode,
  1588. LongToPtr(gdwDesktopId),
  1589. UserMode,
  1590. FALSE,
  1591. TRUE,
  1592. NULL,
  1593. &pmdev,
  1594. GRE_DEFAULT,
  1595. FALSE);
  1596. }
  1597. if (ChangeStat != GRE_DISP_CHANGE_SUCCESSFUL) {
  1598. if (bDisabled) {
  1599. SafeEnableMDEV();
  1600. }
  1601. //
  1602. // If there is a failure, then repaint the whole screen.
  1603. //
  1604. RIPMSG1(RIP_WARNING, "xxxCreateDesktop2 callback for pdesk %#p !",
  1605. pdesk);
  1606. xxxUserResetDisplayDevice();
  1607. Status = STATUS_UNSUCCESSFUL;
  1608. goto Error;
  1609. }
  1610. pdesk->pDispInfo->hDev = pmdev->hdevParent;
  1611. pdesk->pDispInfo->pmdev = pmdev;
  1612. pdesk->dwDesktopId = gdwDesktopId++;
  1613. CopyRect(&pdesk->pDispInfo->rcScreen, &gpDispInfo->rcScreen);
  1614. pdesk->pDispInfo->dmLogPixels = gpDispInfo->dmLogPixels;
  1615. pdesk->pDispInfo->pMonitorFirst = NULL;
  1616. pdesk->pDispInfo->pMonitorPrimary = NULL;
  1617. } else {
  1618. pdesk->pDispInfo = gpDispInfo;
  1619. pdesk->dwDesktopId = GW_DESKTOP_ID;
  1620. }
  1621. /*
  1622. * Heap is HEAP_ZERO_MEMORY, so we should be zero-initialized already.
  1623. */
  1624. UserAssert(pdi->pvwplShellHook == NULL);
  1625. pdi->pvDesktopBase = Win32HeapGetHandle(pdesk->pheapDesktop);
  1626. pdi->pvDesktopLimit = (PBYTE)pdi->pvDesktopBase + ulHeapSize;
  1627. /*
  1628. * Reference the parent windowstation
  1629. */
  1630. LockWinSta(&(pdesk->rpwinstaParent), pwinsta);
  1631. /*
  1632. * Link the desktop into the windowstation list
  1633. */
  1634. if (pwinsta->rpdeskList == NULL) {
  1635. if (!(pwinsta->dwWSF_Flags & WSF_NOIO)) {
  1636. LockDesktop(&grpdeskLogon, pdesk, LDL_DESKLOGON, 0);
  1637. }
  1638. /*
  1639. * Make the first desktop the "owner" of the top desktop window. This
  1640. * is needed to ensure that xxxSetWindowPos will work on desktop
  1641. * windows.
  1642. */
  1643. LockDesktop(&(pwinsta->pTerm->spwndDesktopOwner->head.rpdesk),
  1644. pdesk, LDL_MOTHERDESK_DESK2, (ULONG_PTR)(pwinsta->pTerm->spwndDesktopOwner));
  1645. }
  1646. LockDesktop(&pdesk->rpdeskNext, pwinsta->rpdeskList, LDL_DESK_DESKNEXT1, (ULONG_PTR)pwinsta);
  1647. LockDesktop(&pwinsta->rpdeskList, pdesk, LDL_WINSTA_DESKLIST1, (ULONG_PTR)pwinsta);
  1648. /*
  1649. * Mask off invalid access bits
  1650. */
  1651. if (pAccessState->RemainingDesiredAccess & MAXIMUM_ALLOWED) {
  1652. pAccessState->RemainingDesiredAccess &= ~MAXIMUM_ALLOWED;
  1653. pAccessState->RemainingDesiredAccess |= GENERIC_ALL;
  1654. }
  1655. RtlMapGenericMask( &pAccessState->RemainingDesiredAccess, (PGENERIC_MAPPING)&DesktopMapping);
  1656. pAccessState->RemainingDesiredAccess &=
  1657. (DesktopMapping.GenericAll | ACCESS_SYSTEM_SECURITY);
  1658. *pObject = pdesk;
  1659. /*
  1660. * Add the desktop to the global list of desktops in this win32k.
  1661. */
  1662. DbgTrackAddDesktop(pdesk);
  1663. return STATUS_SUCCESS;
  1664. ErrorOutOfMemory:
  1665. Status = STATUS_NO_MEMORY;
  1666. // fall-through
  1667. Error:
  1668. LogDesktop(pdesk, LD_DEREF_FN_2CREATEDESKTOP, FALSE, 0);
  1669. ObDereferenceObject(pdesk);
  1670. UserAssert(!NT_SUCCESS(Status));
  1671. return Status;
  1672. }
  1673. BOOL xxxCreateDisconnectDesktop(
  1674. HWINSTA hwinsta,
  1675. PWINDOWSTATION pwinsta)
  1676. {
  1677. UNICODE_STRING strDesktop;
  1678. OBJECT_ATTRIBUTES oa;
  1679. HDESK hdeskDisconnect;
  1680. HRGN hrgn;
  1681. NTSTATUS Status;
  1682. /*
  1683. * Create the empty clipping region for the disconnect desktop.
  1684. */
  1685. if ((hrgn = CreateEmptyRgnPublic()) == NULL) {
  1686. RIPMSG0(RIP_WARNING, "Creation of empty region for Disconnect Desktop failed ");
  1687. return FALSE;
  1688. }
  1689. /*
  1690. * If not created yet, then create the Disconnected desktop
  1691. * (used when WinStation is disconnected), and lock the desktop
  1692. * and desktop window to ensure they never get deleted.
  1693. */
  1694. RtlInitUnicodeString(&strDesktop, L"Disconnect");
  1695. InitializeObjectAttributes(&oa, &strDesktop,
  1696. OBJ_OPENIF | OBJ_CASE_INSENSITIVE, hwinsta, NULL);
  1697. hdeskDisconnect = xxxCreateDesktop(&oa,
  1698. KernelMode,
  1699. NULL,
  1700. NULL,
  1701. 0,
  1702. MAXIMUM_ALLOWED);
  1703. if (hdeskDisconnect == NULL) {
  1704. RIPMSG0(RIP_WARNING, "Could not create Disconnect desktop");
  1705. GreDeleteObject(hrgn);
  1706. return FALSE;
  1707. }
  1708. /*
  1709. * Set the disconnect desktop security.
  1710. * Keep around an extra reference to the disconnect desktop from
  1711. * the CSR so it will stay around even if winlogon exits.
  1712. */
  1713. Status = SetDisconnectDesktopSecurity(hdeskDisconnect);
  1714. if (NT_SUCCESS(Status)) {
  1715. Status = ObReferenceObjectByHandle(hdeskDisconnect,
  1716. 0,
  1717. NULL,
  1718. KernelMode,
  1719. &gspdeskDisconnect,
  1720. NULL);
  1721. }
  1722. if (!NT_SUCCESS(Status)) {
  1723. RIPMSG1(RIP_WARNING, "Disconnect Desktop reference failed 0x%x", Status);
  1724. GreDeleteObject(hrgn);
  1725. xxxCloseDesktop(hdeskDisconnect, KernelMode);
  1726. gspdeskDisconnect = NULL;
  1727. return FALSE;
  1728. }
  1729. LogDesktop(gspdeskDisconnect, LDL_DESKDISCONNECT, TRUE, 0);
  1730. /*
  1731. * Set the region of the desktop window to be (0, 0, 0, 0) so
  1732. * that there is no hittesting going on the 'disconnect' desktop
  1733. * But prior to session the null region, we need to null the pointer
  1734. * to the existing shared region so that it doesn't get deleted.
  1735. */
  1736. UserAssert(gspdeskDisconnect->pDeskInfo != NULL);
  1737. gspdeskDisconnect->pDeskInfo->spwnd->hrgnClip = hrgn;
  1738. KeAttachProcess(PsGetProcessPcb(gpepCSRSS));
  1739. Status = ObOpenObjectByPointer(
  1740. gspdeskDisconnect,
  1741. 0,
  1742. NULL,
  1743. EVENT_ALL_ACCESS,
  1744. NULL,
  1745. KernelMode,
  1746. &ghDisconnectDesk);
  1747. if (NT_SUCCESS(Status)) {
  1748. Status = ObOpenObjectByPointer(
  1749. pwinsta,
  1750. 0,
  1751. NULL,
  1752. EVENT_ALL_ACCESS,
  1753. NULL,
  1754. KernelMode,
  1755. &ghDisconnectWinSta);
  1756. }
  1757. KeDetachProcess();
  1758. if (!NT_SUCCESS(Status)) {
  1759. RIPMSG0(RIP_WARNING, "Could not create Disconnect desktop");
  1760. GreDeleteObject(hrgn);
  1761. gspdeskDisconnect->pDeskInfo->spwnd->hrgnClip = NULL;
  1762. if (ghDisconnectDesk != NULL) {
  1763. CloseProtectedHandle(ghDisconnectDesk);
  1764. ghDisconnectDesk = NULL;
  1765. }
  1766. xxxCloseDesktop(hdeskDisconnect, KernelMode);
  1767. return FALSE;
  1768. }
  1769. /*
  1770. * Don't want to do alot of paints if we disconnected before this.
  1771. */
  1772. if (!gbConnected) {
  1773. RIPMSG0(RIP_WARNING,
  1774. "RemoteDisconnect was issued during CreateDesktop(\"Winlogon\"...");
  1775. }
  1776. return TRUE;
  1777. }
  1778. VOID CleanupDirtyDesktops(
  1779. VOID)
  1780. {
  1781. PWINDOWSTATION pwinsta;
  1782. PDESKTOP* ppdesk;
  1783. CheckCritIn();
  1784. for (pwinsta = grpWinStaList; pwinsta != NULL; pwinsta = pwinsta->rpwinstaNext) {
  1785. ppdesk = &pwinsta->rpdeskList;
  1786. while (*ppdesk != NULL) {
  1787. if (!((*ppdesk)->dwDTFlags & DF_DESKCREATED)) {
  1788. RIPMSG1(RIP_WARNING, "Desktop %#p in a dirty state", *ppdesk);
  1789. if (grpdeskLogon == *ppdesk) {
  1790. UnlockDesktop(&grpdeskLogon, LDU_DESKLOGON, 0);
  1791. }
  1792. if (pwinsta->pTerm->spwndDesktopOwner &&
  1793. pwinsta->pTerm->spwndDesktopOwner->head.rpdesk == *ppdesk) {
  1794. UnlockDesktop(&(pwinsta->pTerm->spwndDesktopOwner->head.rpdesk),
  1795. LDU_MOTHERDESK_DESK, (ULONG_PTR)(pwinsta->pTerm->spwndDesktopOwner));
  1796. }
  1797. LockDesktop(ppdesk, (*ppdesk)->rpdeskNext, LDL_WINSTA_DESKLIST1, (ULONG_PTR)pwinsta);
  1798. } else {
  1799. ppdesk = &(*ppdesk)->rpdeskNext;
  1800. }
  1801. }
  1802. }
  1803. }
  1804. VOID W32FreeDesktop(
  1805. PVOID pObj)
  1806. {
  1807. FRE_RIPMSG1(RIP_WARNING,
  1808. "W32FreeDesktop: obj 0x%p is not freed in the regular code path.",
  1809. pObj);
  1810. ObDereferenceObject(pObj);
  1811. }
  1812. HDESK xxxCreateDesktop(
  1813. POBJECT_ATTRIBUTES ccxObjectAttributes,
  1814. KPROCESSOR_MODE ProbeMode,
  1815. PUNICODE_STRING ccxpstrDevice,
  1816. LPDEVMODE ccxlpdevmode,
  1817. DWORD dwFlags,
  1818. DWORD dwDesiredAccess)
  1819. {
  1820. HWINSTA hwinsta;
  1821. HDESK hdesk;
  1822. DESKTOP_CONTEXT Context;
  1823. PDESKTOP pdesk;
  1824. PDESKTOPINFO pdi;
  1825. PWINDOWSTATION pwinsta;
  1826. PDESKTOP pdeskTemp;
  1827. HDESK hdeskTemp;
  1828. PWND pwndDesktop = NULL;
  1829. PWND pwndMessage = NULL;
  1830. PWND pwndTooltip = NULL;
  1831. TL tlpwnd;
  1832. PTHREADINFO ptiCurrent = PtiCurrent();
  1833. BOOL fWasNull;
  1834. BOOL bSuccess;
  1835. PPROCESSINFO ppi;
  1836. PPROCESSINFO ppiSave;
  1837. PTERMINAL pTerm;
  1838. NTSTATUS Status;
  1839. DWORD dwDisableHooks;
  1840. TL tlW32Desktop;
  1841. #if DBG
  1842. /*
  1843. * Too many jumps in this function to use BEGIN/ENDATOMICHCECK
  1844. */
  1845. DWORD dwCritSecUseSave = gdwCritSecUseCount;
  1846. #endif
  1847. CheckCritIn();
  1848. UserAssert(IsWinEventNotifyDeferredOK());
  1849. /*
  1850. * Capture directory handle and check for create access.
  1851. */
  1852. try {
  1853. hwinsta = ccxObjectAttributes->RootDirectory;
  1854. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
  1855. return NULL;
  1856. }
  1857. if (hwinsta != NULL) {
  1858. Status = ObReferenceObjectByHandle(hwinsta,
  1859. WINSTA_CREATEDESKTOP,
  1860. *ExWindowStationObjectType,
  1861. ProbeMode,
  1862. &pwinsta,
  1863. NULL);
  1864. if (NT_SUCCESS(Status)) {
  1865. DWORD dwSessionId = pwinsta->dwSessionId;
  1866. ObDereferenceObject(pwinsta);
  1867. if (dwSessionId != gSessionId) {
  1868. /*
  1869. * Windows Bug: 418526
  1870. * Avoid creating a desktop that belongs to the other
  1871. * session.
  1872. */
  1873. RIPMSGF1(RIP_WARNING,
  1874. "winsta 0x%p belongs to other session",
  1875. pwinsta);
  1876. return NULL;
  1877. }
  1878. } else {
  1879. RIPNTERR0(Status, RIP_VERBOSE, "ObReferenceObjectByHandle Failed");
  1880. return NULL;
  1881. }
  1882. }
  1883. /*
  1884. * Set up creation context
  1885. */
  1886. Context.lpDevMode = ccxlpdevmode;
  1887. Context.pstrDevice = ccxpstrDevice;
  1888. Context.dwFlags = dwFlags;
  1889. Context.dwCallerSessionId = gSessionId;
  1890. /*
  1891. * Create the desktop -- the object manager uses try blocks.
  1892. */
  1893. Status = ObOpenObjectByName(ccxObjectAttributes,
  1894. *ExDesktopObjectType,
  1895. ProbeMode,
  1896. NULL,
  1897. dwDesiredAccess,
  1898. &Context,
  1899. &hdesk);
  1900. if (!NT_SUCCESS(Status)) {
  1901. RIPNTERR1(Status,
  1902. RIP_WARNING,
  1903. "xxxCreateDesktop: ObOpenObjectByName failed with Status 0x%x",
  1904. Status);
  1905. /*
  1906. * Cleanup desktop objects that were created in xxxCreateDesktop2
  1907. * but later on the Ob manager failed the creation for other
  1908. * reasons (ex: no quota).
  1909. */
  1910. CleanupDirtyDesktops();
  1911. return NULL;
  1912. }
  1913. /*
  1914. * If the desktop already exists, we're done. This will only happen
  1915. * if OBJ_OPENIF was specified.
  1916. */
  1917. if (Status == STATUS_OBJECT_NAME_EXISTS) {
  1918. SetHandleFlag(hdesk, HF_PROTECTED, TRUE);
  1919. RIPMSG0(RIP_WARNING, "xxxCreateDesktop: Object name exists");
  1920. return hdesk;
  1921. }
  1922. /*
  1923. * Reference the desktop to finish initialization
  1924. */
  1925. Status = ObReferenceObjectByHandle(
  1926. hdesk,
  1927. 0,
  1928. *ExDesktopObjectType,
  1929. KernelMode,
  1930. &pdesk,
  1931. NULL);
  1932. if (!NT_SUCCESS(Status)) {
  1933. RIPNTERR0(Status, RIP_VERBOSE, "");
  1934. CloseProtectedHandle(hdesk);
  1935. return NULL;
  1936. }
  1937. /*
  1938. * Usermode marking such that any hdesk associated with this desktop will
  1939. * always be referenced in this mode.
  1940. */
  1941. pdesk->dwDTFlags |= DF_DESKCREATED | ((ProbeMode == UserMode) ? DF_USERMODE : 0);
  1942. LogDesktop(pdesk, LD_REF_FN_CREATEDESKTOP, TRUE, (ULONG_PTR)PtiCurrent());
  1943. pwinsta = pdesk->rpwinstaParent;
  1944. pTerm = pwinsta->pTerm;
  1945. pdi = pdesk->pDeskInfo;
  1946. pdi->ppiShellProcess = NULL;
  1947. ppi = PpiCurrent();
  1948. if (gpepCSRSS != NULL) {
  1949. WIN32_OPENMETHOD_PARAMETERS OpenParams;
  1950. /*
  1951. * Map the desktop into CSRSS to ensure that the hard error handler
  1952. * can get access.
  1953. */
  1954. OpenParams.OpenReason = ObOpenHandle;
  1955. OpenParams.Process = gpepCSRSS;
  1956. OpenParams.Object = pdesk;
  1957. OpenParams.GrantedAccess = 0;
  1958. OpenParams.HandleCount = 1;
  1959. if (!NT_SUCCESS(MapDesktop(&OpenParams))) {
  1960. /*
  1961. * Desktop mapping failed.
  1962. */
  1963. CloseProtectedHandle(hdesk);
  1964. LogDesktop(pdesk, LD_DEREF_FN_CREATEDESKTOP2, FALSE, (ULONG_PTR)PtiCurrent());
  1965. ObDereferenceObject(pdesk);
  1966. RIPNTERR0(STATUS_ACCESS_DENIED, RIP_WARNING, "Desktop mapping failed (2)");
  1967. return NULL;
  1968. }
  1969. UserAssert(GetDesktopView(PpiFromProcess(gpepCSRSS), pdesk) != NULL);
  1970. }
  1971. /*
  1972. * Set hook flags
  1973. */
  1974. SetHandleFlag(hdesk, HF_DESKTOPHOOK, dwFlags & DF_ALLOWOTHERACCOUNTHOOK);
  1975. /*
  1976. * Set up to create the desktop window.
  1977. */
  1978. fWasNull = (ptiCurrent->ppi->rpdeskStartup == NULL);
  1979. pdeskTemp = ptiCurrent->rpdesk; // save current desktop
  1980. hdeskTemp = ptiCurrent->hdesk;
  1981. /*
  1982. * Switch ppi values so window will be created using the
  1983. * system's desktop window class.
  1984. */
  1985. ppiSave = ptiCurrent->ppi;
  1986. ptiCurrent->ppi = pTerm->ptiDesktop->ppi;
  1987. /*
  1988. * Lock pdesk: with bogus TS protocol, the session
  1989. * may be killed in the middle of the initialization.
  1990. */
  1991. PushW32ThreadLock(pdesk, &tlW32Desktop, W32FreeDesktop);
  1992. DeferWinEventNotify();
  1993. BeginAtomicCheck();
  1994. if (zzzSetDesktop(ptiCurrent, pdesk, hdesk) == FALSE) {
  1995. goto Error;
  1996. }
  1997. /*
  1998. * Create the desktop window
  1999. */
  2000. /*
  2001. * HACK HACK HACK!!! (adams) In order to create the desktop window
  2002. * with the correct desktop, we set the desktop of the current thread
  2003. * to the new desktop. But in so doing we allow hooks on the current
  2004. * thread to also hook this new desktop. This is bad, because we don't
  2005. * want the desktop window to be hooked while it is created. So we
  2006. * temporarily disable hooks of the current thread and its desktop,
  2007. * and reenable them after switching back to the original desktop.
  2008. */
  2009. dwDisableHooks = ptiCurrent->TIF_flags & TIF_DISABLEHOOKS;
  2010. ptiCurrent->TIF_flags |= TIF_DISABLEHOOKS;
  2011. pwndDesktop = xxxNVCreateWindowEx(
  2012. (DWORD)0,
  2013. (PLARGE_STRING)DESKTOPCLASS,
  2014. NULL,
  2015. (WS_POPUP | WS_CLIPCHILDREN),
  2016. pdesk->pDispInfo->rcScreen.left,
  2017. pdesk->pDispInfo->rcScreen.top,
  2018. pdesk->pDispInfo->rcScreen.right - pdesk->pDispInfo->rcScreen.left,
  2019. pdesk->pDispInfo->rcScreen.bottom - pdesk->pDispInfo->rcScreen.top,
  2020. NULL,
  2021. NULL,
  2022. hModuleWin,
  2023. NULL,
  2024. VER31);
  2025. if (pwndDesktop == NULL) {
  2026. RIPMSGF1(RIP_WARNING,
  2027. "Failed to create the desktop window for pdesk 0x%p",
  2028. pdesk);
  2029. goto Error;
  2030. }
  2031. /*
  2032. * NOTE: In order for the message window to be created without
  2033. * the desktop as it's owner, it needs to be created before
  2034. * setting pdi->spwnd to the desktop window. This is a complete
  2035. * hack and should be fixed.
  2036. */
  2037. pwndMessage = xxxNVCreateWindowEx(
  2038. 0,
  2039. (PLARGE_STRING)gatomMessage,
  2040. NULL,
  2041. (WS_POPUP | WS_CLIPCHILDREN),
  2042. 0,
  2043. 0,
  2044. 100,
  2045. 100,
  2046. NULL,
  2047. NULL,
  2048. hModuleWin,
  2049. NULL,
  2050. VER31);
  2051. if (pwndMessage == NULL) {
  2052. RIPMSGF0(RIP_WARNING, "Failed to create the message window");
  2053. goto Error;
  2054. }
  2055. /*
  2056. * NOTE: Remember what window class this window belongs to.
  2057. * Since the message window does not have its own window proc
  2058. * (they use xxxDefWindowProc) we have to do it here.
  2059. */
  2060. pwndMessage->fnid = FNID_MESSAGEWND;
  2061. UserAssert(pdi->spwnd == NULL);
  2062. Lock(&(pdi->spwnd), pwndDesktop);
  2063. SetFullScreen(pwndDesktop, GDIFULLSCREEN);
  2064. /*
  2065. * Set this windows to the fullscreen window if we don't have one yet.
  2066. *
  2067. * Don't set gspwndFullScreen if gfGdiEnabled has been cleared (we may
  2068. * be in the middle of a disconnect).
  2069. */
  2070. if (!(pwinsta->dwWSF_Flags & WSF_NOIO)) {
  2071. UserAssert(gfGdiEnabled == TRUE);
  2072. if (gspwndFullScreen == NULL) {
  2073. Lock(&(gspwndFullScreen), pwndDesktop);
  2074. }
  2075. }
  2076. /*
  2077. * NT Bug 388747: Link the message window to the mother desktop window
  2078. * so that it properly has a parent. We will do this before we link the
  2079. * desktop window just so the initial message window appears after the
  2080. * initial desktop window (a minor optimization, but not necessary).
  2081. */
  2082. Lock(&pwndMessage->spwndParent, pTerm->spwndDesktopOwner);
  2083. LinkWindow(pwndMessage, NULL, pTerm->spwndDesktopOwner);
  2084. Lock(&pdesk->spwndMessage, pwndMessage);
  2085. Unlock(&pwndMessage->spwndOwner);
  2086. /*
  2087. * Link it as a child but don't use WS_CHILD style
  2088. */
  2089. LinkWindow(pwndDesktop, NULL, pTerm->spwndDesktopOwner);
  2090. Lock(&pwndDesktop->spwndParent, pTerm->spwndDesktopOwner);
  2091. Unlock(&pwndDesktop->spwndOwner);
  2092. /*
  2093. * Make it regional if it's display configuration is regional.
  2094. */
  2095. if (!pdesk->pDispInfo->fDesktopIsRect) {
  2096. pwndDesktop->hrgnClip = pdesk->pDispInfo->hrgnScreen;
  2097. }
  2098. /*
  2099. * Create shared menu window and tooltip window.
  2100. */
  2101. ThreadLock(pdesk->spwndMessage, &tlpwnd);
  2102. /*
  2103. * Create the tooltip window only for desktops in interactive
  2104. * windowstations.
  2105. */
  2106. if (!(pwinsta->dwWSF_Flags & WSF_NOIO)) {
  2107. pwndTooltip = xxxNVCreateWindowEx(
  2108. WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
  2109. (PLARGE_STRING)TOOLTIPCLASS,
  2110. NULL,
  2111. WS_POPUP | WS_BORDER,
  2112. 0,
  2113. 0,
  2114. 100,
  2115. 100,
  2116. pdesk->spwndMessage,
  2117. NULL,
  2118. hModuleWin,
  2119. NULL,
  2120. VER31);
  2121. if (pwndTooltip == NULL) {
  2122. ThreadUnlock(&tlpwnd);
  2123. RIPMSGF0(RIP_WARNING, "Failed to create the tooltip window");
  2124. goto Error;
  2125. }
  2126. Lock(&pdesk->spwndTooltip, pwndTooltip);
  2127. }
  2128. ThreadUnlock(&tlpwnd);
  2129. HMChangeOwnerThread(pdi->spwnd, pTerm->ptiDesktop);
  2130. HMChangeOwnerThread(pwndMessage, pTerm->ptiDesktop);
  2131. if (!(pwinsta->dwWSF_Flags & WSF_NOIO)) {
  2132. HMChangeOwnerThread(pwndTooltip, pTerm->ptiDesktop);
  2133. }
  2134. /*
  2135. * Restore caller's ppi
  2136. */
  2137. PtiCurrent()->ppi = ppiSave;
  2138. /*
  2139. * HACK HACK HACK (adams): Renable hooks.
  2140. */
  2141. UserAssert(ptiCurrent->TIF_flags & TIF_DISABLEHOOKS);
  2142. ptiCurrent->TIF_flags = (ptiCurrent->TIF_flags & ~TIF_DISABLEHOOKS) | dwDisableHooks;
  2143. /*
  2144. * Restore the previous desktop
  2145. */
  2146. if (zzzSetDesktop(ptiCurrent, pdeskTemp, hdeskTemp) == FALSE) {
  2147. goto Error;
  2148. }
  2149. EndAtomicCheck();
  2150. UserAssert(dwCritSecUseSave == gdwCritSecUseCount);
  2151. zzzEndDeferWinEventNotify();
  2152. /*
  2153. * If this is the first desktop, let the worker threads run now
  2154. * that there is someplace to send input to. Reassign the event
  2155. * to handle desktop destruction.
  2156. */
  2157. if (pTerm->pEventInputReady != NULL) {
  2158. /*
  2159. * Set the windowstation for RIT and desktop thread
  2160. * so when EventInputReady is signaled the RIT and the desktop
  2161. * will have a windowstation.
  2162. */
  2163. if (!(pTerm->dwTERMF_Flags & TERMF_NOIO)) {
  2164. gptiRit->pwinsta = pwinsta;
  2165. } else {
  2166. /*
  2167. * let the desktop thread of the system terminal have
  2168. * a rpdesk.
  2169. */
  2170. if (zzzSetDesktop(pTerm->ptiDesktop, pdesk, NULL) == FALSE) {
  2171. goto Error;
  2172. }
  2173. }
  2174. pTerm->ptiDesktop->pwinsta = pwinsta;
  2175. KeSetEvent(pTerm->pEventInputReady, EVENT_INCREMENT, FALSE);
  2176. if (!(pTerm->dwTERMF_Flags & TERMF_NOIO)) {
  2177. LeaveCrit();
  2178. while (grpdeskRitInput == NULL) {
  2179. UserSleep(20);
  2180. RIPMSG0(RIP_WARNING, "Waiting for grpdeskRitInput to be set ...");
  2181. }
  2182. EnterCrit();
  2183. }
  2184. ObDereferenceObject(pTerm->pEventInputReady);
  2185. pTerm->pEventInputReady = NULL;
  2186. }
  2187. /*
  2188. * HACK HACK:
  2189. * LATER
  2190. *
  2191. * If we have a devmode passed in, then switch desktops ...
  2192. */
  2193. if (ccxlpdevmode) {
  2194. TRACE_INIT(("xxxCreateDesktop: about to call switch desktop\n"));
  2195. bSuccess = xxxSwitchDesktop(pwinsta, pdesk, SDF_CREATENEW);
  2196. UserAssertMsg1(bSuccess,
  2197. "Failed to switch desktop 0x%p on create", pdesk);
  2198. } else if (pTerm == &gTermIO) {
  2199. UserAssert(grpdeskRitInput != NULL);
  2200. /*
  2201. * Force the window to the bottom of the z-order if there
  2202. * is an active desktop so any drawing done on the desktop
  2203. * window will not be seen. This will also allow
  2204. * IsWindowVisible to work for apps on invisible
  2205. * desktops.
  2206. */
  2207. ThreadLockWithPti(ptiCurrent, pwndDesktop, &tlpwnd);
  2208. xxxSetWindowPos(pwndDesktop, PWND_BOTTOM, 0, 0, 0, 0,
  2209. SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOMOVE |
  2210. SWP_NOREDRAW | SWP_NOSIZE | SWP_NOSENDCHANGING);
  2211. ThreadUnlock(&tlpwnd);
  2212. }
  2213. /*
  2214. * If it was null when we came in, make it null going out, or else
  2215. * we'll have the wrong desktop selected into this.
  2216. */
  2217. if (fWasNull)
  2218. UnlockDesktop(&ptiCurrent->ppi->rpdeskStartup,
  2219. LDU_PPI_DESKSTARTUP1, (ULONG_PTR)(ptiCurrent->ppi));
  2220. /*
  2221. * Create the disconnect desktop for the console session too.
  2222. */
  2223. if (gspdeskDisconnect == NULL && pdesk == grpdeskLogon) {
  2224. UserAssert(hdesk != NULL);
  2225. /*
  2226. * Create the 'disconnect' desktop
  2227. */
  2228. if (!xxxCreateDisconnectDesktop(hwinsta, pwinsta)) {
  2229. RIPMSG0(RIP_WARNING, "Failed to create the 'disconnect' desktop");
  2230. LogDesktop(pdesk, LD_DEREF_FN_CREATEDESKTOP3, FALSE, (ULONG_PTR)PtiCurrent());
  2231. PopW32ThreadLock(&tlW32Desktop);
  2232. ObDereferenceObject(pdesk);
  2233. xxxCloseDesktop(hdesk, KernelMode);
  2234. return NULL;
  2235. }
  2236. /*
  2237. * Signal that the disconnect desktop got created.
  2238. */
  2239. KeSetEvent(gpEventDiconnectDesktop, EVENT_INCREMENT, FALSE);
  2240. HYDRA_HINT(HH_DISCONNECTDESKTOP);
  2241. }
  2242. Cleanup:
  2243. LogDesktop(pdesk, LD_DEREF_FN_CREATEDESKTOP3, FALSE, (ULONG_PTR)PtiCurrent());
  2244. PopW32ThreadLock(&tlW32Desktop);
  2245. ObDereferenceObject(pdesk);
  2246. TRACE_INIT(("xxxCreateDesktop: Leaving\n"));
  2247. if (hdesk != NULL) {
  2248. SetHandleFlag(hdesk, HF_PROTECTED, TRUE);
  2249. }
  2250. return hdesk;
  2251. Error:
  2252. EndAtomicCheck();
  2253. UserAssert(dwCritSecUseSave == gdwCritSecUseCount);
  2254. if (pwndTooltip != NULL) {
  2255. xxxDestroyWindow(pwndTooltip);
  2256. Unlock(&pdesk->spwndTooltip);
  2257. }
  2258. if (pwndMessage != NULL) {
  2259. xxxDestroyWindow(pwndMessage);
  2260. Unlock(&pdesk->spwndMessage);
  2261. }
  2262. if (pwndDesktop != NULL) {
  2263. xxxDestroyWindow(pwndDesktop);
  2264. Unlock(&pdi->spwnd);
  2265. Unlock(&gspwndFullScreen);
  2266. }
  2267. /*
  2268. * Restore caller's ppi
  2269. */
  2270. PtiCurrent()->ppi = ppiSave;
  2271. UserAssert(ptiCurrent->TIF_flags & TIF_DISABLEHOOKS);
  2272. ptiCurrent->TIF_flags = (ptiCurrent->TIF_flags & ~TIF_DISABLEHOOKS) | dwDisableHooks;
  2273. zzzSetDesktop(ptiCurrent, pdeskTemp, hdeskTemp);
  2274. CloseProtectedHandle(hdesk);
  2275. hdesk = NULL;
  2276. zzzEndDeferWinEventNotify();
  2277. /*
  2278. * If it was null when we came in, make it null going out, or else
  2279. * we'll have the wrong desktop selected into this.
  2280. */
  2281. if (fWasNull) {
  2282. UnlockDesktop(&ptiCurrent->ppi->rpdeskStartup,
  2283. LDU_PPI_DESKSTARTUP1,
  2284. (ULONG_PTR)ptiCurrent->ppi);
  2285. }
  2286. goto Cleanup;
  2287. }
  2288. /***************************************************************************\
  2289. * ParseDesktop
  2290. *
  2291. * Parse a desktop path.
  2292. *
  2293. * History:
  2294. * 14-Jun-1995 JimA Created.
  2295. \***************************************************************************/
  2296. NTSTATUS ParseDesktop(
  2297. PVOID pContainerObject,
  2298. POBJECT_TYPE pObjectType,
  2299. PACCESS_STATE pAccessState,
  2300. KPROCESSOR_MODE AccessMode,
  2301. ULONG Attributes,
  2302. PUNICODE_STRING pstrCompleteName,
  2303. PUNICODE_STRING pstrRemainingName,
  2304. PVOID Context,
  2305. PSECURITY_QUALITY_OF_SERVICE pqos,
  2306. PVOID *pObject)
  2307. {
  2308. PWINDOWSTATION pwinsta = pContainerObject;
  2309. PDESKTOP pdesk;
  2310. PUNICODE_STRING pstrName;
  2311. NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
  2312. *pObject = NULL;
  2313. if (Context && ((PDESKTOP_CONTEXT)Context)->dwCallerSessionId != gSessionId) {
  2314. /*
  2315. * Windows Bug: 418526:
  2316. * If it's a creation request from the other session,
  2317. * we have to bail out ASAP.
  2318. */
  2319. RIPMSGF1(RIP_WARNING,
  2320. "Rejecting desktop creation attempt from other session (%d)",
  2321. ((PDESKTOP_CONTEXT)Context)->dwCallerSessionId);
  2322. return STATUS_INVALID_PARAMETER;
  2323. }
  2324. BEGIN_REENTERCRIT();
  2325. UserAssert(OBJECT_TO_OBJECT_HEADER(pContainerObject)->Type == *ExWindowStationObjectType);
  2326. UserAssert(pObjectType == *ExDesktopObjectType);
  2327. /*
  2328. * See if the desktop exists
  2329. */
  2330. for (pdesk = pwinsta->rpdeskList; pdesk != NULL; pdesk = pdesk->rpdeskNext) {
  2331. pstrName = POBJECT_NAME(pdesk);
  2332. if (pstrName && RtlEqualUnicodeString(pstrRemainingName, pstrName,
  2333. (BOOLEAN)((Attributes & OBJ_CASE_INSENSITIVE) != 0))) {
  2334. if (Context != NULL) {
  2335. if (!(Attributes & OBJ_OPENIF)) {
  2336. /*
  2337. * We are attempting to create a desktop and one
  2338. * already exists.
  2339. */
  2340. Status = STATUS_OBJECT_NAME_COLLISION;
  2341. goto Exit;
  2342. } else {
  2343. Status = STATUS_OBJECT_NAME_EXISTS;
  2344. }
  2345. } else {
  2346. Status = STATUS_SUCCESS;
  2347. }
  2348. ObReferenceObject(pdesk);
  2349. *pObject = pdesk;
  2350. goto Exit;
  2351. }
  2352. }
  2353. /*
  2354. * Handle creation request
  2355. */
  2356. if (Context != NULL) {
  2357. Status = xxxCreateDesktop2(pContainerObject,
  2358. pAccessState,
  2359. AccessMode,
  2360. pstrRemainingName,
  2361. Context,
  2362. pObject);
  2363. }
  2364. Exit:
  2365. END_REENTERCRIT();
  2366. return Status;
  2367. UNREFERENCED_PARAMETER(pObjectType);
  2368. UNREFERENCED_PARAMETER(pstrCompleteName);
  2369. UNREFERENCED_PARAMETER(pqos);
  2370. }
  2371. /***************************************************************************\
  2372. * DestroyDesktop
  2373. *
  2374. * Called upon last close of a desktop to remove the desktop from the
  2375. * desktop list and free all desktop resources.
  2376. *
  2377. * History:
  2378. * 08-Dec-1993 JimA Created.
  2379. \***************************************************************************/
  2380. BOOL DestroyDesktop(
  2381. PDESKTOP pdesk)
  2382. {
  2383. PWINDOWSTATION pwinsta = pdesk->rpwinstaParent;
  2384. PTERMINAL pTerm;
  2385. PDESKTOP *ppdesk;
  2386. if (pdesk->dwDTFlags & DF_DESTROYED) {
  2387. RIPMSG1(RIP_WARNING, "DestroyDesktop: Already destroyed:%#p", pdesk);
  2388. return FALSE;
  2389. }
  2390. /*
  2391. * Unlink the desktop, if it has not yet been unlinked.
  2392. */
  2393. if (pwinsta != NULL) {
  2394. ppdesk = &pwinsta->rpdeskList;
  2395. while (*ppdesk != NULL && *ppdesk != pdesk) {
  2396. ppdesk = &((*ppdesk)->rpdeskNext);
  2397. }
  2398. if (*ppdesk != NULL) {
  2399. /*
  2400. * remove desktop from the list
  2401. */
  2402. LockDesktop(ppdesk, pdesk->rpdeskNext, LDL_WINSTA_DESKLIST2, (ULONG_PTR)pwinsta);
  2403. UnlockDesktop(&pdesk->rpdeskNext, LDU_DESK_DESKNEXT, (ULONG_PTR)pwinsta);
  2404. }
  2405. }
  2406. /*
  2407. * Link it into the destruction list and signal the desktop thread.
  2408. */
  2409. pTerm = pwinsta->pTerm;
  2410. LockDesktop(&pdesk->rpdeskNext, pTerm->rpdeskDestroy, LDL_DESK_DESKNEXT2, 0);
  2411. LockDesktop(&pTerm->rpdeskDestroy, pdesk, LDL_TERM_DESKDESTROY2, (ULONG_PTR)pTerm);
  2412. KeSetEvent(pTerm->pEventDestroyDesktop, EVENT_INCREMENT, FALSE);
  2413. pdesk->dwDTFlags |= DF_DESTROYED;
  2414. TRACE_DESKTOP(("pdesk %#p '%ws' marked as destroyed\n", pdesk, GetDesktopName(pdesk)));
  2415. return TRUE;
  2416. }
  2417. /***************************************************************************\
  2418. * FreeDesktop
  2419. *
  2420. * Called to free desktop object and section when last lock is released.
  2421. *
  2422. * History:
  2423. * 08-Dec-1993 JimA Created.
  2424. \***************************************************************************/
  2425. NTSTATUS FreeDesktop(
  2426. PKWIN32_DELETEMETHOD_PARAMETERS pDeleteParams)
  2427. {
  2428. PDESKTOP pdesk = (PDESKTOP)pDeleteParams->Object;
  2429. NTSTATUS Status = STATUS_SUCCESS;
  2430. BEGIN_REENTERCRIT();
  2431. UserAssert(OBJECT_TO_OBJECT_HEADER(pDeleteParams->Object)->Type == *ExDesktopObjectType);
  2432. #ifdef LOGDESKTOPLOCKS
  2433. if (pdesk->pLog != NULL) {
  2434. /*
  2435. * By the time we get here the lock count for lock/unlock
  2436. * tracking code should be 0
  2437. */
  2438. if (pdesk->nLockCount != 0) {
  2439. RIPMSG3(RIP_WARNING,
  2440. "FreeDesktop pdesk %#p, pLog %#p, nLockCount %d should be 0",
  2441. pdesk, pdesk->pLog, pdesk->nLockCount);
  2442. }
  2443. UserFreePool(pdesk->pLog);
  2444. pdesk->pLog = NULL;
  2445. }
  2446. #endif
  2447. #if DBG
  2448. if (pdesk->pDeskInfo && (pdesk->pDeskInfo->spwnd != NULL)) {
  2449. /*
  2450. * Assert if the desktop has a desktop window but the flag
  2451. * that says the window is destroyed is not set.
  2452. */
  2453. UserAssert(pdesk->dwDTFlags & DF_DESKWNDDESTROYED);
  2454. }
  2455. #endif
  2456. /*
  2457. * Mark the desktop as dying. Make sure we aren't recursing.
  2458. */
  2459. UserAssert(!(pdesk->dwDTFlags & DF_DYING));
  2460. pdesk->dwDTFlags |= DF_DYING;
  2461. #ifdef DEBUG_DESK
  2462. ValidateDesktop(pdesk);
  2463. #endif
  2464. /*
  2465. * If the desktop is mapped into CSR, unmap it. Note the
  2466. * handle count values passed in will cause the desktop
  2467. * to be unmapped and skip the desktop destruction tests.
  2468. */
  2469. FreeView(gpepCSRSS, pdesk);
  2470. if (pdesk->pheapDesktop != NULL) {
  2471. PVOID hheap = Win32HeapGetHandle(pdesk->pheapDesktop);
  2472. Win32HeapDestroy(pdesk->pheapDesktop);
  2473. Status = Win32UnmapViewInSessionSpace(hheap);
  2474. UserAssert(NT_SUCCESS(Status));
  2475. Win32DestroySection(pdesk->hsectionDesktop);
  2476. }
  2477. UnlockWinSta(&pdesk->rpwinstaParent);
  2478. DbgTrackRemoveDesktop(pdesk);
  2479. END_REENTERCRIT();
  2480. return Status;
  2481. }
  2482. /***************************************************************************\
  2483. * CreateDesktopHeap
  2484. *
  2485. * Create a new desktop heap
  2486. *
  2487. * History:
  2488. * 27-Jul-1992 JimA Created.
  2489. \***************************************************************************/
  2490. HANDLE CreateDesktopHeap(
  2491. PWIN32HEAP* ppheapRet,
  2492. ULONG ulHeapSize)
  2493. {
  2494. HANDLE hsection;
  2495. LARGE_INTEGER SectionSize;
  2496. SIZE_T ulViewSize;
  2497. NTSTATUS Status;
  2498. PWIN32HEAP pheap;
  2499. PVOID pHeapBase;
  2500. /*
  2501. * Create desktop heap section and map it into the kernel
  2502. */
  2503. SectionSize.QuadPart = ulHeapSize;
  2504. Status = Win32CreateSection(&hsection,
  2505. SECTION_ALL_ACCESS,
  2506. NULL,
  2507. &SectionSize,
  2508. PAGE_EXECUTE_READWRITE,
  2509. SEC_RESERVE,
  2510. NULL,
  2511. NULL,
  2512. TAG_SECTION_DESKTOP);
  2513. if (!NT_SUCCESS(Status)) {
  2514. RIPNTERR0(Status, RIP_WARNING, "Can't create section for desktop heap.");
  2515. return NULL;
  2516. }
  2517. ulViewSize = ulHeapSize;
  2518. pHeapBase = NULL;
  2519. Status = Win32MapViewInSessionSpace(hsection, &pHeapBase, &ulViewSize);
  2520. if (!NT_SUCCESS(Status)) {
  2521. RIPNTERR0(Status,
  2522. RIP_WARNING,
  2523. "Can't map section for desktop heap into system space.");
  2524. goto Error;
  2525. }
  2526. /*
  2527. * Create desktop heap.
  2528. */
  2529. if ((pheap = UserCreateHeap(
  2530. hsection,
  2531. 0,
  2532. pHeapBase,
  2533. ulHeapSize,
  2534. UserCommitDesktopMemory)) == NULL) {
  2535. RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "Can't create Desktop heap.");
  2536. Win32UnmapViewInSessionSpace(pHeapBase);
  2537. Error:
  2538. Win32DestroySection(hsection);
  2539. *ppheapRet = NULL;
  2540. return NULL;
  2541. }
  2542. UserAssert(Win32HeapGetHandle(pheap) == pHeapBase);
  2543. *ppheapRet = pheap;
  2544. return hsection;
  2545. }
  2546. /***************************************************************************\
  2547. * GetDesktopView
  2548. *
  2549. * Determines if a desktop has already been mapped into a process.
  2550. *
  2551. * History:
  2552. * 10-Apr-1995 JimA Created.
  2553. \***************************************************************************/
  2554. PDESKTOPVIEW GetDesktopView(
  2555. PPROCESSINFO ppi,
  2556. PDESKTOP pdesk)
  2557. {
  2558. PDESKTOPVIEW pdv;
  2559. if (ppi->Process != gpepCSRSS && pdesk == NULL) {
  2560. RIPMSG1(RIP_WARNING, "Process 0x%p isn't CSRSS but pdesk is NULL in GetDesktopView", ppi);
  2561. }
  2562. for (pdv = ppi->pdvList; pdv != NULL; pdv = pdv->pdvNext) {
  2563. if (pdv->pdesk == pdesk) {
  2564. break;
  2565. }
  2566. }
  2567. return pdv;
  2568. }
  2569. /***************************************************************************\
  2570. * _MapDesktopObject
  2571. *
  2572. * Maps a desktop object into the client's address space
  2573. *
  2574. * History:
  2575. * 11-Apr-1995 JimA Created.
  2576. \***************************************************************************/
  2577. PVOID _MapDesktopObject(
  2578. HANDLE h)
  2579. {
  2580. PDESKOBJHEAD pobj;
  2581. PDESKTOPVIEW pdv;
  2582. /*
  2583. * Validate the handle
  2584. */
  2585. pobj = HMValidateHandle(h, TYPE_GENERIC);
  2586. if (pobj == NULL) {
  2587. return NULL;
  2588. }
  2589. UserAssert(HMObjectFlags(pobj) & OCF_DESKTOPHEAP);
  2590. /*
  2591. * Locate the client's view of the desktop. Realistically, this should
  2592. * never fail for valid objects.
  2593. */
  2594. pdv = GetDesktopView(PpiCurrent(), pobj->rpdesk);
  2595. if (pdv == NULL) {
  2596. RIPMSG1(RIP_WARNING, "MapDesktopObject: cannot map handle 0x%p", h);
  2597. return NULL;
  2598. }
  2599. UserAssert(pdv->ulClientDelta != 0);
  2600. return (PVOID)((PBYTE)pobj - pdv->ulClientDelta);
  2601. }
  2602. NTSTATUS DesktopOpenProcedure(
  2603. PKWIN32_OPENMETHOD_PARAMETERS pOpenParams)
  2604. {
  2605. PDESKTOP pdesk = (PDESKTOP)pOpenParams->Object;
  2606. /*
  2607. * Make sure we're not opening a handle for a destroy desktop. If this happens,
  2608. * we probably want to fail it.
  2609. */
  2610. if (pdesk->dwDTFlags & DF_DESTROYED) {
  2611. RIPMSG1(RIP_WARNING,
  2612. "DesktopOpenProcedure: Opening a handle to destroyed desktop 0x%p",
  2613. pdesk);
  2614. return STATUS_ACCESS_DENIED;
  2615. }
  2616. /*
  2617. * Allow desktop open cross session only if no special rights granted.
  2618. */
  2619. if (pOpenParams->GrantedAccess & SPECIFIC_RIGHTS_ALL) {
  2620. if (PsGetProcessSessionId(pOpenParams->Process) != pdesk->dwSessionId) {
  2621. return STATUS_ACCESS_DENIED;
  2622. }
  2623. }
  2624. return STATUS_SUCCESS;
  2625. }
  2626. /***************************************************************************\
  2627. * MapDesktop
  2628. *
  2629. * Attempts to map a desktop heap into a process.
  2630. *
  2631. * History:
  2632. * 20-Oct-1994 JimA Created.
  2633. \***************************************************************************/
  2634. NTSTATUS MapDesktop(
  2635. PKWIN32_OPENMETHOD_PARAMETERS pOpenParams)
  2636. {
  2637. PPROCESSINFO ppi;
  2638. PDESKTOP pdesk = (PDESKTOP)pOpenParams->Object;
  2639. SIZE_T ulViewSize;
  2640. LARGE_INTEGER liOffset;
  2641. PDESKTOPVIEW pdvNew;
  2642. PBYTE pheap;
  2643. HANDLE hsectionDesktop;
  2644. PBYTE pClientBase;
  2645. NTSTATUS Status = STATUS_SUCCESS;
  2646. UserAssert(OBJECT_TO_OBJECT_HEADER(pOpenParams->Object)->Type == *ExDesktopObjectType);
  2647. TAGMSG2(DBGTAG_Callout,
  2648. "Mapping desktop 0x%p into process 0x%p",
  2649. pdesk,
  2650. pOpenParams->Process);
  2651. BEGIN_REENTERCRIT();
  2652. /*
  2653. * Ignore handle inheritance because MmMapViewOfSection cannot be called
  2654. * during process creation.
  2655. */
  2656. if (pOpenParams->OpenReason == ObInheritHandle) {
  2657. goto Exit;
  2658. }
  2659. /*
  2660. * If there is no ppi, we can't map the desktop.
  2661. */
  2662. ppi = PpiFromProcess(pOpenParams->Process);
  2663. if (ppi == NULL) {
  2664. goto Exit;
  2665. }
  2666. /*
  2667. * Do this here, before we (potentially) attach to the process, so
  2668. * we know we're in the right context.
  2669. */
  2670. pheap = Win32HeapGetHandle(pdesk->pheapDesktop);
  2671. hsectionDesktop = pdesk->hsectionDesktop;
  2672. /*
  2673. * We should not map a desktop cross session.
  2674. */
  2675. if (PsGetProcessSessionId(pOpenParams->Process) != pdesk->dwSessionId) {
  2676. FRE_RIPMSG2(RIP_ERROR, "MapDesktop: Trying to map desktop %p into"
  2677. " process %p in a differnt session. How we ended up here?",
  2678. pdesk, pOpenParams->Process);
  2679. Status = STATUS_ACCESS_DENIED;
  2680. goto Exit;
  2681. }
  2682. /*
  2683. * If the desktop has already been mapped we're done.
  2684. */
  2685. if (GetDesktopView(ppi, pdesk) != NULL) {
  2686. goto Exit;
  2687. }
  2688. /*
  2689. * Allocate a view of the desktop.
  2690. */
  2691. pdvNew = UserAllocPoolWithQuota(sizeof(*pdvNew), TAG_PROCESSINFO);
  2692. if (pdvNew == NULL) {
  2693. Status = STATUS_NO_MEMORY;
  2694. goto Exit;
  2695. }
  2696. /*
  2697. * Read/write access has been granted. Map the desktop memory into
  2698. * the client process.
  2699. */
  2700. ulViewSize = 0;
  2701. liOffset.QuadPart = 0;
  2702. pClientBase = NULL;
  2703. Status = MmMapViewOfSection(hsectionDesktop,
  2704. pOpenParams->Process,
  2705. &pClientBase,
  2706. 0,
  2707. 0,
  2708. &liOffset,
  2709. &ulViewSize,
  2710. ViewUnmap,
  2711. SEC_NO_CHANGE,
  2712. PAGE_EXECUTE_READ);
  2713. if (!NT_SUCCESS(Status)) {
  2714. RIPMSG1(RIP_WARNING,
  2715. "MapDesktop - failed to map to client process (Status == 0x%x).",
  2716. Status);
  2717. RIPNTERR0(Status, RIP_VERBOSE, "");
  2718. UserFreePool(pdvNew);
  2719. Status = STATUS_NO_MEMORY;
  2720. goto Exit;
  2721. }
  2722. /*
  2723. * Link the view into the ppi.
  2724. */
  2725. pdvNew->pdesk = pdesk;
  2726. pdvNew->ulClientDelta = (ULONG_PTR)(pheap - pClientBase);
  2727. pdvNew->pdvNext = ppi->pdvList;
  2728. ppi->pdvList = pdvNew;
  2729. Exit:
  2730. END_REENTERCRIT();
  2731. return Status;
  2732. }
  2733. VOID FreeView(
  2734. PEPROCESS Process,
  2735. PDESKTOP pdesk)
  2736. {
  2737. PPROCESSINFO ppi;
  2738. NTSTATUS Status;
  2739. PDESKTOPVIEW pdv, *ppdv;
  2740. /*
  2741. * Bug 277291: gpepCSRSS can be NULL when FreeView is
  2742. * called from FreeDesktop.
  2743. */
  2744. if (Process == NULL) {
  2745. return;
  2746. }
  2747. /*
  2748. * If there is no ppi, then the process is gone and nothing needs to be
  2749. * unmapped.
  2750. */
  2751. ppi = PpiFromProcess(Process);
  2752. if (ppi != NULL) {
  2753. KAPC_STATE ApcState;
  2754. BOOL bAttached;
  2755. PBYTE pHeap;
  2756. /*
  2757. * Before potentially attaching to this process, we need to store
  2758. * away this pointer. However, we don't know that this desktop is
  2759. * even mapped into this process (previously, Win32HeapGetHandle()
  2760. * would only have been called if GetDesktopView returned a non-NULL
  2761. * value, meaning the desktop is mapped into the process). Thus,
  2762. * we need to explicitly check the desktop's heap ptr before we
  2763. * access it.
  2764. */
  2765. if (pdesk->pheapDesktop) {
  2766. pHeap = (PBYTE)Win32HeapGetHandle(pdesk->pheapDesktop);
  2767. } else {
  2768. pHeap = NULL;
  2769. }
  2770. /*
  2771. * We should not have any mapped views cross session.
  2772. */
  2773. if (PsGetProcessSessionId(Process) != pdesk->dwSessionId) {
  2774. KeStackAttachProcess(PsGetProcessPcb(Process), &ApcState);
  2775. bAttached = TRUE;
  2776. } else {
  2777. bAttached = FALSE;
  2778. }
  2779. pdv = GetDesktopView(ppi, pdesk);
  2780. /*
  2781. * Because mapping cannot be done when a handle is inherited, there
  2782. * may not be a view of the desktop. Only unmap if there is a view.
  2783. */
  2784. if (pdv != NULL) {
  2785. UserAssert(pHeap != NULL);
  2786. if (PsGetProcessSessionId(Process) != pdesk->dwSessionId) {
  2787. FRE_RIPMSG2(RIP_ERROR, "FreeView: Trying to free desktop "
  2788. "%p view into process %p in differnt session. "
  2789. "How we ended up here?",
  2790. pdesk, Process);
  2791. }
  2792. Status = MmUnmapViewOfSection(Process,
  2793. pHeap - pdv->ulClientDelta);
  2794. UserAssert(NT_SUCCESS(Status) || Status == STATUS_PROCESS_IS_TERMINATING);
  2795. if (!NT_SUCCESS(Status)) {
  2796. RIPMSG1(RIP_WARNING, "FreeView unmap status = 0x%x", Status);
  2797. }
  2798. /*
  2799. * Unlink and delete the view.
  2800. */
  2801. for (ppdv = &ppi->pdvList; *ppdv && *ppdv != pdv;
  2802. ppdv = &(*ppdv)->pdvNext) {
  2803. /* do nothing */;
  2804. }
  2805. UserAssert(*ppdv);
  2806. *ppdv = pdv->pdvNext;
  2807. UserFreePool(pdv);
  2808. }
  2809. /*
  2810. * No thread in this process should be on this desktop.
  2811. */
  2812. DbgCheckForThreadsOnDesktop(ppi, pdesk);
  2813. if (bAttached) {
  2814. KeUnstackDetachProcess(&ApcState);
  2815. }
  2816. }
  2817. }
  2818. NTSTATUS UnmapDesktop(
  2819. PKWIN32_CLOSEMETHOD_PARAMETERS pCloseParams)
  2820. {
  2821. PDESKTOP pdesk = (PDESKTOP)pCloseParams->Object;
  2822. BEGIN_REENTERCRIT();
  2823. UserAssert(OBJECT_TO_OBJECT_HEADER(pCloseParams->Object)->Type == *ExDesktopObjectType);
  2824. TAGMSG4(DBGTAG_Callout,
  2825. "Unmapping desktop 0x%p from process 0x%p (0x%x <-> 0x%x)",
  2826. pdesk,
  2827. pCloseParams->Process,
  2828. PsGetProcessSessionId(pCloseParams->Process),
  2829. pdesk->dwSessionId);
  2830. /*
  2831. * Update cSystemHandles with the correct information.
  2832. */
  2833. pCloseParams->SystemHandleCount = (ULONG)(OBJECT_TO_OBJECT_HEADER(pCloseParams->Object)->HandleCount) + 1;
  2834. /*
  2835. * Only unmap the desktop if this is the last process handle and
  2836. * the process is not CSR.
  2837. */
  2838. if (pCloseParams->ProcessHandleCount == 1 && pCloseParams->Process != gpepCSRSS) {
  2839. FreeView(pCloseParams->Process, pdesk);
  2840. }
  2841. if (pCloseParams->SystemHandleCount > 2) {
  2842. goto Exit;
  2843. }
  2844. if (pCloseParams->SystemHandleCount == 2 && pdesk->dwConsoleThreadId != 0) {
  2845. /*
  2846. * If a console thread exists and we're down to two handles, it means
  2847. * that the last application handle to the desktop is being closed.
  2848. * Terminate the console thread so the desktop can be freed.
  2849. */
  2850. TerminateConsole(pdesk);
  2851. } else if (pCloseParams->SystemHandleCount == 1) {
  2852. /*
  2853. * If this is the last handle to this desktop in the system,
  2854. * destroy the desktop.
  2855. */
  2856. /*
  2857. * No pti should be linked to this desktop.
  2858. */
  2859. if ((&pdesk->PtiList != pdesk->PtiList.Flink)
  2860. || (&pdesk->PtiList != pdesk->PtiList.Blink)) {
  2861. RIPMSG1(RIP_WARNING, "UnmapDesktop: PtiList not Empty. pdesk:%#p", pdesk);
  2862. }
  2863. DestroyDesktop(pdesk);
  2864. }
  2865. Exit:
  2866. END_REENTERCRIT();
  2867. return STATUS_SUCCESS;
  2868. }
  2869. /***************************************************************************\
  2870. * OkayToCloseDesktop
  2871. *
  2872. * We can only close desktop handles if they're not in use.
  2873. *
  2874. * History:
  2875. * 08-Feb-1999 JerrySh Created.
  2876. \***************************************************************************/
  2877. NTSTATUS OkayToCloseDesktop(
  2878. PKWIN32_OKAYTOCLOSEMETHOD_PARAMETERS pOkCloseParams)
  2879. {
  2880. PDESKTOP pdesk = (PDESKTOP)pOkCloseParams->Object;
  2881. UserAssert(OBJECT_TO_OBJECT_HEADER(pOkCloseParams->Object)->Type == *ExDesktopObjectType);
  2882. /*
  2883. * Kernel mode code can close anything.
  2884. */
  2885. if (pOkCloseParams->PreviousMode == KernelMode) {
  2886. return STATUS_SUCCESS;
  2887. /*
  2888. * Do not allow a user mode process to close a kernel handle of ours.
  2889. * It shouldn't. In addition, if this happens cross-session, we will try to
  2890. * attach to the system processes and will bugcheck since the seesion
  2891. * address space is not mapped into it. Same for the session manager
  2892. * process. See bug# 759533.
  2893. */
  2894. } else if (PsGetProcessSessionIdEx(pOkCloseParams->Process) == -1) {
  2895. return STATUS_ACCESS_DENIED;
  2896. }
  2897. /*
  2898. * We can't close the desktop if we're still initializing it.
  2899. */
  2900. if (!(pdesk->dwDTFlags & DF_DESKCREATED)) {
  2901. RIPMSG1(RIP_WARNING, "Trying to close desktop %#p during initialization", pdesk);
  2902. return STATUS_UNSUCCESSFUL;
  2903. }
  2904. /*
  2905. * We can't close a desktop that's being used.
  2906. */
  2907. if (CheckHandleInUse(pOkCloseParams->Handle) || CheckHandleFlag(pOkCloseParams->Process, pdesk->dwSessionId, pOkCloseParams->Handle, HF_PROTECTED)) {
  2908. RIPMSG1(RIP_WARNING, "Trying to close desktop %#p while still in use", pdesk);
  2909. return STATUS_UNSUCCESSFUL;
  2910. }
  2911. return STATUS_SUCCESS;
  2912. }
  2913. /***************************************************************************\
  2914. * xxxUserResetDisplayDevice
  2915. *
  2916. * Called to reset the display device after a switch to another device.
  2917. * Used when opening a new device, or when switching back to an old desktop
  2918. *
  2919. * History:
  2920. * 31-May-1994 AndreVa Created.
  2921. \***************************************************************************/
  2922. VOID xxxUserResetDisplayDevice(
  2923. VOID)
  2924. {
  2925. /*
  2926. * Handle early system initialization gracefully.
  2927. */
  2928. if (grpdeskRitInput != NULL) {
  2929. TL tlpwnd;
  2930. gpqCursor = NULL;
  2931. /*
  2932. * Note that we want to clip the cursor here *before* redrawing the
  2933. * desktop window. Otherwise, when we callback apps might encounter
  2934. * a cursor position that doesn't make sense.
  2935. */
  2936. zzzInternalSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y);
  2937. SetPointer(TRUE);
  2938. UserAssert(grpdeskRitInput != NULL);
  2939. ThreadLock(grpdeskRitInput->pDeskInfo->spwnd, &tlpwnd);
  2940. xxxRedrawWindow(grpdeskRitInput->pDeskInfo->spwnd,
  2941. NULL,
  2942. NULL,
  2943. RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW |
  2944. RDW_ALLCHILDREN);
  2945. ThreadUnlock(&tlpwnd);
  2946. }
  2947. }
  2948. /***************************************************************************\
  2949. * OpenDesktopCompletion
  2950. *
  2951. * Verifies that a given desktop has successfully opened.
  2952. *
  2953. * History:
  2954. * 03-Oct-1995 JimA Created.
  2955. \***************************************************************************/
  2956. BOOL OpenDesktopCompletion(
  2957. PDESKTOP pdesk,
  2958. HDESK hdesk,
  2959. DWORD dwFlags,
  2960. BOOL* pbShutDown)
  2961. {
  2962. PPROCESSINFO ppi = PpiCurrent();
  2963. PWINDOWSTATION pwinsta;
  2964. /*
  2965. * Fail if the windowstation is locked.
  2966. */
  2967. pwinsta = pdesk->rpwinstaParent;
  2968. if (pwinsta->dwWSF_Flags & WSF_OPENLOCK &&
  2969. PsGetProcessId(ppi->Process) != gpidLogon) {
  2970. LUID luidCaller;
  2971. NTSTATUS Status;
  2972. /*
  2973. * If logoff is occuring and the caller does not
  2974. * belong to the session that is ending, allow the
  2975. * open to proceed.
  2976. */
  2977. Status = GetProcessLuid(NULL, &luidCaller);
  2978. if (!NT_SUCCESS(Status) ||
  2979. (pwinsta->dwWSF_Flags & WSF_REALSHUTDOWN) ||
  2980. RtlEqualLuid(&luidCaller, &pwinsta->luidEndSession)) {
  2981. RIPERR0(ERROR_BUSY, RIP_WARNING, "OpenDesktopCompletion failed");
  2982. /*
  2983. * Set the shut down flag.
  2984. */
  2985. *pbShutDown = TRUE;
  2986. return FALSE;
  2987. }
  2988. }
  2989. SetHandleFlag(hdesk, HF_DESKTOPHOOK, dwFlags & DF_ALLOWOTHERACCOUNTHOOK);
  2990. return TRUE;
  2991. }
  2992. /***************************************************************************\
  2993. * _OpenDesktop (API)
  2994. *
  2995. * Open a desktop object.
  2996. *
  2997. * History:
  2998. * 16-Jan-1991 JimA Created scaffold code.
  2999. * 20-Apr-2001 Mohamed Removed xxx prefix since the function doesn't leave
  3000. * the Critical Section.
  3001. \***************************************************************************/
  3002. HDESK _OpenDesktop(
  3003. POBJECT_ATTRIBUTES ccxObjA,
  3004. KPROCESSOR_MODE AccessMode,
  3005. DWORD dwFlags,
  3006. DWORD dwDesiredAccess,
  3007. BOOL* pbShutDown)
  3008. {
  3009. HDESK hdesk;
  3010. PDESKTOP pdesk;
  3011. NTSTATUS Status;
  3012. /*
  3013. * Require read/write access
  3014. */
  3015. dwDesiredAccess |= DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS;
  3016. /*
  3017. * Open the desktop -- Ob routines capture Obj attributes.
  3018. */
  3019. Status = ObOpenObjectByName(
  3020. ccxObjA,
  3021. *ExDesktopObjectType,
  3022. AccessMode,
  3023. NULL,
  3024. dwDesiredAccess,
  3025. NULL,
  3026. &hdesk);
  3027. if (!NT_SUCCESS(Status)) {
  3028. RIPNTERR1(Status, RIP_VERBOSE, "_OpenDesktop: ObOpenObjectByName failed with Status: 0x%x.", Status);
  3029. return NULL;
  3030. }
  3031. /*
  3032. * Reference the desktop
  3033. */
  3034. Status = ObReferenceObjectByHandle(
  3035. hdesk,
  3036. 0,
  3037. *ExDesktopObjectType,
  3038. AccessMode,
  3039. &pdesk,
  3040. NULL);
  3041. if (!NT_SUCCESS(Status)) {
  3042. RIPNTERR1(Status, RIP_VERBOSE, "_OpenDesktop: ObReferenceObjectByHandle failed with Status: 0x%x.", Status);
  3043. Error:
  3044. CloseProtectedHandle(hdesk);
  3045. return NULL;
  3046. }
  3047. if (pdesk->dwSessionId != gSessionId) {
  3048. RIPNTERR1(STATUS_INVALID_HANDLE, RIP_WARNING,
  3049. "_OpenDesktop pdesk %#p belongs to a different session",
  3050. pdesk);
  3051. ObDereferenceObject(pdesk);
  3052. goto Error;
  3053. }
  3054. LogDesktop(pdesk, LD_REF_FN_OPENDESKTOP, TRUE, (ULONG_PTR)PtiCurrent());
  3055. /*
  3056. * Complete the desktop open
  3057. */
  3058. if (!OpenDesktopCompletion(pdesk, hdesk, dwFlags, pbShutDown)) {
  3059. CloseProtectedHandle(hdesk);
  3060. hdesk = NULL;
  3061. }
  3062. LogDesktop(pdesk, LD_DEREF_FN_OPENDESKTOP, FALSE, (ULONG_PTR)PtiCurrent());
  3063. ObDereferenceObject(pdesk);
  3064. if (hdesk != NULL) {
  3065. SetHandleFlag(hdesk, HF_PROTECTED, TRUE);
  3066. }
  3067. return hdesk;
  3068. }
  3069. /***************************************************************************\
  3070. * xxxSwitchDesktop (API)
  3071. *
  3072. * Switch input focus to another desktop and bring it to the top of the
  3073. * desktops
  3074. *
  3075. * dwFlags:
  3076. * SDF_CREATENEW is set when a new desktop has been created on the device, and
  3077. * when we do not want to send another enable\disable
  3078. *
  3079. * SDF_SLOVERRIDE is set when we want to ignore WSF_SWITCHLOCK being set on
  3080. * the desktop's winsta.
  3081. *
  3082. * History:
  3083. * 16-Jan-1991 JimA Created scaffold code.
  3084. * 11-Oct-2000 JasonSch Added SDF_SLOVERRIDE flag.
  3085. \***************************************************************************/
  3086. BOOL xxxSwitchDesktop(
  3087. PWINDOWSTATION pwinsta,
  3088. PDESKTOP pdesk,
  3089. DWORD dwFlags)
  3090. {
  3091. PETHREAD Thread;
  3092. PWND pwndSetForeground;
  3093. TL tlpwndChild;
  3094. TL tlpwnd;
  3095. TL tlhdesk;
  3096. PQ pq;
  3097. BOOL bUpdateCursor = FALSE;
  3098. PLIST_ENTRY pHead, pEntry;
  3099. PTHREADINFO pti;
  3100. PTHREADINFO ptiCurrent = PtiCurrent();
  3101. PTERMINAL pTerm;
  3102. NTSTATUS Status;
  3103. HDESK hdesk;
  3104. BOOL bRet = TRUE;
  3105. CheckCritIn();
  3106. UserAssert(IsWinEventNotifyDeferredOK());
  3107. if (pdesk == NULL) {
  3108. return FALSE;
  3109. }
  3110. if (pdesk == grpdeskRitInput) {
  3111. return TRUE;
  3112. }
  3113. if (pdesk->dwDTFlags & DF_DESTROYED) {
  3114. RIPMSG1(RIP_ERROR, "xxxSwitchDesktop: destroyed:%#p", pdesk);
  3115. return FALSE;
  3116. }
  3117. UserAssert(!(pdesk->dwDTFlags & (DF_DESKWNDDESTROYED | DF_DYING)));
  3118. if (pwinsta == NULL)
  3119. pwinsta = pdesk->rpwinstaParent;
  3120. /*
  3121. * Get the windowstation, and assert if this process doesn't have one.
  3122. */
  3123. UserAssert(pwinsta);
  3124. if (pwinsta == NULL) {
  3125. RIPMSG1(RIP_WARNING,
  3126. "xxxSwitchDesktop: failed for pwinsta NULL pdesk %#p", pdesk);
  3127. return FALSE;
  3128. }
  3129. /*
  3130. * Don't allow invisible desktops to become active
  3131. */
  3132. if (pwinsta->dwWSF_Flags & WSF_NOIO) {
  3133. RIPMSG1(RIP_VERBOSE,
  3134. "xxxSwitchDesktop: failed for NOIO pdesk %#p", pdesk);
  3135. return FALSE;
  3136. }
  3137. pTerm = pwinsta->pTerm;
  3138. UserAssert(grpdeskRitInput == pwinsta->pdeskCurrent);
  3139. TRACE_INIT(("xxxSwitchDesktop: Entering, desktop = %ws, createdNew = %01lx\n", POBJECT_NAME(pdesk), (DWORD)((dwFlags & SDF_CREATENEW) != 0)));
  3140. if (grpdeskRitInput) {
  3141. TRACE_INIT((" coming from desktop = %ws\n", POBJECT_NAME(grpdeskRitInput)));
  3142. }
  3143. /*
  3144. * Wait if the logon has the windowstation locked
  3145. */
  3146. Thread = PsGetCurrentThread();
  3147. /*
  3148. * Allow switches to the disconnected desktop
  3149. */
  3150. if (pdesk != gspdeskDisconnect) {
  3151. if (!PsIsSystemThread(Thread) && pdesk != grpdeskLogon &&
  3152. (((pwinsta->dwWSF_Flags & WSF_SWITCHLOCK) != 0) &&
  3153. (dwFlags & SDF_SLOVERRIDE) == 0) &&
  3154. PsGetThreadProcessId(Thread) != gpidLogon) {
  3155. return FALSE;
  3156. }
  3157. }
  3158. /*
  3159. * We don't allow switching away from the disconnect desktop.
  3160. */
  3161. if (gbDesktopLocked && ((!gspdeskDisconnect) || (pdesk != gspdeskDisconnect))) {
  3162. TRACE_DESKTOP(("Attempt to switch away from the disconnect desktop\n"));
  3163. /*
  3164. * we should not lock this global !!! clupu
  3165. */
  3166. LockDesktop(&gspdeskShouldBeForeground, pdesk, LDL_DESKSHOULDBEFOREGROUND1, 0);
  3167. return TRUE;
  3168. }
  3169. /*
  3170. * HACKHACK LATER !!!
  3171. * Where should we really switch the desktop ...
  3172. * And we need to send repaint messages to everyone...
  3173. *
  3174. */
  3175. UserAssert(grpdeskRitInput == pwinsta->pdeskCurrent);
  3176. if ((dwFlags & SDF_CREATENEW) == 0 && grpdeskRitInput &&
  3177. (grpdeskRitInput->pDispInfo->hDev != pdesk->pDispInfo->hDev)) {
  3178. if (grpdeskRitInput->pDispInfo == gpDispInfo) {
  3179. if (!SafeDisableMDEV()) {
  3180. RIPMSG1(RIP_WARNING, "xxxSwitchDesktop: DrvDisableMDEV failed for pdesk %#p",
  3181. grpdeskRitInput);
  3182. return FALSE;
  3183. }
  3184. } else if (!DrvDisableMDEV(grpdeskRitInput->pDispInfo->pmdev, TRUE)) {
  3185. RIPMSG1(RIP_WARNING, "xxxSwitchDesktop: DrvDisableMDEV failed for pdesk %#p",
  3186. grpdeskRitInput);
  3187. return FALSE;
  3188. }
  3189. SafeEnableMDEV();
  3190. bUpdateCursor = TRUE;
  3191. }
  3192. /*
  3193. * Grab a handle to the pdesk.
  3194. */
  3195. Status = ObOpenObjectByPointer(pdesk,
  3196. OBJ_KERNEL_HANDLE,
  3197. NULL,
  3198. EVENT_ALL_ACCESS,
  3199. NULL,
  3200. KernelMode,
  3201. &hdesk);
  3202. if (!NT_SUCCESS(Status)) {
  3203. RIPMSG2(RIP_WARNING, "Could not get a handle for pdesk %#p Status 0x%x",
  3204. pdesk, Status);
  3205. return FALSE;
  3206. }
  3207. ThreadLockDesktopHandle(ptiCurrent, &tlhdesk, hdesk);
  3208. #if DBG
  3209. /*
  3210. * The current desktop is now the new desktop.
  3211. */
  3212. pwinsta->pdeskCurrent = pdesk;
  3213. #endif
  3214. /*
  3215. * Kill any journalling that is occuring. If an app is journaling to the
  3216. * CoolSwitch window, zzzCancelJournalling() will kill the window.
  3217. */
  3218. if (ptiCurrent->rpdesk != NULL) {
  3219. zzzCancelJournalling();
  3220. }
  3221. /*
  3222. * Remove the cool switch window if it's on the RIT. Sending the message
  3223. * is OK because the destination is the RIT, which should never block.
  3224. */
  3225. if (gspwndAltTab != NULL) {
  3226. TL tlpwndT;
  3227. ThreadLockWithPti(ptiCurrent, gspwndAltTab, &tlpwndT);
  3228. xxxSendMessage(gspwndAltTab, WM_CLOSE, 0, 0);
  3229. ThreadUnlock(&tlpwndT);
  3230. }
  3231. /*
  3232. * Remove all trace of previous active window.
  3233. */
  3234. if (grpdeskRitInput != NULL) {
  3235. UserAssert(grpdeskRitInput->spwndForeground == NULL);
  3236. if (grpdeskRitInput->pDeskInfo->spwnd != NULL) {
  3237. if (gpqForeground != NULL) {
  3238. Lock(&grpdeskRitInput->spwndForeground,
  3239. gpqForeground->spwndActive);
  3240. /*
  3241. * This is an API so ptiCurrent can pretty much be on any
  3242. * state. It might not be in grpdeskRitInput (current) or
  3243. * pdesk (the one we're switching to). It can be sharing its
  3244. * queue with other threads from another desktop. This is
  3245. * tricky because we're calling xxxSetForegroundWindow and
  3246. * xxxSetWindowPos but PtiCurrent might be on whatever
  3247. * desktop. We cannot cleanly switch ptiCurrent to the
  3248. * proper desktop because it might be sharing its queue with
  3249. * other threads, own windows, hooks, etc. So this is kind
  3250. * of broken.
  3251. *
  3252. * Old Comment:
  3253. * Fixup the current-thread (system) desktop. This could be
  3254. * needed in case the xxxSetForegroundWindow() calls
  3255. * xxxDeactivate(). There is logic in their which requires
  3256. * the desktop. This is only needed temporarily for this case.
  3257. *
  3258. * We would only go into xxxDeactivate if ptiCurrent->pq ==
  3259. * qpqForeground; but if this is the case, then ptiCurrent
  3260. * must be in grpdeskRitInput already. So I don't think we
  3261. * need this at all. Let's find out. Note that we might
  3262. * switch queues while processing the xxxSetForegroundWindow
  3263. * call. That should be fine as long as we don't switch
  3264. * desktops.
  3265. */
  3266. UserAssert(ptiCurrent->pq != gpqForeground ||
  3267. ptiCurrent->rpdesk == grpdeskRitInput);
  3268. /*
  3269. * The SetForegroundWindow call must succed here, so we call
  3270. * xxxSetForegroundWindow2() directly.
  3271. */
  3272. xxxSetForegroundWindow2(NULL, ptiCurrent, 0);
  3273. }
  3274. }
  3275. }
  3276. /*
  3277. * Post update events to all queues sending input to the desktop
  3278. * that is becoming inactive. This keeps the queues in sync up
  3279. * to the desktop switch.
  3280. */
  3281. if (grpdeskRitInput != NULL) {
  3282. pHead = &grpdeskRitInput->PtiList;
  3283. for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) {
  3284. pti = CONTAINING_RECORD(pEntry, THREADINFO, PtiLink);
  3285. pq = pti->pq;
  3286. if (pq->QF_flags & QF_UPDATEKEYSTATE) {
  3287. PostUpdateKeyStateEvent(pq);
  3288. }
  3289. /*
  3290. * Clear the reset bit to ensure that we can properly reset the
  3291. * key state when this desktop again becomes active.
  3292. */
  3293. pq->QF_flags &= ~QF_KEYSTATERESET;
  3294. }
  3295. }
  3296. /*
  3297. * Are we switching away from a destroyed desktop? If so, we might never
  3298. * unlock the pdesk->rpdeskinfo->spwnd.
  3299. */
  3300. if (grpdeskRitInput != NULL) {
  3301. if (grpdeskRitInput->dwDTFlags & DF_ZOMBIE) {
  3302. FRE_RIPMSG1(RIP_ERROR, "xxxSwitchDesktop: switching away from a destroyed desktop. pdesk = %p", grpdeskRitInput);
  3303. }
  3304. }
  3305. /*
  3306. * Send the RIT input to the desktop. We do this before any window
  3307. * management since DoPaint() uses grpdeskRitInput to go looking for
  3308. * windows with update regions.
  3309. */
  3310. LockDesktop(&grpdeskRitInput, pdesk, LDL_DESKRITINPUT, 0);
  3311. /*
  3312. * Free any spbs that are only valid for the previous desktop.
  3313. */
  3314. FreeAllSpbs();
  3315. /*
  3316. * Lock it into the RIT thread (we could use this desktop rather than
  3317. * the global grpdeskRitInput to direct input!)
  3318. */
  3319. if (zzzSetDesktop(gptiRit, pdesk, NULL) == FALSE) { // DeferWinEventNotify() ?? IANJA ??
  3320. bRet = FALSE;
  3321. goto Error;
  3322. }
  3323. /*
  3324. * Lock the desktop into the desktop thread. Be sure
  3325. * that the thread is using an unattached queue before
  3326. * setting the desktop. This is needed to ensure that
  3327. * the thread does not using a shared journal queue
  3328. * for the old desktop.
  3329. */
  3330. if (pTerm->ptiDesktop->pq != pTerm->pqDesktop) {
  3331. UserAssert(pTerm->pqDesktop->cThreads == 0);
  3332. AllocQueue(NULL, pTerm->pqDesktop);
  3333. pTerm->pqDesktop->cThreads++;
  3334. zzzAttachToQueue(pTerm->ptiDesktop, pTerm->pqDesktop, NULL, FALSE);
  3335. }
  3336. if (zzzSetDesktop(pTerm->ptiDesktop, pdesk, NULL) == FALSE) { // DeferWinEventNotify() ?? IANJA ??
  3337. bRet = FALSE;
  3338. goto Error;
  3339. }
  3340. /*
  3341. * Makes sure the desktop thread is running on the active destkop.
  3342. */
  3343. if (pTerm->ptiDesktop->rpdesk != grpdeskRitInput) {
  3344. FRE_RIPMSG0(RIP_ERROR, "xxxSwitchDesktop: desktop thread not running on grpdeskRitInput");
  3345. }
  3346. /*
  3347. * Bring the desktop window to the top and invalidate
  3348. * everything.
  3349. */
  3350. ThreadLockWithPti(ptiCurrent, pdesk->pDeskInfo->spwnd, &tlpwnd);
  3351. /*
  3352. * Suspend DirectDraw before we bring up the desktop window, so we make
  3353. * sure that everything is repainted properly once DirectDraw is disabled.
  3354. */
  3355. GreSuspendDirectDraw(pdesk->pDispInfo->hDev, TRUE);
  3356. xxxSetWindowPos(pdesk->pDeskInfo->spwnd, // WHAT KEEPS pdesk LOCKED - IANJA ???
  3357. NULL,
  3358. 0,
  3359. 0,
  3360. 0,
  3361. 0,
  3362. SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOCOPYBITS);
  3363. /*
  3364. * At this point, my understanding is that the new desktop window has been
  3365. * brought to the front, and therefore the vis-region of any app on any
  3366. * other desktop is now NULL.
  3367. *
  3368. * So this is the appropriate time to resume DirectDraw, which will
  3369. * ensure the DirectDraw app can not draw anything in the future.
  3370. *
  3371. * If this is not the case, then this code needs to be moved to a more
  3372. * appropriate location.
  3373. *
  3374. * [andreva] 6-26-96
  3375. */
  3376. GreResumeDirectDraw(pdesk->pDispInfo->hDev, TRUE);
  3377. /*
  3378. * Find the first visible top-level window.
  3379. */
  3380. pwndSetForeground = pdesk->spwndForeground;
  3381. if (pwndSetForeground == NULL || HMIsMarkDestroy(pwndSetForeground)) {
  3382. pwndSetForeground = pdesk->pDeskInfo->spwnd->spwndChild;
  3383. while ((pwndSetForeground != NULL) &&
  3384. !TestWF(pwndSetForeground, WFVISIBLE)) {
  3385. pwndSetForeground = pwndSetForeground->spwndNext;
  3386. }
  3387. }
  3388. Unlock(&pdesk->spwndForeground);
  3389. /*
  3390. * Now set it to the foreground.
  3391. */
  3392. if (pwndSetForeground == NULL) {
  3393. xxxSetForegroundWindow2(NULL, NULL, 0);
  3394. } else {
  3395. UserAssert(GETPTI(pwndSetForeground)->rpdesk == grpdeskRitInput);
  3396. /*
  3397. * If the new foreground window is a minimized fullscreen app,
  3398. * make it fullscreen.
  3399. */
  3400. if (GetFullScreen(pwndSetForeground) == FULLSCREENMIN) {
  3401. SetFullScreen(pwndSetForeground, FULLSCREEN);
  3402. }
  3403. ThreadLockAlwaysWithPti(ptiCurrent, pwndSetForeground, &tlpwndChild);
  3404. /*
  3405. * The SetForegroundWindow call must succed here, so we call
  3406. * xxxSetForegroundWindow2() directly
  3407. */
  3408. xxxSetForegroundWindow2(pwndSetForeground, ptiCurrent, 0);
  3409. ThreadUnlock(&tlpwndChild);
  3410. }
  3411. ThreadUnlock(&tlpwnd);
  3412. /*
  3413. * Overwrite key state of all queues sending input to the new
  3414. * active desktop with the current async key state. This
  3415. * prevents apps on inactive desktops from spying on active
  3416. * desktops. This blows away anything set with SetKeyState,
  3417. * but there is no way of preserving this without giving
  3418. * away information about what keys were hit on other
  3419. * desktops.
  3420. */
  3421. pHead = &grpdeskRitInput->PtiList;
  3422. for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) {
  3423. pti = CONTAINING_RECORD(pEntry, THREADINFO, PtiLink);
  3424. pq = pti->pq;
  3425. if (!(pq->QF_flags & QF_KEYSTATERESET)) {
  3426. pq->QF_flags |= QF_UPDATEKEYSTATE | QF_KEYSTATERESET;
  3427. RtlFillMemory(pq->afKeyRecentDown, CBKEYSTATERECENTDOWN, 0xff);
  3428. PostUpdateKeyStateEvent(pq);
  3429. }
  3430. }
  3431. /*
  3432. * If there is a hard-error popup up, nuke it and notify the
  3433. * hard error thread that it needs to pop it up again.
  3434. */
  3435. if (gHardErrorHandler.pti) {
  3436. IPostQuitMessage(gHardErrorHandler.pti, 0);
  3437. }
  3438. /*
  3439. * Notify anyone waiting for a desktop switch.
  3440. */
  3441. UserAssert(!(pdesk->rpwinstaParent->dwWSF_Flags & WSF_NOIO));
  3442. KePulseEvent(gpEventSwitchDesktop, EVENT_INCREMENT, FALSE);
  3443. /*
  3444. * Reset the cursor when we come back from another pdev.
  3445. */
  3446. if (bUpdateCursor == TRUE) {
  3447. gpqCursor = NULL;
  3448. zzzInternalSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y);
  3449. SetPointer(TRUE);
  3450. }
  3451. /*
  3452. * If this desktop was not active during last display settings change
  3453. * let's now bradcast the settings change to its windows. This code is
  3454. * copied from xxxResetDisplayDevice().
  3455. */
  3456. if ((pdesk->dwDTFlags & DF_NEWDISPLAYSETTINGS) && pdesk->pDeskInfo && pdesk->pDeskInfo->spwnd) {
  3457. pdesk->dwDTFlags &= ~DF_NEWDISPLAYSETTINGS;
  3458. xxxBroadcastDisplaySettingsChange(pdesk, TRUE);
  3459. }
  3460. Error:
  3461. ThreadUnlockDesktopHandle(&tlhdesk);
  3462. TRACE_INIT(("xxxSwitchDesktop: Leaving\n"));
  3463. return bRet;
  3464. }
  3465. /***************************************************************************\
  3466. * zzzSetDesktop
  3467. *
  3468. * Set desktop and desktop info in the specified pti.
  3469. *
  3470. * History:
  3471. * 23-Dec-1993 JimA Created.
  3472. \***************************************************************************/
  3473. BOOL zzzSetDesktop(
  3474. PTHREADINFO pti,
  3475. PDESKTOP pdesk,
  3476. HDESK hdesk)
  3477. {
  3478. PTEB pteb;
  3479. OBJECT_HANDLE_INFORMATION ohi;
  3480. PDESKTOP pdeskRef;
  3481. PDESKTOP pdeskOld;
  3482. PCLIENTTHREADINFO pctiOld;
  3483. TL tlpdesk;
  3484. PTHREADINFO ptiCurrent = PtiCurrent();
  3485. BOOL bRet = TRUE;
  3486. if (pti == NULL) {
  3487. UserAssert(pti);
  3488. return FALSE;
  3489. }
  3490. /*
  3491. * A handle without an object pointer is bad news.
  3492. */
  3493. UserAssert(pdesk != NULL || hdesk == NULL);
  3494. /*
  3495. * This desktop must not be destroyed.
  3496. */
  3497. if (pdesk != NULL && (pdesk->dwDTFlags & (DF_DESKWNDDESTROYED | DF_DYING)) &&
  3498. pdesk != pti->rpdesk) {
  3499. /*
  3500. * We need to make an exception for the desktop thread where it is
  3501. * possible that all remaining desktops are marked for destruction so
  3502. * the desktop thread will not be able to run on grpdeskRitInput.
  3503. * Windows Bug #422389.
  3504. */
  3505. if (pti != gTermIO.ptiDesktop) {
  3506. RIPMSG2(RIP_ERROR, "Assigning pti %#p to a dying desktop %#p",
  3507. pti, pdesk);
  3508. return FALSE;
  3509. } else {
  3510. UserAssert(pdesk == grpdeskRitInput);
  3511. }
  3512. }
  3513. /*
  3514. * Catch reset of important desktops.
  3515. */
  3516. UserAssertMsg0(pti->rpdesk == NULL ||
  3517. pti->rpdesk->dwConsoleThreadId != TIDq(pti) ||
  3518. pti->cWindows == 0,
  3519. "Reset of console desktop");
  3520. /*
  3521. * Clear hook flag.
  3522. */
  3523. pti->TIF_flags &= ~TIF_ALLOWOTHERACCOUNTHOOK;
  3524. /*
  3525. * Get granted access
  3526. */
  3527. pti->hdesk = hdesk;
  3528. if (hdesk != NULL) {
  3529. if (NT_SUCCESS(ObReferenceObjectByHandle(hdesk,
  3530. 0,
  3531. *ExDesktopObjectType,
  3532. (pdesk->dwDTFlags & DF_USERMODE)? UserMode : KernelMode,
  3533. &pdeskRef,
  3534. &ohi))) {
  3535. UserAssert(pdesk->dwSessionId == gSessionId);
  3536. LogDesktop(pdeskRef, LD_REF_FN_SETDESKTOP, TRUE, (ULONG_PTR)PtiCurrent());
  3537. UserAssert(pdeskRef == pdesk);
  3538. LogDesktop(pdesk, LD_DEREF_FN_SETDESKTOP, FALSE, (ULONG_PTR)PtiCurrent());
  3539. ObDereferenceObject(pdeskRef);
  3540. pti->amdesk = ohi.GrantedAccess;
  3541. if (CheckHandleFlag(NULL, pdesk->dwSessionId, hdesk, HF_DESKTOPHOOK)) {
  3542. pti->TIF_flags |= TIF_ALLOWOTHERACCOUNTHOOK;
  3543. }
  3544. SetHandleFlag(hdesk, HF_PROTECTED, TRUE);
  3545. } else {
  3546. pti->amdesk = 0;
  3547. }
  3548. } else {
  3549. pti->amdesk = 0;
  3550. }
  3551. /*
  3552. * Do nothing else if the thread has initialized and the desktop is not
  3553. * changing.
  3554. */
  3555. if (pdesk != NULL && pdesk == pti->rpdesk) {
  3556. return TRUE;
  3557. }
  3558. /*
  3559. * Save old pointers for later. Locking the old desktop ensures that we
  3560. * will be able to free the CLIENTTHREADINFO structure.
  3561. */
  3562. pdeskOld = pti->rpdesk;
  3563. ThreadLockDesktop(ptiCurrent, pdeskOld, &tlpdesk, LDLT_FN_SETDESKTOP);
  3564. pctiOld = pti->pcti;
  3565. /*
  3566. * Remove the pti from the current desktop.
  3567. */
  3568. if (pti->rpdesk) {
  3569. UserAssert(ISATOMICCHECK() || pti->pq == NULL || pti->pq->cThreads == 1);
  3570. RemoveEntryList(&pti->PtiLink);
  3571. }
  3572. LockDesktop(&pti->rpdesk, pdesk, LDL_PTI_DESK, (ULONG_PTR)pti);
  3573. /*
  3574. * If there is no desktop, we need to fake a desktop info structure so
  3575. * that the IsHooked() macro can test a "valid" fsHooks value. Also link
  3576. * the pti to the desktop.
  3577. */
  3578. if (pdesk != NULL) {
  3579. pti->pDeskInfo = pdesk->pDeskInfo;
  3580. InsertHeadList(&pdesk->PtiList, &pti->PtiLink);
  3581. } else {
  3582. pti->pDeskInfo = &diStatic;
  3583. }
  3584. pteb = PsGetThreadTeb(pti->pEThread);
  3585. if (pteb) {
  3586. PDESKTOPVIEW pdv;
  3587. if (pdesk && (pdv = GetDesktopView(pti->ppi, pdesk))) {
  3588. try {
  3589. pti->pClientInfo->pDeskInfo =
  3590. (PDESKTOPINFO)((PBYTE)pti->pDeskInfo - pdv->ulClientDelta);
  3591. pti->pClientInfo->ulClientDelta = pdv->ulClientDelta;
  3592. pti->ulClientDelta = pdv->ulClientDelta;
  3593. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
  3594. bRet = FALSE;
  3595. goto Error;
  3596. }
  3597. } else {
  3598. try {
  3599. pti->pClientInfo->pDeskInfo = NULL;
  3600. pti->pClientInfo->ulClientDelta = 0;
  3601. pti->ulClientDelta = 0;
  3602. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
  3603. bRet = FALSE;
  3604. goto Error;
  3605. }
  3606. /*
  3607. * Reset the cursor level to its orginal state.
  3608. */
  3609. pti->iCursorLevel = TEST_GTERMF(GTERMF_MOUSE) ? 0 : -1;
  3610. if (pti->pq)
  3611. pti->pq->iCursorLevel = pti->iCursorLevel;
  3612. }
  3613. }
  3614. /*
  3615. * Allocate thread information visible from client, then copy and free
  3616. * any old info we have lying around.
  3617. */
  3618. if (pdesk != NULL) {
  3619. /*
  3620. * Do not use DesktopAlloc here because the desktop might
  3621. * have DF_DESTROYED set.
  3622. */
  3623. pti->pcti = DesktopAllocAlways(pdesk,
  3624. sizeof(CLIENTTHREADINFO),
  3625. DTAG_CLIENTTHREADINFO);
  3626. }
  3627. try {
  3628. if (pdesk == NULL || pti->pcti == NULL) {
  3629. pti->pcti = &(pti->cti);
  3630. pti->pClientInfo->pClientThreadInfo = NULL;
  3631. } else {
  3632. pti->pClientInfo->pClientThreadInfo =
  3633. (PCLIENTTHREADINFO)((PBYTE)pti->pcti - pti->pClientInfo->ulClientDelta);
  3634. }
  3635. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
  3636. if (pti->pcti != &(pti->cti)) {
  3637. DesktopFree(pdesk, pti->pcti);
  3638. }
  3639. bRet = FALSE;
  3640. goto Error;
  3641. }
  3642. if (pctiOld != NULL) {
  3643. if (pctiOld != pti->pcti) {
  3644. RtlCopyMemory(pti->pcti, pctiOld, sizeof(CLIENTTHREADINFO));
  3645. }
  3646. if (pctiOld != &(pti->cti)) {
  3647. DesktopFree(pdeskOld, pctiOld);
  3648. }
  3649. } else {
  3650. RtlZeroMemory(pti->pcti, sizeof(CLIENTTHREADINFO));
  3651. }
  3652. /*
  3653. * If journalling is occuring on the new desktop, attach to
  3654. * the journal queue.
  3655. * Assert that the pti and the pdesk point to the same deskinfo
  3656. * if not, we will check the wrong hooks.
  3657. */
  3658. UserAssert(pdesk == NULL || pti->pDeskInfo == pdesk->pDeskInfo);
  3659. UserAssert(pti->rpdesk == pdesk);
  3660. if (pti->pq != NULL) {
  3661. PQ pq = GetJournallingQueue(pti);
  3662. if (pq != NULL) {
  3663. pq->cThreads++;
  3664. zzzAttachToQueue(pti, pq, NULL, FALSE);
  3665. }
  3666. }
  3667. Error:
  3668. ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_SETDESKTOP);
  3669. return bRet;
  3670. }
  3671. /***************************************************************************\
  3672. * xxxSetThreadDesktop (API)
  3673. *
  3674. * Associate the current thread with a desktop.
  3675. *
  3676. * History:
  3677. * 16-Jan-1991 JimA Created stub.
  3678. \***************************************************************************/
  3679. BOOL xxxSetThreadDesktop(
  3680. HDESK hdesk,
  3681. PDESKTOP pdesk)
  3682. {
  3683. PTHREADINFO ptiCurrent;
  3684. PPROCESSINFO ppiCurrent;
  3685. PQ pqAttach;
  3686. ptiCurrent = PtiCurrent();
  3687. ppiCurrent = ptiCurrent->ppi;
  3688. /*
  3689. * If the handle has not been mapped in, do it now.
  3690. */
  3691. if (pdesk != NULL) {
  3692. WIN32_OPENMETHOD_PARAMETERS OpenParams;
  3693. OpenParams.OpenReason = ObOpenHandle;
  3694. OpenParams.Process = ppiCurrent->Process;
  3695. OpenParams.Object = pdesk;
  3696. OpenParams.GrantedAccess = 0;
  3697. OpenParams.HandleCount = 1;
  3698. if (!NT_SUCCESS(MapDesktop(&OpenParams))) {
  3699. return FALSE;
  3700. }
  3701. UserAssert(GetDesktopView(ppiCurrent, pdesk) != NULL);
  3702. }
  3703. /*
  3704. * Check non-system thread status.
  3705. */
  3706. if (PsGetCurrentProcess() != gpepCSRSS) {
  3707. /*
  3708. * Fail if the non-system thread has any windows or thread hooks.
  3709. */
  3710. if (ptiCurrent->cWindows != 0 || ptiCurrent->fsHooks) {
  3711. RIPERR0(ERROR_BUSY, RIP_WARNING, "Thread has windows or hooks");
  3712. return FALSE;
  3713. }
  3714. /*
  3715. * If this is the first desktop assigned to the process,
  3716. * make it the startup desktop.
  3717. */
  3718. if (ppiCurrent->rpdeskStartup == NULL && hdesk != NULL) {
  3719. LockDesktop(&ppiCurrent->rpdeskStartup, pdesk, LDL_PPI_DESKSTARTUP1, (ULONG_PTR)ppiCurrent);
  3720. ppiCurrent->hdeskStartup = hdesk;
  3721. }
  3722. }
  3723. /*
  3724. * If the desktop is changing and the thread is sharing a queue, detach
  3725. * the thread. This will ensure that threads sharing queues are all on
  3726. * the same desktop. This will prevent zzzDestroyQueue from getting
  3727. * confused and setting ptiKeyboard and ptiMouse to NULL when a thread
  3728. * detachs.
  3729. */
  3730. if (ptiCurrent->rpdesk != pdesk) {
  3731. if (ptiCurrent->pq->cThreads > 1) {
  3732. pqAttach = AllocQueue(NULL, NULL);
  3733. if (pqAttach != NULL) {
  3734. pqAttach->cThreads++;
  3735. zzzAttachToQueue(ptiCurrent, pqAttach, NULL, FALSE);
  3736. } else {
  3737. RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "Thread could not be detached");
  3738. return FALSE;
  3739. }
  3740. } else if (ptiCurrent->pq == gpqForeground) {
  3741. /*
  3742. * This thread doesn't own any windows, still it's attached to
  3743. * qpgForeground and it's the only thread attached to it. Since
  3744. * any threads attached to qpgForeground must be in grpdeskRitInput,
  3745. * we must set qpgForeground to NULL here because this thread is
  3746. * going to another desktop.
  3747. */
  3748. UserAssert(ptiCurrent->pq->spwndActive == NULL);
  3749. UserAssert(ptiCurrent->pq->spwndCapture == NULL);
  3750. UserAssert(ptiCurrent->pq->spwndFocus == NULL);
  3751. UserAssert(ptiCurrent->pq->spwndActivePrev == NULL);
  3752. xxxSetForegroundWindow2(NULL, ptiCurrent, 0);
  3753. } else if (ptiCurrent->rpdesk == NULL) {
  3754. /*
  3755. * We need to initialize iCursorLevel.
  3756. */
  3757. ptiCurrent->iCursorLevel = TEST_GTERMF(GTERMF_MOUSE) ? 0 : -1;
  3758. ptiCurrent->pq->iCursorLevel = ptiCurrent->iCursorLevel;
  3759. }
  3760. UserAssert(ptiCurrent->pq != gpqForeground);
  3761. }
  3762. if (zzzSetDesktop(ptiCurrent, pdesk, hdesk) == FALSE) {
  3763. return FALSE;
  3764. }
  3765. return TRUE;
  3766. }
  3767. /***************************************************************************\
  3768. * xxxGetThreadDesktop (API)
  3769. *
  3770. * Return a handle to the desktop assigned to the specified thread.
  3771. *
  3772. * History:
  3773. * 16-Jan-1991 JimA Created stub.
  3774. \***************************************************************************/
  3775. HDESK xxxGetThreadDesktop(
  3776. DWORD dwThread,
  3777. HDESK hdeskConsole,
  3778. KPROCESSOR_MODE AccessMode)
  3779. {
  3780. PTHREADINFO pti = PtiFromThreadId(dwThread);
  3781. PPROCESSINFO ppiThread;
  3782. HDESK hdesk;
  3783. NTSTATUS Status;
  3784. if (pti == NULL) {
  3785. /*
  3786. * If the thread has a console use that desktop. If
  3787. * not, then the thread is either invalid or not
  3788. * a Win32 thread.
  3789. */
  3790. if (hdeskConsole == NULL) {
  3791. RIPERR1(ERROR_INVALID_PARAMETER, RIP_VERBOSE,
  3792. "xxxGetThreadDesktop: invalid threadId 0x%x",
  3793. dwThread);
  3794. return NULL;
  3795. }
  3796. hdesk = hdeskConsole;
  3797. ppiThread = PpiFromProcess(gpepCSRSS);
  3798. } else {
  3799. hdesk = pti->hdesk;
  3800. ppiThread = pti->ppi;
  3801. }
  3802. /*
  3803. * If there is no desktop, return NULL with no error
  3804. */
  3805. if (hdesk != NULL) {
  3806. /*
  3807. * If the thread belongs to this process, return the
  3808. * handle. Otherwise, enumerate the handle table of
  3809. * this process to find a handle with the same
  3810. * attributes.
  3811. */
  3812. if (ppiThread != PpiCurrent()) {
  3813. PVOID pobj;
  3814. OBJECT_HANDLE_INFORMATION ohi;
  3815. RIPMSG4(RIP_VERBOSE, "[%x.%x] %s called xxxGetThreadDesktop for pti %#p",
  3816. PsGetCurrentProcessId(),
  3817. PsGetCurrentThreadId(),
  3818. PsGetCurrentProcessImageFileName(),
  3819. pti);
  3820. KeAttachProcess(PsGetProcessPcb(ppiThread->Process));
  3821. Status = ObReferenceObjectByHandle(hdesk,
  3822. 0,
  3823. *ExDesktopObjectType,
  3824. AccessMode,
  3825. &pobj,
  3826. &ohi);
  3827. KeDetachProcess();
  3828. if (!NT_SUCCESS(Status) ||
  3829. !ObFindHandleForObject(PsGetCurrentProcess(), pobj, NULL, &ohi, &hdesk)) {
  3830. RIPMSG0(RIP_VERBOSE, "Cannot find hdesk for current process");
  3831. hdesk = NULL;
  3832. } else {
  3833. LogDesktop(pobj, LD_REF_FN_GETTHREADDESKTOP, TRUE, (ULONG_PTR)PtiCurrent());
  3834. }
  3835. if (NT_SUCCESS(Status)) {
  3836. LogDesktop(pobj, LD_DEREF_FN_GETTHREADDESKTOP, FALSE, (ULONG_PTR)PtiCurrent());
  3837. ObDereferenceObject(pobj);
  3838. }
  3839. }
  3840. if (hdesk == NULL) {
  3841. RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "xxxGetThreadDesktop: hdesk is null");
  3842. } else {
  3843. SetHandleFlag(hdesk, HF_PROTECTED, TRUE);
  3844. }
  3845. }
  3846. return hdesk;
  3847. }
  3848. /***************************************************************************\
  3849. * _GetInputDesktop (API)
  3850. *
  3851. * Obsolete - kept for compatibility only. Return a handle to the
  3852. * desktop currently receiving input. Returns the first handle to
  3853. * the input desktop found.
  3854. *
  3855. * History:
  3856. * 16-Jan-1991 JimA Created scaffold code.
  3857. \***************************************************************************/
  3858. HDESK _GetInputDesktop(
  3859. VOID)
  3860. {
  3861. HDESK hdesk;
  3862. if (ObFindHandleForObject(PsGetCurrentProcess(), grpdeskRitInput, NULL, NULL, &hdesk)) {
  3863. SetHandleFlag(hdesk, HF_PROTECTED, TRUE);
  3864. return hdesk;
  3865. } else {
  3866. return NULL;
  3867. }
  3868. }
  3869. /***************************************************************************\
  3870. * xxxCloseDesktop (API)
  3871. *
  3872. * Close a reference to a desktop and destroy the desktop if it is no
  3873. * longer referenced.
  3874. *
  3875. * History:
  3876. * 16-Jan-1991 JimA Created scaffold code.
  3877. * 11-Feb-1991 JimA Added access checks.
  3878. \***************************************************************************/
  3879. BOOL xxxCloseDesktop(
  3880. HDESK hdesk,
  3881. KPROCESSOR_MODE AccessMode)
  3882. {
  3883. PDESKTOP pdesk;
  3884. PTHREADINFO ptiT;
  3885. PPROCESSINFO ppi;
  3886. NTSTATUS Status;
  3887. ppi = PpiCurrent();
  3888. /*
  3889. * Get a pointer to the desktop.
  3890. */
  3891. Status = ObReferenceObjectByHandle(
  3892. hdesk,
  3893. 0,
  3894. *ExDesktopObjectType,
  3895. AccessMode,
  3896. &pdesk,
  3897. NULL);
  3898. if (!NT_SUCCESS(Status)) {
  3899. RIPNTERR0(Status, RIP_VERBOSE, "");
  3900. return FALSE;
  3901. }
  3902. UserAssert(pdesk->dwSessionId == gSessionId);
  3903. LogDesktop(pdesk, LD_REF_FN_CLOSEDESKTOP, TRUE, (ULONG_PTR)PtiCurrent());
  3904. if (ppi->Process != gpepCSRSS) {
  3905. /*
  3906. * Disallow closing of the desktop if the handle is in use by
  3907. * any threads in the process.
  3908. */
  3909. for (ptiT = ppi->ptiList; ptiT != NULL; ptiT = ptiT->ptiSibling) {
  3910. if (ptiT->hdesk == hdesk) {
  3911. RIPERR2(ERROR_BUSY, RIP_WARNING,
  3912. "CloseDesktop: Desktop %#p still in use by thread %#p",
  3913. pdesk, ptiT);
  3914. LogDesktop(pdesk, LD_DEREF_FN_CLOSEDESKTOP1, FALSE, (ULONG_PTR)PtiCurrent());
  3915. ObDereferenceObject(pdesk);
  3916. return FALSE;
  3917. }
  3918. }
  3919. /*
  3920. * If this is the startup desktop, unlock it
  3921. */
  3922. /*
  3923. * Bug 41394. Make sure that hdesk == ppi->hdeskStartup. We might
  3924. * be getting a handle to the desktop object that is different
  3925. * from ppi->hdeskStartup but we still end up
  3926. * setting ppi->hdeskStartup to NULL.
  3927. */
  3928. if ((pdesk == ppi->rpdeskStartup) && (hdesk == ppi->hdeskStartup)) {
  3929. UnlockDesktop(&ppi->rpdeskStartup, LDU_PPI_DESKSTARTUP2, (ULONG_PTR)ppi);
  3930. ppi->hdeskStartup = NULL;
  3931. }
  3932. }
  3933. /*
  3934. * Clear hook flag
  3935. */
  3936. SetHandleFlag(hdesk, HF_DESKTOPHOOK, FALSE);
  3937. /*
  3938. * Close the handle
  3939. */
  3940. Status = CloseProtectedHandle(hdesk);
  3941. LogDesktop(pdesk, LD_DEREF_FN_CLOSEDESKTOP2, FALSE, (ULONG_PTR)PtiCurrent());
  3942. ObDereferenceObject(pdesk);
  3943. UserAssert(NT_SUCCESS(Status));
  3944. return TRUE;
  3945. }
  3946. /***************************************************************************\
  3947. * TerminateConsole
  3948. *
  3949. * Post a quit message to a console thread and wait for it to terminate.
  3950. *
  3951. * History:
  3952. * 08-May-1995 JimA Created.
  3953. \***************************************************************************/
  3954. VOID TerminateConsole(
  3955. PDESKTOP pdesk)
  3956. {
  3957. NTSTATUS Status;
  3958. PETHREAD Thread;
  3959. PTHREADINFO pti;
  3960. if (pdesk->dwConsoleThreadId == 0) {
  3961. return;
  3962. }
  3963. /*
  3964. * Locate the console thread.
  3965. */
  3966. Status = LockThreadByClientId(LongToHandle(pdesk->dwConsoleThreadId), &Thread);
  3967. if (!NT_SUCCESS(Status)) {
  3968. return;
  3969. }
  3970. /*
  3971. * Post a quit message to the console.
  3972. */
  3973. pti = PtiFromThread(Thread);
  3974. if (pti == NULL) {
  3975. FRE_RIPMSG1(RIP_ERROR,
  3976. "PtiFromThread for CIT 0x%p returned NULL!",
  3977. Thread);
  3978. }
  3979. if (pti != NULL) {
  3980. _PostThreadMessage(pti, WM_QUIT, 0, 0);
  3981. }
  3982. /*
  3983. * Clear thread id so we don't post twice
  3984. */
  3985. pdesk->dwConsoleThreadId = 0;
  3986. UnlockThread(Thread);
  3987. }
  3988. /***************************************************************************\
  3989. * CheckHandleFlag
  3990. *
  3991. * Returns TRUE if the desktop handle allows other accounts
  3992. * to hook this process.
  3993. *
  3994. * History:
  3995. * 07-13-95 JimA Created.
  3996. \***************************************************************************/
  3997. BOOL CheckHandleFlag(
  3998. PEPROCESS Process,
  3999. DWORD dwSessionId,
  4000. HANDLE hObject,
  4001. DWORD dwFlag)
  4002. {
  4003. ULONG Index = ((PEXHANDLE)&hObject)->Index * HF_LIMIT + dwFlag;
  4004. BOOL fRet = FALSE, bAttached = FALSE;
  4005. PPROCESSINFO ppi;
  4006. KAPC_STATE ApcState;
  4007. EnterHandleFlagsCrit();
  4008. if (Process == NULL) {
  4009. ppi = PpiCurrent();
  4010. } else {
  4011. if (PsGetProcessSessionId(Process) != dwSessionId) {
  4012. KeStackAttachProcess(PsGetProcessPcb(Process), &ApcState);
  4013. bAttached = TRUE;
  4014. }
  4015. ppi = PpiFromProcess(Process);
  4016. }
  4017. if (ppi != NULL) {
  4018. fRet = (Index < ppi->bmHandleFlags.SizeOfBitMap &&
  4019. RtlCheckBit(&ppi->bmHandleFlags, Index));
  4020. }
  4021. if (bAttached) {
  4022. KeUnstackDetachProcess(&ApcState);
  4023. }
  4024. LeaveHandleFlagsCrit();
  4025. return fRet;
  4026. }
  4027. /***************************************************************************\
  4028. * SetHandleFlag
  4029. *
  4030. * Sets and clears the ability of a desktop handle to allow
  4031. * other accounts to hook this process.
  4032. *
  4033. * History:
  4034. * 07-13-95 JimA Created.
  4035. \***************************************************************************/
  4036. BOOL SetHandleFlag(
  4037. HANDLE hObject,
  4038. DWORD dwFlag,
  4039. BOOL fSet)
  4040. {
  4041. PPROCESSINFO ppi;
  4042. ULONG Index = ((PEXHANDLE)&hObject)->Index * HF_LIMIT + dwFlag;
  4043. PRTL_BITMAP pbm;
  4044. ULONG cBits;
  4045. PULONG Buffer;
  4046. BOOL fRet = TRUE;
  4047. UserAssert(dwFlag < HF_LIMIT);
  4048. EnterHandleFlagsCrit();
  4049. if ((ppi = PpiCurrent()) != NULL) {
  4050. pbm = &ppi->bmHandleFlags;
  4051. if (fSet) {
  4052. /*
  4053. * Expand the bitmap if needed
  4054. */
  4055. if (Index >= pbm->SizeOfBitMap) {
  4056. /*
  4057. * Index is zero-based - cBits is an exact number of dwords
  4058. */
  4059. cBits = ((Index + 1) + 0x1F) & ~0x1F;
  4060. Buffer = UserAllocPoolWithQuotaZInit(cBits / 8, TAG_PROCESSINFO);
  4061. if (Buffer == NULL) {
  4062. fRet = FALSE;
  4063. goto Exit;
  4064. }
  4065. if (pbm->Buffer) {
  4066. RtlCopyMemory(Buffer, pbm->Buffer, pbm->SizeOfBitMap / 8);
  4067. UserFreePool(pbm->Buffer);
  4068. }
  4069. RtlInitializeBitMap(pbm, Buffer, cBits);
  4070. }
  4071. RtlSetBits(pbm, Index, 1);
  4072. } else if (Index < pbm->SizeOfBitMap) {
  4073. RtlClearBits(pbm, Index, 1);
  4074. }
  4075. }
  4076. Exit:
  4077. LeaveHandleFlagsCrit();
  4078. return fRet;
  4079. }
  4080. /***************************************************************************\
  4081. * CheckHandleInUse
  4082. *
  4083. * Returns TRUE if the handle is currently in use.
  4084. *
  4085. * History:
  4086. * 02-Jun-1999 JerrySh Created.
  4087. \***************************************************************************/
  4088. BOOL CheckHandleInUse(
  4089. HANDLE hObject)
  4090. {
  4091. BOOL fRet;
  4092. EnterHandleFlagsCrit();
  4093. fRet = ((gProcessInUse == PsGetCurrentProcess()) &&
  4094. (gHandleInUse == hObject));
  4095. LeaveHandleFlagsCrit();
  4096. return fRet;
  4097. }
  4098. /***************************************************************************\
  4099. * SetHandleInUse
  4100. *
  4101. * Mark the handle as in use.
  4102. *
  4103. * History:
  4104. * 02-Jun-1999 JerrySh Created.
  4105. \***************************************************************************/
  4106. VOID SetHandleInUse(
  4107. HANDLE hObject)
  4108. {
  4109. EnterHandleFlagsCrit();
  4110. gProcessInUse = PsGetCurrentProcess();
  4111. gHandleInUse = hObject;
  4112. LeaveHandleFlagsCrit();
  4113. }
  4114. /***************************************************************************\
  4115. * xxxResolveDesktopForWOW
  4116. *
  4117. * Checks whether given process has access to the provided windowstation/desktop
  4118. * or the defaults if none are specified. (WinSta0\Default).
  4119. *
  4120. * History:
  4121. * 03-Jan-2002 Mohamed Modified to use dynamically allocated VM for
  4122. * string buffers and CR for security on handle
  4123. * manipulation. Using UserMode handles intentionally
  4124. * to undergo the needed security access checks.
  4125. \***************************************************************************/
  4126. NTSTATUS xxxResolveDesktopForWOW(
  4127. IN OUT PUNICODE_STRING pstrDesktop)
  4128. {
  4129. NTSTATUS Status = STATUS_SUCCESS;
  4130. UNICODE_STRING strDesktop, strWinSta, strStatic;
  4131. WCHAR wchStaticBuffer[STATIC_UNICODE_BUFFER_LENGTH];
  4132. LPWSTR pszDesktop;
  4133. BOOL fWinStaDefaulted;
  4134. BOOL fDesktopDefaulted;
  4135. HWINSTA hwinsta;
  4136. HDESK hdesk;
  4137. PUNICODE_STRING pstrStatic;
  4138. POBJECT_ATTRIBUTES pObjA = NULL;
  4139. SIZE_T cbObjA;
  4140. BOOL bShutDown = FALSE;
  4141. /*
  4142. * Determine windowstation and desktop names.
  4143. */
  4144. if (pstrDesktop == NULL) {
  4145. return STATUS_INVALID_PARAMETER;
  4146. }
  4147. strStatic.Length = 0;
  4148. strStatic.MaximumLength = STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR);
  4149. strStatic.Buffer = wchStaticBuffer;
  4150. if (pstrDesktop->Length == 0) {
  4151. RtlInitUnicodeString(&strDesktop, L"Default");
  4152. fWinStaDefaulted = fDesktopDefaulted = TRUE;
  4153. } else {
  4154. USHORT cch;
  4155. /*
  4156. * The name be of the form windowstation\desktop. Parse the string
  4157. * to separate out the names.
  4158. */
  4159. strWinSta = *pstrDesktop;
  4160. cch = strWinSta.Length / sizeof(WCHAR);
  4161. pszDesktop = strWinSta.Buffer;
  4162. while (cch && *pszDesktop != L'\\') {
  4163. cch--;
  4164. pszDesktop++;
  4165. }
  4166. fDesktopDefaulted = FALSE;
  4167. if (cch == 0) {
  4168. /*
  4169. * No windowstation name was specified, only the desktop.
  4170. */
  4171. strDesktop = strWinSta;
  4172. fWinStaDefaulted = TRUE;
  4173. } else {
  4174. /*
  4175. * Both names were in the string.
  4176. */
  4177. strDesktop.Buffer = pszDesktop + 1;
  4178. strDesktop.Length = strDesktop.MaximumLength = (cch - 1) * sizeof(WCHAR);
  4179. strWinSta.Length = (USHORT)(pszDesktop - strWinSta.Buffer) * sizeof(WCHAR);
  4180. /*
  4181. * zero terminate the strWinSta buffer so the rebuild of the desktop
  4182. * name at the end of the function works.
  4183. */
  4184. *pszDesktop = (WCHAR)0;
  4185. fWinStaDefaulted = FALSE;
  4186. RtlAppendUnicodeToString(&strStatic, (PWSTR)szWindowStationDirectory);
  4187. RtlAppendUnicodeToString(&strStatic, L"\\");
  4188. RtlAppendUnicodeStringToString(&strStatic, &strWinSta);
  4189. }
  4190. }
  4191. if (fWinStaDefaulted) {
  4192. /*
  4193. * Default Window Station.
  4194. */
  4195. RtlInitUnicodeString(&strWinSta, L"WinSta0");
  4196. RtlAppendUnicodeToString(&strStatic, (PWSTR)szWindowStationDirectory);
  4197. RtlAppendUnicodeToString(&strStatic, L"\\");
  4198. RtlAppendUnicodeStringToString(&strStatic, &strWinSta);
  4199. }
  4200. /*
  4201. * Open the computed windowstation. This will also do an access check.
  4202. */
  4203. /*
  4204. * Allocate an object attributes structure, a UNICODE_STRING structure and a string
  4205. * buffer of suitable length in user address space.
  4206. */
  4207. cbObjA = sizeof(*pObjA) + sizeof(*pstrStatic) + STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR);
  4208. Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
  4209. &pObjA, 0, &cbObjA, MEM_COMMIT, PAGE_READWRITE);
  4210. pstrStatic = (PUNICODE_STRING)((PBYTE)pObjA + sizeof(*pObjA));
  4211. if (NT_SUCCESS(Status)) {
  4212. /*
  4213. * Note -- the string must be in client-space or the address
  4214. * validation in _OpenWindowStation will fail. And we use UserMode
  4215. * for KPROCESSOR_MODE to be able to utilize security checks;
  4216. * KernelMode would bypass the checks. The side-effect of this is
  4217. * that the returned hwinsta and hdesk handles are UserMode handles
  4218. * and must be handled with care.
  4219. */
  4220. try {
  4221. pstrStatic->Length = 0;
  4222. pstrStatic->MaximumLength = STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR);
  4223. pstrStatic->Buffer = (PWSTR)((PBYTE)pstrStatic + sizeof(*pstrStatic));
  4224. RtlCopyUnicodeString(pstrStatic, &strStatic);
  4225. InitializeObjectAttributes(pObjA,
  4226. pstrStatic,
  4227. OBJ_CASE_INSENSITIVE,
  4228. NULL,
  4229. NULL);
  4230. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  4231. Status = GetExceptionCode();
  4232. }
  4233. if (NT_SUCCESS(Status)) {
  4234. hwinsta = _OpenWindowStation(pObjA, MAXIMUM_ALLOWED, UserMode);
  4235. } else {
  4236. hwinsta = NULL;
  4237. }
  4238. if (!hwinsta) {
  4239. ZwFreeVirtualMemory(NtCurrentProcess(),
  4240. &pObjA,
  4241. &cbObjA,
  4242. MEM_RELEASE);
  4243. return STATUS_ACCESS_DENIED;
  4244. }
  4245. } else {
  4246. return STATUS_NO_MEMORY;
  4247. }
  4248. /*
  4249. * Do an access check on the desktop by opening it
  4250. */
  4251. /*
  4252. * Note -- the string must be in client-space or the
  4253. * address validation in _OpenDesktop will fail.
  4254. */
  4255. try {
  4256. RtlCopyUnicodeString(pstrStatic, &strDesktop);
  4257. InitializeObjectAttributes( pObjA,
  4258. pstrStatic,
  4259. OBJ_CASE_INSENSITIVE,
  4260. hwinsta,
  4261. NULL);
  4262. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  4263. Status = GetExceptionCode();
  4264. }
  4265. if (NT_SUCCESS(Status)) {
  4266. hdesk = _OpenDesktop(pObjA,
  4267. UserMode,
  4268. 0,
  4269. MAXIMUM_ALLOWED,
  4270. &bShutDown);
  4271. } else {
  4272. hdesk = NULL;
  4273. }
  4274. ZwFreeVirtualMemory(NtCurrentProcess(), &pObjA, &cbObjA, MEM_RELEASE);
  4275. UserVerify(NT_SUCCESS(ObCloseHandle(hwinsta, UserMode)));
  4276. if (!hdesk) {
  4277. return STATUS_ACCESS_DENIED;
  4278. }
  4279. CloseProtectedHandle(hdesk);
  4280. /*
  4281. * Copy the final Computed String
  4282. */
  4283. RtlCopyUnicodeString(pstrDesktop, &strWinSta);
  4284. RtlAppendUnicodeToString(pstrDesktop, L"\\");
  4285. RtlAppendUnicodeStringToString(pstrDesktop, &strDesktop);
  4286. return STATUS_SUCCESS;
  4287. }
  4288. /***************************************************************************\
  4289. * xxxResolveDesktop
  4290. *
  4291. * Attempts to return handles to a windowstation and desktop associated
  4292. * with the logon session.
  4293. *
  4294. * History:
  4295. * 25-Apr-1994 JimA Created.
  4296. * 03-Jan-2002 Mohamed Modified it to use dynamically allocated VM for
  4297. * string buffers and CR for security on handle
  4298. * manipulation. Using UserMode handles intentionally
  4299. * to undergo the needed security access checks.
  4300. \***************************************************************************/
  4301. HDESK xxxResolveDesktop(
  4302. HANDLE hProcess,
  4303. PUNICODE_STRING pstrDesktop,
  4304. HWINSTA *phwinsta,
  4305. BOOL fInherit,
  4306. BOOL* pbShutDown)
  4307. {
  4308. PEPROCESS Process;
  4309. PPROCESSINFO ppi;
  4310. HWINSTA hwinsta;
  4311. HDESK hdesk;
  4312. PDESKTOP pdesk;
  4313. PWINDOWSTATION pwinsta;
  4314. BOOL fInteractive;
  4315. UNICODE_STRING strDesktop,
  4316. strWinSta,
  4317. strStatic;
  4318. PUNICODE_STRING pstrStatic;
  4319. WCHAR wchStaticBuffer[STATIC_UNICODE_BUFFER_LENGTH];
  4320. LPWSTR pszDesktop;
  4321. POBJECT_ATTRIBUTES pObjA = NULL;
  4322. SIZE_T cbObjA;
  4323. WCHAR awchName[sizeof(L"Service-0x0000-0000$") / sizeof(WCHAR)];
  4324. BOOL fWinStaDefaulted;
  4325. BOOL fDesktopDefaulted;
  4326. LUID luidService;
  4327. NTSTATUS Status;
  4328. HWINSTA hwinstaDup;
  4329. CheckCritIn();
  4330. Status = ObReferenceObjectByHandle(hProcess,
  4331. PROCESS_QUERY_INFORMATION,
  4332. *PsProcessType,
  4333. UserMode,
  4334. &Process,
  4335. NULL);
  4336. if (!NT_SUCCESS(Status)) {
  4337. RIPMSG1(RIP_WARNING, "xxxResolveDesktop: Could not reference process handle (0x%X)", hProcess);
  4338. return NULL;
  4339. }
  4340. hwinsta = hwinstaDup = NULL;
  4341. hdesk = NULL;
  4342. strStatic.Length = 0;
  4343. strStatic.MaximumLength = STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR);
  4344. strStatic.Buffer = wchStaticBuffer;
  4345. /*
  4346. * If the process already has a windowstation and a startup desktop,
  4347. * return them.
  4348. *
  4349. * Make sure the process has not been destroyed first. Windows NT Bug
  4350. * #214643.
  4351. */
  4352. ppi = PpiFromProcess(Process);
  4353. if (ppi != NULL) {
  4354. if (ppi->W32PF_Flags & W32PF_TERMINATED) {
  4355. ObDereferenceObject(Process);
  4356. RIPMSG1(RIP_WARNING,
  4357. "xxxResolveDesktop: ppi 0x%p has been destroyed",
  4358. ppi);
  4359. return NULL;
  4360. }
  4361. if (ppi->hwinsta != NULL && ppi->hdeskStartup != NULL) {
  4362. /*
  4363. * If the target process is the current process, simply return
  4364. * the handles. Otherwise, open the objects.
  4365. */
  4366. if (Process == PsGetCurrentProcess()) {
  4367. hwinsta = ppi->hwinsta;
  4368. hdesk = ppi->hdeskStartup;
  4369. } else {
  4370. Status = ObOpenObjectByPointer(ppi->rpwinsta,
  4371. 0,
  4372. NULL,
  4373. MAXIMUM_ALLOWED,
  4374. *ExWindowStationObjectType,
  4375. UserMode,
  4376. &hwinsta);
  4377. if (NT_SUCCESS(Status)) {
  4378. Status = ObOpenObjectByPointer(ppi->rpdeskStartup,
  4379. 0,
  4380. NULL,
  4381. MAXIMUM_ALLOWED,
  4382. *ExDesktopObjectType,
  4383. UserMode,
  4384. &hdesk);
  4385. if (!NT_SUCCESS(Status)) {
  4386. UserVerify(NT_SUCCESS(ObCloseHandle(hwinsta, UserMode)));
  4387. hwinsta = NULL;
  4388. }
  4389. }
  4390. if (!NT_SUCCESS(Status)) {
  4391. RIPNTERR2(Status,
  4392. RIP_WARNING,
  4393. "xxxResolveDesktop: Failed to reference winsta=0x%p or desktop=0x%p",
  4394. ppi->rpwinsta,
  4395. ppi->rpdeskStartup);
  4396. }
  4397. }
  4398. RIPMSG2(RIP_VERBOSE,
  4399. "xxxResolveDesktop: to hwinsta=%#p desktop=%#p",
  4400. hwinsta, hdesk);
  4401. ObDereferenceObject(Process);
  4402. *phwinsta = hwinsta;
  4403. return hdesk;
  4404. }
  4405. }
  4406. /*
  4407. * Determine windowstation and desktop names.
  4408. */
  4409. if (pstrDesktop == NULL || pstrDesktop->Length == 0) {
  4410. RtlInitUnicodeString(&strDesktop, L"Default");
  4411. fWinStaDefaulted = fDesktopDefaulted = TRUE;
  4412. } else {
  4413. USHORT cch;
  4414. /*
  4415. * The name is of the form windowstation\desktop. Parse the string
  4416. * to separate out the names.
  4417. */
  4418. strWinSta = *pstrDesktop;
  4419. cch = strWinSta.Length / sizeof(WCHAR);
  4420. pszDesktop = strWinSta.Buffer;
  4421. while (cch && *pszDesktop != L'\\') {
  4422. cch--;
  4423. pszDesktop++;
  4424. }
  4425. fDesktopDefaulted = FALSE;
  4426. if (cch == 0) {
  4427. /*
  4428. * No windowstation name was specified, only the desktop.
  4429. */
  4430. strDesktop = strWinSta;
  4431. fWinStaDefaulted = TRUE;
  4432. } else {
  4433. /*
  4434. * Both names were in the string.
  4435. */
  4436. strDesktop.Buffer = pszDesktop + 1;
  4437. strDesktop.Length = strDesktop.MaximumLength = (cch - 1) * sizeof(WCHAR);
  4438. strWinSta.Length = (USHORT)(pszDesktop - strWinSta.Buffer) * sizeof(WCHAR);
  4439. fWinStaDefaulted = FALSE;
  4440. RtlAppendUnicodeToString(&strStatic, (PWSTR)szWindowStationDirectory);
  4441. RtlAppendUnicodeToString(&strStatic, L"\\");
  4442. RtlAppendUnicodeStringToString(&strStatic, &strWinSta);
  4443. if (!NT_SUCCESS(Status = _UserTestForWinStaAccess(&strStatic,TRUE))) {
  4444. RIPMSG3(RIP_WARNING,
  4445. "xxxResolveDesktop: Error (0x%x) resolving winsta='%.*ws'",
  4446. Status,
  4447. strStatic.Length,
  4448. strStatic.Buffer);
  4449. goto ReturnNull;
  4450. }
  4451. }
  4452. }
  4453. /*
  4454. * If the desktop name is defaulted, make the handles not inheritable.
  4455. */
  4456. if (fDesktopDefaulted) {
  4457. fInherit = FALSE;
  4458. }
  4459. /*
  4460. * If a windowstation has not been assigned to this process yet and
  4461. * there are existing windowstations, attempt an open.
  4462. */
  4463. if (hwinsta == NULL && grpWinStaList) {
  4464. /*
  4465. * If the windowstation name was defaulted, create a name based on
  4466. * the session.
  4467. */
  4468. if (fWinStaDefaulted) {
  4469. /*
  4470. * Default Window Station.
  4471. */
  4472. RtlInitUnicodeString(&strWinSta, L"WinSta0");
  4473. RtlAppendUnicodeToString(&strStatic, szWindowStationDirectory);
  4474. RtlAppendUnicodeToString(&strStatic, L"\\");
  4475. RtlAppendUnicodeStringToString(&strStatic, &strWinSta);
  4476. if (gbRemoteSession) {
  4477. /*
  4478. * Fake this out if it's an non-interactive winstation startup.
  4479. * We don't want an extra winsta.
  4480. */
  4481. fInteractive = NT_SUCCESS(_UserTestForWinStaAccess(&strStatic, TRUE));
  4482. } else {
  4483. fInteractive = NT_SUCCESS(_UserTestForWinStaAccess(&strStatic,fInherit));
  4484. }
  4485. if (!fInteractive) {
  4486. GetProcessLuid(NULL, &luidService);
  4487. swprintf(awchName,
  4488. L"Service-0x%x-%x$",
  4489. luidService.HighPart,
  4490. luidService.LowPart);
  4491. RtlInitUnicodeString(&strWinSta, awchName);
  4492. }
  4493. }
  4494. /*
  4495. * If no windowstation name was passed in and a windowstation
  4496. * handle was inherited, assign it.
  4497. */
  4498. if (fWinStaDefaulted) {
  4499. if (ObFindHandleForObject(Process, NULL, *ExWindowStationObjectType,
  4500. NULL, &hwinsta)) {
  4501. /*
  4502. * If the handle belongs to another process, dup it into
  4503. * this one.
  4504. */
  4505. if (Process != PsGetCurrentProcess()) {
  4506. Status = ZwDuplicateObject(hProcess,
  4507. hwinsta,
  4508. NtCurrentProcess(),
  4509. &hwinstaDup,
  4510. 0,
  4511. 0,
  4512. DUPLICATE_SAME_ACCESS);
  4513. if (!NT_SUCCESS(Status)) {
  4514. hwinsta = NULL;
  4515. } else {
  4516. hwinsta = hwinstaDup;
  4517. }
  4518. }
  4519. }
  4520. }
  4521. /*
  4522. * If we were assigned to a windowstation, make sure
  4523. * it matches our fInteractive flag
  4524. */
  4525. if (hwinsta != NULL) {
  4526. Status = ObReferenceObjectByHandle(hwinsta,
  4527. 0,
  4528. *ExWindowStationObjectType,
  4529. KernelMode,
  4530. &pwinsta,
  4531. NULL);
  4532. if (NT_SUCCESS(Status)) {
  4533. BOOL fIO = (pwinsta->dwWSF_Flags & WSF_NOIO) ? FALSE : TRUE;
  4534. if (fIO != fInteractive) {
  4535. if (hwinstaDup) {
  4536. CloseProtectedHandle(hwinsta);
  4537. }
  4538. hwinsta = NULL;
  4539. }
  4540. ObDereferenceObject(pwinsta);
  4541. }
  4542. }
  4543. /*
  4544. * If not, open the computed windowstation.
  4545. */
  4546. if (NT_SUCCESS(Status) && hwinsta == NULL) {
  4547. /*
  4548. * Fill in the path to the windowstation
  4549. */
  4550. strStatic.Length = 0;
  4551. RtlAppendUnicodeToString(&strStatic, szWindowStationDirectory);
  4552. RtlAppendUnicodeToString(&strStatic, L"\\");
  4553. RtlAppendUnicodeStringToString(&strStatic, &strWinSta);
  4554. /*
  4555. * Allocate an object attributes structure, a UNICODE_STRING structure and a string
  4556. * buffer of suitable length in user address space.
  4557. */
  4558. cbObjA = sizeof(*pObjA) + sizeof(*pstrStatic) + STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR);
  4559. Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
  4560. &pObjA, 0, &cbObjA, MEM_COMMIT, PAGE_READWRITE);
  4561. pstrStatic = (PUNICODE_STRING)((PBYTE)pObjA + sizeof(*pObjA));
  4562. if (NT_SUCCESS(Status)) {
  4563. /*
  4564. * Note -- the string must be in client-space or the
  4565. * address validation in _OpenWindowStation will fail.
  4566. */
  4567. try {
  4568. pstrStatic->Length = 0;
  4569. pstrStatic->MaximumLength = STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR);
  4570. pstrStatic->Buffer = (PWSTR)((PBYTE)pstrStatic + sizeof(*pstrStatic));
  4571. RtlCopyUnicodeString(pstrStatic, &strStatic);
  4572. InitializeObjectAttributes(pObjA,
  4573. pstrStatic,
  4574. OBJ_CASE_INSENSITIVE,
  4575. NULL,
  4576. NULL);
  4577. if (fInherit) {
  4578. pObjA->Attributes |= OBJ_INHERIT;
  4579. }
  4580. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  4581. Status = GetExceptionCode();
  4582. }
  4583. if (NT_SUCCESS(Status)) {
  4584. hwinsta = _OpenWindowStation(pObjA, MAXIMUM_ALLOWED, UserMode);
  4585. }
  4586. }
  4587. }
  4588. /*
  4589. * Only allow service logons at the console. I don't think our
  4590. * win32k exit routines cope with more than one windowstation.
  4591. *
  4592. * If the open failed and the process is in a non-interactive logon
  4593. * session, attempt to create a windowstation and desktop for that
  4594. * session. Note that the desktop handle will be closed after the
  4595. * desktop has been assigned.
  4596. */
  4597. if (!gbRemoteSession && NT_SUCCESS(Status) &&
  4598. hwinsta == NULL && !fInteractive && fWinStaDefaulted) {
  4599. *phwinsta = xxxConnectService(&strStatic, &hdesk);
  4600. /*
  4601. * Clean up and leave.
  4602. */
  4603. if (pObjA != NULL) {
  4604. ZwFreeVirtualMemory(NtCurrentProcess(),
  4605. &pObjA,
  4606. &cbObjA,
  4607. MEM_RELEASE);
  4608. }
  4609. ObDereferenceObject(Process);
  4610. RIPMSG2(RIP_VERBOSE,
  4611. "xxxResolveDesktop: xxxConnectService was called"
  4612. "to hwinsta=%#p desktop=%#p",
  4613. *phwinsta, hdesk);
  4614. return hdesk;
  4615. }
  4616. }
  4617. /*
  4618. * Attempt to assign a desktop.
  4619. */
  4620. if (hwinsta != NULL) {
  4621. /*
  4622. * Every gui thread needs an associated desktop. We'll use the
  4623. * default to start with and the application can override it if it
  4624. * wants.
  4625. */
  4626. if (hdesk == NULL) {
  4627. /*
  4628. * If no desktop name was passed in and a desktop handle was
  4629. * inherited, assign it.
  4630. */
  4631. if (fDesktopDefaulted) {
  4632. if (ObFindHandleForObject(Process, NULL, *ExDesktopObjectType,
  4633. NULL, &hdesk)) {
  4634. /*
  4635. * If the handle belongs to another process, dup it into
  4636. * this one.
  4637. */
  4638. if (Process != PsGetCurrentProcess()) {
  4639. HDESK hdeskDup;
  4640. Status = ZwDuplicateObject(hProcess,
  4641. hdesk,
  4642. NtCurrentProcess(),
  4643. &hdeskDup,
  4644. 0,
  4645. 0,
  4646. DUPLICATE_SAME_ACCESS);
  4647. if (!NT_SUCCESS(Status)) {
  4648. CloseProtectedHandle(hdesk);
  4649. hdesk = NULL;
  4650. } else {
  4651. hdesk = hdeskDup;
  4652. }
  4653. }
  4654. /*
  4655. * Map the desktop into the process.
  4656. */
  4657. if (hdesk != NULL && ppi != NULL) {
  4658. Status = ObReferenceObjectByHandle(hdesk,
  4659. 0,
  4660. *ExDesktopObjectType,
  4661. KernelMode,
  4662. &pdesk,
  4663. NULL);
  4664. if (NT_SUCCESS(Status)) {
  4665. LogDesktop(pdesk, LD_REF_FN_RESOLVEDESKTOP, TRUE, (ULONG_PTR)PtiCurrent());
  4666. {
  4667. WIN32_OPENMETHOD_PARAMETERS OpenParams;
  4668. OpenParams.OpenReason = ObOpenHandle;
  4669. OpenParams.Process = Process;
  4670. OpenParams.Object = pdesk;
  4671. OpenParams.GrantedAccess = 0;
  4672. OpenParams.HandleCount = 1;
  4673. if (!NT_SUCCESS(MapDesktop(&OpenParams))) {
  4674. Status = STATUS_NO_MEMORY;
  4675. CloseProtectedHandle(hdesk);
  4676. hdesk = NULL;
  4677. }
  4678. }
  4679. UserAssert(hdesk == NULL ||
  4680. GetDesktopView(ppi, pdesk) != NULL);
  4681. LogDesktop(pdesk, LD_DEREF_FN_RESOLVEDESKTOP, FALSE, (ULONG_PTR)PtiCurrent());
  4682. ObDereferenceObject(pdesk);
  4683. } else {
  4684. CloseProtectedHandle(hdesk);
  4685. hdesk = NULL;
  4686. }
  4687. }
  4688. }
  4689. }
  4690. /*
  4691. * If not, open the desktop.
  4692. */
  4693. if (NT_SUCCESS(Status) && hdesk == NULL) {
  4694. RtlCopyUnicodeString(&strStatic, &strDesktop);
  4695. if (pObjA == NULL) {
  4696. /*
  4697. * Allocate an object attributes structure, a UNICODE_STRING structure and a string
  4698. * buffer of suitable length in user address space.
  4699. */
  4700. cbObjA = sizeof(*pObjA) + sizeof(*pstrStatic) + STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR);
  4701. Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
  4702. &pObjA, 0, &cbObjA, MEM_COMMIT, PAGE_READWRITE);
  4703. pstrStatic = (PUNICODE_STRING)((PBYTE)pObjA + sizeof(*pObjA));
  4704. }
  4705. if (NT_SUCCESS(Status)) {
  4706. /*
  4707. * Note -- the string must be in client-space or the
  4708. * address validation in _OpenDesktop will fail.
  4709. */
  4710. try {
  4711. pstrStatic->Length = 0;
  4712. pstrStatic->MaximumLength = STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR);
  4713. pstrStatic->Buffer = (PWSTR)((PBYTE)pstrStatic + sizeof(*pstrStatic));
  4714. RtlCopyUnicodeString(pstrStatic, &strStatic);
  4715. InitializeObjectAttributes( pObjA,
  4716. pstrStatic,
  4717. OBJ_CASE_INSENSITIVE,
  4718. hwinsta,
  4719. NULL
  4720. );
  4721. if (fInherit) {
  4722. pObjA->Attributes |= OBJ_INHERIT;
  4723. }
  4724. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  4725. Status = GetExceptionCode();
  4726. }
  4727. if (NT_SUCCESS(Status)) {
  4728. hdesk = _OpenDesktop(pObjA,
  4729. UserMode,
  4730. 0,
  4731. MAXIMUM_ALLOWED,
  4732. pbShutDown);
  4733. }
  4734. }
  4735. }
  4736. }
  4737. if (hdesk == NULL) {
  4738. UserVerify(NT_SUCCESS(ObCloseHandle(hwinsta, UserMode)));
  4739. hwinsta = NULL;
  4740. }
  4741. }
  4742. goto ExitNormally;
  4743. ReturnNull:
  4744. UserAssert(hdesk == NULL);
  4745. if (hwinsta != NULL) {
  4746. UserVerify(NT_SUCCESS(ObCloseHandle(hwinsta, UserMode)));
  4747. hwinsta = NULL;
  4748. }
  4749. ExitNormally:
  4750. if (pObjA != NULL) {
  4751. ZwFreeVirtualMemory(NtCurrentProcess(), &pObjA, &cbObjA, MEM_RELEASE);
  4752. }
  4753. ObDereferenceObject(Process);
  4754. *phwinsta = hwinsta;
  4755. return hdesk;
  4756. }
  4757. #ifdef REDIRECTION
  4758. #define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | \
  4759. DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | \
  4760. DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | \
  4761. DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | \
  4762. DESKTOP_SWITCHDESKTOP | DESKTOP_QUERY_INFORMATION | \
  4763. DESKTOP_REDIRECT | STANDARD_RIGHTS_REQUIRED)
  4764. #else
  4765. #define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | \
  4766. DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | \
  4767. DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | \
  4768. DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | \
  4769. DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED)
  4770. #endif
  4771. NTSTATUS
  4772. SetDisconnectDesktopSecurity(
  4773. IN HDESK hdeskDisconnect)
  4774. {
  4775. ULONG ulLength;
  4776. NTSTATUS Status = STATUS_SUCCESS;
  4777. SID_IDENTIFIER_AUTHORITY NtSidAuthority = SECURITY_NT_AUTHORITY;
  4778. PACCESS_ALLOWED_ACE pace = NULL;
  4779. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  4780. PSID pSystemSid = NULL;
  4781. /*
  4782. * Get the well-known system SID.
  4783. */
  4784. pSystemSid = UserAllocPoolWithQuota(RtlLengthRequiredSid(1), TAG_SECURITY);
  4785. if (pSystemSid != NULL) {
  4786. *(RtlSubAuthoritySid(pSystemSid, 0)) = SECURITY_LOCAL_SYSTEM_RID;
  4787. Status = RtlInitializeSid(pSystemSid, &NtSidAuthority, (UCHAR)1);
  4788. } else {
  4789. Status = STATUS_INSUFFICIENT_RESOURCES;
  4790. }
  4791. if (!NT_SUCCESS(Status)) {
  4792. goto done;
  4793. }
  4794. /*
  4795. * Allocate and ACE that give System all ACCESS (No access to any one else).
  4796. */
  4797. pace = AllocAce(NULL, ACCESS_ALLOWED_ACE_TYPE, 0,
  4798. DESKTOP_ALL,
  4799. pSystemSid, &ulLength);
  4800. if (pace == NULL) {
  4801. RIPMSG0(RIP_WARNING, "GetDisconnectDesktopSecurityDescriptor: AllocAce for Desktop Attributes failed");
  4802. Status = STATUS_INSUFFICIENT_RESOURCES;
  4803. goto done;
  4804. }
  4805. /*
  4806. * Create the security descriptor.
  4807. */
  4808. pSecurityDescriptor = CreateSecurityDescriptor(pace, ulLength, FALSE);
  4809. if (pSecurityDescriptor == NULL) {
  4810. RIPMSG0(RIP_WARNING, "GetDisconnectDesktopSecurityDescriptor: CreateSecurityDescriptor failed");
  4811. Status = STATUS_INSUFFICIENT_RESOURCES;
  4812. goto done;
  4813. }
  4814. /*
  4815. * Set security on Disconnected desktop.
  4816. */
  4817. Status = ZwSetSecurityObject(hdeskDisconnect,
  4818. DACL_SECURITY_INFORMATION,
  4819. pSecurityDescriptor);
  4820. done:
  4821. /*
  4822. * Cleanup allocations.
  4823. */
  4824. if (pSystemSid != NULL) {
  4825. UserFreePool(pSystemSid);
  4826. }
  4827. if (pace != NULL) {
  4828. UserFreePool(pace);
  4829. }
  4830. if (pSecurityDescriptor != NULL) {
  4831. UserFreePool(pSecurityDescriptor);
  4832. }
  4833. return Status;
  4834. }
  4835. #ifdef DEBUG_DESK
  4836. VOID ValidateDesktop(
  4837. PDESKTOP pdesk)
  4838. {
  4839. /*
  4840. * Verify that the desktop has been cleaned out.
  4841. */
  4842. PHE pheT, pheMax;
  4843. BOOL fDirty = FALSE;
  4844. pheMax = &gSharedInfo.aheList[giheLast];
  4845. for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) {
  4846. switch (pheT->bType) {
  4847. case TYPE_WINDOW:
  4848. if (((PWND)pheT->phead)->head.rpdesk == pdesk) {
  4849. DbgPrint("Window at 0x%p exists\n", pheT->phead);
  4850. break;
  4851. }
  4852. continue;
  4853. case TYPE_MENU:
  4854. if (((PMENU)pheT->phead)->head.rpdesk == pdesk) {
  4855. DbgPrint("Menu at 0x%p exists\n", pheT->phead);
  4856. break;
  4857. }
  4858. continue;
  4859. case TYPE_CALLPROC:
  4860. if (((PCALLPROCDATA)pheT->phead)->head.rpdesk == pdesk) {
  4861. DbgPrint("Callproc at 0x%p exists\n", pheT->phead);
  4862. break;
  4863. }
  4864. continue;
  4865. case TYPE_HOOK:
  4866. if (((PHOOK)pheT->phead)->head.rpdesk == pdesk) {
  4867. DbgPrint("Hook at 0x%p exists\n", pheT->phead);
  4868. break;
  4869. }
  4870. continue;
  4871. default:
  4872. continue;
  4873. }
  4874. fDirty = TRUE;
  4875. }
  4876. UserAssert(!fDirty);
  4877. }
  4878. #endif
  4879. /***************************************************************************\
  4880. * DbgCheckForThreadsOnDesktop
  4881. *
  4882. * Validates that no threads in the process are still on this desktop.
  4883. *
  4884. * NB: This desktop can be in a different session than the process, so you
  4885. * CANNOT deref pdesk here.
  4886. *
  4887. * History:
  4888. * 27-Jun-2001 JasonSch Created.
  4889. \***************************************************************************/
  4890. VOID DbgCheckForThreadsOnDesktop(
  4891. PPROCESSINFO ppi,
  4892. PDESKTOP pdesk)
  4893. {
  4894. #if DBG
  4895. PTHREADINFO pti = ppi->ptiList;
  4896. while (pti != NULL) {
  4897. UserAssertMsg2(pti->rpdesk != pdesk,
  4898. "pti 0x%p still on pdesk 0x%p",
  4899. pti,
  4900. pdesk);
  4901. pti = pti->ptiSibling;
  4902. }
  4903. #else
  4904. UNREFERENCED_PARAMETER(ppi);
  4905. UNREFERENCED_PARAMETER(pdesk);
  4906. #endif
  4907. }