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.

2884 lines
88 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. srvinit.c
  5. Abstract:
  6. This is the main initialization file for the console
  7. Server.
  8. Author:
  9. Therese Stowell (thereses) 11-Nov-1990
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. CONST PCSR_API_ROUTINE ConsoleServerApiDispatchTable[ConsolepMaxApiNumber - ConsolepOpenConsole] = {
  15. SrvOpenConsole,
  16. SrvGetConsoleInput,
  17. SrvWriteConsoleInput,
  18. SrvReadConsoleOutput,
  19. SrvWriteConsoleOutput,
  20. SrvReadConsoleOutputString,
  21. SrvWriteConsoleOutputString,
  22. SrvFillConsoleOutput,
  23. SrvGetConsoleMode,
  24. SrvGetConsoleNumberOfFonts,
  25. SrvGetConsoleNumberOfInputEvents,
  26. SrvGetConsoleScreenBufferInfo,
  27. SrvGetConsoleCursorInfo,
  28. SrvGetConsoleMouseInfo,
  29. SrvGetConsoleFontInfo,
  30. SrvGetConsoleFontSize,
  31. SrvGetConsoleCurrentFont,
  32. SrvSetConsoleMode,
  33. SrvSetConsoleActiveScreenBuffer,
  34. SrvFlushConsoleInputBuffer,
  35. SrvGetLargestConsoleWindowSize,
  36. SrvSetConsoleScreenBufferSize,
  37. SrvSetConsoleCursorPosition,
  38. SrvSetConsoleCursorInfo,
  39. SrvSetConsoleWindowInfo,
  40. SrvScrollConsoleScreenBuffer,
  41. SrvSetConsoleTextAttribute,
  42. SrvSetConsoleFont,
  43. SrvSetConsoleIcon,
  44. SrvReadConsole,
  45. SrvWriteConsole,
  46. SrvDuplicateHandle,
  47. SrvGetHandleInformation,
  48. SrvSetHandleInformation,
  49. SrvCloseHandle,
  50. SrvVerifyConsoleIoHandle,
  51. SrvAllocConsole,
  52. SrvFreeConsole,
  53. SrvGetConsoleTitle,
  54. SrvSetConsoleTitle,
  55. SrvCreateConsoleScreenBuffer,
  56. SrvInvalidateBitMapRect,
  57. SrvVDMConsoleOperation,
  58. SrvSetConsoleCursor,
  59. SrvShowConsoleCursor,
  60. SrvConsoleMenuControl,
  61. SrvSetConsolePalette,
  62. SrvSetConsoleDisplayMode,
  63. SrvRegisterConsoleVDM,
  64. SrvGetConsoleHardwareState,
  65. SrvSetConsoleHardwareState,
  66. SrvGetConsoleDisplayMode,
  67. SrvAddConsoleAlias,
  68. SrvGetConsoleAlias,
  69. SrvGetConsoleAliasesLength,
  70. SrvGetConsoleAliasExesLength,
  71. SrvGetConsoleAliases,
  72. SrvGetConsoleAliasExes,
  73. SrvExpungeConsoleCommandHistory,
  74. SrvSetConsoleNumberOfCommands,
  75. SrvGetConsoleCommandHistoryLength,
  76. SrvGetConsoleCommandHistory,
  77. SrvSetConsoleCommandHistoryMode,
  78. SrvGetConsoleCP,
  79. SrvSetConsoleCP,
  80. SrvSetConsoleKeyShortcuts,
  81. SrvSetConsoleMenuClose,
  82. SrvConsoleNotifyLastClose,
  83. SrvGenerateConsoleCtrlEvent,
  84. SrvGetConsoleKeyboardLayoutName,
  85. SrvGetConsoleWindow,
  86. #if defined(FE_SB)
  87. SrvGetConsoleCharType,
  88. SrvSetConsoleLocalEUDC,
  89. SrvSetConsoleCursorMode,
  90. SrvGetConsoleCursorMode,
  91. SrvRegisterConsoleOS2,
  92. SrvSetConsoleOS2OemFormat,
  93. #if defined(FE_IME)
  94. SrvGetConsoleNlsMode,
  95. SrvSetConsoleNlsMode,
  96. SrvRegisterConsoleIME,
  97. SrvUnregisterConsoleIME,
  98. #endif // FE_IME
  99. #endif // FE_SB
  100. SrvGetConsoleLangId,
  101. SrvAttachConsole,
  102. SrvGetConsoleSelectionInfo,
  103. SrvGetConsoleProcessList,
  104. };
  105. CONST BOOLEAN ConsoleServerApiServerValidTable[ConsolepMaxApiNumber - ConsolepOpenConsole] = {
  106. FALSE, // OpenConsole
  107. FALSE, // GetConsoleInput,
  108. FALSE, // WriteConsoleInput,
  109. FALSE, // ReadConsoleOutput,
  110. FALSE, // WriteConsoleOutput,
  111. FALSE, // ReadConsoleOutputString,
  112. FALSE, // WriteConsoleOutputString,
  113. FALSE, // FillConsoleOutput,
  114. FALSE, // GetConsoleMode,
  115. FALSE, // GetNumberOfConsoleFonts,
  116. FALSE, // GetNumberOfConsoleInputEvents,
  117. FALSE, // GetConsoleScreenBufferInfo,
  118. FALSE, // GetConsoleCursorInfo,
  119. FALSE, // GetConsoleMouseInfo,
  120. FALSE, // GetConsoleFontInfo,
  121. FALSE, // GetConsoleFontSize,
  122. FALSE, // GetCurrentConsoleFont,
  123. FALSE, // SetConsoleMode,
  124. FALSE, // SetConsoleActiveScreenBuffer,
  125. FALSE, // FlushConsoleInputBuffer,
  126. FALSE, // GetLargestConsoleWindowSize,
  127. FALSE, // SetConsoleScreenBufferSize,
  128. FALSE, // SetConsoleCursorPosition,
  129. FALSE, // SetConsoleCursorInfo,
  130. FALSE, // SetConsoleWindowInfo,
  131. FALSE, // ScrollConsoleScreenBuffer,
  132. FALSE, // SetConsoleTextAttribute,
  133. FALSE, // SetConsoleFont,
  134. FALSE, // SetConsoleIcon
  135. FALSE, // ReadConsole,
  136. FALSE, // WriteConsole,
  137. FALSE, // DuplicateHandle,
  138. FALSE, // GetHandleInformation,
  139. FALSE, // SetHandleInformation,
  140. FALSE, // CloseHandle
  141. FALSE, // VerifyConsoleIoHandle
  142. FALSE, // AllocConsole,
  143. FALSE, // FreeConsole
  144. FALSE, // GetConsoleTitle,
  145. FALSE, // SetConsoleTitle,
  146. FALSE, // CreateConsoleScreenBuffer
  147. FALSE, // InvalidateConsoleBitmapRect
  148. FALSE, // VDMConsoleOperation
  149. FALSE, // SetConsoleCursor,
  150. FALSE, // ShowConsoleCursor
  151. FALSE, // ConsoleMenuControl
  152. FALSE, // SetConsolePalette
  153. FALSE, // SetConsoleDisplayMode
  154. FALSE, // RegisterConsoleVDM,
  155. FALSE, // GetConsoleHardwareState
  156. FALSE, // SetConsoleHardwareState
  157. TRUE, // GetConsoleDisplayMode
  158. FALSE, // AddConsoleAlias,
  159. FALSE, // GetConsoleAlias,
  160. FALSE, // GetConsoleAliasesLength,
  161. FALSE, // GetConsoleAliasExesLength,
  162. FALSE, // GetConsoleAliases,
  163. FALSE, // GetConsoleAliasExes
  164. FALSE, // ExpungeConsoleCommandHistory,
  165. FALSE, // SetConsoleNumberOfCommands,
  166. FALSE, // GetConsoleCommandHistoryLength,
  167. FALSE, // GetConsoleCommandHistory,
  168. FALSE, // SetConsoleCommandHistoryMode
  169. FALSE, // SrvGetConsoleCP,
  170. FALSE, // SrvSetConsoleCP,
  171. FALSE, // SrvSetConsoleKeyShortcuts,
  172. FALSE, // SrvSetConsoleMenuClose
  173. FALSE, // SrvConsoleNotifyLastClose
  174. FALSE, // SrvGenerateConsoleCtrlEvent
  175. FALSE, // SrvGetConsoleKeyboardLayoutName
  176. FALSE, // SrvGetConsoleWindow,
  177. #if defined(FE_SB)
  178. FALSE, // GetConsoleCharType
  179. FALSE, // SrvSetConsoleLocalEUDC,
  180. FALSE, // SrvSetConsoleCursorMode,
  181. FALSE, // SrvGetConsoleCursorMode
  182. FALSE, // SrvRegisterConsoleOS2,
  183. FALSE, // SrvSetConsoleOS2OemFormat,
  184. #if defined(FE_IME)
  185. FALSE, // GetConsoleNlsMode
  186. FALSE, // SetConsoleNlsMode
  187. FALSE, // RegisterConsoleIME
  188. FALSE, // UnregisterConsoleIME
  189. #endif // FE_IME
  190. #endif // FE_SB
  191. FALSE, // GetConsoleLangId
  192. FALSE, // AttachConsole
  193. FALSE, // GetConsoleSelectionInfo,
  194. FALSE, // GetConsoleProcessList
  195. };
  196. #if DBG
  197. CONST PSZ ConsoleServerApiNameTable[ConsolepMaxApiNumber - ConsolepOpenConsole] = {
  198. "SrvOpenConsole",
  199. "SrvGetConsoleInput",
  200. "SrvWriteConsoleInput",
  201. "SrvReadConsoleOutput",
  202. "SrvWriteConsoleOutput",
  203. "SrvReadConsoleOutputString",
  204. "SrvWriteConsoleOutputString",
  205. "SrvFillConsoleOutput",
  206. "SrvGetConsoleMode",
  207. "SrvGetConsoleNumberOfFonts",
  208. "SrvGetConsoleNumberOfInputEvents",
  209. "SrvGetConsoleScreenBufferInfo",
  210. "SrvGetConsoleCursorInfo",
  211. "SrvGetConsoleMouseInfo",
  212. "SrvGetConsoleFontInfo",
  213. "SrvGetConsoleFontSize",
  214. "SrvGetConsoleCurrentFont",
  215. "SrvSetConsoleMode",
  216. "SrvSetConsoleActiveScreenBuffer",
  217. "SrvFlushConsoleInputBuffer",
  218. "SrvGetLargestConsoleWindowSize",
  219. "SrvSetConsoleScreenBufferSize",
  220. "SrvSetConsoleCursorPosition",
  221. "SrvSetConsoleCursorInfo",
  222. "SrvSetConsoleWindowInfo",
  223. "SrvScrollConsoleScreenBuffer",
  224. "SrvSetConsoleTextAttribute",
  225. "SrvSetConsoleFont",
  226. "SrvSetConsoleIcon",
  227. "SrvReadConsole",
  228. "SrvWriteConsole",
  229. "SrvDuplicateHandle",
  230. "SrvGetHandleInformation",
  231. "SrvSetHandleInformation",
  232. "SrvCloseHandle",
  233. "SrvVerifyConsoleIoHandle",
  234. "SrvAllocConsole",
  235. "SrvFreeConsole",
  236. "SrvGetConsoleTitle",
  237. "SrvSetConsoleTitle",
  238. "SrvCreateConsoleScreenBuffer",
  239. "SrvInvalidateBitMapRect",
  240. "SrvVDMConsoleOperation",
  241. "SrvSetConsoleCursor",
  242. "SrvShowConsoleCursor",
  243. "SrvConsoleMenuControl",
  244. "SrvSetConsolePalette",
  245. "SrvSetConsoleDisplayMode",
  246. "SrvRegisterConsoleVDM",
  247. "SrvGetConsoleHardwareState",
  248. "SrvSetConsoleHardwareState",
  249. "SrvGetConsoleDisplayMode",
  250. "SrvAddConsoleAlias",
  251. "SrvGetConsoleAlias",
  252. "SrvGetConsoleAliasesLength",
  253. "SrvGetConsoleAliasExesLength",
  254. "SrvGetConsoleAliases",
  255. "SrvGetConsoleAliasExes",
  256. "SrvExpungeConsoleCommandHistory",
  257. "SrvSetConsoleNumberOfCommands",
  258. "SrvGetConsoleCommandHistoryLength",
  259. "SrvGetConsoleCommandHistory",
  260. "SrvSetConsoleCommandHistoryMode",
  261. "SrvGetConsoleCP",
  262. "SrvSetConsoleCP",
  263. "SrvSetConsoleKeyShortcuts",
  264. "SrvSetConsoleMenuClose",
  265. "SrvConsoleNotifyLastClose",
  266. "SrvGenerateConsoleCtrlEvent",
  267. "SrvGetConsoleKeyboardLayoutName",
  268. "SrvGetConsoleWindow",
  269. #if defined(FE_SB)
  270. "SrvGetConsoleCharType",
  271. "SrvSetConsoleLocalEUDC",
  272. "SrvSetConsoleCursorMode",
  273. "SrvGetConsoleCursorMode",
  274. "SrvRegisterConsoleOS2",
  275. "SrvSetConsoleOS2OemFormat",
  276. #if defined(FE_IME)
  277. "SrvGetConsoleNlsMode",
  278. "SrvSetConsoleNlsMode",
  279. "SrvRegisterConsoleIME",
  280. "SrvUnregisterConsoleIME",
  281. #endif // FE_IME
  282. #endif // FE_SB
  283. "SrvGetConsoleLangId",
  284. "SrvAttachConsole",
  285. "SrvGetConsoleSelectionInfo",
  286. "SrvGetConsoleProcessList",
  287. };
  288. #endif // DBG
  289. BOOL FullScreenInitialized;
  290. CRITICAL_SECTION ConsoleVDMCriticalSection;
  291. PCONSOLE_INFORMATION ConsoleVDMOnSwitching;
  292. CRITICAL_SECTION ConsoleInitWindowsLock;
  293. BOOL fOneTimeInitialized;
  294. UINT OEMCP;
  295. UINT WINDOWSCP;
  296. UINT ConsoleOutputCP;
  297. CONSOLE_REGISTRY_INFO DefaultRegInfo;
  298. #if defined(FE_SB)
  299. BOOLEAN gfIsDBCSACP;
  300. #endif
  301. VOID
  302. UnregisterVDM(
  303. IN PCONSOLE_INFORMATION Console
  304. );
  305. ULONG
  306. NonConsoleProcessShutdown(
  307. PCSR_PROCESS Process,
  308. DWORD dwFlags
  309. );
  310. ULONG
  311. ConsoleClientShutdown(
  312. PCSR_PROCESS Process,
  313. ULONG Flags,
  314. BOOLEAN fFirstPass
  315. );
  316. NTSTATUS
  317. ConsoleClientConnectRoutine(
  318. IN PCSR_PROCESS Process,
  319. IN OUT PVOID ConnectionInfo,
  320. IN OUT PULONG ConnectionInfoLength
  321. );
  322. VOID
  323. ConsoleClientDisconnectRoutine(
  324. IN PCSR_PROCESS Process
  325. );
  326. VOID ConsolePlaySound(
  327. VOID
  328. );
  329. HANDLE ghInstance;
  330. HICON ghDefaultIcon;
  331. HICON ghDefaultSmIcon;
  332. HCURSOR ghNormalCursor;
  333. PWIN32HEAP pConHeap;
  334. DWORD dwConBaseTag;
  335. DWORD gExtendedEditKey;
  336. BOOL gfTrimLeadingZeros;
  337. BOOL gfEnableColorSelection;
  338. BOOL gfLoadConIme;
  339. VOID LoadLinkInfo(
  340. PCONSOLE_INFO ConsoleInfo,
  341. LPWSTR Title,
  342. LPDWORD TitleLength,
  343. LPWSTR CurDir,
  344. LPWSTR AppName
  345. )
  346. {
  347. DWORD dwLinkLen;
  348. WCHAR LinkName[MAX_PATH + 1];
  349. LNKPROPNTCONSOLE linkprops;
  350. LPWSTR pszIconLocation;
  351. int nIconIndex;
  352. ConsoleInfo->uCodePage = OEMCP;
  353. // Do some initialization
  354. ConsoleInfo->hIcon = ghDefaultIcon;
  355. ConsoleInfo->hSmIcon = ghDefaultSmIcon;
  356. pszIconLocation = NULL;
  357. nIconIndex = 0;
  358. // Try to impersonate the client-side thread
  359. if (!CsrImpersonateClient(NULL)) {
  360. ConsoleInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME;
  361. goto DefaultInit;
  362. }
  363. // Did we get started from a link?
  364. if (ConsoleInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) {
  365. DWORD Success;
  366. DWORD oldLen;
  367. // Get the filename of the link (TitleLength is BYTES, not CHARS)
  368. dwLinkLen = (DWORD)(min(*TitleLength,(MAX_PATH+1)*sizeof(WCHAR)));
  369. RtlCopyMemory(LinkName, Title, dwLinkLen);
  370. LinkName[ MAX_PATH ] = (WCHAR)0;
  371. // Get the title for the window, which is effectively the link file name
  372. oldLen = *TitleLength;
  373. *TitleLength = GetTitleFromLinkName( LinkName, Title );
  374. if (*TitleLength < oldLen)
  375. Title[ *TitleLength / sizeof(WCHAR) ] = L'\0';
  376. // try to get console properties from the link
  377. Success = GetLinkProperties( LinkName,
  378. &linkprops,
  379. sizeof(linkprops)
  380. );
  381. if (Success == LINK_NOINFO) {
  382. ConsoleInfo->dwStartupFlags &= (~STARTF_TITLEISLINKNAME);
  383. goto NormalInit;
  384. }
  385. if (linkprops.pszIconLocation && *linkprops.pszIconLocation) {
  386. pszIconLocation = linkprops.pszIconLocation;
  387. nIconIndex = linkprops.uIcon;
  388. ConsoleInfo->iIconId = 0;
  389. }
  390. // Transfer link settings
  391. ConsoleInfo->dwHotKey = linkprops.uHotKey;
  392. ConsoleInfo->wShowWindow = (WORD)linkprops.uShowCmd;
  393. if (Success == LINK_SIMPLEINFO) {
  394. ConsoleInfo->dwStartupFlags &= (~STARTF_TITLEISLINKNAME);
  395. goto NormalInit;
  396. }
  397. // Transfer console link settings
  398. ConsoleInfo->wFillAttribute = linkprops.console_props.wFillAttribute;
  399. ConsoleInfo->wPopupFillAttribute = linkprops.console_props.wPopupFillAttribute;
  400. RtlCopyMemory( &ConsoleInfo->dwScreenBufferSize,
  401. &linkprops.console_props.dwScreenBufferSize,
  402. sizeof(NT_CONSOLE_PROPS) - FIELD_OFFSET(NT_CONSOLE_PROPS, dwScreenBufferSize)
  403. );
  404. ConsoleInfo->uCodePage = linkprops.fe_console_props.uCodePage;
  405. ConsoleInfo->dwStartupFlags &= ~(STARTF_USESIZE | STARTF_USECOUNTCHARS);
  406. }
  407. NormalInit:
  408. //
  409. // Go get the icon
  410. //
  411. if (pszIconLocation == NULL) {
  412. dwLinkLen = RtlDosSearchPath_U(CurDir,
  413. AppName,
  414. NULL,
  415. sizeof(LinkName),
  416. LinkName,
  417. NULL);
  418. if (dwLinkLen > 0 && dwLinkLen < sizeof(LinkName)) {
  419. pszIconLocation = LinkName;
  420. } else {
  421. pszIconLocation = AppName;
  422. }
  423. }
  424. if (pszIconLocation != NULL) {
  425. HICON hIcon, hSmIcon;
  426. hIcon = hSmIcon = NULL;
  427. PrivateExtractIconExW(pszIconLocation,
  428. nIconIndex,
  429. &hIcon,
  430. &hSmIcon,
  431. 1);
  432. /*
  433. * If there is no large icon, use the default ones.
  434. * If there is only a large icon in the resource, do not use
  435. * the default small one but let it be NULL so we'll stretch
  436. * the large one.
  437. */
  438. if (hIcon != NULL) {
  439. ConsoleInfo->hIcon = hIcon;
  440. ConsoleInfo->hSmIcon = hSmIcon;
  441. }
  442. }
  443. CsrRevertToSelf();
  444. if (!IsValidCodePage(ConsoleInfo->uCodePage)) { // fail safe
  445. ConsoleInfo->uCodePage = OEMCP;
  446. }
  447. if (!(ConsoleInfo->dwStartupFlags & STARTF_TITLEISLINKNAME)) {
  448. CONSOLE_REGISTRY_INFO RegInfo;
  449. DefaultInit:
  450. //
  451. // read values from the registry
  452. //
  453. RegInfo = DefaultRegInfo;
  454. GetRegistryValues(Title, &RegInfo);
  455. //
  456. // If a value isn't specified in STARTUPINFO, then use the one
  457. // from the registry.
  458. //
  459. if (!(ConsoleInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE)) {
  460. ConsoleInfo->wFillAttribute = RegInfo.ScreenFill.Attributes;
  461. }
  462. ConsoleInfo->wPopupFillAttribute = RegInfo.PopupFill.Attributes;
  463. if (!(ConsoleInfo->dwStartupFlags & STARTF_USECOUNTCHARS)) {
  464. ConsoleInfo->dwScreenBufferSize = RegInfo.ScreenBufferSize;
  465. }
  466. if (!(ConsoleInfo->dwStartupFlags & STARTF_USESIZE)) {
  467. ConsoleInfo->dwWindowSize = RegInfo.WindowSize;
  468. }
  469. if (!(ConsoleInfo->dwStartupFlags & STARTF_USEPOSITION)) {
  470. ConsoleInfo->dwWindowOrigin = RegInfo.WindowOrigin;
  471. ConsoleInfo->bAutoPosition = RegInfo.AutoPosition;
  472. } else {
  473. ConsoleInfo->bAutoPosition = FALSE;
  474. }
  475. if (!(ConsoleInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)) {
  476. ConsoleInfo->bFullScreen = RegInfo.FullScreen;
  477. } else {
  478. ConsoleInfo->bFullScreen = TRUE;
  479. }
  480. ConsoleInfo->uFontFamily = RegInfo.FontFamily;
  481. ConsoleInfo->uFontWeight = RegInfo.FontWeight;
  482. ConsoleInfo->dwFontSize = RegInfo.FontSize;
  483. RtlCopyMemory(ConsoleInfo->FaceName, RegInfo.FaceName, sizeof(RegInfo.FaceName));
  484. ConsoleInfo->bQuickEdit = RegInfo.QuickEdit;
  485. ConsoleInfo->bInsertMode = RegInfo.InsertMode;
  486. ConsoleInfo->uCursorSize = RegInfo.CursorSize;
  487. ConsoleInfo->uHistoryBufferSize = RegInfo.HistoryBufferSize;
  488. ConsoleInfo->uNumberOfHistoryBuffers = RegInfo.NumberOfHistoryBuffers;
  489. ConsoleInfo->bHistoryNoDup = RegInfo.HistoryNoDup;
  490. RtlCopyMemory(ConsoleInfo->ColorTable, RegInfo.ColorTable, sizeof(RegInfo.ColorTable));
  491. #ifdef FE_SB
  492. ConsoleInfo->uCodePage = RegInfo.CodePage;
  493. #endif
  494. }
  495. }
  496. BOOL
  497. InitWindowClass( VOID )
  498. {
  499. WNDCLASSEX wc;
  500. BOOL retval;
  501. ATOM atomConsoleClass;
  502. ghNormalCursor = LoadCursor(NULL, IDC_ARROW);
  503. ASSERT(ghModuleWin != NULL);
  504. ghDefaultIcon = LoadIcon(ghModuleWin, MAKEINTRESOURCE(IDI_CONSOLE));
  505. ghDefaultSmIcon = LoadImage(ghModuleWin, MAKEINTRESOURCE(IDI_CONSOLE), IMAGE_ICON,
  506. GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
  507. LR_SHARED);
  508. wc.hIcon = ghDefaultIcon;
  509. wc.cbSize = sizeof(WNDCLASSEX);
  510. wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
  511. wc.lpfnWndProc = ConsoleWindowProc;
  512. wc.cbClsExtra = 0;
  513. wc.cbWndExtra = GWL_CONSOLE_WNDALLOC;
  514. wc.hInstance = ghInstance;
  515. wc.hCursor = ghNormalCursor;
  516. wc.hbrBackground = CreateSolidBrush(DefaultRegInfo.ColorTable[LOBYTE(DefaultRegInfo.ScreenFill.Attributes >> 4) & 0xF]);
  517. wc.lpszMenuName = NULL;
  518. wc.lpszClassName = CONSOLE_WINDOW_CLASS;
  519. wc.hIconSm = ghDefaultSmIcon;
  520. atomConsoleClass = RegisterClassEx(&wc);
  521. retval = (atomConsoleClass != 0);
  522. if (retval) {
  523. NtUserConsoleControl(ConsoleClassAtom, &atomConsoleClass, sizeof(ATOM));
  524. }
  525. return retval;
  526. }
  527. NTSTATUS
  528. InitWindowsStuff(
  529. HDESK hdesk,
  530. LPDWORD lpdwThreadId)
  531. {
  532. NTSTATUS Status = STATUS_SUCCESS;
  533. CLIENT_ID ClientId;
  534. CONSOLEDESKTOPCONSOLETHREAD ConsoleDesktopInfo;
  535. INPUT_THREAD_INIT_INFO InputThreadInitInfo;
  536. //
  537. // This routine must be done within a critical section to ensure that
  538. // only one thread can initialize at a time. We need a special critical
  539. // section here because Csr calls into ConsoleAddProcessRoutine with
  540. // it's own critical section locked and then tries to grab the
  541. // ConsoleHandleTableLock. If we call CsrAddStaticServerThread here
  542. // with the ConsoleHandleTableLock locked we could get into a deadlock
  543. // situation. This critical section should not be used anywhere else.
  544. //
  545. RtlEnterCriticalSection(&ConsoleInitWindowsLock);
  546. ConsoleDesktopInfo.hdesk = hdesk;
  547. ConsoleDesktopInfo.dwThreadId = (DWORD)-1;
  548. NtUserConsoleControl(ConsoleDesktopConsoleThread, &ConsoleDesktopInfo,
  549. sizeof(ConsoleDesktopInfo));
  550. if (ConsoleDesktopInfo.dwThreadId == 0) {
  551. if (!fOneTimeInitialized) {
  552. #ifdef FE_SB
  553. InitializeDbcsMisc();
  554. #endif // FE_SB
  555. FullScreenInitialized = InitializeFullScreen();
  556. //
  557. // read the registry values
  558. //
  559. GetRegistryValues(L"", &DefaultRegInfo);
  560. //
  561. // allocate buffer for scrolling
  562. //
  563. Status = InitializeScrollBuffer();
  564. if (!NT_SUCCESS(Status)) {
  565. RIPMSG1(RIP_WARNING, "InitWindowsStuff: InitScrollBuffer failed %x", Status);
  566. goto ErrorExit;
  567. }
  568. }
  569. //
  570. // create GetMessage thread
  571. //
  572. Status = NtCreateEvent(&InputThreadInitInfo.InitCompleteEventHandle,
  573. EVENT_ALL_ACCESS,
  574. NULL,
  575. NotificationEvent,
  576. FALSE);
  577. if (!NT_SUCCESS(Status)) {
  578. goto ErrorExit;
  579. }
  580. Status = NtDuplicateObject(NtCurrentProcess(), hdesk,
  581. NtCurrentProcess(), &InputThreadInitInfo.DesktopHandle, 0,
  582. 0, DUPLICATE_SAME_ACCESS);
  583. if (!NT_SUCCESS(Status)) {
  584. NtClose(InputThreadInitInfo.InitCompleteEventHandle);
  585. goto ErrorExit;
  586. }
  587. //
  588. // Create GetMessage thread.
  589. //
  590. Status = RtlCreateUserThread(NtCurrentProcess(),
  591. (PSECURITY_DESCRIPTOR) NULL,
  592. TRUE,
  593. 0,
  594. 0,
  595. 0x5000,
  596. ConsoleInputThread,
  597. &InputThreadInitInfo,
  598. &InputThreadInitInfo.ThreadHandle,
  599. &ClientId);
  600. if (!NT_SUCCESS(Status)) {
  601. NtClose(InputThreadInitInfo.InitCompleteEventHandle);
  602. CloseDesktop(InputThreadInitInfo.DesktopHandle);
  603. goto ErrorExit;
  604. }
  605. CsrAddStaticServerThread(InputThreadInitInfo.ThreadHandle, &ClientId, 0);
  606. NtResumeThread(InputThreadInitInfo.ThreadHandle, NULL);
  607. NtWaitForSingleObject(InputThreadInitInfo.InitCompleteEventHandle, FALSE, NULL);
  608. NtClose(InputThreadInitInfo.InitCompleteEventHandle);
  609. if (!NT_SUCCESS(InputThreadInitInfo.InitStatus)) {
  610. Status = InputThreadInitInfo.InitStatus;
  611. goto ErrorExit;
  612. }
  613. *lpdwThreadId = HandleToUlong(ClientId.UniqueThread);
  614. fOneTimeInitialized=TRUE;
  615. } else {
  616. *lpdwThreadId = ConsoleDesktopInfo.dwThreadId;
  617. }
  618. ErrorExit:
  619. RtlLeaveCriticalSection(&ConsoleInitWindowsLock);
  620. return Status;
  621. }
  622. NTSTATUS
  623. ConServerDllInitialization(
  624. PCSR_SERVER_DLL LoadedServerDll)
  625. /*++
  626. Routine Description:
  627. This routine is called to initialize the server dll. It initializes
  628. the console handle table.
  629. Arguments:
  630. LoadedServerDll - Pointer to console server dll data
  631. Return Value:
  632. --*/
  633. {
  634. NTSTATUS Status;
  635. LoadedServerDll->ApiNumberBase = CONSRV_FIRST_API_NUMBER;
  636. LoadedServerDll->MaxApiNumber = ConsolepMaxApiNumber;
  637. LoadedServerDll->ApiDispatchTable = (PCSR_API_ROUTINE *)ConsoleServerApiDispatchTable;
  638. LoadedServerDll->ApiServerValidTable = (PBOOLEAN)ConsoleServerApiServerValidTable;
  639. #if DBG
  640. LoadedServerDll->ApiNameTable = ConsoleServerApiNameTable;
  641. #endif
  642. LoadedServerDll->PerProcessDataLength = sizeof(CONSOLE_PER_PROCESS_DATA);
  643. LoadedServerDll->ConnectRoutine = ConsoleClientConnectRoutine;
  644. LoadedServerDll->DisconnectRoutine = ConsoleClientDisconnectRoutine;
  645. LoadedServerDll->AddProcessRoutine = ConsoleAddProcessRoutine;
  646. LoadedServerDll->ShutdownProcessRoutine = ConsoleClientShutdown;
  647. ghInstance = LoadedServerDll->ModuleHandle;
  648. // initialize data structures
  649. InitWin32HeapStubs();
  650. pConHeap = Win32HeapCreate(
  651. "CH_Head",
  652. "CH_Tail",
  653. HEAP_GROWABLE | HEAP_CLASS_5 |
  654. #ifdef PRERELEASE
  655. HEAP_TAIL_CHECKING_ENABLED,
  656. #else
  657. 0,
  658. #endif // PRERELEASE
  659. NULL, // HeapBase
  660. 64 * 1024, // ReserveSize
  661. 4096, // CommitSize
  662. NULL, // Lock to use for serialization
  663. NULL); // GrowthThreshold
  664. if (pConHeap == NULL) {
  665. return STATUS_NO_MEMORY;
  666. }
  667. dwConBaseTag = Win32HeapCreateTag( pConHeap,
  668. 0,
  669. L"CON!",
  670. L"TMP\0"
  671. L"BMP\0"
  672. L"ALIAS\0"
  673. L"HISTORY\0"
  674. L"TITLE\0"
  675. L"HANDLE\0"
  676. L"CONSOLE\0"
  677. L"ICON\0"
  678. L"BUFFER\0"
  679. L"WAIT\0"
  680. L"FONT\0"
  681. L"SCREEN\0"
  682. #if defined(FE_SB)
  683. L"TMP DBCS\0"
  684. L"SCREEN DBCS\0"
  685. L"EUDC\0"
  686. L"CONVAREA\0"
  687. L"IME\0"
  688. #endif
  689. );
  690. Status = InitializeConsoleHandleTable();
  691. if (!NT_SUCCESS(Status)) {
  692. return Status;
  693. }
  694. Status = RtlInitializeCriticalSectionAndSpinCount(&ConsoleInitWindowsLock,
  695. 0x80000000);
  696. if (!NT_SUCCESS(Status)) {
  697. return Status;
  698. }
  699. //
  700. // Initialize Input thread local message queue
  701. //
  702. Status = RtlInitializeCriticalSectionAndSpinCount(&gInputThreadMsgLock,
  703. 0x80000000);
  704. if (!NT_SUCCESS(Status)) {
  705. return Status;
  706. }
  707. InitializeThreadMessages();
  708. #ifdef i386
  709. Status = RtlInitializeCriticalSectionAndSpinCount(&ConsoleVDMCriticalSection,
  710. 0x80000000);
  711. if (!NT_SUCCESS(Status)) {
  712. return Status;
  713. }
  714. ConsoleVDMOnSwitching = NULL;
  715. #endif
  716. OEMCP = GetOEMCP();
  717. WINDOWSCP = GetACP();
  718. #if !defined(FE_SB)
  719. ConsoleOutputCP = OEMCP;
  720. #endif
  721. InitializeFonts();
  722. InputThreadTlsIndex = TlsAlloc();
  723. if (InputThreadTlsIndex == 0xFFFFFFFF) {
  724. return STATUS_UNSUCCESSFUL;
  725. }
  726. #if defined(FE_SB)
  727. gfIsDBCSACP = !!IsAvailableFarEastCodePage(WINDOWSCP);
  728. #endif
  729. return STATUS_SUCCESS;
  730. }
  731. BOOL
  732. MapHandle(
  733. IN HANDLE ClientProcessHandle,
  734. IN HANDLE ServerHandle,
  735. OUT PHANDLE ClientHandle
  736. )
  737. {
  738. //
  739. // map event handle into dll's handle space.
  740. //
  741. return DuplicateHandle(NtCurrentProcess(),
  742. ServerHandle,
  743. ClientProcessHandle,
  744. ClientHandle,
  745. 0,
  746. FALSE,
  747. DUPLICATE_SAME_ACCESS
  748. );
  749. }
  750. VOID
  751. AddProcessToList(
  752. IN OUT PCONSOLE_INFORMATION Console,
  753. IN OUT PCONSOLE_PROCESS_HANDLE ProcessHandleRecord,
  754. IN HANDLE ProcessHandle
  755. )
  756. {
  757. ASSERT(!(Console->Flags & (CONSOLE_TERMINATING | CONSOLE_SHUTTING_DOWN)));
  758. ProcessHandleRecord->ProcessHandle = ProcessHandle;
  759. ProcessHandleRecord->TerminateCount = 0;
  760. InsertHeadList(&Console->ProcessHandleList, &ProcessHandleRecord->ListLink);
  761. SetProcessFocus(ProcessHandleRecord->Process, Console->Flags & CONSOLE_HAS_FOCUS);
  762. }
  763. PCONSOLE_PROCESS_HANDLE
  764. FindProcessInList(
  765. IN PCONSOLE_INFORMATION Console,
  766. IN HANDLE ProcessHandle
  767. )
  768. {
  769. PCONSOLE_PROCESS_HANDLE ProcessHandleRecord;
  770. PLIST_ENTRY ListHead, ListNext;
  771. ListHead = &Console->ProcessHandleList;
  772. ListNext = ListHead->Flink;
  773. while (ListNext != ListHead) {
  774. ProcessHandleRecord = CONTAINING_RECORD( ListNext, CONSOLE_PROCESS_HANDLE, ListLink );
  775. if (ProcessHandleRecord->ProcessHandle == ProcessHandle) {
  776. return ProcessHandleRecord;
  777. }
  778. ListNext = ListNext->Flink;
  779. }
  780. return NULL;
  781. }
  782. VOID
  783. RemoveProcessFromList(
  784. IN OUT PCONSOLE_INFORMATION Console,
  785. IN HANDLE ProcessHandle
  786. )
  787. {
  788. PCONSOLE_PROCESS_HANDLE ProcessHandleRecord;
  789. PLIST_ENTRY ListHead, ListNext;
  790. ListHead = &Console->ProcessHandleList;
  791. ListNext = ListHead->Flink;
  792. while (ListNext != ListHead) {
  793. ProcessHandleRecord = CONTAINING_RECORD( ListNext, CONSOLE_PROCESS_HANDLE, ListLink );
  794. ListNext = ListNext->Flink;
  795. if (ProcessHandleRecord->ProcessHandle == ProcessHandle) {
  796. RemoveEntryList(&ProcessHandleRecord->ListLink);
  797. ConsoleHeapFree(ProcessHandleRecord);
  798. return;
  799. }
  800. }
  801. RIPMSG1(RIP_ERROR, "RemoveProcessFromList: Process %#p not found", ProcessHandle);
  802. }
  803. NTSTATUS
  804. SetUpConsole(
  805. IN OUT PCONSOLE_INFO ConsoleInfo,
  806. IN DWORD TitleLength,
  807. IN LPWSTR Title,
  808. IN LPWSTR CurDir,
  809. IN LPWSTR AppName,
  810. IN PCONSOLE_PER_PROCESS_DATA ProcessData,
  811. IN BOOLEAN WindowVisible,
  812. IN PUNICODE_STRING pstrDesktopName)
  813. {
  814. NTSTATUS Status;
  815. PCONSOLE_INFORMATION Console;
  816. DWORD ConsoleThreadId;
  817. HWINSTA hwinsta;
  818. HDESK hdesk;
  819. USEROBJECTFLAGS UserObjectFlags;
  820. DWORD Length;
  821. //
  822. // Connect to the windowstation and desktop.
  823. //
  824. if (!CsrImpersonateClient(NULL)) {
  825. return STATUS_BAD_IMPERSONATION_LEVEL;
  826. }
  827. hdesk = NtUserResolveDesktop(CONSOLE_CLIENTPROCESSHANDLE(),
  828. pstrDesktopName,
  829. FALSE,
  830. &hwinsta);
  831. CsrRevertToSelf();
  832. if (hdesk == NULL) {
  833. return STATUS_UNSUCCESSFUL;
  834. }
  835. //
  836. // Need to initialize windows stuff once real console app starts.
  837. // This is because for the time being windows expects the first
  838. // app to be a windows app.
  839. //
  840. Status = InitWindowsStuff(hdesk, &ConsoleThreadId);
  841. if (!NT_SUCCESS(Status)) {
  842. CloseDesktop(hdesk);
  843. CloseWindowStation(hwinsta);
  844. return Status;
  845. }
  846. //
  847. // If the windowstation isn't visible, then neither is the window.
  848. //
  849. if (WindowVisible) {
  850. if (GetUserObjectInformation(hwinsta,
  851. UOI_FLAGS,
  852. &UserObjectFlags,
  853. sizeof(UserObjectFlags),
  854. &Length)) {
  855. if (!(UserObjectFlags.dwFlags & WSF_VISIBLE)) {
  856. WindowVisible = FALSE;
  857. }
  858. }
  859. }
  860. //
  861. // We need to see if we were spawned from a link. If we were, we
  862. // need to call back into the shell to try to get all the console
  863. // information from the link.
  864. //
  865. LoadLinkInfo( ConsoleInfo, Title, &TitleLength, CurDir, AppName );
  866. LockConsoleHandleTable();
  867. Status = AllocateConsoleHandle(&ConsoleInfo->ConsoleHandle);
  868. if (!NT_SUCCESS(Status)) {
  869. UnlockConsoleHandleTable();
  870. CloseDesktop(hdesk);
  871. CloseWindowStation(hwinsta);
  872. return Status;
  873. }
  874. Status = AllocateConsole(ConsoleInfo->ConsoleHandle,
  875. Title,
  876. (USHORT)TitleLength,
  877. CONSOLE_CLIENTPROCESSHANDLE(),
  878. &ConsoleInfo->StdIn,
  879. &ConsoleInfo->StdOut,
  880. &ConsoleInfo->StdErr,
  881. ProcessData,
  882. ConsoleInfo,
  883. WindowVisible,
  884. ConsoleThreadId
  885. );
  886. if (!NT_SUCCESS(Status)) {
  887. FreeConsoleHandle(ConsoleInfo->ConsoleHandle);
  888. UnlockConsoleHandleTable();
  889. CloseDesktop(hdesk);
  890. CloseWindowStation(hwinsta);
  891. return Status;
  892. }
  893. CONSOLE_SETCONSOLEHANDLE(ConsoleInfo->ConsoleHandle);
  894. Status = DereferenceConsoleHandle(ConsoleInfo->ConsoleHandle,&Console);
  895. ASSERT (NT_SUCCESS(Status));
  896. //
  897. // increment console reference count
  898. //
  899. RefConsole(Console);
  900. //
  901. // Save the windowstation and desktop handles so they
  902. // can be used later
  903. //
  904. Console->hWinSta = hwinsta;
  905. Console->hDesk = hdesk;
  906. UnlockConsoleHandleTable();
  907. #if defined(FE_IME)
  908. if (CONSOLE_IS_IME_ENABLED())
  909. {
  910. if (WindowVisible)
  911. {
  912. InitConsoleIMEStuff(Console->hDesk, ConsoleThreadId, Console);
  913. }
  914. }
  915. #endif
  916. return Status;
  917. }
  918. NTSTATUS
  919. ConsoleClientConnectRoutine(
  920. IN PCSR_PROCESS Process,
  921. IN OUT PVOID ConnectionInfo,
  922. IN OUT PULONG ConnectionInfoLength)
  923. /*++
  924. Routine Description:
  925. This routine is called when a new process is created. For processes
  926. without parents, it creates the console. For processes with
  927. parents, it duplicates the handle table.
  928. Arguments:
  929. Process - Pointer to process structure.
  930. ConnectionInfo - Pointer to connection info.
  931. ConnectionInfoLength - Connection info length.
  932. Return Value:
  933. --*/
  934. {
  935. NTSTATUS Status;
  936. PCONSOLE_API_CONNECTINFO p = (PCONSOLE_API_CONNECTINFO)ConnectionInfo;
  937. PCONSOLE_INFORMATION Console;
  938. PCONSOLE_PER_PROCESS_DATA ProcessData;
  939. PCONSOLE_PROCESS_HANDLE ProcessHandleRecord;
  940. CONSOLEWINDOWSTATIONPROCESS ConsoleWindowStationInfo;
  941. UNICODE_STRING strDesktopName;
  942. CONSOLE_PROCESS_INFO cpi;
  943. if (p == NULL ||
  944. *ConnectionInfoLength != sizeof( *p ) ||
  945. p->AppNameLength > sizeof(p->AppName) ||
  946. p->CurDirLength > sizeof(p->CurDir) ||
  947. p->TitleLength > sizeof(p->Title)) {
  948. RIPMSG0(RIP_ERROR, "CONSRV: bad connection info");
  949. return STATUS_UNSUCCESSFUL;
  950. }
  951. //
  952. // Make sure the strings are NULL terminated.
  953. //
  954. p->AppName[NELEM(p->AppName) - 1] = 0;
  955. p->CurDir[NELEM(p->CurDir) - 1] = 0;
  956. p->Title[NELEM(p->Title) - 1] = 0;
  957. if (CtrlRoutine == NULL) {
  958. CtrlRoutine = p->CtrlRoutine;
  959. }
  960. #if defined(FE_IME)
  961. if (ConsoleIMERoutine == NULL) {
  962. ConsoleIMERoutine = p->ConsoleIMERoutine;
  963. }
  964. #endif
  965. ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(Process);
  966. Console = NULL;
  967. //
  968. // If this process is not a console app, stop right here - no
  969. // initialization is needed. Just need to remember that this
  970. // is not a console app so that we do no work during
  971. // ConsoleClientDisconnectRoutine().
  972. //
  973. Status = STATUS_SUCCESS;
  974. if ((CONSOLE_GETCONSOLEAPPFROMPROCESSDATA(ProcessData) = p->ConsoleApp)) {
  975. //
  976. // First call off to USER so it unblocks any app waiting on a call
  977. // to WaitForInputIdle. This way apps calling WinExec() to exec console
  978. // apps will return right away.
  979. //
  980. cpi.dwProcessID = HandleToUlong(CONSOLE_CLIENTPROCESSID());
  981. cpi.dwFlags = (p->ConsoleInfo.ConsoleHandle != NULL) ? 0 : CPI_NEWPROCESSWINDOW;
  982. NtUserConsoleControl(ConsoleNotifyConsoleApplication,
  983. &cpi,
  984. sizeof(CONSOLE_PROCESS_INFO));
  985. //
  986. // create console
  987. //
  988. if (p->ConsoleInfo.ConsoleHandle == NULL) {
  989. ProcessHandleRecord = ConsoleHeapAlloc(HANDLE_TAG, sizeof(CONSOLE_PROCESS_HANDLE));
  990. if (ProcessHandleRecord == NULL) {
  991. Status = STATUS_NO_MEMORY;
  992. goto ErrorExit;
  993. }
  994. //
  995. // We are creating a new console, so derereference
  996. // the parent's console, if any.
  997. //
  998. if (ProcessData->ConsoleHandle != NULL) {
  999. RemoveConsole(ProcessData, Process->ProcessHandle, 0);
  1000. }
  1001. //
  1002. // Get the desktop name.
  1003. //
  1004. if (p->DesktopLength) {
  1005. strDesktopName.Buffer = ConsoleHeapAlloc(TMP_TAG,
  1006. p->DesktopLength);
  1007. if (strDesktopName.Buffer == NULL) {
  1008. Status = STATUS_NO_MEMORY;
  1009. goto ErrorExit;
  1010. }
  1011. Status = NtReadVirtualMemory(Process->ProcessHandle,
  1012. (PVOID)p->Desktop,
  1013. strDesktopName.Buffer,
  1014. p->DesktopLength,
  1015. NULL
  1016. );
  1017. if (!NT_SUCCESS(Status)) {
  1018. ConsoleHeapFree(strDesktopName.Buffer);
  1019. goto ErrorExit;
  1020. }
  1021. strDesktopName.MaximumLength = (USHORT)p->DesktopLength;
  1022. strDesktopName.Length = (USHORT)(p->DesktopLength - sizeof(WCHAR));
  1023. } else {
  1024. RtlInitUnicodeString(&strDesktopName, L"Default");
  1025. }
  1026. ProcessData->RootProcess = TRUE;
  1027. Status = SetUpConsole(&p->ConsoleInfo,
  1028. p->TitleLength,
  1029. p->Title,
  1030. p->CurDir,
  1031. p->AppName,
  1032. ProcessData,
  1033. p->WindowVisible,
  1034. &strDesktopName);
  1035. if (p->DesktopLength) {
  1036. ConsoleHeapFree(strDesktopName.Buffer);
  1037. }
  1038. if (!NT_SUCCESS(Status)) {
  1039. goto ErrorExit;
  1040. }
  1041. // Play the Open sound for console apps
  1042. ConsolePlaySound();
  1043. Status = RevalidateConsole(p->ConsoleInfo.ConsoleHandle, &Console);
  1044. ASSERT (NT_SUCCESS(Status));
  1045. } else {
  1046. ProcessHandleRecord = NULL;
  1047. ProcessData->RootProcess = FALSE;
  1048. Status = STATUS_SUCCESS;
  1049. if (!(NT_SUCCESS(RevalidateConsole(p->ConsoleInfo.ConsoleHandle, &Console))) ) {
  1050. Status = STATUS_PROCESS_IS_TERMINATING;
  1051. goto ErrorExit;
  1052. }
  1053. if (Console->Flags & CONSOLE_SHUTTING_DOWN) {
  1054. Status = STATUS_PROCESS_IS_TERMINATING;
  1055. goto ErrorExit;
  1056. }
  1057. Status = MapEventHandles(CONSOLE_CLIENTPROCESSHANDLE(),
  1058. Console,
  1059. &p->ConsoleInfo
  1060. );
  1061. if (!NT_SUCCESS(Status)) {
  1062. goto ErrorExit;
  1063. }
  1064. ProcessHandleRecord = FindProcessInList(Console, CONSOLE_CLIENTPROCESSHANDLE());
  1065. if (ProcessHandleRecord) {
  1066. ProcessHandleRecord->CtrlRoutine = p->CtrlRoutine;
  1067. ProcessHandleRecord->PropRoutine = p->PropRoutine;
  1068. ProcessHandleRecord = NULL;
  1069. }
  1070. }
  1071. if (NT_SUCCESS(Status)) {
  1072. //
  1073. // Associate the correct window station with client process
  1074. // so they can do Global atom calls.
  1075. //
  1076. if (DuplicateHandle( NtCurrentProcess(),
  1077. Console->hWinSta,
  1078. Process->ProcessHandle,
  1079. &ConsoleWindowStationInfo.hwinsta,
  1080. 0,
  1081. FALSE,
  1082. DUPLICATE_SAME_ACCESS
  1083. )
  1084. ) {
  1085. ConsoleWindowStationInfo.dwProcessId = HandleToUlong(CONSOLE_CLIENTPROCESSID());
  1086. NtUserConsoleControl(ConsoleWindowStationProcess,
  1087. &ConsoleWindowStationInfo,
  1088. sizeof(ConsoleWindowStationInfo));
  1089. }
  1090. if (ProcessHandleRecord) {
  1091. ProcessHandleRecord->Process = Process;
  1092. ProcessHandleRecord->CtrlRoutine = p->CtrlRoutine;
  1093. ProcessHandleRecord->PropRoutine = p->PropRoutine;
  1094. AddProcessToList(Console, ProcessHandleRecord, CONSOLE_CLIENTPROCESSHANDLE());
  1095. }
  1096. SetProcessForegroundRights(Process,
  1097. Console->Flags & CONSOLE_HAS_FOCUS);
  1098. AllocateCommandHistory(Console,
  1099. p->AppNameLength,
  1100. p->AppName,
  1101. CONSOLE_CLIENTPROCESSHANDLE());
  1102. } else {
  1103. ErrorExit:
  1104. CONSOLE_SETCONSOLEAPPFROMPROCESSDATA(ProcessData, FALSE);
  1105. if (ProcessHandleRecord)
  1106. ConsoleHeapFree(ProcessHandleRecord);
  1107. if (ProcessData->ConsoleHandle != NULL) {
  1108. RemoveConsole(ProcessData, Process->ProcessHandle, 0);
  1109. }
  1110. }
  1111. if (Console) {
  1112. ConsoleNotifyWinEvent(Console,
  1113. EVENT_CONSOLE_START_APPLICATION,
  1114. HandleToULong(Process->ClientId.UniqueProcess),
  1115. 0);
  1116. UnlockConsole(Console);
  1117. }
  1118. } else if (ProcessData->ConsoleHandle != NULL) {
  1119. //
  1120. // This is a non-console app with a reference to a
  1121. // reference to a parent console. Dereference the
  1122. // console.
  1123. //
  1124. RemoveConsole(ProcessData, Process->ProcessHandle, 0);
  1125. }
  1126. return Status;
  1127. }
  1128. #if defined(FE_IME)
  1129. VOID FreeConsoleIMEStuff(
  1130. PCONSOLE_INFORMATION Console)
  1131. {
  1132. PCONVERSIONAREA_INFORMATION ConvAreaInfo;
  1133. PCONVERSIONAREA_INFORMATION ConvAreaInfoNext;
  1134. ConvAreaInfo = Console->ConsoleIme.ConvAreaRoot;
  1135. while(ConvAreaInfo) {
  1136. ConvAreaInfoNext = ConvAreaInfo->ConvAreaNext;
  1137. FreeConvAreaScreenBuffer(ConvAreaInfo->ScreenBuffer);
  1138. ConsoleHeapFree(ConvAreaInfo);
  1139. ConvAreaInfo = ConvAreaInfoNext;
  1140. }
  1141. if (Console->ConsoleIme.NumberOfConvAreaCompStr) {
  1142. ConsoleHeapFree(Console->ConsoleIme.ConvAreaCompStr);
  1143. }
  1144. if (Console->ConsoleIme.CompStrData) {
  1145. ConsoleHeapFree(Console->ConsoleIme.CompStrData);
  1146. }
  1147. }
  1148. #else
  1149. #define FreeConsoleIMEStuff(Console)
  1150. #endif
  1151. NTSTATUS
  1152. RemoveConsole(
  1153. IN PCONSOLE_PER_PROCESS_DATA ProcessData,
  1154. IN HANDLE ProcessHandle,
  1155. IN HANDLE ProcessId)
  1156. {
  1157. ULONG i;
  1158. PHANDLE_DATA HandleData;
  1159. NTSTATUS Status;
  1160. PCONSOLE_INFORMATION Console;
  1161. Status = RevalidateConsole(ProcessData->ConsoleHandle, &Console);
  1162. //
  1163. // If this process isn't using the console, error.
  1164. //
  1165. if (!NT_SUCCESS(Status)) {
  1166. ASSERT(FALSE);
  1167. return Status;
  1168. }
  1169. if (Console->Flags & CONSOLE_NOTIFY_LAST_CLOSE) {
  1170. if (Console->ProcessIdLastNotifyClose == ProcessId) {
  1171. //
  1172. // If this process is the one who wants last close notification,
  1173. // remove it.
  1174. //
  1175. Console->Flags &= ~CONSOLE_NOTIFY_LAST_CLOSE;
  1176. NtClose(Console->hProcessLastNotifyClose);
  1177. } else if (ProcessData->RootProcess) {
  1178. //
  1179. // Notify the ntvdm process to terminate if the console root
  1180. // process is going away.
  1181. //
  1182. HANDLE ConsoleHandle;
  1183. CONSOLE_PROCESS_TERMINATION_RECORD ProcessHandleList;
  1184. Console->Flags &= ~CONSOLE_NOTIFY_LAST_CLOSE;
  1185. ConsoleHandle = Console->ConsoleHandle;
  1186. ProcessHandleList.ProcessHandle = Console->hProcessLastNotifyClose;
  1187. ProcessHandleList.TerminateCount = 0;
  1188. ProcessHandleList.CtrlRoutine = CtrlRoutine;
  1189. UnlockConsole(Console);
  1190. CreateCtrlThread(&ProcessHandleList,
  1191. 1,
  1192. NULL,
  1193. SYSTEM_ROOT_CONSOLE_EVENT,
  1194. TRUE);
  1195. NtClose(ProcessHandleList.ProcessHandle);
  1196. Status = RevalidateConsole(ConsoleHandle, &Console);
  1197. UserAssert(NT_SUCCESS(Status));
  1198. if (!NT_SUCCESS(Status)) {
  1199. return STATUS_SUCCESS;
  1200. }
  1201. }
  1202. }
  1203. if (Console->VDMProcessId == ProcessId &&
  1204. (Console->Flags & CONSOLE_VDM_REGISTERED)) {
  1205. Console->Flags &= ~CONSOLE_FULLSCREEN_NOPAINT;
  1206. UnregisterVDM(Console);
  1207. }
  1208. if (ProcessHandle != NULL) {
  1209. RemoveProcessFromList(Console, ProcessHandle);
  1210. FreeCommandHistory(Console, ProcessHandle);
  1211. }
  1212. UserAssert(Console->RefCount);
  1213. //
  1214. // close the process's handles.
  1215. //
  1216. for (i = 0; i < ProcessData->HandleTableSize; i++) {
  1217. if (ProcessData->HandleTablePtr[i].HandleType != CONSOLE_FREE_HANDLE) {
  1218. Status = DereferenceIoHandleNoCheck(ProcessData,
  1219. LongToHandle(i),
  1220. &HandleData);
  1221. UserAssert(NT_SUCCESS(Status));
  1222. if (HandleData->HandleType & CONSOLE_INPUT_HANDLE) {
  1223. Status = CloseInputHandle(ProcessData, Console, HandleData, LongToHandle(i));
  1224. } else {
  1225. Status = CloseOutputHandle(ProcessData, Console, HandleData, LongToHandle(i), FALSE);
  1226. }
  1227. }
  1228. }
  1229. FreeProcessData(ProcessData);
  1230. ProcessData->ConsoleHandle = NULL;
  1231. //
  1232. // Decrement the console reference count. Free the console if it goes to
  1233. // zero.
  1234. //
  1235. DerefConsole(Console);
  1236. if (Console->RefCount == 0) {
  1237. FreeConsoleIMEStuff(Console);
  1238. FreeCon(Console);
  1239. } else {
  1240. //
  1241. // The root process is going away, so we need to reparent it.
  1242. //
  1243. if (ProcessData->RootProcess) {
  1244. PLIST_ENTRY ListHead = Console->ProcessHandleList.Flink;
  1245. PCONSOLE_PROCESS_HANDLE ProcessHandleRecord;
  1246. PCSR_THREAD Thread;
  1247. HANDLE hThread;
  1248. RIPMSG1(RIP_WARNING, "Reparenting console 0x%p", ProcessData);
  1249. ProcessHandleRecord = CONTAINING_RECORD(ListHead,
  1250. CONSOLE_PROCESS_HANDLE,
  1251. ListLink);
  1252. ListHead = ProcessHandleRecord->Process->ThreadList.Flink;
  1253. Thread = CONTAINING_RECORD(ListHead, CSR_THREAD, Link);
  1254. ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(ProcessHandleRecord->Process);
  1255. UserAssert(ProcessData->RootProcess == FALSE);
  1256. ProcessData->RootProcess = TRUE;
  1257. Status = NtDuplicateObject(NtCurrentProcess(),
  1258. Thread->ThreadHandle,
  1259. NtCurrentProcess(),
  1260. &hThread,
  1261. 0,
  1262. FALSE,
  1263. DUPLICATE_SAME_ACCESS);
  1264. if (NT_SUCCESS(Status)) {
  1265. /*
  1266. * We can only close this handle if the dup call above
  1267. * succeeded. If it didn't, then we're going to zombie this
  1268. * process, but at least we can keep going.
  1269. */
  1270. NtClose(Console->ClientThreadHandle);
  1271. Console->ClientThreadHandle = hThread;
  1272. } else {
  1273. RIPMSGF1(RIP_WARNING,
  1274. "Failed to dup thread handle: Status = 0x%x",
  1275. Status);
  1276. }
  1277. }
  1278. UnlockConsole(Console);
  1279. }
  1280. return STATUS_SUCCESS;
  1281. }
  1282. VOID
  1283. ConsoleClientDisconnectRoutine(
  1284. IN PCSR_PROCESS Process)
  1285. /*++
  1286. Routine Description:
  1287. This routine is called when a process is destroyed. It closes the
  1288. process's handles and frees the console if it's the last reference.
  1289. Arguments:
  1290. Process - Pointer to process structure.
  1291. Return Value:
  1292. --*/
  1293. {
  1294. PCONSOLE_PER_PROCESS_DATA ProcessData;
  1295. PCONSOLE_INFORMATION Console;
  1296. NTSTATUS Status;
  1297. ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(Process);
  1298. //
  1299. // If this process is not a console app, stop right here - no
  1300. // disconnect processing is needed, because this app didn't create
  1301. // or connect to an existing console.
  1302. //
  1303. if (ProcessData->ConsoleHandle == NULL) {
  1304. #if defined(FE_IME)
  1305. if (ProcessData->hDesk) {
  1306. //
  1307. // If this process is a Console IME,
  1308. // should unregister console IME on this desktop.
  1309. //
  1310. RemoveConsoleIME(Process, HandleToUlong(Process->ClientId.UniqueThread));
  1311. }
  1312. #endif
  1313. return;
  1314. }
  1315. Status = RevalidateConsole(ProcessData->ConsoleHandle, &Console);
  1316. if (NT_SUCCESS(Status)) {
  1317. ConsoleNotifyWinEvent(Console,
  1318. EVENT_CONSOLE_END_APPLICATION,
  1319. HandleToULong(Process->ClientId.UniqueProcess),
  1320. 0);
  1321. UnlockConsole(Console);
  1322. } else {
  1323. RIPMSG2(RIP_WARNING, "RevalidateConsole returned status 0x%x on console 0x%x", Status, ProcessData->ConsoleHandle);
  1324. }
  1325. RemoveConsole(ProcessData,
  1326. CONSOLE_FROMPROCESSPROCESSHANDLE(Process),
  1327. Process->ClientId.UniqueProcess);
  1328. CONSOLE_SETCONSOLEAPPFROMPROCESSDATA(ProcessData, FALSE);
  1329. }
  1330. ULONG
  1331. SrvAllocConsole(
  1332. IN OUT PCSR_API_MSG m,
  1333. IN OUT PCSR_REPLY_STATUS ReplyStatus
  1334. )
  1335. {
  1336. PCONSOLE_ALLOC_MSG a = (PCONSOLE_ALLOC_MSG)&m->u.ApiMessageData;
  1337. PCONSOLE_PER_PROCESS_DATA ProcessData;
  1338. NTSTATUS Status;
  1339. PCONSOLE_INFORMATION Console;
  1340. PCONSOLE_PROCESS_HANDLE ProcessHandleRecord;
  1341. PCSR_PROCESS Process;
  1342. UNICODE_STRING strDesktopName;
  1343. ProcessData = CONSOLE_PERPROCESSDATA();
  1344. ASSERT(!CONSOLE_GETCONSOLEAPPFROMPROCESSDATA(ProcessData));
  1345. if (!CsrValidateMessageBuffer(m, &a->Title, a->TitleLength, sizeof(BYTE)) ||
  1346. !CsrValidateMessageBuffer(m, &a->Desktop, a->DesktopLength, sizeof(BYTE)) ||
  1347. !CsrValidateMessageBuffer(m, &a->CurDir, a->CurDirLength, sizeof(BYTE)) ||
  1348. !CsrValidateMessageBuffer(m, &a->AppName, a->AppNameLength, sizeof(BYTE)) ||
  1349. !CsrValidateMessageBuffer(m, &a->ConsoleInfo, sizeof(*a->ConsoleInfo), sizeof(BYTE))) {
  1350. return STATUS_INVALID_PARAMETER;
  1351. }
  1352. Process = (PCSR_PROCESS)(CSR_SERVER_QUERYCLIENTTHREAD()->Process);
  1353. if (a->DesktopLength) {
  1354. RtlInitUnicodeString(&strDesktopName, a->Desktop);
  1355. } else {
  1356. RtlInitUnicodeString(&strDesktopName, L"Default");
  1357. }
  1358. ProcessHandleRecord = ConsoleHeapAlloc(HANDLE_TAG, sizeof(CONSOLE_PROCESS_HANDLE));
  1359. if (ProcessHandleRecord == NULL) {
  1360. return (ULONG)STATUS_NO_MEMORY;
  1361. }
  1362. Status = SetUpConsole(a->ConsoleInfo,
  1363. a->TitleLength,
  1364. a->Title,
  1365. a->CurDir,
  1366. a->AppName,
  1367. ProcessData,
  1368. TRUE,
  1369. &strDesktopName);
  1370. if (!NT_SUCCESS(Status)) {
  1371. ConsoleHeapFree(ProcessHandleRecord);
  1372. return Status;
  1373. }
  1374. CONSOLE_SETCONSOLEAPP(TRUE);
  1375. Process->Flags |= CSR_PROCESS_CONSOLEAPP;
  1376. Status = RevalidateConsole(a->ConsoleInfo->ConsoleHandle,&Console);
  1377. ASSERT (NT_SUCCESS(Status));
  1378. ProcessHandleRecord->Process = CSR_SERVER_QUERYCLIENTTHREAD()->Process;
  1379. ProcessHandleRecord->CtrlRoutine = a->CtrlRoutine;
  1380. ProcessHandleRecord->PropRoutine = a->PropRoutine;
  1381. ASSERT (!(Console->Flags & CONSOLE_SHUTTING_DOWN));
  1382. AddProcessToList(Console, ProcessHandleRecord, CONSOLE_CLIENTPROCESSHANDLE());
  1383. SetProcessForegroundRights(Process, Console->Flags & CONSOLE_HAS_FOCUS);
  1384. AllocateCommandHistory(Console,
  1385. a->AppNameLength,
  1386. a->AppName,
  1387. CONSOLE_CLIENTPROCESSHANDLE());
  1388. UnlockConsole(Console);
  1389. return STATUS_SUCCESS;
  1390. UNREFERENCED_PARAMETER(ReplyStatus);
  1391. }
  1392. ULONG
  1393. SrvFreeConsole(
  1394. IN OUT PCSR_API_MSG m,
  1395. IN OUT PCSR_REPLY_STATUS ReplyStatus
  1396. )
  1397. {
  1398. PCONSOLE_FREE_MSG a = (PCONSOLE_FREE_MSG)&m->u.ApiMessageData;
  1399. PCONSOLE_PER_PROCESS_DATA ProcessData;
  1400. NTSTATUS Status;
  1401. ProcessData = CONSOLE_PERPROCESSDATA();
  1402. ASSERT (CONSOLE_GETCONSOLEAPPFROMPROCESSDATA(ProcessData));
  1403. if (CONSOLE_GETCONSOLEHANDLEFROMPROCESSDATA(ProcessData) != a->ConsoleHandle) {
  1404. RIPMSG1(RIP_WARNING, "SrvFreeConsole: invalid console handle %x", a->ConsoleHandle);
  1405. return STATUS_INVALID_HANDLE;
  1406. }
  1407. Status = RemoveConsole(ProcessData,
  1408. CONSOLE_CLIENTPROCESSHANDLE(),
  1409. CONSOLE_CLIENTPROCESSID());
  1410. if (NT_SUCCESS(Status)) {
  1411. CONSOLE_SETCONSOLEAPP(FALSE);
  1412. }
  1413. return Status;
  1414. UNREFERENCED_PARAMETER(ReplyStatus);
  1415. }
  1416. ULONG
  1417. SrvAttachConsole(
  1418. IN OUT PCSR_API_MSG m,
  1419. IN OUT PCSR_REPLY_STATUS ReplyStatus
  1420. )
  1421. {
  1422. PCONSOLE_ATTACH_MSG a = (PCONSOLE_ATTACH_MSG)&m->u.ApiMessageData;
  1423. DWORD ProcessId;
  1424. NTSTATUS Status;
  1425. PCSR_PROCESS ParentProcess;
  1426. PCSR_PROCESS Process;
  1427. CLIENT_ID ClientId;
  1428. OBJECT_ATTRIBUTES Obja;
  1429. HANDLE ProcessHandle;
  1430. PCONSOLE_INFORMATION Console;
  1431. PCONSOLE_PER_PROCESS_DATA ProcessData;
  1432. PCONSOLE_PER_PROCESS_DATA ParentProcessData;
  1433. PCONSOLE_PROCESS_HANDLE ProcessHandleRecord;
  1434. Process = (PCSR_PROCESS)(CSR_SERVER_QUERYCLIENTTHREAD()->Process);
  1435. //
  1436. // Make sure we have a valid buffer
  1437. //
  1438. if (!CsrValidateMessageBuffer(m, &a->ConsoleInfo, sizeof(*a->ConsoleInfo), sizeof(BYTE))) {
  1439. return STATUS_INVALID_PARAMETER;
  1440. }
  1441. //
  1442. // Make sure we're not already attached to a console
  1443. //
  1444. ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(Process);
  1445. if (CONSOLE_GETCONSOLEAPPFROMPROCESSDATA(ProcessData)) {
  1446. return STATUS_ACCESS_DENIED;
  1447. }
  1448. //
  1449. // Figure out what process we're attaching to.
  1450. //
  1451. if (a->ProcessId == (DWORD)-1) {
  1452. ProcessId = ProcessData->ParentProcessId;
  1453. } else {
  1454. ProcessId = a->ProcessId;
  1455. }
  1456. //
  1457. // Lock the process we're attaching to so it can't go away.
  1458. //
  1459. Status = CsrLockProcessByClientId(LongToHandle(ProcessId), &ParentProcess);
  1460. if (!NT_SUCCESS(Status)) {
  1461. return Status;
  1462. }
  1463. //
  1464. // Make sure we have access to the process.
  1465. //
  1466. if (!CsrImpersonateClient(NULL)) {
  1467. CsrUnlockProcess(ParentProcess);
  1468. return STATUS_BAD_IMPERSONATION_LEVEL;
  1469. }
  1470. ClientId.UniqueThread = NULL;
  1471. ClientId.UniqueProcess = UlongToHandle(ProcessId);
  1472. InitializeObjectAttributes(
  1473. &Obja,
  1474. NULL,
  1475. 0,
  1476. NULL,
  1477. NULL
  1478. );
  1479. Status = NtOpenProcess(
  1480. &ProcessHandle,
  1481. PROCESS_ALL_ACCESS,
  1482. &Obja,
  1483. &ClientId
  1484. );
  1485. CsrRevertToSelf();
  1486. if (!NT_SUCCESS(Status)) {
  1487. CsrUnlockProcess(ParentProcess);
  1488. return Status;
  1489. }
  1490. NtClose(ProcessHandle);
  1491. //
  1492. // Add current process to parent process's console.
  1493. //
  1494. Process->Flags |= CSR_PROCESS_CONSOLEAPP;
  1495. ParentProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(ParentProcess);
  1496. *ProcessData = *ParentProcessData;
  1497. Status = ConsoleAddProcessRoutine(ParentProcess, Process);
  1498. if (NT_SUCCESS(Status)) {
  1499. CONSOLE_SETCONSOLEAPP(TRUE);
  1500. Status = RevalidateConsole(ProcessData->ConsoleHandle, &Console);
  1501. }
  1502. CsrUnlockProcess(ParentProcess);
  1503. if (!NT_SUCCESS(Status)) {
  1504. return Status;
  1505. }
  1506. //
  1507. // Initialize per process console settings.
  1508. //
  1509. Status = MapEventHandles(CONSOLE_CLIENTPROCESSHANDLE(),
  1510. Console,
  1511. a->ConsoleInfo
  1512. );
  1513. if (!NT_SUCCESS(Status)) {
  1514. CONSOLE_SETCONSOLEAPPFROMPROCESSDATA(ProcessData, FALSE);
  1515. UnlockConsole(Console);
  1516. RemoveConsole(ProcessData, Process->ProcessHandle, 0);
  1517. return Status;
  1518. }
  1519. NtCurrentPeb()->ProcessParameters->ConsoleHandle =
  1520. a->ConsoleInfo->ConsoleHandle = ProcessData->ConsoleHandle;
  1521. a->ConsoleInfo->StdIn = INDEX_TO_HANDLE(0);
  1522. a->ConsoleInfo->StdOut = INDEX_TO_HANDLE(1);
  1523. a->ConsoleInfo->StdErr = INDEX_TO_HANDLE(2);
  1524. ProcessHandleRecord = FindProcessInList(Console, CONSOLE_CLIENTPROCESSHANDLE());
  1525. if (ProcessHandleRecord) {
  1526. ProcessHandleRecord->CtrlRoutine = a->CtrlRoutine;
  1527. ProcessHandleRecord->PropRoutine = a->PropRoutine;
  1528. }
  1529. SetProcessForegroundRights(Process,
  1530. Console->Flags & CONSOLE_HAS_FOCUS);
  1531. UnlockConsole(Console);
  1532. return Status;
  1533. UNREFERENCED_PARAMETER(ReplyStatus);
  1534. }
  1535. NTSTATUS
  1536. MyRegOpenKey(
  1537. IN HANDLE hKey,
  1538. IN LPWSTR lpSubKey,
  1539. OUT PHANDLE phResult
  1540. )
  1541. {
  1542. OBJECT_ATTRIBUTES Obja;
  1543. UNICODE_STRING SubKey;
  1544. //
  1545. // Convert the subkey to a counted Unicode string.
  1546. //
  1547. RtlInitUnicodeString( &SubKey, lpSubKey );
  1548. //
  1549. // Initialize the OBJECT_ATTRIBUTES structure and open the key.
  1550. //
  1551. InitializeObjectAttributes(
  1552. &Obja,
  1553. &SubKey,
  1554. OBJ_CASE_INSENSITIVE,
  1555. hKey,
  1556. NULL
  1557. );
  1558. return NtOpenKey(
  1559. phResult,
  1560. KEY_READ,
  1561. &Obja
  1562. );
  1563. }
  1564. NTSTATUS
  1565. MyRegQueryValue(
  1566. IN HANDLE hKey,
  1567. IN LPWSTR lpValueName,
  1568. IN DWORD dwValueLength,
  1569. OUT LPBYTE lpData
  1570. )
  1571. {
  1572. UNICODE_STRING ValueName;
  1573. ULONG BufferLength;
  1574. ULONG ResultLength;
  1575. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  1576. NTSTATUS Status;
  1577. //
  1578. // Convert the subkey to a counted Unicode string.
  1579. //
  1580. RtlInitUnicodeString( &ValueName, lpValueName );
  1581. BufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + dwValueLength;
  1582. KeyValueInformation = ConsoleHeapAlloc(TMP_TAG, BufferLength);
  1583. if (KeyValueInformation == NULL)
  1584. return STATUS_NO_MEMORY;
  1585. Status = NtQueryValueKey(
  1586. hKey,
  1587. &ValueName,
  1588. KeyValuePartialInformation,
  1589. KeyValueInformation,
  1590. BufferLength,
  1591. &ResultLength
  1592. );
  1593. if (NT_SUCCESS(Status)) {
  1594. ASSERT(KeyValueInformation->DataLength <= dwValueLength);
  1595. RtlCopyMemory(lpData,
  1596. KeyValueInformation->Data,
  1597. KeyValueInformation->DataLength);
  1598. if (KeyValueInformation->Type == REG_SZ ||
  1599. KeyValueInformation->Type == REG_MULTI_SZ
  1600. ) {
  1601. if (KeyValueInformation->DataLength + sizeof(WCHAR) > dwValueLength) {
  1602. KeyValueInformation->DataLength -= sizeof(WCHAR);
  1603. }
  1604. lpData[KeyValueInformation->DataLength++] = 0;
  1605. lpData[KeyValueInformation->DataLength] = 0;
  1606. }
  1607. }
  1608. ConsoleHeapFree(KeyValueInformation);
  1609. return Status;
  1610. }
  1611. #if defined(FE_SB)
  1612. NTSTATUS
  1613. MyRegQueryValueEx(
  1614. IN HANDLE hKey,
  1615. IN LPWSTR lpValueName,
  1616. IN DWORD dwValueLength,
  1617. OUT LPBYTE lpData,
  1618. OUT LPDWORD lpDataLength
  1619. )
  1620. {
  1621. UNICODE_STRING ValueName;
  1622. ULONG BufferLength;
  1623. ULONG ResultLength;
  1624. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  1625. NTSTATUS Status;
  1626. //
  1627. // Convert the subkey to a counted Unicode string.
  1628. //
  1629. RtlInitUnicodeString( &ValueName, lpValueName );
  1630. BufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + dwValueLength;
  1631. KeyValueInformation = ConsoleHeapAlloc(TMP_TAG, BufferLength);
  1632. if (KeyValueInformation == NULL)
  1633. return STATUS_NO_MEMORY;
  1634. Status = NtQueryValueKey(
  1635. hKey,
  1636. &ValueName,
  1637. KeyValuePartialInformation,
  1638. KeyValueInformation,
  1639. BufferLength,
  1640. &ResultLength
  1641. );
  1642. if (NT_SUCCESS(Status)) {
  1643. ASSERT(KeyValueInformation->DataLength <= dwValueLength);
  1644. RtlCopyMemory(lpData,
  1645. KeyValueInformation->Data,
  1646. KeyValueInformation->DataLength);
  1647. if (lpDataLength)
  1648. {
  1649. *lpDataLength = KeyValueInformation->DataLength;
  1650. }
  1651. }
  1652. ConsoleHeapFree(KeyValueInformation);
  1653. return Status;
  1654. }
  1655. NTSTATUS
  1656. MyRegEnumValue(
  1657. IN HANDLE hKey,
  1658. IN DWORD dwIndex,
  1659. OUT DWORD dwValueLength,
  1660. OUT LPWSTR lpValueName,
  1661. OUT DWORD dwDataLength,
  1662. OUT LPBYTE lpData
  1663. )
  1664. {
  1665. ULONG BufferLength;
  1666. ULONG ResultLength;
  1667. PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
  1668. NTSTATUS Status;
  1669. //
  1670. // Convert the subkey to a counted Unicode string.
  1671. //
  1672. BufferLength = sizeof(KEY_VALUE_FULL_INFORMATION) + dwValueLength + dwDataLength;
  1673. KeyValueInformation = ConsoleHeapAlloc(TMP_TAG, BufferLength);
  1674. if (KeyValueInformation == NULL)
  1675. return STATUS_NO_MEMORY;
  1676. Status = NtEnumerateValueKey(
  1677. hKey,
  1678. dwIndex,
  1679. KeyValueFullInformation,
  1680. KeyValueInformation,
  1681. BufferLength,
  1682. &ResultLength
  1683. );
  1684. if (NT_SUCCESS(Status)) {
  1685. ASSERT(KeyValueInformation->NameLength <= dwValueLength);
  1686. RtlMoveMemory(lpValueName,
  1687. KeyValueInformation->Name,
  1688. KeyValueInformation->NameLength);
  1689. lpValueName[ KeyValueInformation->NameLength >> 1 ] = UNICODE_NULL;
  1690. ASSERT(KeyValueInformation->DataLength <= dwDataLength);
  1691. RtlMoveMemory(lpData,
  1692. (PBYTE)KeyValueInformation + KeyValueInformation->DataOffset,
  1693. KeyValueInformation->DataLength);
  1694. if (KeyValueInformation->Type == REG_SZ) {
  1695. if (KeyValueInformation->DataLength + sizeof(WCHAR) > dwDataLength) {
  1696. KeyValueInformation->DataLength -= sizeof(WCHAR);
  1697. }
  1698. lpData[KeyValueInformation->DataLength++] = 0;
  1699. lpData[KeyValueInformation->DataLength] = 0;
  1700. }
  1701. }
  1702. ConsoleHeapFree(KeyValueInformation);
  1703. return Status;
  1704. }
  1705. #endif
  1706. #define SYSTEM_ROOT (L"%SystemRoot%")
  1707. #define SYSTEM_ROOT_LENGTH (sizeof(SYSTEM_ROOT) - sizeof(WCHAR))
  1708. LPWSTR
  1709. TranslateConsoleTitle(
  1710. LPWSTR ConsoleTitle,
  1711. PUSHORT pcbTranslatedTitle,
  1712. BOOL Unexpand,
  1713. BOOL Substitute
  1714. )
  1715. /*++
  1716. Routine Description:
  1717. This routine translates path characters into '_' characters because
  1718. the NT registry apis do not allow the creation of keys with
  1719. names that contain path characters. It also converts absolute paths
  1720. into %SystemRoot% relative ones. As an example, if both behaviors were
  1721. specified it would convert a title like C:\WINNT\System32\cmd.exe to
  1722. %SystemRoot%_System32_cmd.exe.
  1723. Arguments:
  1724. ConsoleTitle - Pointer to string to translate.
  1725. pcbTranslatedTitle - On return, contains size of translated title.
  1726. Unexpand - Convert absolute path to %SystemRoot% relative one.
  1727. Substitute - Replace '\' with '_' in path.
  1728. Return Value:
  1729. Pointer to translated title or NULL.
  1730. Note:
  1731. This routine allocates a buffer that must be freed.
  1732. --*/
  1733. {
  1734. USHORT cbConsoleTitle, i;
  1735. USHORT cbSystemRoot;
  1736. LPWSTR TranslatedConsoleTitle, Tmp;
  1737. cbConsoleTitle = (USHORT)((lstrlenW(ConsoleTitle) + 1) * sizeof(WCHAR));
  1738. cbSystemRoot = (USHORT)(lstrlenW(USER_SHARED_DATA->NtSystemRoot) * sizeof(WCHAR));
  1739. if (Unexpand && !MyStringCompareW(ConsoleTitle,
  1740. USER_SHARED_DATA->NtSystemRoot,
  1741. cbSystemRoot,
  1742. TRUE)) {
  1743. cbConsoleTitle -= cbSystemRoot;
  1744. (PBYTE)ConsoleTitle += cbSystemRoot;
  1745. cbSystemRoot = SYSTEM_ROOT_LENGTH;
  1746. } else {
  1747. cbSystemRoot = 0;
  1748. }
  1749. Tmp = TranslatedConsoleTitle = ConsoleHeapAlloc(TITLE_TAG, cbSystemRoot + cbConsoleTitle);
  1750. if (TranslatedConsoleTitle == NULL) {
  1751. return NULL;
  1752. }
  1753. RtlCopyMemory(TranslatedConsoleTitle, SYSTEM_ROOT, cbSystemRoot);
  1754. (PBYTE)TranslatedConsoleTitle += cbSystemRoot;
  1755. for (i=0;i<cbConsoleTitle;i+=sizeof(WCHAR)) {
  1756. if (Substitute && *ConsoleTitle == '\\') {
  1757. *TranslatedConsoleTitle++ = (WCHAR)'_';
  1758. } else {
  1759. *TranslatedConsoleTitle++ = *ConsoleTitle;
  1760. }
  1761. ConsoleTitle++;
  1762. }
  1763. if (pcbTranslatedTitle) {
  1764. *pcbTranslatedTitle = cbSystemRoot + cbConsoleTitle;
  1765. }
  1766. return Tmp;
  1767. }
  1768. ULONG
  1769. ConsoleClientShutdown(
  1770. PCSR_PROCESS Process,
  1771. ULONG Flags,
  1772. BOOLEAN fFirstPass
  1773. )
  1774. {
  1775. PCONSOLE_INFORMATION Console;
  1776. PCONSOLE_PER_PROCESS_DATA ProcessData;
  1777. NTSTATUS Status;
  1778. HWND hWnd;
  1779. HANDLE TerminationEvent;
  1780. HANDLE ConsoleHandle;
  1781. NTSTATUS WaitStatus;
  1782. USERTHREAD_USEDESKTOPINFO utudi;
  1783. //
  1784. // Find the console associated with this process
  1785. //
  1786. ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(Process);
  1787. //
  1788. // If this process is not a console app, stop right here unless
  1789. // this is the second pass of shutdown, in which case we'll take
  1790. // it.
  1791. //
  1792. if (!ProcessData || !CONSOLE_GETCONSOLEAPPFROMPROCESSDATA(ProcessData)) {
  1793. #if defined(FE_IME)
  1794. if (fFirstPass &&
  1795. (ProcessData->ConsoleHandle == NULL) &&
  1796. (ProcessData->hDesk != NULL))
  1797. {
  1798. //
  1799. // If this process is a Console IME,
  1800. // should unregister console IME on this desktop.
  1801. //
  1802. RemoveConsoleIME(Process, HandleToUlong(Process->ClientId.UniqueThread));
  1803. }
  1804. #endif
  1805. if (fFirstPass) {
  1806. return SHUTDOWN_UNKNOWN_PROCESS;
  1807. }
  1808. return NonConsoleProcessShutdown(Process, Flags);
  1809. }
  1810. //
  1811. // Find the console structure pointer.
  1812. //
  1813. ConsoleHandle = CONSOLE_GETCONSOLEHANDLEFROMPROCESSDATA(ProcessData);
  1814. Status = RevalidateConsole(
  1815. ConsoleHandle,
  1816. &Console);
  1817. if (!NT_SUCCESS(Status)) {
  1818. return SHUTDOWN_UNKNOWN_PROCESS;
  1819. }
  1820. //
  1821. // If this is the invisible WOW console, return UNKNOWN so USER
  1822. // enumerates 16-bit gui apps.
  1823. //
  1824. if ((Console->Flags & CONSOLE_NO_WINDOW) &&
  1825. (Console->Flags & CONSOLE_WOW_REGISTERED)) {
  1826. UnlockConsole(Console);
  1827. return SHUTDOWN_UNKNOWN_PROCESS;
  1828. }
  1829. //
  1830. // Sometimes the console structure is around even though the
  1831. // hWnd has been NULLed out. In this case, go to non-console
  1832. // process shutdown.
  1833. //
  1834. hWnd = Console->hWnd;
  1835. if (hWnd == NULL || !IsWindow(hWnd)) {
  1836. UnlockConsole(Console);
  1837. return NonConsoleProcessShutdown(Process, Flags);
  1838. }
  1839. //
  1840. // Make a copy of the console termination event
  1841. //
  1842. Status = NtDuplicateObject(NtCurrentProcess(),
  1843. Console->TerminationEvent,
  1844. NtCurrentProcess(),
  1845. &TerminationEvent,
  1846. 0,
  1847. FALSE,
  1848. DUPLICATE_SAME_ACCESS
  1849. );
  1850. if (!NT_SUCCESS(Status)) {
  1851. UnlockConsole(Console);
  1852. return NonConsoleProcessShutdown(Process, Flags);
  1853. }
  1854. //
  1855. // Attach to the desktop.
  1856. //
  1857. utudi.hThread = Console->InputThreadInfo->ThreadHandle;
  1858. utudi.drdRestore.pdeskRestore = NULL;
  1859. Status = NtUserSetInformationThread(NtCurrentThread(),
  1860. UserThreadUseDesktop,
  1861. &utudi,
  1862. sizeof(utudi));
  1863. UnlockConsole(Console);
  1864. if (!NT_SUCCESS(Status)) {
  1865. NtClose(TerminationEvent);
  1866. return NonConsoleProcessShutdown(Process, Flags);
  1867. }
  1868. //
  1869. // We're done looking at this process structure, so dereference it.
  1870. //
  1871. CsrDereferenceProcess(Process);
  1872. //
  1873. // Synchronously talk to this console.
  1874. //
  1875. Status = ShutdownConsole(ConsoleHandle, Flags);
  1876. //
  1877. // Detach from the desktop.
  1878. //
  1879. utudi.hThread = NULL;
  1880. NtUserSetInformationThread(NtCurrentThread(),
  1881. UserThreadUseDesktop,
  1882. &utudi,
  1883. sizeof(utudi));
  1884. //
  1885. // If Status == STATUS_PROCESS_IS_TERMINATING, then we should wait
  1886. // for the console to exit.
  1887. //
  1888. if (Status == STATUS_PROCESS_IS_TERMINATING) {
  1889. WaitStatus = InternalWaitCancel(TerminationEvent, 500000);
  1890. if (WaitStatus == STATUS_WAIT_1) {
  1891. Status = SHUTDOWN_CANCEL;
  1892. } else if (WaitStatus != STATUS_TIMEOUT) {
  1893. Status = SHUTDOWN_KNOWN_PROCESS;
  1894. } else {
  1895. #if DBG
  1896. PLIST_ENTRY ListHead, ListNext;
  1897. PCONSOLE_PROCESS_HANDLE ProcessHandleRecord;
  1898. PCSR_PROCESS Process;
  1899. RIPMSG0(RIP_ERROR | RIP_THERESMORE, "********************************************");
  1900. RIPMSG1(RIP_ERROR | RIP_THERESMORE, "Shutdown wait timed out on console %p", Console);
  1901. RIPMSG1(RIP_ERROR | RIP_THERESMORE, "Reference count is %d", Console->RefCount);
  1902. RIPMSG0(RIP_ERROR | RIP_THERESMORE, "Dump these processes and see if they're hung");
  1903. ListHead = &Console->ProcessHandleList;
  1904. ListNext = ListHead->Flink;
  1905. while (ListNext != ListHead) {
  1906. ProcessHandleRecord = CONTAINING_RECORD(ListNext, CONSOLE_PROCESS_HANDLE, ListLink);
  1907. Process = ProcessHandleRecord->Process;
  1908. RIPMSG2(RIP_ERROR | RIP_THERESMORE, "CsrProcess = %p ProcessId = %x", Process, Process->ClientId.UniqueProcess);
  1909. ListNext = ListNext->Flink;
  1910. }
  1911. RIPMSG0(RIP_ERROR, "********************************************");
  1912. #endif
  1913. Status = SHUTDOWN_CANCEL;
  1914. }
  1915. }
  1916. NtClose(TerminationEvent);
  1917. return Status;
  1918. }
  1919. ULONG
  1920. NonConsoleProcessShutdown(
  1921. PCSR_PROCESS Process,
  1922. DWORD dwFlags
  1923. )
  1924. {
  1925. CONSOLE_PROCESS_TERMINATION_RECORD TerminateRecord;
  1926. DWORD EventType;
  1927. BOOL Success;
  1928. HANDLE ProcessHandle;
  1929. Success = DuplicateHandle(NtCurrentProcess(),
  1930. Process->ProcessHandle,
  1931. NtCurrentProcess(),
  1932. &ProcessHandle,
  1933. 0,
  1934. FALSE,
  1935. DUPLICATE_SAME_ACCESS);
  1936. if (!Success)
  1937. ProcessHandle = Process->ProcessHandle;
  1938. TerminateRecord.ProcessHandle = ProcessHandle;
  1939. TerminateRecord.TerminateCount = 0;
  1940. TerminateRecord.CtrlRoutine = CtrlRoutine;
  1941. CsrDereferenceProcess(Process);
  1942. EventType = CTRL_LOGOFF_EVENT;
  1943. if (dwFlags & EWX_SHUTDOWN)
  1944. EventType = CTRL_SHUTDOWN_EVENT;
  1945. CreateCtrlThread(&TerminateRecord,
  1946. 1,
  1947. NULL,
  1948. EventType,
  1949. TRUE);
  1950. if (Success)
  1951. CloseHandle(ProcessHandle);
  1952. return SHUTDOWN_KNOWN_PROCESS;
  1953. }
  1954. VOID
  1955. InitializeConsoleAttributes( VOID )
  1956. /*++
  1957. Routine Description:
  1958. This routine initializes default attributes from the current
  1959. user's registry values. It gets called during logon/logoff.
  1960. Arguments:
  1961. none
  1962. Return Value:
  1963. none
  1964. --*/
  1965. {
  1966. //
  1967. // Store default values in structure and mark it
  1968. // as invalid (by resetting LastWriteTime).
  1969. //
  1970. DefaultRegInfo.ScreenFill.Attributes = 0x07; // white on black
  1971. DefaultRegInfo.ScreenFill.Char.UnicodeChar = (WCHAR)' ';
  1972. DefaultRegInfo.PopupFill.Attributes = 0xf5; // purple on white
  1973. DefaultRegInfo.PopupFill.Char.UnicodeChar = (WCHAR)' ';
  1974. DefaultRegInfo.InsertMode = FALSE;
  1975. DefaultRegInfo.QuickEdit = FALSE;
  1976. DefaultRegInfo.AutoPosition = TRUE;
  1977. DefaultRegInfo.FullScreen = FALSE;
  1978. DefaultRegInfo.ScreenBufferSize.X = 80;
  1979. DefaultRegInfo.ScreenBufferSize.Y = 25;
  1980. DefaultRegInfo.WindowSize.X = 80;
  1981. DefaultRegInfo.WindowSize.Y = 25;
  1982. DefaultRegInfo.WindowOrigin.X = 0;
  1983. DefaultRegInfo.WindowOrigin.Y = 0;
  1984. DefaultRegInfo.FontSize.X = 0;
  1985. DefaultRegInfo.FontSize.Y = 0;
  1986. DefaultRegInfo.FontFamily = 0;
  1987. DefaultRegInfo.FontWeight = 0;
  1988. DefaultRegInfo.FaceName[0] = L'\0';
  1989. DefaultRegInfo.CursorSize = CURSOR_SMALL_SIZE;
  1990. DefaultRegInfo.HistoryBufferSize = DEFAULT_NUMBER_OF_COMMANDS;
  1991. DefaultRegInfo.NumberOfHistoryBuffers = DEFAULT_NUMBER_OF_BUFFERS;
  1992. DefaultRegInfo.HistoryNoDup = FALSE;
  1993. DefaultRegInfo.ColorTable[ 0] = RGB(0, 0, 0 );
  1994. DefaultRegInfo.ColorTable[ 1] = RGB(0, 0, 0x80);
  1995. DefaultRegInfo.ColorTable[ 2] = RGB(0, 0x80,0 );
  1996. DefaultRegInfo.ColorTable[ 3] = RGB(0, 0x80,0x80);
  1997. DefaultRegInfo.ColorTable[ 4] = RGB(0x80,0, 0 );
  1998. DefaultRegInfo.ColorTable[ 5] = RGB(0x80,0, 0x80);
  1999. DefaultRegInfo.ColorTable[ 6] = RGB(0x80,0x80,0 );
  2000. DefaultRegInfo.ColorTable[ 7] = RGB(0xC0,0xC0,0xC0);
  2001. DefaultRegInfo.ColorTable[ 8] = RGB(0x80,0x80,0x80);
  2002. DefaultRegInfo.ColorTable[ 9] = RGB(0, 0, 0xFF);
  2003. DefaultRegInfo.ColorTable[10] = RGB(0, 0xFF,0 );
  2004. DefaultRegInfo.ColorTable[11] = RGB(0, 0xFF,0xFF);
  2005. DefaultRegInfo.ColorTable[12] = RGB(0xFF,0, 0 );
  2006. DefaultRegInfo.ColorTable[13] = RGB(0xFF,0, 0xFF);
  2007. DefaultRegInfo.ColorTable[14] = RGB(0xFF,0xFF,0 );
  2008. DefaultRegInfo.ColorTable[15] = RGB(0xFF,0xFF,0xFF);
  2009. #if defined(FE_SB) // scotthsu
  2010. DefaultRegInfo.CodePage = OEMCP;
  2011. #endif
  2012. DefaultRegInfo.LastWriteTime = 0;
  2013. //
  2014. // Get system metrics for this user
  2015. //
  2016. InitializeSystemMetrics();
  2017. }
  2018. VOID
  2019. GetRegistryValues(
  2020. IN LPWSTR ConsoleTitle,
  2021. OUT PCONSOLE_REGISTRY_INFO RegInfo
  2022. )
  2023. /*++
  2024. Routine Description:
  2025. This routine reads in values from the registry and places them
  2026. in the supplied structure.
  2027. Arguments:
  2028. ConsoleTitle - name of subkey to open
  2029. RegInfo - pointer to structure to receive information
  2030. Return Value:
  2031. none
  2032. --*/
  2033. {
  2034. HANDLE hCurrentUserKey;
  2035. HANDLE hConsoleKey;
  2036. HANDLE hTitleKey;
  2037. NTSTATUS Status;
  2038. LPWSTR TranslatedConsoleTitle;
  2039. DWORD dwValue;
  2040. DWORD i;
  2041. WCHAR awchFaceName[LF_FACESIZE];
  2042. WCHAR awchBuffer[64];
  2043. KEY_BASIC_INFORMATION KeyInfo;
  2044. ULONG ResultLength;
  2045. //
  2046. // Impersonate the client process
  2047. //
  2048. if (!CsrImpersonateClient(NULL)) {
  2049. RIPMSG0(RIP_WARNING, "GetRegistryValues Impersonate failed");
  2050. return;
  2051. }
  2052. //
  2053. // Open the current user registry key
  2054. //
  2055. Status = RtlOpenCurrentUser(MAXIMUM_ALLOWED, &hCurrentUserKey);
  2056. if (!NT_SUCCESS(Status)) {
  2057. CsrRevertToSelf();
  2058. return;
  2059. }
  2060. //
  2061. // Open the console registry key
  2062. //
  2063. Status = MyRegOpenKey(hCurrentUserKey,
  2064. CONSOLE_REGISTRY_STRING,
  2065. &hConsoleKey);
  2066. if (!NT_SUCCESS(Status)) {
  2067. NtClose(hCurrentUserKey);
  2068. CsrRevertToSelf();
  2069. return;
  2070. }
  2071. //
  2072. // If we're not reading the default key, check if the default values
  2073. // need to be updated
  2074. //
  2075. Status = NtQueryKey(hConsoleKey,
  2076. KeyBasicInformation,
  2077. &KeyInfo,
  2078. sizeof(KeyInfo),
  2079. &ResultLength);
  2080. if (!NT_ERROR(Status)) {
  2081. if (DefaultRegInfo.LastWriteTime != KeyInfo.LastWriteTime.QuadPart) {
  2082. DefaultRegInfo.LastWriteTime = KeyInfo.LastWriteTime.QuadPart;
  2083. if (RegInfo != &DefaultRegInfo) {
  2084. GetRegistryValues(L"", &DefaultRegInfo);
  2085. *RegInfo = DefaultRegInfo;
  2086. }
  2087. }
  2088. }
  2089. //
  2090. // Open the console title subkey
  2091. //
  2092. TranslatedConsoleTitle = TranslateConsoleTitle(ConsoleTitle, NULL, TRUE, TRUE);
  2093. if (TranslatedConsoleTitle == NULL) {
  2094. NtClose(hConsoleKey);
  2095. NtClose(hCurrentUserKey);
  2096. CsrRevertToSelf();
  2097. return;
  2098. }
  2099. Status = MyRegOpenKey(hConsoleKey,
  2100. TranslatedConsoleTitle,
  2101. &hTitleKey);
  2102. ConsoleHeapFree(TranslatedConsoleTitle);
  2103. if (!NT_SUCCESS(Status)) {
  2104. TranslatedConsoleTitle = TranslateConsoleTitle(ConsoleTitle, NULL, FALSE, TRUE);
  2105. if (TranslatedConsoleTitle) {
  2106. Status = MyRegOpenKey(hConsoleKey,
  2107. TranslatedConsoleTitle,
  2108. &hTitleKey);
  2109. ConsoleHeapFree(TranslatedConsoleTitle);
  2110. }
  2111. }
  2112. if (!NT_SUCCESS(Status)) {
  2113. NtClose(hConsoleKey);
  2114. NtClose(hCurrentUserKey);
  2115. CsrRevertToSelf();
  2116. return;
  2117. }
  2118. //
  2119. // Initial screen fill
  2120. //
  2121. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2122. CONSOLE_REGISTRY_FILLATTR,
  2123. sizeof(dwValue), (PBYTE)&dwValue))) {
  2124. RegInfo->ScreenFill.Attributes = (WORD)dwValue;
  2125. }
  2126. //
  2127. // Initial popup fill
  2128. //
  2129. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2130. CONSOLE_REGISTRY_POPUPATTR,
  2131. sizeof(dwValue), (PBYTE)&dwValue))) {
  2132. RegInfo->PopupFill.Attributes = (WORD)dwValue;
  2133. }
  2134. //
  2135. // Initial insert mode
  2136. //
  2137. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2138. CONSOLE_REGISTRY_INSERTMODE,
  2139. sizeof(dwValue), (PBYTE)&dwValue))) {
  2140. RegInfo->InsertMode = !!dwValue;
  2141. }
  2142. //
  2143. // Initial quick edit mode
  2144. //
  2145. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2146. CONSOLE_REGISTRY_QUICKEDIT,
  2147. sizeof(dwValue), (PBYTE)&dwValue))) {
  2148. RegInfo->QuickEdit = !!dwValue;
  2149. }
  2150. #ifdef i386
  2151. //
  2152. // Initial full screen mode
  2153. //
  2154. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2155. CONSOLE_REGISTRY_FULLSCR,
  2156. sizeof(dwValue), (PBYTE)&dwValue))) {
  2157. RegInfo->FullScreen = !!dwValue;
  2158. }
  2159. #endif
  2160. #if defined(FE_SB) // scotthsu
  2161. //
  2162. // Code Page
  2163. //
  2164. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2165. CONSOLE_REGISTRY_CODEPAGE,
  2166. sizeof(dwValue), (PBYTE)&dwValue))) {
  2167. RegInfo->CodePage = (UINT)dwValue;
  2168. // If this routine specified default settings for console property,
  2169. // then make sure code page value when Fae East environment.
  2170. // If code page value does not the same to OEMCP and any FE's code page then
  2171. // we are override code page value to OEMCP on default console property.
  2172. // Because, Far East environment has limitation that doesn not switch to
  2173. // another FE's code page by the SetConsoleCP/SetConsoleOutputCP.
  2174. //
  2175. // Compare of ConsoleTitle and L"" has limit to default property of console.
  2176. // It means, this code doesn't care user defined property.
  2177. // Content of user defined property has responsibility to themselves.
  2178. if (wcscmp(ConsoleTitle, L"") == 0 &&
  2179. IsAvailableFarEastCodePage(RegInfo->CodePage) &&
  2180. OEMCP != RegInfo->CodePage) {
  2181. RegInfo->CodePage = OEMCP;
  2182. }
  2183. }
  2184. #endif // FE_SB
  2185. //
  2186. // Initial screen buffer size
  2187. //
  2188. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2189. CONSOLE_REGISTRY_BUFFERSIZE,
  2190. sizeof(dwValue), (PBYTE)&dwValue))) {
  2191. RegInfo->ScreenBufferSize.X = LOWORD(dwValue);
  2192. RegInfo->ScreenBufferSize.Y = HIWORD(dwValue);
  2193. if (RegInfo->ScreenBufferSize.X <= 0)
  2194. RegInfo->ScreenBufferSize.X = 1;
  2195. if (RegInfo->ScreenBufferSize.Y <= 0)
  2196. RegInfo->ScreenBufferSize.Y = 1;
  2197. }
  2198. //
  2199. // Initial window size
  2200. //
  2201. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2202. CONSOLE_REGISTRY_WINDOWSIZE,
  2203. sizeof(dwValue), (PBYTE)&dwValue))) {
  2204. RegInfo->WindowSize.X = LOWORD(dwValue);
  2205. RegInfo->WindowSize.Y = HIWORD(dwValue);
  2206. if (RegInfo->WindowSize.X <= 0)
  2207. RegInfo->WindowSize.X = 1;
  2208. else if (RegInfo->WindowSize.X > RegInfo->ScreenBufferSize.X)
  2209. RegInfo->WindowSize.X = RegInfo->ScreenBufferSize.X;
  2210. if (RegInfo->WindowSize.Y <= 0)
  2211. RegInfo->WindowSize.Y = 1;
  2212. else if (RegInfo->WindowSize.Y > RegInfo->ScreenBufferSize.Y)
  2213. RegInfo->WindowSize.Y = RegInfo->ScreenBufferSize.Y;
  2214. }
  2215. //
  2216. // Initial window position
  2217. //
  2218. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2219. CONSOLE_REGISTRY_WINDOWPOS,
  2220. sizeof(dwValue), (PBYTE)&dwValue))) {
  2221. RegInfo->WindowOrigin.X = LOWORD(dwValue);
  2222. RegInfo->WindowOrigin.Y = HIWORD(dwValue);
  2223. RegInfo->AutoPosition = FALSE;
  2224. }
  2225. //
  2226. // Initial font size
  2227. //
  2228. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2229. CONSOLE_REGISTRY_FONTSIZE,
  2230. sizeof(dwValue), (PBYTE)&dwValue))) {
  2231. RegInfo->FontSize.X = LOWORD(dwValue);
  2232. RegInfo->FontSize.Y = HIWORD(dwValue);
  2233. }
  2234. //
  2235. // Initial font family
  2236. //
  2237. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2238. CONSOLE_REGISTRY_FONTFAMILY,
  2239. sizeof(dwValue), (PBYTE)&dwValue))) {
  2240. RegInfo->FontFamily = dwValue;
  2241. }
  2242. //
  2243. // Initial font weight
  2244. //
  2245. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2246. CONSOLE_REGISTRY_FONTWEIGHT,
  2247. sizeof(dwValue), (PBYTE)&dwValue))) {
  2248. RegInfo->FontWeight = dwValue;
  2249. }
  2250. //
  2251. // Initial font face name
  2252. //
  2253. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2254. CONSOLE_REGISTRY_FACENAME,
  2255. sizeof(awchFaceName), (PBYTE)awchFaceName))) {
  2256. RtlCopyMemory(RegInfo->FaceName, awchFaceName, sizeof(awchFaceName));
  2257. RegInfo->FaceName[NELEM(RegInfo->FaceName) - 1] = 0;
  2258. }
  2259. //
  2260. // Initial cursor size
  2261. //
  2262. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2263. CONSOLE_REGISTRY_CURSORSIZE,
  2264. sizeof(dwValue), (PBYTE)&dwValue))) {
  2265. RegInfo->CursorSize = dwValue;
  2266. }
  2267. //
  2268. // Initial history buffer size
  2269. //
  2270. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2271. CONSOLE_REGISTRY_HISTORYSIZE,
  2272. sizeof(dwValue), (PBYTE)&dwValue))) {
  2273. RegInfo->HistoryBufferSize = dwValue;
  2274. }
  2275. //
  2276. // Initial number of history buffers
  2277. //
  2278. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2279. CONSOLE_REGISTRY_HISTORYBUFS,
  2280. sizeof(dwValue), (PBYTE)&dwValue))) {
  2281. RegInfo->NumberOfHistoryBuffers = dwValue;
  2282. }
  2283. //
  2284. // Initial history duplication mode
  2285. //
  2286. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2287. CONSOLE_REGISTRY_HISTORYNODUP,
  2288. sizeof(dwValue), (PBYTE)&dwValue))) {
  2289. RegInfo->HistoryNoDup = dwValue;
  2290. }
  2291. for (i=0; i<16; i++) {
  2292. wsprintf(awchBuffer, CONSOLE_REGISTRY_COLORTABLE, i);
  2293. if (NT_SUCCESS(MyRegQueryValue(hTitleKey, awchBuffer,
  2294. sizeof(dwValue), (PBYTE)&dwValue))) {
  2295. RegInfo->ColorTable[ i ] = dwValue;
  2296. }
  2297. }
  2298. if (RegInfo == &DefaultRegInfo) {
  2299. //
  2300. // If the common (default) setting has been changed,
  2301. //
  2302. //
  2303. // Get registry for conime flag
  2304. //
  2305. if (NT_SUCCESS(MyRegQueryValue(hConsoleKey, CONSOLE_REGISTRY_LOAD_CONIME, sizeof dwValue, (PBYTE)&dwValue))) {
  2306. gfLoadConIme = (dwValue != 0);
  2307. } else {
  2308. gfLoadConIme = TRUE;
  2309. }
  2310. //
  2311. // get extended edit mode and keys from registry.
  2312. //
  2313. if (NT_SUCCESS(MyRegQueryValue(hConsoleKey,
  2314. CONSOLE_REGISTRY_EXTENDEDEDITKEY,
  2315. sizeof dwValue,
  2316. (PBYTE)&dwValue)) &&
  2317. dwValue <= 1) {
  2318. ExtKeyDefBuf buf;
  2319. gExtendedEditKey = dwValue;
  2320. //
  2321. // Initialize Extended Edit keys
  2322. //
  2323. InitExtendedEditKeys(NULL);
  2324. if (NT_SUCCESS(MyRegQueryValue(hConsoleKey,
  2325. CONSOLE_REGISTRY_EXTENDEDEDITKEY_CUSTOM,
  2326. sizeof(buf),
  2327. (PBYTE)&buf))) {
  2328. InitExtendedEditKeys(&buf);
  2329. } else {
  2330. RIPMSG0(RIP_VERBOSE, "Error reading ExtendedEditkeyCustom.");
  2331. }
  2332. } else {
  2333. gExtendedEditKey = 0;
  2334. RIPMSG0(RIP_VERBOSE, "Error reading ExtendedEditkey.");
  2335. }
  2336. //
  2337. // Word delimiters
  2338. //
  2339. if (gExtendedEditKey) {
  2340. // If extended edit key is given, provide extended word delimiters
  2341. // by default.
  2342. memcpy((LPBYTE)gaWordDelimChars, (LPBYTE)gaWordDelimCharsDefault,
  2343. sizeof gaWordDelimChars[0] * WORD_DELIM_MAX);
  2344. } else {
  2345. // Otherwise, stick to the original word delimiter.
  2346. gaWordDelimChars[0] = L'\0';
  2347. }
  2348. // Read word delimiters from registry
  2349. if (NT_SUCCESS(MyRegQueryValue(hConsoleKey,
  2350. CONSOLE_REGISTRY_WORD_DELIM,
  2351. sizeof awchBuffer,
  2352. (PBYTE)awchBuffer))) {
  2353. // OK, copy it to the word delimiter array.
  2354. wcsncpy(gaWordDelimChars, awchBuffer, WORD_DELIM_MAX);
  2355. gaWordDelimChars[WORD_DELIM_MAX - 1] = 0;
  2356. }
  2357. //
  2358. // Read Trim Zero Heading flag
  2359. //
  2360. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2361. CONSOLE_REGISTRY_TRIMZEROHEADINGS,
  2362. sizeof(dwValue), (PBYTE)&dwValue))) {
  2363. gfTrimLeadingZeros = dwValue;
  2364. } else {
  2365. gfTrimLeadingZeros = FALSE;
  2366. }
  2367. //
  2368. // Color selected area function enable flag
  2369. //
  2370. if (NT_SUCCESS(MyRegQueryValue(hTitleKey,
  2371. CONSOLE_REGISTRY_ENABLE_COLOR_SELECTION,
  2372. sizeof(dwValue), (PBYTE)&dwValue))) {
  2373. gfEnableColorSelection = !!dwValue;
  2374. }
  2375. else {
  2376. gfEnableColorSelection = FALSE;
  2377. }
  2378. }
  2379. //
  2380. // Close the registry keys
  2381. //
  2382. NtClose(hTitleKey);
  2383. NtClose(hConsoleKey);
  2384. NtClose(hCurrentUserKey);
  2385. CsrRevertToSelf();
  2386. }
  2387. NTSTATUS
  2388. GetConsoleLangId(
  2389. IN UINT OutputCP,
  2390. OUT LANGID* pLangId
  2391. )
  2392. {
  2393. NTSTATUS Status;
  2394. if (CONSOLE_IS_DBCS_ENABLED()){
  2395. if (pLangId != NULL) {
  2396. switch (OutputCP) {
  2397. case 932:
  2398. *pLangId = MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT);
  2399. break;
  2400. case 949:
  2401. *pLangId = MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN);
  2402. break;
  2403. case 936:
  2404. *pLangId = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
  2405. break;
  2406. case 950:
  2407. *pLangId = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL);
  2408. break;
  2409. default:
  2410. *pLangId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
  2411. break;
  2412. }
  2413. }
  2414. Status = STATUS_SUCCESS;
  2415. }
  2416. else {
  2417. Status = STATUS_NOT_SUPPORTED;
  2418. }
  2419. return Status;
  2420. }
  2421. ULONG
  2422. SrvGetConsoleLangId(
  2423. IN OUT PCSR_API_MSG m,
  2424. IN OUT PCSR_REPLY_STATUS ReplyStatus
  2425. )
  2426. {
  2427. PCONSOLE_LANGID_MSG a = (PCONSOLE_LANGID_MSG)&m->u.ApiMessageData;
  2428. NTSTATUS Status;
  2429. PCONSOLE_INFORMATION Console;
  2430. Status = ApiPreamble(a->ConsoleHandle,
  2431. &Console
  2432. );
  2433. if (!NT_SUCCESS(Status)) {
  2434. return Status;
  2435. }
  2436. Status = GetConsoleLangId(Console->OutputCP, &a->LangId);
  2437. UnlockConsole(Console);
  2438. return Status;
  2439. UNREFERENCED_PARAMETER(ReplyStatus);
  2440. }