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.

1271 lines
32 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. dllinit.c
  5. Abstract:
  6. This module implements console dll initialization
  7. Author:
  8. Therese Stowell (thereses) 11-Nov-1990
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #if !defined(BUILD_WOW64)
  14. #include <cpl.h>
  15. #define DEFAULT_WINDOW_TITLE (L"Command Prompt")
  16. extern HANDLE InputWaitHandle;
  17. extern WCHAR ExeNameBuffer[];
  18. extern USHORT ExeNameLength;
  19. extern WCHAR StartDirBuffer[];
  20. extern USHORT StartDirLength;
  21. DWORD
  22. CtrlRoutine(
  23. IN LPVOID lpThreadParameter
  24. );
  25. DWORD
  26. PropRoutine(
  27. IN LPVOID lpThreadParameter
  28. );
  29. #if defined(FE_SB)
  30. #if defined(FE_IME)
  31. DWORD
  32. ConsoleIMERoutine(
  33. IN LPVOID lpThreadParameter
  34. );
  35. #endif // FE_IME
  36. #endif // FE_SB
  37. #define MAX_SESSION_PATH 256
  38. #define SESSION_ROOT L"\\Sessions"
  39. BOOLEAN
  40. ConsoleApp( VOID )
  41. /*++
  42. This routine determines whether the current process is a console or
  43. windows app.
  44. Parameters:
  45. none.
  46. Return Value:
  47. TRUE if console app.
  48. --*/
  49. {
  50. PIMAGE_NT_HEADERS NtHeaders;
  51. NtHeaders = RtlImageNtHeader(GetModuleHandle(NULL));
  52. return ((NtHeaders != NULL) &&
  53. (NtHeaders->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)) ? TRUE : FALSE;
  54. }
  55. VOID
  56. SetUpAppName(
  57. IN OUT LPDWORD CurDirLength,
  58. OUT LPWSTR CurDir,
  59. IN OUT LPDWORD AppNameLength,
  60. OUT LPWSTR AppName
  61. )
  62. {
  63. DWORD Length;
  64. *CurDirLength -= sizeof(WCHAR);
  65. Length = (StartDirLength*sizeof(WCHAR)) > *CurDirLength ? *CurDirLength : (StartDirLength*sizeof(WCHAR));
  66. RtlCopyMemory(CurDir,StartDirBuffer,Length+sizeof(WCHAR));
  67. *CurDirLength = Length + sizeof(WCHAR); // add terminating NULL
  68. *AppNameLength -= sizeof(WCHAR);
  69. Length = (ExeNameLength*sizeof(WCHAR)) > *AppNameLength ? *AppNameLength : (ExeNameLength*sizeof(WCHAR));
  70. RtlCopyMemory(AppName,ExeNameBuffer,Length+sizeof(WCHAR));
  71. *AppNameLength = Length + sizeof(WCHAR); // add terminating NULL
  72. }
  73. ULONG
  74. ParseReserved(
  75. WCHAR *pchReserved,
  76. WCHAR *pchFind
  77. )
  78. {
  79. ULONG dw;
  80. WCHAR *pch, *pchT, ch;
  81. UNICODE_STRING uString;
  82. dw = 0;
  83. if ((pch = wcsstr(pchReserved, pchFind)) != NULL) {
  84. pch += lstrlenW(pchFind);
  85. pchT = pch;
  86. while (*pchT >= '0' && *pchT <= '9')
  87. pchT++;
  88. ch = *pchT;
  89. *pchT = 0;
  90. RtlInitUnicodeString(&uString, pch);
  91. *pchT = ch;
  92. RtlUnicodeStringToInteger(&uString, 0, &dw);
  93. }
  94. return dw;
  95. }
  96. VOID
  97. SetUpConsoleInfo(
  98. IN BOOL DllInit,
  99. OUT LPDWORD TitleLength,
  100. OUT LPWSTR Title OPTIONAL,
  101. OUT LPDWORD DesktopLength,
  102. OUT LPWSTR *Desktop OPTIONAL,
  103. OUT PCONSOLE_INFO ConsoleInfo
  104. )
  105. /*++
  106. This routine fills in the ConsoleInfo structure with the values
  107. specified by the user.
  108. Parameters:
  109. ConsoleInfo - pointer to structure to fill in.
  110. Return Value:
  111. none.
  112. --*/
  113. {
  114. STARTUPINFOW StartupInfo;
  115. HANDLE h;
  116. int id;
  117. HANDLE ghInstance;
  118. BOOL Success;
  119. GetStartupInfoW(&StartupInfo);
  120. ghInstance = (HANDLE)((PVOID)NtCurrentPeb()->ImageBaseAddress );
  121. // these will eventually be filled in using menu input
  122. ConsoleInfo->nFont = 0;
  123. ConsoleInfo->nInputBufferSize = 0;
  124. ConsoleInfo->hIcon = NULL;
  125. ConsoleInfo->hSmIcon = NULL;
  126. ConsoleInfo->iIconId = 0;
  127. ConsoleInfo->dwStartupFlags = StartupInfo.dwFlags;
  128. #if defined(FE_SB)
  129. ConsoleInfo->uCodePage = GetOEMCP();
  130. #endif
  131. if (StartupInfo.lpTitle == NULL) {
  132. StartupInfo.lpTitle = DEFAULT_WINDOW_TITLE;
  133. }
  134. //
  135. // if the desktop name was specified, set up the pointers.
  136. //
  137. if (DllInit && Desktop != NULL &&
  138. StartupInfo.lpDesktop != NULL && *StartupInfo.lpDesktop != 0) {
  139. *DesktopLength = (lstrlenW(StartupInfo.lpDesktop) + 1) * sizeof(WCHAR);
  140. *Desktop = StartupInfo.lpDesktop;
  141. } else {
  142. *DesktopLength = 0;
  143. if (Desktop != NULL)
  144. *Desktop = NULL;
  145. }
  146. // Nope, do normal initialization (TitleLength is in BYTES, not CHARS!)
  147. *TitleLength = (USHORT)((lstrlenW(StartupInfo.lpTitle)+1)*sizeof(WCHAR));
  148. *TitleLength = (USHORT)(min(*TitleLength,MAX_TITLE_LENGTH));
  149. if (DllInit) {
  150. RtlCopyMemory(Title,StartupInfo.lpTitle,*TitleLength);
  151. // ensure the title is NULL terminated
  152. if (*TitleLength == MAX_TITLE_LENGTH)
  153. Title[ (MAX_TITLE_LENGTH/sizeof(WCHAR)) - 1 ] = L'\0';
  154. }
  155. if (StartupInfo.dwFlags & STARTF_USESHOWWINDOW) {
  156. ConsoleInfo->wShowWindow = StartupInfo.wShowWindow;
  157. }
  158. if (StartupInfo.dwFlags & STARTF_USEFILLATTRIBUTE) {
  159. ConsoleInfo->wFillAttribute = (WORD)StartupInfo.dwFillAttribute;
  160. }
  161. if (StartupInfo.dwFlags & STARTF_USECOUNTCHARS) {
  162. ConsoleInfo->dwScreenBufferSize.X = (WORD)(StartupInfo.dwXCountChars);
  163. ConsoleInfo->dwScreenBufferSize.Y = (WORD)(StartupInfo.dwYCountChars);
  164. }
  165. if (StartupInfo.dwFlags & STARTF_USESIZE) {
  166. ConsoleInfo->dwWindowSize.X = (WORD)(StartupInfo.dwXSize);
  167. ConsoleInfo->dwWindowSize.Y = (WORD)(StartupInfo.dwYSize);
  168. }
  169. if (StartupInfo.dwFlags & STARTF_USEPOSITION) {
  170. ConsoleInfo->dwWindowOrigin.X = (WORD)(StartupInfo.dwX);
  171. ConsoleInfo->dwWindowOrigin.Y = (WORD)(StartupInfo.dwY);
  172. }
  173. //
  174. // Grab information passed on lpReserved line...
  175. //
  176. if (StartupInfo.lpReserved != 0) {
  177. //
  178. // the program manager has an icon for the exe. store the
  179. // index in the iIconId field.
  180. //
  181. ConsoleInfo->iIconId = ParseReserved(StartupInfo.lpReserved, L"dde.");
  182. //
  183. // The new "Chicago" way of doing things is to pass the hotkey in the
  184. // hStdInput field and set the STARTF_USEHOTKEY flag. So, if this is
  185. // specified, we get the hotkey from there instead
  186. //
  187. if (StartupInfo.dwFlags & STARTF_USEHOTKEY) {
  188. ConsoleInfo->dwHotKey = HandleToUlong(StartupInfo.hStdInput);
  189. } else {
  190. ConsoleInfo->dwHotKey = ParseReserved(StartupInfo.lpReserved, L"hotkey.");
  191. }
  192. }
  193. }
  194. VOID
  195. SetUpHandles(
  196. IN PCONSOLE_INFO ConsoleInfo
  197. )
  198. /*++
  199. This routine sets up the console and std* handles for the process.
  200. Parameters:
  201. ConsoleInfo - pointer to structure containing handles.
  202. Return Value:
  203. none.
  204. --*/
  205. {
  206. if (ConsoleInfo->dwStartupFlags & STARTF_USEHOTKEY) {
  207. NtCurrentPeb()->ProcessParameters->WindowFlags &= ~STARTF_USEHOTKEY;
  208. }
  209. if (ConsoleInfo->dwStartupFlags & STARTF_HASSHELLDATA) {
  210. NtCurrentPeb()->ProcessParameters->WindowFlags &= ~STARTF_HASSHELLDATA;
  211. }
  212. SET_CONSOLE_HANDLE(ConsoleInfo->ConsoleHandle);
  213. if (!(ConsoleInfo->dwStartupFlags & STARTF_USESTDHANDLES)) {
  214. SetStdHandle(STD_INPUT_HANDLE,ConsoleInfo->StdIn);
  215. SetStdHandle(STD_OUTPUT_HANDLE,ConsoleInfo->StdOut);
  216. SetStdHandle(STD_ERROR_HANDLE,ConsoleInfo->StdErr);
  217. }
  218. }
  219. #endif //!defined(BUILD_WOW64)
  220. #if !defined(BUILD_WOW6432)
  221. BOOL
  222. WINAPI
  223. GetConsoleLangId(
  224. OUT LANGID *lpLangId
  225. )
  226. /*++
  227. Parameters:
  228. lpLangId - Supplies a pointer to a LANGID in which to store the Language ID.
  229. Return Value:
  230. TRUE - The operation was successful.
  231. FALSE/NULL - The operation failed. Extended error status is available
  232. using GetLastError.
  233. --*/
  234. {
  235. CONSOLE_API_MSG m;
  236. PCONSOLE_LANGID_MSG a = &m.u.GetConsoleLangId;
  237. a->ConsoleHandle = GET_CONSOLE_HANDLE;
  238. CsrClientCallServer( (PCSR_API_MSG)&m,
  239. NULL,
  240. CSR_MAKE_API_NUMBER( CONSRV_SERVERDLL_INDEX,
  241. ConsolepGetLangId
  242. ),
  243. sizeof( *a )
  244. );
  245. if (NT_SUCCESS( m.ReturnValue )) {
  246. try {
  247. *lpLangId = a->LangId;
  248. } except( EXCEPTION_EXECUTE_HANDLER ) {
  249. return FALSE;
  250. }
  251. return TRUE;
  252. } else {
  253. return FALSE;
  254. }
  255. }
  256. #endif //!defined(BUILD_WOW6432)
  257. #if !defined(BUILD_WOW64)
  258. VOID
  259. SetTEBLangID(
  260. VOID
  261. )
  262. /*++
  263. Sets the Language Id in the TEB to Far East if code page CP are
  264. Japanese/Korean/Chinese. This is done in order for FormatMessage
  265. to display any Far East character when cmd is running in its code page.
  266. All messages displayed in non-FE code page will be displayed in English.
  267. --*/
  268. {
  269. LANGID LangId;
  270. if (GetConsoleLangId(&LangId)) {
  271. SetThreadLocale( MAKELCID(LangId, SORT_DEFAULT) );
  272. }
  273. }
  274. #endif //!defined(BUILD_WOW64)
  275. #if !defined(BUILD_WOW6432)
  276. BOOL
  277. APIENTRY
  278. ConnectConsoleInternal(IN PWSTR pObjectDirectory,
  279. IN OUT PCONSOLE_API_CONNECTINFO pConnectInfo,
  280. OUT PBOOLEAN pServerProcess
  281. )
  282. /*++
  283. Routine Description:
  284. Helper function for establishing a connection with the console server.
  285. Waits for the server to signal completion.
  286. Arguments:
  287. pObjectDirectory - Supplies a null terminated string that is the same
  288. as the value of the ObjectDirectory= argument passed to the CSRSS
  289. program.
  290. pConnectInfo - Supplies and recieves the connection information.
  291. pServerProcess - Recieves TRUE if this is a server process.
  292. Return Value:
  293. TRUE - Success
  294. FALSE - An error occured.
  295. --*/
  296. {
  297. NTSTATUS Status;
  298. ULONG ConnectionInformationLength = sizeof(CONSOLE_API_CONNECTINFO);
  299. Status = CsrClientConnectToServer( pObjectDirectory,
  300. CONSRV_SERVERDLL_INDEX,
  301. pConnectInfo,
  302. &ConnectionInformationLength,
  303. pServerProcess
  304. );
  305. if (!NT_SUCCESS( Status )) {
  306. return FALSE;
  307. }
  308. //
  309. // we return success although no console api can be called because
  310. // loading shouldn't fail. we'll fail the api calls later.
  311. //
  312. if (*pServerProcess) {
  313. return TRUE;
  314. }
  315. //
  316. // if this is not a console app, return success - nothing else to do.
  317. //
  318. if (!pConnectInfo->ConsoleApp) {
  319. return TRUE;
  320. }
  321. //
  322. // wait for initialization to complete. we have to use the NT
  323. // wait because the heap hasn't been initialized yet.
  324. //
  325. Status = NtWaitForMultipleObjects(NUMBER_OF_INITIALIZATION_EVENTS,
  326. pConnectInfo->ConsoleInfo.InitEvents,
  327. WaitAny,
  328. FALSE,
  329. NULL
  330. );
  331. if (!NT_SUCCESS(Status)) {
  332. SET_LAST_NT_ERROR(Status);
  333. return FALSE;
  334. }
  335. NtClose(pConnectInfo->ConsoleInfo.InitEvents[INITIALIZATION_SUCCEEDED]);
  336. NtClose(pConnectInfo->ConsoleInfo.InitEvents[INITIALIZATION_FAILED]);
  337. if (Status != INITIALIZATION_SUCCEEDED) {
  338. SET_CONSOLE_HANDLE(NULL);
  339. return FALSE;
  340. }
  341. return TRUE;
  342. }
  343. #endif //!defined(BUILD_WOW6432)
  344. #if !defined(BUILD_WOW64)
  345. BOOLEAN
  346. ConDllInitialize(
  347. IN ULONG Reason,
  348. IN PWSTR pObjectDirectory OPTIONAL
  349. )
  350. /*++
  351. Routine Description:
  352. This function implements console dll initialization.
  353. Arguments:
  354. Reason - DLL_PROCESS_ATTACH, DLL_THREAD_ATTACH, etc.
  355. pObjectDiretory - Session directory name; only valid/required when
  356. Reason == DLL_PROCESS_ATTACH.
  357. Return Value:
  358. STATUS_SUCCESS
  359. --*/
  360. {
  361. NTSTATUS Status = STATUS_SUCCESS;
  362. BOOL bStatus;
  363. BOOLEAN ServerProcess;
  364. //
  365. // if we're attaching the DLL, we need to connect to the server.
  366. // if no console exists, we also need to create it and set up stdin,
  367. // stdout, and stderr.
  368. //
  369. if (Reason == DLL_PROCESS_ATTACH) {
  370. CONSOLE_API_CONNECTINFO ConnectionInformation;
  371. //
  372. // Remember in the connect information if this app is a console
  373. // app. need to actually connect to the console server for windowed
  374. // apps so that we know NOT to do any special work during
  375. // ConsoleClientDisconnectRoutine(). Store ConsoleApp info in the
  376. // CSR managed per-process data.
  377. //
  378. Status = RtlInitializeCriticalSection(&DllLock);
  379. if (!NT_SUCCESS(Status)) {
  380. return FALSE;
  381. }
  382. ConnectionInformation.CtrlRoutine = CtrlRoutine;
  383. ConnectionInformation.PropRoutine = PropRoutine;
  384. #if defined(FE_SB)
  385. #if defined(FE_IME)
  386. ConnectionInformation.ConsoleIMERoutine = ConsoleIMERoutine;
  387. #endif // FE_IME
  388. #endif // FE_SB
  389. ConnectionInformation.WindowVisible = TRUE;
  390. ConnectionInformation.ConsoleApp = ConsoleApp();
  391. if (GET_CONSOLE_HANDLE == CONSOLE_DETACHED_PROCESS) {
  392. SET_CONSOLE_HANDLE(NULL);
  393. ConnectionInformation.ConsoleApp = FALSE;
  394. } else if (GET_CONSOLE_HANDLE == CONSOLE_NEW_CONSOLE) {
  395. SET_CONSOLE_HANDLE(NULL);
  396. } else if (GET_CONSOLE_HANDLE == CONSOLE_CREATE_NO_WINDOW) {
  397. SET_CONSOLE_HANDLE(NULL);
  398. ConnectionInformation.WindowVisible = FALSE;
  399. }
  400. if (!ConnectionInformation.ConsoleApp) {
  401. SET_CONSOLE_HANDLE(NULL);
  402. }
  403. ConnectionInformation.ConsoleInfo.ConsoleHandle = GET_CONSOLE_HANDLE;
  404. //
  405. // if no console exists, pass parameters for console creation
  406. //
  407. if (GET_CONSOLE_HANDLE == NULL && ConnectionInformation.ConsoleApp) {
  408. SetUpConsoleInfo(TRUE,
  409. &ConnectionInformation.TitleLength,
  410. ConnectionInformation.Title,
  411. &ConnectionInformation.DesktopLength,
  412. &ConnectionInformation.Desktop,
  413. &ConnectionInformation.ConsoleInfo);
  414. } else {
  415. ConnectionInformation.TitleLength = 0;
  416. ConnectionInformation.DesktopLength = 0;
  417. }
  418. if (ConnectionInformation.ConsoleApp) {
  419. InitExeName();
  420. ConnectionInformation.CurDirLength = sizeof(ConnectionInformation.CurDir);
  421. ConnectionInformation.AppNameLength = sizeof(ConnectionInformation.AppName);
  422. SetUpAppName(&ConnectionInformation.CurDirLength,
  423. ConnectionInformation.CurDir,
  424. &ConnectionInformation.AppNameLength,
  425. ConnectionInformation.AppName);
  426. } else {
  427. ConnectionInformation.AppNameLength = 0;
  428. ConnectionInformation.CurDirLength = 0;
  429. }
  430. //
  431. // initialize ctrl handling. This should work for all apps, so
  432. // initialize it before we check for ConsoleApp (which means the
  433. // console bit was set in the module header).
  434. //
  435. InitializeCtrlHandling();
  436. //
  437. // Connect to the server process
  438. //
  439. ASSERT(pObjectDirectory != NULL);
  440. bStatus = ConnectConsoleInternal(pObjectDirectory,
  441. &ConnectionInformation,
  442. &ServerProcess
  443. );
  444. if (!bStatus) {
  445. return FALSE;
  446. }
  447. //
  448. // we return success although no console api can be called because
  449. // loading shouldn't fail. we'll fail the api calls later.
  450. //
  451. if (ServerProcess) {
  452. return TRUE;
  453. }
  454. //
  455. // if this is not a console app, return success - nothing else to do.
  456. //
  457. if (!ConnectionInformation.ConsoleApp) {
  458. return TRUE;
  459. }
  460. //
  461. // if console was just created, fill in peb values
  462. //
  463. if (GET_CONSOLE_HANDLE == NULL) {
  464. SetUpHandles(&ConnectionInformation.ConsoleInfo);
  465. }
  466. InputWaitHandle = ConnectionInformation.ConsoleInfo.InputWaitHandle;
  467. SetTEBLangID();
  468. } else if (Reason == DLL_THREAD_ATTACH) {
  469. if (ConsoleApp()) {
  470. SetTEBLangID();
  471. }
  472. }
  473. return TRUE;
  474. }
  475. #endif //!defined(BUILD_WOW64)
  476. #if !defined(BUILD_WOW6432)
  477. BOOL
  478. APIENTRY
  479. AllocConsoleInternal(IN LPWSTR lpTitle,
  480. IN DWORD dwTitleLength,
  481. IN LPWSTR lpDesktop,
  482. IN DWORD dwDesktopLength,
  483. IN LPWSTR lpCurDir,
  484. IN DWORD dwCurDirLength,
  485. IN LPWSTR lpAppName,
  486. IN DWORD dwAppNameLength,
  487. IN LPTHREAD_START_ROUTINE CtrlRoutine,
  488. IN LPTHREAD_START_ROUTINE PropRoutine,
  489. IN OUT PCONSOLE_INFO pConsoleInfo
  490. )
  491. /*++
  492. Routine Description:
  493. Marshels the parameters for the ConsolepAlloc command.
  494. Arguments:
  495. See the CONSOLE_ALLOC_MSG structure and AllocConsole.
  496. Return Value:
  497. TRUE - Success
  498. FALSE - An error occured.
  499. --*/
  500. {
  501. CONSOLE_API_MSG m;
  502. PCONSOLE_ALLOC_MSG a = &m.u.AllocConsole;
  503. PCSR_CAPTURE_HEADER CaptureBuffer = NULL;
  504. BOOL bStatus = FALSE;
  505. NTSTATUS Status;
  506. try {
  507. a->CtrlRoutine = CtrlRoutine;
  508. a->PropRoutine = PropRoutine;
  509. // Allocate 4 extra pointer sizes to compensate for any alignment done
  510. // by CsrCaptureMessageBuffer.
  511. CaptureBuffer = CsrAllocateCaptureBuffer( 5,
  512. dwTitleLength + dwDesktopLength + dwCurDirLength +
  513. dwAppNameLength + sizeof( CONSOLE_INFO ) + (4 * sizeof(PVOID))
  514. );
  515. if (CaptureBuffer == NULL) {
  516. SET_LAST_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  517. bStatus = FALSE;
  518. leave;
  519. }
  520. // Allocate the CONSOLE_INFO first so that it is aligned on a pointer
  521. // boundry. This is necessary since NtWaitForMultipleObject expects
  522. // its arguments aligned on a handle boundry.
  523. CsrCaptureMessageBuffer( CaptureBuffer,
  524. pConsoleInfo,
  525. sizeof( CONSOLE_INFO ),
  526. (PVOID *) &a->ConsoleInfo
  527. );
  528. a->TitleLength = dwTitleLength;
  529. CsrCaptureMessageBuffer( CaptureBuffer,
  530. lpTitle,
  531. dwTitleLength,
  532. (PVOID *) &a->Title
  533. );
  534. a->DesktopLength = dwDesktopLength;
  535. CsrCaptureMessageBuffer( CaptureBuffer,
  536. lpDesktop,
  537. dwDesktopLength,
  538. (PVOID *) &a->Desktop
  539. );
  540. a->CurDirLength = dwCurDirLength;
  541. CsrCaptureMessageBuffer( CaptureBuffer,
  542. lpCurDir,
  543. dwCurDirLength,
  544. (PVOID *) &a->CurDir
  545. );
  546. a->AppNameLength = dwAppNameLength;
  547. CsrCaptureMessageBuffer( CaptureBuffer,
  548. lpAppName,
  549. dwAppNameLength,
  550. (PVOID *) &a->AppName
  551. );
  552. //
  553. // Connect to the server process
  554. //
  555. CsrClientCallServer( (PCSR_API_MSG)&m,
  556. CaptureBuffer,
  557. CSR_MAKE_API_NUMBER( CONSRV_SERVERDLL_INDEX,
  558. ConsolepAlloc
  559. ),
  560. sizeof( *a )
  561. );
  562. if (!NT_SUCCESS( m.ReturnValue )) {
  563. SET_LAST_NT_ERROR (m.ReturnValue);
  564. bStatus = FALSE;
  565. leave;
  566. }
  567. Status = NtWaitForMultipleObjects(NUMBER_OF_INITIALIZATION_EVENTS,
  568. a->ConsoleInfo->InitEvents,
  569. WaitAny,
  570. FALSE,
  571. NULL
  572. );
  573. if (!NT_SUCCESS(Status)) {
  574. SET_LAST_NT_ERROR(Status);
  575. bStatus = FALSE;
  576. leave;
  577. }
  578. //The handles to be closed are events, so NtClose works fine.
  579. NtClose(a->ConsoleInfo->InitEvents[INITIALIZATION_SUCCEEDED]);
  580. NtClose(a->ConsoleInfo->InitEvents[INITIALIZATION_FAILED]);
  581. if (Status != INITIALIZATION_SUCCEEDED) {
  582. SET_CONSOLE_HANDLE(NULL);
  583. bStatus = FALSE;
  584. leave;
  585. }
  586. RtlCopyMemory(pConsoleInfo, a->ConsoleInfo, sizeof(CONSOLE_INFO));
  587. bStatus = TRUE;
  588. }
  589. finally {
  590. if (CaptureBuffer) {
  591. CsrFreeCaptureBuffer( CaptureBuffer );
  592. }
  593. }
  594. return bStatus;
  595. }
  596. #endif //!defined(BUILD_WOW6432)
  597. #if !defined(BUILD_WOW64)
  598. BOOL
  599. APIENTRY
  600. AllocConsole( VOID )
  601. /*++
  602. Routine Description:
  603. This API creates a console for the calling process.
  604. Arguments:
  605. none.
  606. Return Value:
  607. TRUE - function was successful.
  608. --*/
  609. {
  610. CONSOLE_INFO ConsoleInfo;
  611. STARTUPINFOW StartupInfo;
  612. WCHAR CurDir[MAX_PATH+1];
  613. WCHAR AppName[MAX_APP_NAME_LENGTH/2];
  614. BOOL Status = FALSE;
  615. DWORD dwTitleLength;
  616. DWORD dwDesktopLength;
  617. DWORD dwCurDirLength;
  618. DWORD dwAppNameLength;
  619. LockDll();
  620. try {
  621. if (GET_CONSOLE_HANDLE != NULL) {
  622. SetLastError(ERROR_ACCESS_DENIED);
  623. Status = FALSE;
  624. leave;
  625. }
  626. //
  627. // set up initialization parameters
  628. //
  629. SetUpConsoleInfo(FALSE,
  630. &dwTitleLength,
  631. NULL,
  632. &dwDesktopLength,
  633. NULL,
  634. &ConsoleInfo);
  635. InitExeName();
  636. dwCurDirLength = sizeof(CurDir);
  637. dwAppNameLength = sizeof(AppName);
  638. SetUpAppName(&dwCurDirLength,
  639. CurDir,
  640. &dwAppNameLength,
  641. AppName);
  642. GetStartupInfoW(&StartupInfo);
  643. if (StartupInfo.lpTitle == NULL) {
  644. StartupInfo.lpTitle = DEFAULT_WINDOW_TITLE;
  645. }
  646. dwTitleLength = (USHORT)((lstrlenW(StartupInfo.lpTitle)+1)*sizeof(WCHAR));
  647. dwTitleLength = (USHORT)(min(dwTitleLength,MAX_TITLE_LENGTH));
  648. if (StartupInfo.lpDesktop != NULL && *StartupInfo.lpDesktop != 0) {
  649. dwDesktopLength = (USHORT)((lstrlenW(StartupInfo.lpDesktop)+1)*sizeof(WCHAR));
  650. dwDesktopLength = (USHORT)(min(dwDesktopLength,MAX_TITLE_LENGTH));
  651. } else {
  652. dwDesktopLength = 0;
  653. }
  654. Status = AllocConsoleInternal(StartupInfo.lpTitle,
  655. dwTitleLength,
  656. StartupInfo.lpDesktop,
  657. dwDesktopLength,
  658. CurDir,
  659. dwCurDirLength,
  660. AppName,
  661. dwAppNameLength,
  662. CtrlRoutine,
  663. PropRoutine,
  664. &ConsoleInfo
  665. );
  666. if (!Status) {
  667. leave;
  668. }
  669. //
  670. // fill in peb values
  671. //
  672. SetUpHandles(&ConsoleInfo);
  673. //
  674. // create ctrl-c thread
  675. //
  676. InitializeCtrlHandling();
  677. InputWaitHandle = ConsoleInfo.InputWaitHandle;
  678. SetTEBLangID();
  679. Status = TRUE;
  680. } finally {
  681. UnlockDll();
  682. }
  683. return Status;
  684. }
  685. #endif //!defined(BUILD_WOW64)
  686. #if !defined(BUILD_WOW6432)
  687. BOOL
  688. APIENTRY
  689. FreeConsoleInternal(
  690. VOID
  691. )
  692. /*++
  693. Routine Description:
  694. Marshels the parameters for the ConsolepFree command.
  695. Arguments:
  696. See the CONSOLE_FREE_MSG structure and FreeConsole.
  697. Return Value:
  698. TRUE - Success
  699. FALSE - An error occured.
  700. --*/
  701. {
  702. CONSOLE_API_MSG m;
  703. PCONSOLE_FREE_MSG a = &m.u.FreeConsole;
  704. a->ConsoleHandle = GET_CONSOLE_HANDLE;
  705. //
  706. // Connect to the server process
  707. //
  708. CsrClientCallServer( (PCSR_API_MSG)&m,
  709. NULL,
  710. CSR_MAKE_API_NUMBER( CONSRV_SERVERDLL_INDEX,
  711. ConsolepFree
  712. ),
  713. sizeof( *a )
  714. );
  715. if (!NT_SUCCESS( m.ReturnValue )) {
  716. SET_LAST_NT_ERROR (m.ReturnValue);
  717. return FALSE;
  718. } else {
  719. SET_CONSOLE_HANDLE(NULL);
  720. return TRUE;
  721. }
  722. }
  723. #endif //!defined(BUILD_WOW6432)
  724. #if !defined(BUILD_WOW64)
  725. BOOL
  726. APIENTRY
  727. FreeConsole( VOID )
  728. /*++
  729. Routine Description:
  730. This API frees the calling process's console.
  731. Arguments:
  732. none.
  733. Return Value:
  734. TRUE - function was successful.
  735. --*/
  736. {
  737. BOOL Success=TRUE;
  738. LockDll();
  739. if (GET_CONSOLE_HANDLE == NULL) {
  740. SET_LAST_ERROR(ERROR_INVALID_PARAMETER);
  741. Success = FALSE;
  742. } else {
  743. Success = FreeConsoleInternal();
  744. if (Success) {
  745. CloseHandle(InputWaitHandle);
  746. }
  747. }
  748. UnlockDll();
  749. return Success;
  750. }
  751. DWORD
  752. PropRoutine(
  753. IN LPVOID lpThreadParameter
  754. )
  755. /*++
  756. Routine Description:
  757. This thread is created when the user tries to change console
  758. properties from the system menu. It invokes the control panel
  759. applet.
  760. Arguments:
  761. lpThreadParameter - not used.
  762. Return Value:
  763. STATUS_SUCCESS - function was successful
  764. --*/
  765. {
  766. NTSTATUS Status;
  767. HANDLE hLibrary;
  768. APPLET_PROC pfnCplApplet;
  769. static BOOL fInPropRoutine = FALSE;
  770. //
  771. // Prevent the user from launching multiple applets attached
  772. // to a single console
  773. //
  774. if (fInPropRoutine) {
  775. if (lpThreadParameter) {
  776. CloseHandle((HANDLE)lpThreadParameter);
  777. }
  778. return (ULONG)STATUS_UNSUCCESSFUL;
  779. }
  780. fInPropRoutine = TRUE;
  781. hLibrary = LoadLibraryW(L"CONSOLE.DLL");
  782. if (hLibrary != NULL) {
  783. pfnCplApplet = (APPLET_PROC)GetProcAddress(hLibrary, "CPlApplet");
  784. if (pfnCplApplet != NULL) {
  785. (*pfnCplApplet)((HWND)lpThreadParameter, CPL_INIT, 0, 0);
  786. (*pfnCplApplet)((HWND)lpThreadParameter, CPL_DBLCLK, 0, 0);
  787. (*pfnCplApplet)((HWND)lpThreadParameter, CPL_EXIT, 0, 0);
  788. Status = STATUS_SUCCESS;
  789. } else {
  790. Status = STATUS_UNSUCCESSFUL;
  791. }
  792. FreeLibrary(hLibrary);
  793. } else {
  794. Status = STATUS_UNSUCCESSFUL;
  795. }
  796. fInPropRoutine = FALSE;
  797. return Status;
  798. }
  799. #endif //!defined(BUILD_WOW64)
  800. #if !defined(BUILD_WOW6432)
  801. BOOL
  802. APIENTRY
  803. AttachConsoleInternal(
  804. IN DWORD dwProcessId,
  805. IN LPTHREAD_START_ROUTINE CtrlRoutine,
  806. IN LPTHREAD_START_ROUTINE PropRoutine,
  807. IN OUT PCONSOLE_INFO pConsoleInfo
  808. )
  809. /*++
  810. Routine Description:
  811. Marshels the parameters for the ConsolepAttach command.
  812. Arguments:
  813. See the CONSOLE_ATTACH_MSG structure and AttachConsole.
  814. Return Value:
  815. TRUE - Success
  816. FALSE - An error occured.
  817. --*/
  818. {
  819. CONSOLE_API_MSG m;
  820. PCONSOLE_ATTACH_MSG a = &m.u.AttachConsole;
  821. PCSR_CAPTURE_HEADER CaptureBuffer = NULL;
  822. BOOL Status = FALSE;
  823. NTSTATUS St;
  824. try {
  825. a->ProcessId = dwProcessId;
  826. a->CtrlRoutine = CtrlRoutine;
  827. a->PropRoutine = PropRoutine;
  828. CaptureBuffer = CsrAllocateCaptureBuffer( 1,
  829. sizeof( CONSOLE_INFO )
  830. );
  831. if (CaptureBuffer == NULL) {
  832. SET_LAST_ERROR(ERROR_NOT_ENOUGH_MEMORY);
  833. Status = FALSE;
  834. leave;
  835. }
  836. CsrCaptureMessageBuffer( CaptureBuffer,
  837. pConsoleInfo,
  838. sizeof( CONSOLE_INFO ),
  839. (PVOID *) &a->ConsoleInfo
  840. );
  841. //
  842. // Connect to the server process
  843. //
  844. CsrClientCallServer( (PCSR_API_MSG)&m,
  845. CaptureBuffer,
  846. CSR_MAKE_API_NUMBER( CONSRV_SERVERDLL_INDEX,
  847. ConsolepAttach
  848. ),
  849. sizeof( *a )
  850. );
  851. if (!NT_SUCCESS( m.ReturnValue )) {
  852. SET_LAST_NT_ERROR (m.ReturnValue);
  853. Status = FALSE;
  854. leave;
  855. }
  856. St = NtWaitForMultipleObjects(NUMBER_OF_INITIALIZATION_EVENTS,
  857. a->ConsoleInfo->InitEvents,
  858. WaitAny,
  859. FALSE,
  860. NULL
  861. );
  862. if (!NT_SUCCESS(St)) {
  863. SET_LAST_NT_ERROR(St);
  864. Status = FALSE;
  865. leave;
  866. }
  867. //The handles to be closed are events, so NtClose works fine.
  868. NtClose(a->ConsoleInfo->InitEvents[INITIALIZATION_SUCCEEDED]);
  869. NtClose(a->ConsoleInfo->InitEvents[INITIALIZATION_FAILED]);
  870. if (St != INITIALIZATION_SUCCEEDED) {
  871. SET_CONSOLE_HANDLE(NULL);
  872. Status = FALSE;
  873. leave;
  874. }
  875. RtlCopyMemory(pConsoleInfo, a->ConsoleInfo, sizeof(CONSOLE_INFO));
  876. Status = TRUE;
  877. }
  878. finally {
  879. if (CaptureBuffer) {
  880. CsrFreeCaptureBuffer( CaptureBuffer );
  881. }
  882. }
  883. return Status;
  884. }
  885. #endif //!defined(BUILD_WOW6432)
  886. #if !defined(BUILD_WOW64)
  887. BOOL
  888. APIENTRY
  889. AttachConsole(
  890. IN DWORD dwProcessId
  891. )
  892. /*++
  893. Routine Description:
  894. This API attaches the calling process to the console of the given process.
  895. Arguments:
  896. none.
  897. Return Value:
  898. TRUE - function was successful.
  899. --*/
  900. {
  901. CONSOLE_INFO ConsoleInfo;
  902. DWORD dwTitleLength;
  903. DWORD dwDesktopLength;
  904. BOOL Status = FALSE;
  905. LockDll();
  906. try {
  907. //
  908. // bail if we already have a console
  909. //
  910. if (GET_CONSOLE_HANDLE != NULL) {
  911. SetLastError(ERROR_ACCESS_DENIED);
  912. Status = FALSE;
  913. leave;
  914. }
  915. //
  916. // set up initialization parameters
  917. //
  918. SetUpConsoleInfo(FALSE,
  919. &dwTitleLength,
  920. NULL,
  921. &dwDesktopLength,
  922. NULL,
  923. &ConsoleInfo);
  924. //
  925. // attach to the console
  926. //
  927. Status = AttachConsoleInternal(dwProcessId,
  928. CtrlRoutine,
  929. PropRoutine,
  930. &ConsoleInfo
  931. );
  932. if (!Status) {
  933. leave;
  934. }
  935. //
  936. // fill in peb values
  937. //
  938. SetUpHandles(&ConsoleInfo);
  939. //
  940. // create ctrl-c thread
  941. //
  942. InitializeCtrlHandling();
  943. InputWaitHandle = ConsoleInfo.InputWaitHandle;
  944. SetTEBLangID();
  945. Status = TRUE;
  946. } finally {
  947. UnlockDll();
  948. }
  949. return Status;
  950. }
  951. #endif //!defined(BUILD_WOW64)