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.

2192 lines
64 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: misc.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains citrix code.
  7. *
  8. \***************************************************************************/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. USHORT gPreviousProtocolType = PROTOCOL_CONSOLE;
  12. LPCWSTR G_DisconnectDisplayDriverName = L"TSDDD\0";
  13. extern HANDLE ghSwitcher;
  14. HDEV DrvGetHDEV(PUNICODE_STRING pusDeviceName);
  15. VOID DrvReleaseHDEV(PUNICODE_STRING pstrDeviceName);
  16. NTSTATUS xxxRequestOutOfFullScreenMode(
  17. VOID);
  18. NTSTATUS xxxRemoteConsoleShadowStart(
  19. IN PDOCONNECTDATA pDoConnectData,
  20. IN PWCHAR DisplayDriverName);
  21. NTSTATUS xxxRemoteConsoleShadowStop(
  22. VOID);
  23. /*
  24. * FindMirrorDriver
  25. *
  26. * Helper function that searches for the named driver as a mirror device
  27. * and fills in pDisplayDevice
  28. *
  29. * Returns TRUE if successful; FALSE otherwise.
  30. */
  31. NTSTATUS FindMirrorDriver(
  32. IN PCWSTR pwszDispDriverName,
  33. OUT PDISPLAY_DEVICEW pDisplayDevice)
  34. {
  35. DWORD iDevNum = 0;
  36. BOOLEAN fFound = FALSE;
  37. WCHAR Buffer[256];
  38. WCHAR Service[128];
  39. PWCHAR pCurr = NULL;
  40. UNICODE_STRING UnicodeString;
  41. UNICODE_STRING DrvNameString;
  42. RtlInitUnicodeString(&DrvNameString, pwszDispDriverName);
  43. pDisplayDevice->cb = sizeof(DISPLAY_DEVICEW);
  44. while (NT_SUCCESS(DrvEnumDisplayDevices(NULL,
  45. gpDispInfo->pMonitorPrimary->hDev,
  46. iDevNum++,
  47. pDisplayDevice,
  48. 0,
  49. KernelMode))) {
  50. if (!(pDisplayDevice->StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)) {
  51. continue;
  52. }
  53. RtlZeroMemory(Buffer, sizeof(Buffer));
  54. wcsncpy(Buffer, pDisplayDevice->DeviceKey, 250);
  55. pCurr = Buffer + wcslen(Buffer) - 1;
  56. while ((pCurr > Buffer) && (*pCurr != L'\\')) {
  57. pCurr--;
  58. }
  59. if (*pCurr == L'\\') {
  60. RTL_QUERY_REGISTRY_TABLE QueryTable[] = {
  61. { NULL,
  62. RTL_QUERY_REGISTRY_DIRECT,
  63. L"Service",
  64. &UnicodeString,
  65. REG_NONE,
  66. NULL,
  67. 0
  68. },
  69. { 0, 0, 0, 0, 0, 0, 0 }
  70. };
  71. pCurr++;
  72. wcscpy(pCurr, L"Video");
  73. RtlZeroMemory(Service, sizeof(Service));
  74. UnicodeString.Length = 0;
  75. UnicodeString.MaximumLength = sizeof(Service);
  76. UnicodeString.Buffer = Service;
  77. if (NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  78. Buffer,
  79. QueryTable,
  80. NULL,
  81. NULL))) {
  82. if (RtlCompareUnicodeString(&UnicodeString,
  83. &DrvNameString,
  84. TRUE) == 0) {
  85. fFound = TRUE;
  86. break;
  87. }
  88. }
  89. }
  90. }
  91. return (fFound ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
  92. }
  93. /*
  94. * All of the following are gotten from ICASRV.
  95. */
  96. CACHE_STATISTICS ThinWireCache;
  97. BOOL DrvSetGraphicsDevices(
  98. LPCWSTR pDisplayDriverName);
  99. BOOL AttachInputDevices(BOOL bLocalDevices);
  100. VOID RemoveInputDevices(
  101. VOID);
  102. VOID CloseLocalGraphicsDevices(
  103. VOID);
  104. VOID OpenLocalGraphicsDevices(
  105. VOID);
  106. extern PKTIMER gptmrWD;
  107. /*
  108. * Read current power policy from Kernel, and set our variables.
  109. */
  110. VOID ReadCurrentPowerSettting(
  111. VOID)
  112. {
  113. SYSTEM_POWER_POLICY PowerPolicy;
  114. BOOL bGotPowerPolicy;
  115. LeaveCrit();
  116. bGotPowerPolicy = (STATUS_SUCCESS == ZwPowerInformation(SystemPowerPolicyCurrent, NULL, 0, &PowerPolicy, sizeof(PowerPolicy)));
  117. EnterCrit();
  118. if (bGotPowerPolicy) {
  119. xxxSystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
  120. PowerPolicy.VideoTimeout,
  121. 0,
  122. 0);
  123. xxxSystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
  124. PowerPolicy.VideoTimeout,
  125. 0,
  126. 0);
  127. }
  128. }
  129. BOOL IsSessionSwitchBlocked(
  130. VOID)
  131. {
  132. return gfSessionSwitchBlock;
  133. }
  134. /*
  135. * This function blocks session switch from happening paired with
  136. * UserSessionSwitchBlock_End.
  137. */
  138. NTSTATUS UserSessionSwitchBlock_Start(
  139. VOID)
  140. {
  141. NTSTATUS Status;
  142. EnterCrit();
  143. if (!gfSwitchInProgress && SharedUserData->ActiveConsoleId == gSessionId && !gfSessionSwitchBlock) {
  144. gfSessionSwitchBlock = TRUE;
  145. Status = STATUS_SUCCESS;
  146. } else {
  147. Status = STATUS_CTX_NOT_CONSOLE;
  148. }
  149. LeaveCrit();
  150. return Status;
  151. }
  152. /*
  153. * This function removes the block on session switch initiated via
  154. * UserSessionSwitchBlock_Start().
  155. */
  156. VOID UserSessionSwitchBlock_End(
  157. VOID)
  158. {
  159. EnterCrit();
  160. UserAssert(SharedUserData->ActiveConsoleId == gSessionId);
  161. UserAssert(IsSessionSwitchBlocked());
  162. gfSessionSwitchBlock = FALSE;
  163. LeaveCrit();
  164. }
  165. NTSTATUS UserSessionSwitchEnterCrit(
  166. VOID)
  167. {
  168. /*
  169. * This is intended for code that needs synchronization with session
  170. * switching from local to remote or remote to local.
  171. *
  172. * If a session switch is in progress fail, otherwise return with the
  173. * USER critical section held. The call must call
  174. * UserSessionSwitchLeaveCrit() to release the USER critical section.
  175. */
  176. EnterCrit();
  177. if (!gfSwitchInProgress) {
  178. return STATUS_SUCCESS;
  179. } else{
  180. LeaveCrit();
  181. return STATUS_UNSUCCESSFUL;
  182. }
  183. }
  184. VOID UserSessionSwitchLeaveCrit(
  185. VOID)
  186. {
  187. LeaveCrit();
  188. }
  189. VOID UserGetDisconnectDeviceResolutionHint(
  190. PDEVMODEW pDevmodeInformation)
  191. {
  192. /*
  193. * When switching to the disconnected DD it is better using the current
  194. * display resolution in order to avoid apps to move on the desktop as
  195. * a result of the resize. DrvGetDisplayDriverParameters() calls this
  196. * function for the disconnected display.
  197. */
  198. if (gProtocolType == PROTOCOL_DISCONNECT) {
  199. pDevmodeInformation->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
  200. pDevmodeInformation->dmPelsWidth = gpsi->aiSysMet[SM_CXVIRTUALSCREEN];
  201. pDevmodeInformation->dmPelsHeight = gpsi->aiSysMet[SM_CYVIRTUALSCREEN];
  202. }
  203. }
  204. NTSTATUS RemoteConnect(
  205. IN PDOCONNECTDATA pDoConnectData,
  206. IN ULONG DisplayDriverNameLength,
  207. IN PWCHAR DisplayDriverName)
  208. {
  209. NTSTATUS Status = STATUS_SUCCESS;
  210. PWCHAR pSep;
  211. //
  212. // This API is Also used to initialize the console shadow by loading
  213. // the console shadow mirroring Display driver.
  214. //
  215. if (pDoConnectData->fConsoleShadowFlag) {
  216. Status = xxxRemoteConsoleShadowStart(pDoConnectData, DisplayDriverName);
  217. return Status;
  218. }
  219. TRACE_HYDAPI(("RemoteConnect: display %ws\n", DisplayDriverName));
  220. HYDRA_HINT(HH_REMOTECONNECT);
  221. UserAssert(ISCSRSS());
  222. /*
  223. * Indicate that a protocol switch is pending.
  224. */
  225. UserAssert(!gfSwitchInProgress);
  226. /*
  227. * If we are asked to block session switch, don't proceed.
  228. */
  229. if (gfSessionSwitchBlock) {
  230. return STATUS_UNSUCCESSFUL;
  231. }
  232. SetConsoleSwitchInProgress(TRUE);
  233. gpThinWireCache = &ThinWireCache;
  234. ghRemoteMouseChannel = pDoConnectData->IcaMouseChannel;
  235. ghRemoteVideoChannel = pDoConnectData->IcaVideoChannel;
  236. ghRemoteBeepChannel = pDoConnectData->IcaBeepChannel;
  237. ghRemoteKeyboardChannel = pDoConnectData->IcaKeyboardChannel;
  238. ghRemoteThinwireChannel = pDoConnectData->IcaThinwireChannel;
  239. gProtocolType = pDoConnectData->drProtocolType;
  240. gPreviousProtocolType = pDoConnectData->drProtocolType;
  241. gRemoteClientKeyboardType = pDoConnectData->ClientKeyboardType;
  242. gbClientDoubleClickSupport = pDoConnectData->fClientDoubleClickSupport;
  243. gfEnableWindowsKey = pDoConnectData->fEnableWindowsKey;
  244. RtlCopyMemory(gWinStationInfo.ProtocolName, pDoConnectData->ProtocolName,
  245. WPROTOCOLNAME_LENGTH * sizeof(WCHAR));
  246. RtlCopyMemory(gWinStationInfo.AudioDriverName, pDoConnectData->AudioDriverName,
  247. WAUDIONAME_LENGTH * sizeof(WCHAR));
  248. RtlZeroMemory(gstrBaseWinStationName,
  249. WINSTATIONNAME_LENGTH * sizeof(WCHAR));
  250. RtlCopyMemory(gstrBaseWinStationName, pDoConnectData->WinStationName,
  251. min(WINSTATIONNAME_LENGTH * sizeof(WCHAR), sizeof(pDoConnectData->WinStationName)));
  252. if (pSep = wcschr(gstrBaseWinStationName, L'#')) {
  253. *pSep = UNICODE_NULL;
  254. }
  255. gbConnected = TRUE;
  256. /*
  257. * WinStations must have the video device handle passed to them.
  258. */
  259. if (!gVideoFileObject) {
  260. PFILE_OBJECT pFileObject;
  261. PDEVICE_OBJECT pDeviceObject;
  262. //
  263. // Dereference the file handle
  264. // and obtain a pointer to the device object for the handle.
  265. //
  266. Status = ObReferenceObjectByHandle(ghRemoteVideoChannel,
  267. 0,
  268. NULL,
  269. KernelMode,
  270. (PVOID*)&pFileObject,
  271. NULL);
  272. if (NT_SUCCESS(Status)) {
  273. gVideoFileObject = pFileObject;
  274. //
  275. // Get a pointer to the device object for this file.
  276. //
  277. pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
  278. Status = ObReferenceObjectByHandle(ghRemoteThinwireChannel,
  279. 0,
  280. NULL,
  281. KernelMode,
  282. (PVOID*)&gThinwireFileObject,
  283. NULL);
  284. /*
  285. * This must be done before any thinwire data.
  286. */
  287. if (NT_SUCCESS(Status)) {
  288. if (!GreMultiUserInitSession(ghRemoteThinwireChannel,
  289. (PBYTE)gpThinWireCache,
  290. gVideoFileObject,
  291. gThinwireFileObject,
  292. DisplayDriverNameLength,
  293. DisplayDriverName)) {
  294. RIPMSG0(RIP_WARNING, "UserInit: GreMultiUserInitSession failed");
  295. Status = STATUS_UNSUCCESSFUL;
  296. } else {
  297. if (IsRemoteConnection()) {
  298. DWORD BytesReturned;
  299. Status = GreDeviceIoControl(pDeviceObject,
  300. IOCTL_VIDEO_ICA_ENABLE_GRAPHICS,
  301. NULL,
  302. 0,
  303. NULL,
  304. 0,
  305. &BytesReturned);
  306. if (!NT_SUCCESS(Status)) {
  307. RIPMSG1(RIP_WARNING,
  308. "UserInit: Enable graphics status 0x%x",
  309. Status);
  310. }
  311. }
  312. }
  313. }
  314. }
  315. }
  316. if (!NT_SUCCESS(Status)) {
  317. RIPMSG0(RIP_WARNING, "RemoteConnect failed");
  318. goto Exit;
  319. }
  320. Status = ObReferenceObjectByHandle(ghRemoteBeepChannel,
  321. 0,
  322. NULL,
  323. KernelMode,
  324. (PVOID*)&gpRemoteBeepDevice,
  325. NULL);
  326. if (!NT_SUCCESS(Status)) {
  327. RIPMSG1(RIP_WARNING,
  328. "Bad Remote Beep Channel, Status = 0x%x",
  329. Status);
  330. goto Exit;
  331. }
  332. /*
  333. * For session 0 we are done, since the initialization below
  334. * has already been taken care of.
  335. */
  336. if (!gbRemoteSession) {
  337. TRACE_INIT(("RemoteConnect Is OK for session %d\n", gSessionId));
  338. Status = STATUS_SUCCESS;
  339. goto Exit;
  340. }
  341. if (InitVideo(FALSE) == NULL) {
  342. gbConnected = FALSE;
  343. RIPMSG0(RIP_WARNING, "InitVideo failed");
  344. Status = STATUS_UNSUCCESSFUL;
  345. goto Exit;
  346. }
  347. if (!LW_BrushInit()) {
  348. RIPMSG0(RIP_WARNING, "LW_BrushInit failed");
  349. Status = STATUS_NO_MEMORY;
  350. goto Exit;
  351. }
  352. InitLoadResources();
  353. /*
  354. * Create and initialize a timer object
  355. * and pass a pointer to this object via the display driver to the WD.
  356. * The RIT will do a KeWaitForObject() on this timer object.
  357. * When the WD calls KeSetTimer() it will NOT specify a DPC routine.
  358. * When the timer goes off the RIT will get signaled and will make the
  359. * appropriate call to the display driver to flush the frame buffer.
  360. */
  361. gptmrWD = UserAllocPoolNonPagedNS(sizeof(KTIMER), TAG_SYSTEM);
  362. if (gptmrWD == NULL) {
  363. Status = STATUS_NO_MEMORY;
  364. RIPMSG0(RIP_WARNING, "RemoteConnect failed to create gptmrWD");
  365. goto Exit;
  366. }
  367. KeInitializeTimerEx(gptmrWD, SynchronizationTimer);
  368. /*
  369. * Video is initialized at this point.
  370. */
  371. gbVideoInitialized = TRUE;
  372. Exit:
  373. if (Status == STATUS_SUCCESS) {
  374. if (gProtocolType == PROTOCOL_CONSOLE) {
  375. SharedUserData->ActiveConsoleId = gSessionId;
  376. }
  377. }
  378. SetConsoleSwitchInProgress(FALSE);
  379. if (Status == STATUS_SUCCESS) {
  380. if (gbRemoteSession && gProtocolType == PROTOCOL_CONSOLE) {
  381. /*
  382. * For session 0 we receive power event callouts for us to
  383. * intitialize our power vars, but not for other sessions.
  384. * Thus, we have to read the power settings from kernel, and
  385. * initialize our variables. We do it only for PROTOCOL_CONSOLE
  386. * since, monitor power settings does not make sense to other
  387. * (non-console) sesssions.
  388. */
  389. ReadCurrentPowerSettting();
  390. }
  391. }
  392. return Status;
  393. }
  394. NTSTATUS xxxRemoteConsoleShadowStop(
  395. VOID)
  396. {
  397. DEVMODEW devmodeInformation = {0};
  398. DISPLAY_DEVICEW displayDevice;
  399. WCHAR *pwszDeviceName = &displayDevice.DeviceName[0];
  400. UNICODE_STRING strDeviceName;
  401. NTSTATUS Status;
  402. LONG lResult;
  403. TRACE_HYDAPI(("xxxRemoteConsoleShadowStop\n"));
  404. /*
  405. * Only allow CSRSS to do this
  406. */
  407. if (!ISCSRSS() || !ISTS()) {
  408. return STATUS_ACCESS_DENIED;
  409. }
  410. ASSERT(gfRemotingConsole == TRUE);
  411. ASSERT(gConsoleShadowhDev != NULL);
  412. if (gConsoleShadowhDev == NULL) {
  413. return STATUS_UNSUCCESSFUL;
  414. }
  415. /*
  416. * Tell thinwire driver about the disconnect.
  417. */
  418. bDrvDisconnect(gConsoleShadowhDev,
  419. ghConsoleShadowThinwireChannel,
  420. gConsoleShadowThinwireFileObject);
  421. DrvGetHdevName(gConsoleShadowhDev, pwszDeviceName);
  422. RtlInitUnicodeString(&strDeviceName, pwszDeviceName);
  423. /*
  424. * Free up resources.
  425. */
  426. DrvReleaseHDEV(&strDeviceName);
  427. gfRemotingConsole = FALSE;
  428. /*
  429. * Set up the dev mode info.
  430. */
  431. devmodeInformation.dmSize = sizeof(devmodeInformation);
  432. devmodeInformation.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
  433. /*
  434. * Width and height of zero mean detach.
  435. */
  436. TRACE_HYDAPI(("Unloading Chained DD"));
  437. /*
  438. * Like the load, this is in two stages - update the registry...
  439. */
  440. lResult = xxxUserChangeDisplaySettings(&strDeviceName,
  441. &devmodeInformation,
  442. NULL,
  443. CDS_UPDATEREGISTRY | CDS_NORESET,
  444. NULL,
  445. KernelMode);
  446. if (lResult == DISP_CHANGE_SUCCESSFUL) {
  447. /*
  448. * ... and force the change to be applied.
  449. */
  450. xxxUserChangeDisplaySettings(NULL,
  451. NULL,
  452. NULL,
  453. 0,
  454. NULL,
  455. KernelMode);
  456. GreConsoleShadowStop();
  457. }
  458. if (lResult != DISP_CHANGE_SUCCESSFUL) {
  459. Status = STATUS_UNSUCCESSFUL;
  460. } else {
  461. Status = STATUS_SUCCESS;
  462. }
  463. if (gConsoleShadowVideoFileObject != NULL) {
  464. ObDereferenceObject(gConsoleShadowVideoFileObject);
  465. gConsoleShadowVideoFileObject = NULL;
  466. }
  467. if (gConsoleShadowThinwireFileObject != NULL) {
  468. ObDereferenceObject(gConsoleShadowThinwireFileObject);
  469. gConsoleShadowThinwireFileObject = NULL;
  470. }
  471. if (gpConsoleShadowBeepDevice != NULL) {
  472. ObDereferenceObject(gpConsoleShadowBeepDevice);
  473. gpConsoleShadowBeepDevice = NULL;
  474. }
  475. if (gpConsoleShadowDisplayChangeEvent != NULL) {
  476. ObDereferenceObject(gpConsoleShadowDisplayChangeEvent);
  477. gpConsoleShadowDisplayChangeEvent = NULL;
  478. }
  479. gConsoleShadowhDev = NULL;
  480. /*
  481. * NB - Don't set console session state to disconnected or we won't
  482. * be able to shadow it again.
  483. */
  484. return Status;
  485. }
  486. NTSTATUS xxxRemoteConsoleShadowStart(
  487. IN PDOCONNECTDATA pDoConnectData,
  488. IN PWCHAR DisplayDriverName)
  489. {
  490. NTSTATUS Status = STATUS_SUCCESS;
  491. LONG lResult;
  492. PFILE_OBJECT pFileObject;
  493. PDEVICE_OBJECT pDeviceObject;
  494. DEVMODEW devmodeInformation = {0};
  495. DISPLAY_DEVICEW displayDevice = {0};
  496. UNICODE_STRING strDeviceName;
  497. BOOL fResult;
  498. TRACE_HYDAPI(("xxxRemoteConsoleShadowStart\n"));
  499. /*
  500. * we must be connected the local console.
  501. */
  502. ASSERT(gbConnected);
  503. ASSERT(!IsRemoteConnection());
  504. if (!gbConnected || IsRemoteConnection()) {
  505. return STATUS_UNSUCCESSFUL;
  506. }
  507. UserAssert(ISCSRSS());
  508. ASSERT(gfRemotingConsole == FALSE);
  509. ASSERT(gConsoleShadowhDev == NULL);
  510. gfRemotingConsole = FALSE;
  511. gConsoleShadowhDev = NULL;
  512. gpConsoleShadowThinWireCache = &ThinWireCache;
  513. ghConsoleShadowMouseChannel = pDoConnectData->IcaMouseChannel;
  514. ghConsoleShadowVideoChannel = pDoConnectData->IcaVideoChannel;
  515. ghConsoleShadowBeepChannel = pDoConnectData->IcaBeepChannel;
  516. ghConsoleShadowKeyboardChannel = pDoConnectData->IcaKeyboardChannel;
  517. ghConsoleShadowThinwireChannel = pDoConnectData->IcaThinwireChannel;
  518. gConsoleShadowProtocolType = pDoConnectData->drProtocolType;
  519. gRemoteClientKeyboardType = pDoConnectData->ClientKeyboardType;
  520. gbClientDoubleClickSupport = pDoConnectData->fClientDoubleClickSupport;
  521. gfEnableWindowsKey = pDoConnectData->fEnableWindowsKey;
  522. /*
  523. * WinStations must have the video device handle passed to them.
  524. */
  525. //
  526. // Dereference the file handle
  527. // and obtain a pointer to the device object for the handle.
  528. //
  529. Status = ObReferenceObjectByHandle(pDoConnectData->DisplayChangeEvent,
  530. EVENT_MODIFY_STATE,
  531. *ExEventObjectType,
  532. KernelMode,
  533. (PVOID*)&gpConsoleShadowDisplayChangeEvent,
  534. NULL);
  535. if (!NT_SUCCESS(Status)) {
  536. goto exit;
  537. }
  538. Status = ObReferenceObjectByHandle(ghConsoleShadowVideoChannel,
  539. 0,
  540. NULL,
  541. KernelMode,
  542. (PVOID*)&pFileObject,
  543. NULL);
  544. if (NT_SUCCESS(Status)) {
  545. gConsoleShadowVideoFileObject = pFileObject;
  546. //
  547. // Get a pointer to the device object for this file.
  548. //
  549. pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
  550. Status = ObReferenceObjectByHandle(ghConsoleShadowThinwireChannel,
  551. 0,
  552. NULL,
  553. KernelMode,
  554. (PVOID*)&gConsoleShadowThinwireFileObject,
  555. NULL);
  556. /*
  557. * This must be done before any thinwire data.
  558. */
  559. if (NT_SUCCESS(Status)) {
  560. if (!GreConsoleShadowStart(ghConsoleShadowThinwireChannel,
  561. (PBYTE)gpConsoleShadowThinWireCache,
  562. gConsoleShadowVideoFileObject,
  563. gConsoleShadowThinwireFileObject)) {
  564. RIPMSG0(RIP_WARNING, "UserInit: GreMultiUserInitSession failed");
  565. Status = STATUS_UNSUCCESSFUL;
  566. }
  567. }
  568. }
  569. if (!NT_SUCCESS(Status)) {
  570. goto exit;
  571. }
  572. Status = ObReferenceObjectByHandle(ghConsoleShadowBeepChannel,
  573. 0,
  574. NULL,
  575. KernelMode,
  576. (PVOID*)&gpConsoleShadowBeepDevice,
  577. NULL);
  578. if (!NT_SUCCESS(Status)) {
  579. goto exit;
  580. }
  581. /*
  582. * Find our DD from the list of possible devices
  583. */
  584. Status = FindMirrorDriver(DisplayDriverName, &displayDevice);
  585. if (!NT_SUCCESS(Status))
  586. {
  587. TRACE_INIT(("xxxRemoteConsoleShadowStart - FindMirrorDriver failed\n"));
  588. ASSERT(gfRemotingConsole == FALSE);
  589. goto exit;
  590. }
  591. RtlInitUnicodeString(&strDeviceName, &displayDevice.DeviceName[0]);
  592. /*
  593. * Set up the dev mode info.
  594. */
  595. devmodeInformation.dmSize = sizeof(devmodeInformation);
  596. devmodeInformation.dmFields = DM_POSITION | DM_BITSPERPEL |
  597. DM_PELSWIDTH | DM_PELSHEIGHT;
  598. devmodeInformation.dmBitsPerPel = pDoConnectData->drBitsPerPel;
  599. /*
  600. * The position and size are be set up to overlap the whole logical
  601. * desktop so that any secondary displays are included.
  602. */
  603. devmodeInformation.dmPosition.x = gpsi->aiSysMet[SM_XVIRTUALSCREEN];
  604. devmodeInformation.dmPosition.y = gpsi->aiSysMet[SM_YVIRTUALSCREEN];
  605. devmodeInformation.dmPelsWidth = gpsi->aiSysMet[SM_CXVIRTUALSCREEN];
  606. devmodeInformation.dmPelsHeight = gpsi->aiSysMet[SM_CYVIRTUALSCREEN];
  607. /*
  608. * Now load it - first pass sets up the registry
  609. */
  610. lResult = xxxUserChangeDisplaySettings(&strDeviceName,
  611. &devmodeInformation,
  612. NULL,
  613. CDS_UPDATEREGISTRY | CDS_NORESET,
  614. NULL,
  615. KernelMode);
  616. if (lResult == DISP_CHANGE_SUCCESSFUL) {
  617. /*
  618. * This pass actually updates the system.
  619. */
  620. lResult = xxxUserChangeDisplaySettings(NULL,
  621. NULL,
  622. NULL,
  623. 0,
  624. NULL,
  625. KernelMode);
  626. if (lResult == DISP_CHANGE_SUCCESSFUL) {
  627. /*
  628. * The chained DD should be loaded by now; open the hdev to it
  629. * which we will use later to actually call the various connect
  630. * functions.
  631. */
  632. gConsoleShadowhDev = DrvGetHDEV(&strDeviceName);
  633. if (gConsoleShadowhDev) {
  634. gfRemotingConsole = TRUE;
  635. /*
  636. * In case the display driver has not been unloaded at the end
  637. * of the previous shadow, reconnect to it.
  638. */
  639. fResult = bDrvReconnect(gConsoleShadowhDev, ghConsoleShadowThinwireChannel,
  640. gConsoleShadowThinwireFileObject, FALSE);
  641. /*
  642. * This is normally done in the RIT but for the console, the
  643. * RIT has already started before the DD is loaded...
  644. *
  645. * Pass a pointer to the timer to the WD via the display driver
  646. */
  647. if (fResult) {
  648. HDXDrvEscape(gConsoleShadowhDev,
  649. ESC_SET_WD_TIMEROBJ,
  650. (PVOID)gptmrWD,
  651. sizeof(gptmrWD));
  652. } else {
  653. Status = STATUS_UNSUCCESSFUL;
  654. }
  655. } else {
  656. Status = STATUS_UNSUCCESSFUL;
  657. }
  658. }
  659. }
  660. if (lResult != DISP_CHANGE_SUCCESSFUL) {
  661. Status = STATUS_UNSUCCESSFUL;
  662. }
  663. exit:
  664. if (!NT_SUCCESS(Status)) {
  665. if (gConsoleShadowVideoFileObject != NULL) {
  666. ObDereferenceObject(gConsoleShadowVideoFileObject);
  667. gConsoleShadowVideoFileObject = NULL;
  668. }
  669. if (gConsoleShadowThinwireFileObject != NULL) {
  670. ObDereferenceObject(gConsoleShadowThinwireFileObject);
  671. gConsoleShadowThinwireFileObject = NULL;
  672. }
  673. if (gpConsoleShadowBeepDevice != NULL) {
  674. ObDereferenceObject(gpConsoleShadowBeepDevice);
  675. gpConsoleShadowBeepDevice = NULL;
  676. }
  677. if (gpConsoleShadowDisplayChangeEvent != NULL) {
  678. ObDereferenceObject(gpConsoleShadowDisplayChangeEvent);
  679. gpConsoleShadowDisplayChangeEvent = NULL;
  680. }
  681. }
  682. return Status;
  683. }
  684. NTSTATUS
  685. xxxRemoteSetDisconnectDisplayMode(
  686. VOID)
  687. {
  688. NTSTATUS Status;
  689. USHORT prevProtocolType = gProtocolType;
  690. LONG lResult;
  691. /*
  692. * We rely on the GDI driver load : in the disconnected mode, the only
  693. * valid display driver to load is the one with the disconnect attribute.
  694. *
  695. */
  696. gProtocolType = PROTOCOL_DISCONNECT;
  697. lResult = xxxUserChangeDisplaySettings(NULL,
  698. NULL,
  699. grpdeskRitInput,
  700. CDS_RAWMODE,
  701. NULL,
  702. KernelMode);
  703. if (lResult != DISP_CHANGE_SUCCESSFUL) {
  704. Status = STATUS_UNSUCCESSFUL;
  705. gProtocolType = prevProtocolType;
  706. } else {
  707. Status = STATUS_SUCCESS;
  708. if (prevProtocolType == PROTOCOL_CONSOLE) {
  709. SharedUserData->ActiveConsoleId = -1;
  710. }
  711. }
  712. if (!NT_SUCCESS(Status)) {
  713. TRACE_INIT(("xxxRemoteSetDisconnectDisplayMode - Couldn't load Disconnect DD - lResult %x\n", lResult));
  714. RIPMSGF1(RIP_WARNING,
  715. "Couldn't load Disconnect DD - lResult 0x%x",
  716. lResult);
  717. }
  718. return Status;
  719. }
  720. NTSTATUS
  721. xxxRemoteDisconnect(
  722. VOID)
  723. {
  724. NTSTATUS Status = STATUS_SUCCESS;
  725. LARGE_INTEGER li;
  726. USHORT ProtocolType = gProtocolType;
  727. BOOL bCurrentPowerOn, SwitchedToDisconnectDesktop = FALSE;
  728. TRACE_HYDAPI(("xxxRemoteDisconnect\n"));
  729. /*
  730. * Only allow CSRSS to do this
  731. */
  732. if (!ISCSRSS() || !ISTS()) {
  733. return STATUS_ACCESS_DENIED;
  734. }
  735. if (!IsRemoteConnection()) {
  736. /*
  737. * Let's loop until the system has settled down and no mode switch
  738. * is currently occuring.
  739. */
  740. while (ghSwitcher != NULL) {
  741. xxxSleepThread(0, 1, FALSE);
  742. }
  743. }
  744. /*
  745. * If preparing for a disconnect from the console we need to exit fullscreen mode
  746. * if we are in full screen mode.
  747. */
  748. if (!IsRemoteConnection() && gbFullScreen == FULLSCREEN) {
  749. Status = xxxRequestOutOfFullScreenMode();
  750. if (!NT_SUCCESS(Status)) {
  751. RIPMSGF1(RIP_WARNING,
  752. "xxxRequestOutOfFullScreenMode failed, Status 0x%x",
  753. Status);
  754. return Status;
  755. }
  756. }
  757. HYDRA_HINT(HH_REMOTEDISCONNECT);
  758. RtlZeroMemory(gstrBaseWinStationName,
  759. WINSTATIONNAME_LENGTH * sizeof(WCHAR));
  760. UserAssert(gbConnected);
  761. /*
  762. * Indicate that a protocol switch is pending.
  763. */
  764. UserAssert(!gfSwitchInProgress);
  765. /*
  766. * If we are asked to block session switch, don't go ahead.
  767. */
  768. if (gfSessionSwitchBlock) {
  769. return STATUS_UNSUCCESSFUL;
  770. }
  771. SetConsoleSwitchInProgress(TRUE);
  772. /*
  773. * If we are on the console and PsW32GdiOff happens, we want to bring
  774. * the display back before doing any display change otherwise we'll
  775. * confuse GDI by disabling an already disabled MDEV.
  776. */
  777. if (!IsRemoteConnection()) {
  778. bCurrentPowerOn = DrvQueryMDEVPowerState(gpDispInfo->pmdev);
  779. if (!bCurrentPowerOn) {
  780. SafeEnableMDEV();
  781. DrvSetMDEVPowerState(gpDispInfo->pmdev, TRUE);
  782. DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD0);
  783. }
  784. }
  785. if (!IsRemoteConnection() && gbSnapShotWindowsAndMonitors && IsMultimon()) {
  786. SnapShotMonitorsAndWindowsRects();
  787. }
  788. if (gspdeskDisconnect == NULL) {
  789. /*
  790. * Convert dwMilliseconds to a relative-time(i.e. negative)
  791. * LARGE_INTEGER. NT Base calls take time values in 100 nanosecond
  792. * units. Timeout after 5 minutes.
  793. */
  794. li.QuadPart = Int32x32To64(-10000, 300000);
  795. KeWaitForSingleObject(gpEventDiconnectDesktop,
  796. WrUserRequest,
  797. KernelMode,
  798. FALSE,
  799. &li);
  800. }
  801. /*
  802. * Setup to shutdown screen saver and exit video power down mode on disconnect
  803. */
  804. if (glinp.dwFlags & LINP_POWERTIMEOUTS) {
  805. /*
  806. * Call video driver here to exit power down mode.
  807. */
  808. TAGMSG0(DBGTAG_Power, "Exit video power down mode");
  809. DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD0);
  810. }
  811. glinp.dwFlags = (glinp.dwFlags & ~LINP_INPUTTIMEOUTS);
  812. /*
  813. * If the disconnected desktop has not yet be setup. Do not do any
  814. * disconnect processing. It's better for the thinwire driver to try
  815. * and write rather than for the transmit buffers to be freed (trap).
  816. */
  817. if (gspdeskDisconnect) {
  818. /*
  819. * Blank the screen
  820. *
  821. * No need to stop graphics mode for disconnects
  822. */
  823. Status = xxxRemoteStopScreenUpdates();
  824. if (!NT_SUCCESS(Status)) {
  825. RIPMSGF1(RIP_WARNING,
  826. "xxxRemoteStopScreenUpdates failed with Status 0x%x",
  827. Status);
  828. goto done;
  829. } else {
  830. SwitchedToDisconnectDesktop = TRUE;
  831. }
  832. /*
  833. * If there are any shadow connections, then redraw the screen now.
  834. */
  835. if (gnShadowers)
  836. RemoteRedrawScreen();
  837. } else {
  838. RIPMSG0(RIP_WARNING, "xxxRemoteDisconnect failed. The disconnect desktop was not created");
  839. Status = STATUS_UNSUCCESSFUL;
  840. goto done;
  841. }
  842. /*
  843. * Tell thinwire driver about this
  844. */
  845. if (IsRemoteConnection()) {
  846. bDrvDisconnect(gpDispInfo->hDev,
  847. ghRemoteThinwireChannel,
  848. gThinwireFileObject);
  849. } else {
  850. /*
  851. * For a locally connected session, unload current display driver
  852. * and load disconnect DD.
  853. */
  854. Status = xxxRemoteSetDisconnectDisplayMode();
  855. /*
  856. * If are we disconnecting from local console, detach console input
  857. * devices and attach remote input devices (remote input devices are
  858. * 'empty handles' at this point but that is OK. Also free the
  859. * Scancode Map.
  860. */
  861. if (NT_SUCCESS(Status)) {
  862. CloseLocalGraphicsDevices();
  863. if (gpScancodeMap != 0) {
  864. UserFreePool(gpScancodeMap);
  865. gpScancodeMap = NULL;
  866. }
  867. }
  868. }
  869. /*
  870. * If we are disconnecting from the local console we need to detach
  871. * input devices and unregister for CDROM notifications. Do all this
  872. * only if the disconnect was successful so far.
  873. */
  874. if (NT_SUCCESS(Status) && ((gPreviousProtocolType = ProtocolType) == PROTOCOL_CONSOLE)) {
  875. xxxUnregisterDeviceClassNotifications();
  876. RemoveInputDevices();
  877. }
  878. if (NT_SUCCESS(Status)) {
  879. gbConnected = FALSE;
  880. }
  881. done:
  882. /*
  883. * If we did not succeed for some reason switch back to the orginal
  884. * desktop from the Disconnected desktop.
  885. */
  886. if (!NT_SUCCESS(Status) && SwitchedToDisconnectDesktop) {
  887. /*
  888. * Following call will revert to whatever desktop was present
  889. * before the Disconnect.
  890. */
  891. RemoteRedrawScreen();
  892. }
  893. if (!NT_SUCCESS(Status) && !IsRemoteConnection()) {
  894. CleanupMonitorsAndWindowsSnapShot();
  895. }
  896. /*
  897. * If we disconnected from the console we need to switch away from the
  898. * local graphics device, otherwise applications using CreateDC could
  899. * access the local devices.
  900. */
  901. if (NT_SUCCESS(Status) && ProtocolType == PROTOCOL_CONSOLE) {
  902. DrvSetGraphicsDevices(G_DisconnectDisplayDriverName);
  903. }
  904. SetConsoleSwitchInProgress(FALSE);
  905. return Status;
  906. }
  907. NTSTATUS xxxRemoteReconnect(
  908. IN PDORECONNECTDATA pDoReconnectData)
  909. {
  910. NTSTATUS Status = STATUS_SUCCESS;
  911. BOOL fResult;
  912. PWCHAR pSep;
  913. BOOL bSwitchingFromDisconectDD = FALSE;
  914. BOOL bChangedDisplaySettings = FALSE;
  915. BOOL bDisplayReconnected = FALSE;
  916. BOOL bRegisteredCDRomNotifications = FALSE;
  917. BOOL bOpenedLocalGraphicsDevices = FALSE;
  918. int iMouseTrails = gMouseTrails + 1;
  919. TL tlPool;
  920. PMONITORRECTS pmr = NULL;
  921. BOOL bSwitchGraphicsDeviceList = FALSE;
  922. BOOL bSwitchedProtocoltype = FALSE;
  923. USHORT protocolType = gProtocolType;
  924. DORECONNECTDATA CapturedDoReconnectData;
  925. TRACE_HYDAPI(("xxxRemoteReconnect\n"));
  926. /*
  927. * Only allow CSRSS to do this.
  928. */
  929. if (!ISCSRSS() || !ISTS()) {
  930. return STATUS_ACCESS_DENIED;
  931. }
  932. HYDRA_HINT(HH_REMOTERECONNECT);
  933. /*
  934. * Indicate that a protocol switch is pending.
  935. */
  936. UserAssert(!gfSwitchInProgress);
  937. try {
  938. CapturedDoReconnectData = ProbeAndReadStructure(pDoReconnectData,
  939. DORECONNECTDATA);
  940. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  941. return STATUS_UNSUCCESSFUL;
  942. }
  943. /*
  944. * If we are asked to block session switch, don't continue on this path.
  945. */
  946. if (gfSessionSwitchBlock) {
  947. return STATUS_UNSUCCESSFUL;
  948. }
  949. SetConsoleSwitchInProgress(TRUE);
  950. /*
  951. * Kill the mouse trails timer if any.
  952. */
  953. SetMouseTrails(0);
  954. gRemoteClientKeyboardType = CapturedDoReconnectData.ClientKeyboardType;
  955. gbClientDoubleClickSupport = CapturedDoReconnectData.fClientDoubleClickSupport;
  956. gfEnableWindowsKey = CapturedDoReconnectData.fEnableWindowsKey;
  957. RtlCopyMemory(gstrBaseWinStationName,
  958. CapturedDoReconnectData.WinStationName,
  959. min(WINSTATIONNAME_LENGTH * sizeof(WCHAR), sizeof(CapturedDoReconnectData.WinStationName)));
  960. RtlCopyMemory(gWinStationInfo.ProtocolName,
  961. CapturedDoReconnectData.ProtocolName,
  962. WPROTOCOLNAME_LENGTH * sizeof(WCHAR));
  963. RtlCopyMemory(gWinStationInfo.AudioDriverName,
  964. CapturedDoReconnectData.AudioDriverName,
  965. WAUDIONAME_LENGTH * sizeof(WCHAR));
  966. if (pSep = wcschr(gstrBaseWinStationName, L'#')) {
  967. *pSep = UNICODE_NULL;
  968. }
  969. if (gnShadowers) {
  970. xxxRemoteStopScreenUpdates();
  971. }
  972. if (CapturedDoReconnectData.drProtocolType != gPreviousProtocolType && gPreviousProtocolType != PROTOCOL_CONSOLE) {
  973. Status = xxxRemoteSetDisconnectDisplayMode();
  974. if (!NT_SUCCESS(Status)) {
  975. goto done;
  976. }
  977. }
  978. /*
  979. * Call thinwire driver to check for thinwire mode compatibility.
  980. */
  981. gProtocolType=CapturedDoReconnectData.drProtocolType;
  982. bSwitchedProtocoltype = TRUE;
  983. if (gProtocolType != PROTOCOL_CONSOLE && gProtocolType == gPreviousProtocolType) {
  984. fResult = bDrvReconnect(gpDispInfo->hDev,
  985. ghRemoteThinwireChannel,
  986. gThinwireFileObject,
  987. TRUE);
  988. bDisplayReconnected = fResult;
  989. } else {
  990. bSwitchingFromDisconectDD = TRUE;
  991. if (!IsRemoteConnection()) {
  992. OpenLocalGraphicsDevices();
  993. bOpenedLocalGraphicsDevices = TRUE;
  994. if (gpScancodeMap == NULL) {
  995. InitKeyboard();
  996. }
  997. }
  998. fResult = DrvSetGraphicsDevices(CapturedDoReconnectData.DisplayDriverName);
  999. bSwitchGraphicsDeviceList = TRUE;
  1000. }
  1001. if (!fResult) {
  1002. if (gnShadowers) {
  1003. RemoteRedrawScreen();
  1004. }
  1005. Status = STATUS_UNSUCCESSFUL;
  1006. goto done;
  1007. }
  1008. /*
  1009. * If instructed to do so, change Display mode before Reconnecting. Use
  1010. * display resolution information from Reconnect data.
  1011. */
  1012. if (CapturedDoReconnectData.fChangeDisplaySettings || gProtocolType != gPreviousProtocolType) {
  1013. LONG lResult;
  1014. /*
  1015. * Remeber monitor positions now (it would be too late after changing
  1016. * the display settings, since monitors will have new positions).
  1017. * This is necssary because the fisrt pass of windows positions
  1018. * recalculations, done in xxxUserChangeDisplaySettings, is done
  1019. * while the current desktop is the disconnected desktop and will
  1020. * not correctly position windows in the application desktop. We
  1021. * need to do a second pass once we have switched to application
  1022. * desktop. But for xxxDesktopRecalc to correctly position
  1023. * fullscreen windows, we need to remember what the monitor rects
  1024. * where before changing display settings.
  1025. */
  1026. pmr = SnapshotMonitorRects();
  1027. if (pmr != NULL) {
  1028. ThreadLockPool(ptiCurrent, pmr, &tlPool);
  1029. }
  1030. lResult = xxxUserChangeDisplaySettings(NULL,
  1031. NULL,
  1032. grpdeskRitInput,
  1033. CDS_RAWMODE,
  1034. NULL,
  1035. KernelMode);
  1036. if (lResult != DISP_CHANGE_SUCCESSFUL) {
  1037. Status = STATUS_UNSUCCESSFUL;
  1038. } else {
  1039. Status = STATUS_SUCCESS;
  1040. }
  1041. /*
  1042. * If Display settings change fails, let us disconnect the display
  1043. * driver as the reconnect is going to be failed anyway.
  1044. */
  1045. if (!NT_SUCCESS(Status)) {
  1046. TRACE_INIT(("xxxRemoteReconnect - Failed ChangeDisplaySettings\n"));
  1047. goto done;
  1048. } else {
  1049. bChangedDisplaySettings = TRUE;
  1050. }
  1051. }
  1052. UserAssert(gptmrWD != NULL);
  1053. /*
  1054. * When reconnecting, we have to attach the input devices when
  1055. * necessary. The input device are only detached when we disconnect from
  1056. * the console. In that case, if we later reconnect localy, we attach
  1057. * the local input devices, and if we reconnect remotly, we attach the
  1058. * remote devices. When we disconnect a remote session, the bet is that
  1059. * we will reconnect remotely so we don't go through the overhead of
  1060. * detaching input devices at disconnect and re-attaching them at
  1061. * reconnect. If the prediction was wrong (i.e., we reconnect locally
  1062. * after disconnecting remotely) then at reconnect time we need to
  1063. * detach the remote input devices before attaching the local input
  1064. * devices.
  1065. */
  1066. if (IsRemoteConnection()) {
  1067. if (bSwitchingFromDisconectDD) {
  1068. BOOL fSuccess;
  1069. fSuccess = !!HDXDrvEscape(gpDispInfo->hDev,
  1070. ESC_SET_WD_TIMEROBJ,
  1071. (PVOID)gptmrWD,
  1072. sizeof(gptmrWD));
  1073. if (!fSuccess) {
  1074. Status = STATUS_UNSUCCESSFUL;
  1075. RIPMSGF0(RIP_WARNING,
  1076. "Failed to pass gptmrWD to display driver");
  1077. }
  1078. }
  1079. if (gPreviousProtocolType == PROTOCOL_CONSOLE) {
  1080. AttachInputDevices(FALSE);
  1081. }
  1082. } else {
  1083. if (gPreviousProtocolType != PROTOCOL_CONSOLE) {
  1084. RemoveInputDevices();
  1085. }
  1086. AttachInputDevices(TRUE);
  1087. LeaveCrit();
  1088. RegisterCDROMNotify();
  1089. bRegisteredCDRomNotifications = TRUE;
  1090. EnterCrit();
  1091. }
  1092. /*
  1093. * Now we can switch out from disconnected desktop, to normal desktop,
  1094. * in order to reenable screen update.
  1095. */
  1096. RemoteRedrawScreen();
  1097. /*
  1098. * At this point we need to update the windows sizes and positions on
  1099. * the desktop. This is necessary for the case where we reconnect with a
  1100. * smaller resolution. When calling this API, the
  1101. * TerminalServerRequestThread (a CSRSS thread) is using the
  1102. * disconnected desktop as its temporary desktop. That's why the
  1103. * xxxUserChangeDisplaySettings call above does not resize windows for
  1104. * the default desktop. The solution is to set the default desktop as
  1105. * the temporary desktop, after we switch to it in RemoteRedrawScreen
  1106. * and to call xxxDesktopRecalc.
  1107. */
  1108. if (bChangedDisplaySettings) {
  1109. USERTHREAD_USEDESKTOPINFO utudi;
  1110. NTSTATUS tempstatus;
  1111. utudi.hThread = NULL;
  1112. utudi.drdRestore.pdeskRestore = NULL;
  1113. tempstatus = xxxSetCsrssThreadDesktop(grpdeskRitInput, &utudi.drdRestore);
  1114. if (NT_SUCCESS(tempstatus)) {
  1115. if (pmr != NULL) {
  1116. UpdateMonitorRectsSnapShot(pmr);
  1117. xxxDesktopRecalc(pmr);
  1118. }
  1119. if (!IsRemoteConnection() && gbSnapShotWindowsAndMonitors) {
  1120. RestoreMonitorsAndWindowsRects();
  1121. }
  1122. xxxSetInformationThread(NtCurrentThread(), UserThreadUseDesktop, &utudi, sizeof(utudi));
  1123. }
  1124. }
  1125. /*
  1126. * Re-init'ing the keyboard may not be as neccessary. Possibly the keyboard
  1127. * attributes have changed.
  1128. */
  1129. InitKeyboard();
  1130. /*
  1131. * This is neccessary to sync up the client and the host.
  1132. */
  1133. UpdateKeyLights(FALSE);
  1134. SetPointer(TRUE);
  1135. gbConnected = TRUE;
  1136. done:
  1137. /*
  1138. * Recreate the mouse trails timer if there is need for it.
  1139. */
  1140. SetMouseTrails(iMouseTrails);
  1141. /*
  1142. * If we failed after after the Display driver was reconnected, we need
  1143. * to disconnect it now, otherwise we have an inconsitancy beetween the
  1144. * disconnected state of Win32k and the connected state of the display driver.
  1145. */
  1146. if (!NT_SUCCESS(Status) && bDisplayReconnected) {
  1147. bDrvDisconnect(gpDispInfo->hDev,
  1148. ghRemoteThinwireChannel,
  1149. gThinwireFileObject);
  1150. }
  1151. if (Status == STATUS_SUCCESS && !IsRemoteConnection()) {
  1152. SharedUserData->ActiveConsoleId = gSessionId;
  1153. }
  1154. SetConsoleSwitchInProgress(FALSE);
  1155. /*
  1156. * In the failure of reconnect - unregister the CDROM notifications
  1157. * if they were registered.
  1158. */
  1159. if (!NT_SUCCESS(Status)) {
  1160. if (bRegisteredCDRomNotifications) {
  1161. xxxUnregisterDeviceClassNotifications();
  1162. }
  1163. if (bOpenedLocalGraphicsDevices) {
  1164. CloseLocalGraphicsDevices();
  1165. }
  1166. if (bSwitchedProtocoltype) {
  1167. gProtocolType = protocolType;
  1168. }
  1169. if (bSwitchGraphicsDeviceList) {
  1170. fResult = DrvSetGraphicsDevices(CapturedDoReconnectData.DisplayDriverName);
  1171. }
  1172. }
  1173. if (pmr != NULL) {
  1174. ThreadUnlockAndFreePool(PtiCurrent(), &tlPool);
  1175. }
  1176. return Status;
  1177. }
  1178. NTSTATUS xxxRemoteNotify(
  1179. IN PDONOTIFYDATA pDoNotifyData)
  1180. {
  1181. LRESULT lResult;
  1182. DONOTIFYDATA CapturedDoNotifyData;
  1183. /*
  1184. * Only allow CSRSS to do this.
  1185. */
  1186. if (!ISCSRSS() || !ISTS()) {
  1187. return STATUS_ACCESS_DENIED;
  1188. }
  1189. try {
  1190. CapturedDoNotifyData = ProbeAndReadStructure(pDoNotifyData, DONOTIFYDATA);
  1191. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  1192. return STATUS_UNSUCCESSFUL;
  1193. }
  1194. switch (CapturedDoNotifyData.NotifyEvent) {
  1195. case Notify_DisableScrnSaver:
  1196. /*
  1197. * Tell winlogon about the session shadow state
  1198. */
  1199. ASSERT(gbConnected);
  1200. if (gspwndLogonNotify != NULL) {
  1201. _PostMessage(gspwndLogonNotify, WM_LOGONNOTIFY,
  1202. SESSION_DISABLESCRNSAVER, 0);
  1203. }
  1204. break;
  1205. case Notify_EnableScrnSaver:
  1206. /*
  1207. * Tell winlogon about the session shadow state
  1208. */
  1209. ASSERT(gbConnected);
  1210. if (gspwndLogonNotify != NULL) {
  1211. _PostMessage(gspwndLogonNotify, WM_LOGONNOTIFY,
  1212. SESSION_ENABLESCRNSAVER, 0);
  1213. }
  1214. break;
  1215. case Notify_Disconnect:
  1216. /*
  1217. * Tell winlogon about the disconnect
  1218. */
  1219. ASSERT(!gbConnected);
  1220. if (gspwndLogonNotify != NULL) {
  1221. _PostMessage(gspwndLogonNotify, WM_LOGONNOTIFY,
  1222. SESSION_DISCONNECTED, 0);
  1223. }
  1224. break;
  1225. case Notify_SyncDisconnect:
  1226. /*
  1227. * Synchronously tell winlogon about the disconnect.
  1228. */
  1229. UserAssert(!gbConnected);
  1230. if (gspwndLogonNotify != NULL) {
  1231. TL tlpwnd;
  1232. ThreadLockAlways(gspwndLogonNotify, &tlpwnd);
  1233. xxxSendMessageTimeout(gspwndLogonNotify,
  1234. WM_LOGONNOTIFY,
  1235. SESSION_DISCONNECTED,
  1236. 0,
  1237. SMTO_NORMAL,
  1238. 60 * 1000,
  1239. &lResult);
  1240. ThreadUnlock(&tlpwnd);
  1241. }
  1242. break;
  1243. case Notify_Reconnect:
  1244. /*
  1245. * Tell winlogon about the reconnect.
  1246. */
  1247. UserAssert(gbConnected);
  1248. if (gspwndLogonNotify != NULL) {
  1249. _PostMessage(gspwndLogonNotify,
  1250. WM_LOGONNOTIFY,
  1251. SESSION_RECONNECTED,
  1252. 0);
  1253. }
  1254. break;
  1255. case Notify_PreReconnect:
  1256. /*
  1257. * Tell winlogon that the session is about to be reconnected.
  1258. */
  1259. if (gspwndLogonNotify != NULL) {
  1260. TL tlpwnd;
  1261. ThreadLockAlways(gspwndLogonNotify, &tlpwnd);
  1262. xxxSendMessageTimeout(gspwndLogonNotify,
  1263. WM_LOGONNOTIFY,
  1264. SESSION_PRERECONNECT,
  1265. 0,
  1266. SMTO_NORMAL,
  1267. 60 * 1000,
  1268. &lResult);
  1269. ThreadUnlock(&tlpwnd);
  1270. }
  1271. break;
  1272. case Notify_HelpAssistantShadowStart:
  1273. /*
  1274. * Tell winlogon that a Help Assistant is about to begin shadowing.
  1275. */
  1276. if (gspwndLogonNotify != NULL) {
  1277. TL tlpwnd;
  1278. ThreadLockAlways(gspwndLogonNotify, &tlpwnd);
  1279. xxxSendMessageTimeout(gspwndLogonNotify,
  1280. WM_LOGONNOTIFY,
  1281. SESSION_HELPASSISTANTSHADOWSTART,
  1282. 0,
  1283. SMTO_NORMAL,
  1284. 60 * 1000,
  1285. &lResult);
  1286. ThreadUnlock(&tlpwnd);
  1287. }
  1288. break;
  1289. case Notify_HelpAssistantShadowFinish:
  1290. /*
  1291. * Tell winlogon that a Help Assistant has just finished shadowing.
  1292. */
  1293. if (gspwndLogonNotify != NULL) {
  1294. _PostMessage(gspwndLogonNotify, WM_LOGONNOTIFY,
  1295. SESSION_HELPASSISTANTSHADOWFINISH, 0);
  1296. }
  1297. break;
  1298. case Notify_PreReconnectDesktopSwitch:
  1299. /*
  1300. * Tell winlogon that the reconnected session is about to have its
  1301. * desktop switched.
  1302. */
  1303. if (gspwndLogonNotify != NULL) {
  1304. TL tlpwnd;
  1305. ThreadLockAlways(gspwndLogonNotify, &tlpwnd);
  1306. if (!xxxSendMessageTimeout(gspwndLogonNotify,
  1307. WM_LOGONNOTIFY,
  1308. SESSION_PRERECONNECTDESKTOPSWITCH,
  1309. 0,
  1310. SMTO_NORMAL,
  1311. 10 * 1000,
  1312. &lResult)) {
  1313. /*
  1314. * Message timed out, and wasn't sent, so let's post this
  1315. * message and return.
  1316. */
  1317. _PostMessage(gspwndLogonNotify,
  1318. WM_LOGONNOTIFY,
  1319. SESSION_PRERECONNECTDESKTOPSWITCH,
  1320. 0);
  1321. }
  1322. ThreadUnlock(&tlpwnd);
  1323. }
  1324. break;
  1325. case Notify_StopReadInput:
  1326. /*
  1327. * Set the global variable indicating that we should stop reading
  1328. * input.
  1329. */
  1330. gbStopReadInput = TRUE;
  1331. break;
  1332. case Notify_DisconnectPipe:
  1333. /*
  1334. * Tell winlogon to disconnect the auto logon named pipe.
  1335. */
  1336. if (gspwndLogonNotify != NULL) {
  1337. _PostMessage(gspwndLogonNotify,
  1338. WM_LOGONNOTIFY,
  1339. SESSION_DISCONNECTPIPE,
  1340. 0);
  1341. }
  1342. break;
  1343. default:
  1344. ASSERT(FALSE);
  1345. }
  1346. return STATUS_SUCCESS;
  1347. }
  1348. /*
  1349. * This allows ICASRV to cleanly logoff the user. We send a message to
  1350. * winlogon and let him do it. We used to call ExitWindowsEx() directly, but
  1351. * that caused too many problems when it was called from CSRSS.
  1352. */
  1353. NTSTATUS RemoteLogoff(
  1354. VOID)
  1355. {
  1356. TRACE_HYDAPI(("RemoteLogoff\n"));
  1357. /*
  1358. * Only allow CSRSS to do this
  1359. */
  1360. if (!ISCSRSS() || !ISTS()) {
  1361. return STATUS_ACCESS_DENIED;
  1362. }
  1363. HYDRA_HINT(HH_REMOTELOGOFF);
  1364. UserAssert(ISCSRSS());
  1365. /*
  1366. * Tell winlogon about the logoff
  1367. */
  1368. if (gspwndLogonNotify != NULL) {
  1369. _PostMessage(gspwndLogonNotify,
  1370. WM_LOGONNOTIFY,
  1371. SESSION_LOGOFF,
  1372. EWX_LOGOFF | EWX_FORCE);
  1373. }
  1374. return STATUS_SUCCESS;
  1375. }
  1376. NTSTATUS xxxRemoteStopScreenUpdates(
  1377. VOID)
  1378. {
  1379. NTSTATUS Status = STATUS_SUCCESS;
  1380. NTSTATUS SaveStatus = STATUS_SUCCESS;
  1381. WORD NewButtonState;
  1382. TRACE_HYDAPI(("xxxRemoteStopScreenUpdates"));
  1383. CheckCritIn();
  1384. UserAssert(ISCSRSS());
  1385. /*
  1386. * No need to do this multiple times.
  1387. */
  1388. if (gbFreezeScreenUpdates) {
  1389. return STATUS_SUCCESS;
  1390. }
  1391. /*
  1392. * This could be called directly from the command channel.
  1393. */
  1394. if (!gspdeskDisconnect) {
  1395. return STATUS_SUCCESS;
  1396. }
  1397. /*
  1398. * If not connected, forget it.
  1399. */
  1400. if (ghRemoteVideoChannel == NULL) {
  1401. return STATUS_NO_SUCH_DEVICE;
  1402. }
  1403. /*
  1404. * Mouse buttons up (ensures no mouse buttons are left in a down state).
  1405. */
  1406. NewButtonState = gwMKButtonState & ~gwMKCurrentButton;
  1407. if ((NewButtonState & MOUSE_BUTTON_LEFT) != (gwMKButtonState & MOUSE_BUTTON_LEFT)) {
  1408. xxxButtonEvent(MOUSE_BUTTON_LEFT,
  1409. gptCursorAsync,
  1410. TRUE,
  1411. NtGetTickCount(),
  1412. 0L,
  1413. #ifdef GENERIC_INPUT
  1414. NULL,
  1415. NULL,
  1416. #endif
  1417. 0L,
  1418. FALSE);
  1419. }
  1420. if ((NewButtonState & MOUSE_BUTTON_RIGHT) != (gwMKButtonState & MOUSE_BUTTON_RIGHT)) {
  1421. xxxButtonEvent(MOUSE_BUTTON_RIGHT,
  1422. gptCursorAsync,
  1423. TRUE,
  1424. NtGetTickCount(),
  1425. 0L,
  1426. #ifdef GENERIC_INPUT
  1427. NULL,
  1428. NULL,
  1429. #endif
  1430. 0L,
  1431. FALSE);
  1432. }
  1433. gwMKButtonState = NewButtonState;
  1434. /*
  1435. * Send shift key breaks to win32 (ensures no shift keys are left on).
  1436. */
  1437. // { 0, 0xb8, KEY_BREAK, 0, 0 }, // L alt
  1438. xxxPushKeyEvent(VK_LMENU, 0xb8, KEYEVENTF_KEYUP, 0);
  1439. // { 0, 0xb8, KEY_BREAK | KEY_E0, 0, 0 }, // R alt
  1440. xxxPushKeyEvent(VK_RMENU, 0xb8, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  1441. // { 0, 0x9d, KEY_BREAK, 0, 0 }, // L ctrl
  1442. xxxPushKeyEvent(VK_LCONTROL, 0x9d, KEYEVENTF_KEYUP, 0);
  1443. // { 0, 0x9d, KEY_BREAK | KEY_E0, 0, 0 }, // R ctrl
  1444. xxxPushKeyEvent(VK_RCONTROL, 0x9d, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  1445. // { 0, 0xaa, KEY_BREAK, 0, 0 }, // L shift
  1446. xxxPushKeyEvent(VK_LSHIFT, 0xaa, KEYEVENTF_KEYUP, 0);
  1447. // { 0, 0xb6, KEY_BREAK, 0, 0 } // R shift
  1448. xxxPushKeyEvent(VK_RSHIFT, 0xb6, KEYEVENTF_KEYUP, 0);
  1449. Status = RemoteDisableScreen();
  1450. if (!NT_SUCCESS(Status)) {
  1451. return STATUS_NO_SUCH_DEVICE;
  1452. }
  1453. UserAssert(gspdeskDisconnect != NULL && grpdeskRitInput == gspdeskDisconnect);
  1454. gbFreezeScreenUpdates = TRUE;
  1455. return Status;
  1456. }
  1457. /*
  1458. * Taken from Internal Key Event.
  1459. * Minus any permissions checking.
  1460. */
  1461. VOID xxxPushKeyEvent(
  1462. BYTE bVk,
  1463. BYTE bScan,
  1464. DWORD dwFlags,
  1465. DWORD dwExtraInfo)
  1466. {
  1467. USHORT usFlaggedVK;
  1468. usFlaggedVK = (USHORT)bVk;
  1469. if (dwFlags & KEYEVENTF_KEYUP)
  1470. usFlaggedVK |= KBDBREAK;
  1471. // IanJa: not all extended keys are numpad, but this seems to work.
  1472. if (dwFlags & KEYEVENTF_EXTENDEDKEY)
  1473. usFlaggedVK |= KBDNUMPAD | KBDEXT;
  1474. xxxKeyEvent(usFlaggedVK, bScan, NtGetTickCount(), dwExtraInfo,
  1475. #ifdef GENERIC_INPUT
  1476. NULL,
  1477. NULL,
  1478. #endif
  1479. FALSE);
  1480. }
  1481. NTSTATUS
  1482. RemoteThinwireStats(
  1483. OUT PVOID Stats)
  1484. {
  1485. DWORD sThinwireStatsLength = sizeof(CACHE_STATISTICS);
  1486. TRACE_HYDAPI(("RemoteThinwireStats\n"));
  1487. /*
  1488. * Only allow CSRSS to do this
  1489. */
  1490. if (!ISCSRSS() || !ISTS()) {
  1491. return STATUS_ACCESS_DENIED;
  1492. }
  1493. UserAssert(ISCSRSS());
  1494. if (gpThinWireCache != NULL) {
  1495. try {
  1496. ProbeForWrite(Stats, sThinwireStatsLength, sizeof(BYTE));
  1497. RtlCopyMemory(Stats, gpThinWireCache, sThinwireStatsLength);
  1498. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  1499. return GetExceptionCode();
  1500. }
  1501. return STATUS_SUCCESS;
  1502. }
  1503. return STATUS_NO_SUCH_DEVICE;
  1504. }
  1505. NTSTATUS
  1506. RemoteNtSecurity(
  1507. VOID)
  1508. {
  1509. TRACE_HYDAPI(("RemoteNtSecurity\n"));
  1510. /*
  1511. * Only allow CSRSS to do this
  1512. */
  1513. if (!ISCSRSS() || !ISTS()) {
  1514. return STATUS_ACCESS_DENIED;
  1515. }
  1516. UserAssert(ISCSRSS());
  1517. UserAssert(gspwndLogonNotify != NULL);
  1518. if (gspwndLogonNotify != NULL) {
  1519. _PostMessage(gspwndLogonNotify, WM_HOTKEY, 0, 0);
  1520. }
  1521. return STATUS_SUCCESS;
  1522. }
  1523. NTSTATUS
  1524. xxxRemoteShadowSetup(
  1525. VOID)
  1526. {
  1527. TRACE_HYDAPI(("xxxRemoteShadowSetup\n"));
  1528. /*
  1529. * Only allow CSRSS to do this.
  1530. */
  1531. if (!ISCSRSS() || !ISTS()) {
  1532. return STATUS_ACCESS_DENIED;
  1533. }
  1534. /*
  1535. * Blank the screen.
  1536. */
  1537. if (gnShadowers || gbConnected) {
  1538. xxxRemoteStopScreenUpdates();
  1539. }
  1540. gnShadowers++;
  1541. return STATUS_SUCCESS;
  1542. }
  1543. NTSTATUS
  1544. RemoteShadowStart(
  1545. IN PVOID pThinwireData,
  1546. ULONG ThinwireDataLength)
  1547. {
  1548. BOOL fResult;
  1549. PUCHAR pCapturedThinWireData = NULL;
  1550. TRACE_HYDAPI(("RemoteShadowStart\n"));
  1551. /*
  1552. * Only allow CSRSS to do this.
  1553. */
  1554. if (!ISCSRSS() || !ISTS()) {
  1555. return STATUS_ACCESS_DENIED;
  1556. }
  1557. /*
  1558. * Probe all read arguments.
  1559. */
  1560. try {
  1561. ProbeForRead(pThinwireData, ThinwireDataLength, sizeof(BYTE));
  1562. pCapturedThinWireData = UserAllocPoolWithQuota(ThinwireDataLength, TAG_SYSTEM);
  1563. if (pCapturedThinWireData) {
  1564. RtlCopyMemory(pCapturedThinWireData, pThinwireData, ThinwireDataLength);
  1565. } else {
  1566. ExRaiseStatus(STATUS_NO_MEMORY);
  1567. }
  1568. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  1569. if (pCapturedThinWireData) {
  1570. UserFreePool(pCapturedThinWireData);
  1571. }
  1572. return GetExceptionCode();
  1573. }
  1574. /*
  1575. * Call thinwire driver and check for thinwire mode compatibility
  1576. */
  1577. fResult = bDrvShadowConnect(GETCONSOLEHDEV(),
  1578. pCapturedThinWireData,
  1579. ThinwireDataLength);
  1580. if (pCapturedThinWireData) {
  1581. UserFreePool(pCapturedThinWireData);
  1582. }
  1583. /*
  1584. * Although originally defined as BOOL, allow more meaningful return
  1585. * codes.
  1586. */
  1587. if (!fResult) {
  1588. return STATUS_CTX_BAD_VIDEO_MODE;
  1589. } else if (fResult != TRUE) {
  1590. return fResult;
  1591. }
  1592. RemoteRedrawScreen();
  1593. SetPointer(TRUE);
  1594. SETSYSMETBOOL(REMOTECONTROL, TRUE);
  1595. return STATUS_SUCCESS;
  1596. }
  1597. NTSTATUS
  1598. xxxRemoteShadowStop(
  1599. VOID)
  1600. {
  1601. TRACE_HYDAPI(("xxxRemoteShadowStop\n"));
  1602. /*
  1603. * Only allow CSRSS to do this
  1604. */
  1605. if (!ISCSRSS() || !ISTS()) {
  1606. return STATUS_ACCESS_DENIED;
  1607. }
  1608. /*
  1609. * Blank the screen.
  1610. */
  1611. xxxRemoteStopScreenUpdates();
  1612. return STATUS_SUCCESS;
  1613. }
  1614. NTSTATUS
  1615. RemoteShadowCleanup(
  1616. IN PVOID pThinwireData,
  1617. ULONG ThinwireDataLength)
  1618. {
  1619. PUCHAR pCapturedThinWireData = NULL;
  1620. TRACE_HYDAPI(("RemoteShadowCleanup\n"));
  1621. /*
  1622. * Only allow CSRSS to do this
  1623. */
  1624. if (!ISCSRSS() || !ISTS()) {
  1625. return STATUS_ACCESS_DENIED;
  1626. }
  1627. /*
  1628. * Probe all read arguments.
  1629. */
  1630. try {
  1631. ProbeForRead(pThinwireData, ThinwireDataLength, sizeof(BYTE));
  1632. pCapturedThinWireData = UserAllocPoolWithQuota(ThinwireDataLength, TAG_SYSTEM);
  1633. if (pCapturedThinWireData) {
  1634. RtlCopyMemory(pCapturedThinWireData, pThinwireData, ThinwireDataLength);
  1635. } else {
  1636. ExRaiseStatus(STATUS_NO_MEMORY);
  1637. }
  1638. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  1639. if (pCapturedThinWireData) {
  1640. UserFreePool(pCapturedThinWireData);
  1641. }
  1642. return GetExceptionCode();
  1643. }
  1644. /*
  1645. * Tell the Thinwire driver about it.
  1646. */
  1647. bDrvShadowDisconnect(GETCONSOLEHDEV(),
  1648. pCapturedThinWireData,
  1649. ThinwireDataLength);
  1650. if (pCapturedThinWireData) {
  1651. UserFreePool(pCapturedThinWireData);
  1652. }
  1653. if (gnShadowers > 0) {
  1654. gnShadowers--;
  1655. }
  1656. if (gnShadowers || gbConnected) {
  1657. RemoteRedrawScreen();
  1658. }
  1659. SetPointer(TRUE);
  1660. if (gnShadowers == 0) {
  1661. SETSYSMETBOOL(REMOTECONTROL, FALSE);
  1662. }
  1663. return STATUS_SUCCESS;
  1664. }
  1665. NTSTATUS
  1666. xxxRemotePassthruEnable(
  1667. VOID)
  1668. {
  1669. IO_STATUS_BLOCK IoStatus;
  1670. static BOOL KeyboardType101;
  1671. TRACE_HYDAPI(("xxxRemotePassthruEnable\n"));
  1672. /*
  1673. * Only allow CSRSS to do this.
  1674. */
  1675. if (!ISCSRSS() || !ISTS()) {
  1676. return STATUS_ACCESS_DENIED;
  1677. }
  1678. UserAssert(gbConnected);
  1679. UserAssert(gnShadowers == 0);
  1680. KeyboardType101 = !(gapulCvt_VK == gapulCvt_VK_84);
  1681. ZwDeviceIoControlFile(ghRemoteKeyboardChannel, NULL, NULL, NULL,
  1682. &IoStatus, IOCTL_KEYBOARD_ICA_TYPE,
  1683. &KeyboardType101, sizeof(KeyboardType101),
  1684. NULL, 0);
  1685. if (guKbdTblSize != 0) {
  1686. ZwDeviceIoControlFile(ghRemoteKeyboardChannel, NULL, NULL, NULL,
  1687. &IoStatus, IOCTL_KEYBOARD_ICA_LAYOUT,
  1688. ghKbdTblBase, guKbdTblSize,
  1689. gpKbdTbl, 0);
  1690. }
  1691. xxxRemoteStopScreenUpdates();
  1692. /*
  1693. * Tell thinwire driver about this.
  1694. */
  1695. if (gfRemotingConsole) {
  1696. ASSERT(gConsoleShadowhDev != NULL);
  1697. bDrvDisconnect(gConsoleShadowhDev, ghConsoleShadowThinwireChannel,
  1698. gConsoleShadowThinwireFileObject);
  1699. } else {
  1700. bDrvDisconnect(gpDispInfo->hDev, ghRemoteThinwireChannel,
  1701. gThinwireFileObject);
  1702. }
  1703. return STATUS_SUCCESS;
  1704. }
  1705. NTSTATUS
  1706. RemotePassthruDisable(
  1707. VOID)
  1708. {
  1709. BOOL fResult;
  1710. TRACE_HYDAPI(("RemotePassthruDisable\n"));
  1711. /*
  1712. * Only allow CSRSS to do this
  1713. */
  1714. if (!ISCSRSS() || !ISTS()) {
  1715. return STATUS_ACCESS_DENIED;
  1716. }
  1717. UserAssert(gnShadowers == 0);
  1718. UserAssert(ISCSRSS());
  1719. if (gfRemotingConsole) {
  1720. ASSERT(gConsoleShadowhDev != NULL);
  1721. fResult = bDrvReconnect(gConsoleShadowhDev, ghConsoleShadowThinwireChannel,
  1722. gConsoleShadowThinwireFileObject, TRUE);
  1723. } else {
  1724. fResult = bDrvReconnect(gpDispInfo->hDev, ghRemoteThinwireChannel,
  1725. gThinwireFileObject, TRUE);
  1726. }
  1727. if (!fResult) {
  1728. return STATUS_CTX_BAD_VIDEO_MODE;
  1729. }
  1730. if (gbConnected) {
  1731. RemoteRedrawScreen();
  1732. UpdateKeyLights(FALSE); // Make sure LED's are correct
  1733. }
  1734. return STATUS_SUCCESS;
  1735. }
  1736. NTSTATUS
  1737. CtxDisplayIOCtl(
  1738. ULONG DisplayIOCtlFlags,
  1739. PUCHAR pDisplayIOCtlData,
  1740. ULONG cbDisplayIOCtlData)
  1741. {
  1742. BOOL fResult;
  1743. TRACE_HYDAPI(("CtxDisplayIOCtl\n"));
  1744. fResult = bDrvDisplayIOCtl(GETCONSOLEHDEV(), pDisplayIOCtlData, cbDisplayIOCtlData);
  1745. if (!fResult) {
  1746. return STATUS_CTX_BAD_VIDEO_MODE;
  1747. }
  1748. if ((DisplayIOCtlFlags & DISPLAY_IOCTL_FLAG_REDRAW)) {
  1749. RemoteRedrawRectangle(0,0,0xffff,0xffff);
  1750. }
  1751. return STATUS_SUCCESS;
  1752. }
  1753. /*
  1754. * This is for things like user32.dll init routines that don't want to use
  1755. * winsta.dll for queries.
  1756. */
  1757. DWORD
  1758. RemoteConnectState(
  1759. VOID)
  1760. {
  1761. DWORD state;
  1762. if (!gbRemoteSession) {
  1763. state = CTX_W32_CONNECT_STATE_CONSOLE;
  1764. } else if (!gbVideoInitialized) {
  1765. state = CTX_W32_CONNECT_STATE_IDLE;
  1766. } else if (gbExitInProgress) {
  1767. state = CTX_W32_CONNECT_STATE_EXIT_IN_PROGRESS;
  1768. } else if (gbConnected) {
  1769. state = CTX_W32_CONNECT_STATE_CONNECTED;
  1770. } else {
  1771. state = CTX_W32_CONNECT_STATE_DISCONNECTED;
  1772. }
  1773. return state;
  1774. }
  1775. BOOL
  1776. _GetWinStationInfo(
  1777. PWSINFO pWsInfo)
  1778. {
  1779. CheckCritIn();
  1780. try {
  1781. ProbeForWrite(pWsInfo, sizeof(gWinStationInfo), DATAALIGN);
  1782. RtlCopyMemory(pWsInfo, &gWinStationInfo, sizeof(gWinStationInfo));
  1783. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  1784. return FALSE;
  1785. }
  1786. return TRUE;
  1787. }