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.

3136 lines
106 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. stream.c
  5. Abstract:
  6. This file implements the NT console server stream API
  7. Author:
  8. Therese Stowell (thereses) 6-Nov-1990
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #define IS_CONTROL_CHAR(wch) ((wch) < L' ')
  14. #define IS_GLYPH_CHAR(wch) (((wch) < L' ') || ((wch) == 0x007F))
  15. #define LINE_INPUT_BUFFER_SIZE (256 * sizeof(WCHAR))
  16. HANDLE
  17. FindActiveScreenBufferHandle(
  18. IN PCONSOLE_PER_PROCESS_DATA ProcessData,
  19. IN PCONSOLE_INFORMATION Console
  20. )
  21. {
  22. ULONG i;
  23. HANDLE ActiveScreenHandle;
  24. PHANDLE_DATA ActiveScreenHandleData;
  25. NTSTATUS Status;
  26. ActiveScreenHandle = INVALID_HANDLE_VALUE;
  27. for (i=0;i<ProcessData->HandleTableSize;i++) {
  28. Status = DereferenceIoHandleNoCheck(ProcessData,
  29. LongToHandle(i),
  30. &ActiveScreenHandleData
  31. );
  32. if (NT_SUCCESS(Status) &&
  33. Console->CurrentScreenBuffer == ActiveScreenHandleData->Buffer.ScreenBuffer) {
  34. ASSERT (ActiveScreenHandleData->HandleType & (CONSOLE_OUTPUT_HANDLE | CONSOLE_GRAPHICS_OUTPUT_HANDLE));
  35. ActiveScreenHandle = LongToHandle(i);
  36. break;
  37. }
  38. }
  39. return ActiveScreenHandle;
  40. }
  41. ULONG
  42. SrvOpenConsole(
  43. IN OUT PCSR_API_MSG m,
  44. IN OUT PCSR_REPLY_STATUS ReplyStatus
  45. )
  46. /*++
  47. Routine Description:
  48. This routine returns a handle to the input buffer or active screen buffer.
  49. Arguments:
  50. ApiMessageData - Points to parameter structure.
  51. Return Value:
  52. --*/
  53. {
  54. PCONSOLE_OPENCONSOLE_MSG a = (PCONSOLE_OPENCONSOLE_MSG)&m->u.ApiMessageData;
  55. NTSTATUS Status;
  56. PCONSOLE_INFORMATION Console;
  57. HANDLE Handle;
  58. PHANDLE_DATA HandleData;
  59. PCONSOLE_PER_PROCESS_DATA ProcessData;
  60. Status = ApiPreamble(a->ConsoleHandle,
  61. &Console
  62. );
  63. if (!NT_SUCCESS(Status)) {
  64. return Status;
  65. }
  66. try {
  67. Handle = INVALID_HANDLE_VALUE;
  68. ProcessData = CONSOLE_PERPROCESSDATA();
  69. if (a->HandleType == CONSOLE_INPUT_HANDLE) {
  70. Status = AllocateIoHandle(ProcessData,
  71. a->HandleType,
  72. &Handle
  73. );
  74. if (!NT_SUCCESS(Status)) {
  75. leave;
  76. }
  77. Status = DereferenceIoHandleNoCheck(ProcessData,
  78. Handle,
  79. &HandleData
  80. );
  81. ASSERT (NT_SUCCESS(Status));
  82. if (!NT_SUCCESS(Status)) {
  83. leave;
  84. }
  85. if (!InitializeInputHandle(HandleData, &Console->InputBuffer)) {
  86. Status = STATUS_NO_MEMORY;
  87. leave;
  88. }
  89. if (a->InheritHandle) {
  90. HandleData->HandleType |= CONSOLE_INHERITABLE;
  91. }
  92. Status = ConsoleAddShare(a->DesiredAccess,
  93. a->ShareMode,
  94. &HandleData->Buffer.InputBuffer->ShareAccess,
  95. HandleData
  96. );
  97. if (!NT_SUCCESS(Status)) {
  98. HandleData->Buffer.InputBuffer->RefCount--;
  99. leave;
  100. }
  101. } else if (a->HandleType == CONSOLE_OUTPUT_HANDLE){
  102. PSCREEN_INFORMATION ScreenInfo;
  103. //
  104. // open a handle to the active screen buffer.
  105. //
  106. ScreenInfo = Console->CurrentScreenBuffer;
  107. if (ScreenInfo == NULL) {
  108. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  109. leave;
  110. }
  111. Status = AllocateIoHandle(ProcessData,
  112. a->HandleType,
  113. &Handle
  114. );
  115. if (!NT_SUCCESS(Status)) {
  116. leave;
  117. }
  118. Status = DereferenceIoHandleNoCheck(ProcessData,
  119. Handle,
  120. &HandleData
  121. );
  122. ASSERT (NT_SUCCESS(Status));
  123. if (!NT_SUCCESS(Status)) {
  124. leave;
  125. }
  126. InitializeOutputHandle(HandleData, ScreenInfo);
  127. if (a->InheritHandle) {
  128. HandleData->HandleType |= CONSOLE_INHERITABLE;
  129. }
  130. Status = ConsoleAddShare(a->DesiredAccess,
  131. a->ShareMode,
  132. &HandleData->Buffer.ScreenBuffer->ShareAccess,
  133. HandleData
  134. );
  135. if (!NT_SUCCESS(Status)) {
  136. HandleData->Buffer.ScreenBuffer->RefCount--;
  137. leave;
  138. }
  139. }
  140. else {
  141. Status = STATUS_INVALID_PARAMETER;
  142. leave;
  143. }
  144. a->Handle = INDEX_TO_HANDLE(Handle);
  145. Status = STATUS_SUCCESS;
  146. } finally {
  147. if (!NT_SUCCESS(Status) && Handle != INVALID_HANDLE_VALUE) {
  148. FreeIoHandle(ProcessData,
  149. Handle
  150. );
  151. }
  152. UnlockConsole(Console);
  153. }
  154. return Status;
  155. UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
  156. }
  157. /*
  158. * Convert real Windows NT modifier bit into bizarre Console bits
  159. */
  160. #define EITHER_CTRL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
  161. #define EITHER_ALT_PRESSED (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
  162. #define MOD_PRESSED (SHIFT_PRESSED | EITHER_CTRL_PRESSED | EITHER_ALT_PRESSED)
  163. DWORD ConsKbdState[] = {
  164. 0,
  165. SHIFT_PRESSED,
  166. EITHER_CTRL_PRESSED,
  167. SHIFT_PRESSED | EITHER_CTRL_PRESSED,
  168. EITHER_ALT_PRESSED,
  169. SHIFT_PRESSED | EITHER_ALT_PRESSED,
  170. EITHER_CTRL_PRESSED | EITHER_ALT_PRESSED,
  171. SHIFT_PRESSED | EITHER_CTRL_PRESSED | EITHER_ALT_PRESSED
  172. };
  173. #define KEYEVENTSTATE_EQUAL_WINMODS(Event, WinMods)\
  174. ((Event.Event.KeyEvent.dwControlKeyState & ConsKbdState[WinMods]) && \
  175. !(Event.Event.KeyEvent.dwControlKeyState & MOD_PRESSED & ~ConsKbdState[WinMods]))
  176. BOOL IsDbcsExemptionForHighAnsi(
  177. UINT wCodePage,
  178. WORD wNumpadChar)
  179. {
  180. UserAssert(HIBYTE(wNumpadChar) == 0);
  181. if (wCodePage == CP_JAPANESE && IS_JPN_1BYTE_KATAKANA(wNumpadChar)) {
  182. /*
  183. * If hkl is JAPANESE and NumpadChar is in KANA range,
  184. * NumpadChar should be handled by the input locale.
  185. */
  186. return FALSE;
  187. }
  188. else if (wNumpadChar >= 0x80 && wNumpadChar <= 0xff) {
  189. /*
  190. * Otherwise if NumpadChar is in High ANSI range,
  191. * use 1252 for conversion.
  192. */
  193. return TRUE;
  194. }
  195. /*
  196. * None of the above.
  197. * This case includes the compound Leading Byte and Trailing Byte,
  198. * which is larger than 0xff.
  199. */
  200. return FALSE;
  201. }
  202. NTSTATUS
  203. GetChar(
  204. IN PINPUT_INFORMATION InputInfo,
  205. OUT PWCHAR Char,
  206. IN BOOLEAN Wait,
  207. IN PCONSOLE_INFORMATION Console,
  208. IN PHANDLE_DATA HandleData,
  209. IN PCSR_API_MSG Message OPTIONAL,
  210. IN CSR_WAIT_ROUTINE WaitRoutine OPTIONAL,
  211. IN PVOID WaitParameter OPTIONAL,
  212. IN ULONG WaitParameterLength OPTIONAL,
  213. IN BOOLEAN WaitBlockExists OPTIONAL,
  214. OUT PBOOLEAN CommandLineEditingKeys OPTIONAL,
  215. OUT PBOOLEAN CommandLinePopupKeys OPTIONAL,
  216. OUT PBOOLEAN EnableScrollMode OPTIONAL,
  217. OUT PDWORD KeyState OPTIONAL
  218. )
  219. /*++
  220. Routine Description:
  221. This routine is used in stream input. It gets input and filters it
  222. for unicode characters.
  223. Arguments:
  224. InputInfo - Pointer to input buffer information.
  225. Char - Unicode char input.
  226. Wait - TRUE if the routine shouldn't wait for input.
  227. Console - Pointer to console buffer information.
  228. HandleData - Pointer to handle data structure.
  229. Message - csr api message.
  230. WaitRoutine - Routine to call when wait is woken up.
  231. WaitParameter - Parameter to pass to wait routine.
  232. WaitParameterLength - Length of wait parameter.
  233. WaitBlockExists - TRUE if wait block has already been created.
  234. CommandLineEditingKeys - if present, arrow keys will be returned. on
  235. output, if TRUE, Char contains virtual key code for arrow key.
  236. CommandLinePopupKeys - if present, arrow keys will be returned. on
  237. output, if TRUE, Char contains virtual key code for arrow key.
  238. Return Value:
  239. --*/
  240. {
  241. ULONG NumRead;
  242. INPUT_RECORD Event;
  243. NTSTATUS Status;
  244. if (ARGUMENT_PRESENT(CommandLineEditingKeys)) {
  245. *CommandLineEditingKeys = FALSE;
  246. }
  247. if (ARGUMENT_PRESENT(CommandLinePopupKeys)) {
  248. *CommandLinePopupKeys = FALSE;
  249. }
  250. if (ARGUMENT_PRESENT(EnableScrollMode)) {
  251. *EnableScrollMode = FALSE;
  252. }
  253. if (ARGUMENT_PRESENT(KeyState)) {
  254. *KeyState = 0;
  255. }
  256. NumRead = 1;
  257. while (TRUE) {
  258. Status =ReadInputBuffer(InputInfo,
  259. &Event,
  260. &NumRead,
  261. FALSE,
  262. Wait,
  263. TRUE,
  264. Console,
  265. HandleData,
  266. Message,
  267. WaitRoutine,
  268. WaitParameter,
  269. WaitParameterLength,
  270. WaitBlockExists
  271. #if defined(FE_SB)
  272. ,
  273. TRUE
  274. #endif
  275. );
  276. if (!NT_SUCCESS(Status)) {
  277. return Status;
  278. }
  279. if (NumRead == 0) {
  280. if (Wait) {
  281. ASSERT (FALSE);
  282. }
  283. else {
  284. return STATUS_UNSUCCESSFUL;
  285. }
  286. }
  287. if (Event.EventType == KEY_EVENT) {
  288. BOOL fCommandLineEditKey;
  289. if (ARGUMENT_PRESENT(CommandLineEditingKeys)) {
  290. fCommandLineEditKey = IsCommandLineEditingKey(&Event.Event.KeyEvent);
  291. } else if (ARGUMENT_PRESENT(CommandLinePopupKeys)) {
  292. fCommandLineEditKey = IsCommandLinePopupKey(&Event.Event.KeyEvent);
  293. } else {
  294. fCommandLineEditKey = FALSE;
  295. }
  296. //
  297. // Always return keystate if caller asked for it.
  298. //
  299. if (ARGUMENT_PRESENT(KeyState)) {
  300. *KeyState = Event.Event.KeyEvent.dwControlKeyState;
  301. }
  302. if (Event.Event.KeyEvent.uChar.UnicodeChar != 0 &&
  303. !fCommandLineEditKey) {
  304. //
  305. // chars that are generated using alt+numpad
  306. //
  307. if (!Event.Event.KeyEvent.bKeyDown &&
  308. Event.Event.KeyEvent.wVirtualKeyCode == VK_MENU) {
  309. if (Event.Event.KeyEvent.dwControlKeyState & ALTNUMPAD_BIT)
  310. {
  311. if (CONSOLE_IS_DBCS_CP(Console) && HIBYTE(Event.Event.KeyEvent.uChar.UnicodeChar)) {
  312. char chT[2] = {
  313. HIBYTE(Event.Event.KeyEvent.uChar.UnicodeChar),
  314. LOBYTE(Event.Event.KeyEvent.uChar.UnicodeChar),
  315. };
  316. *Char = CharToWchar(Console, Console->CP, chT);
  317. } else {
  318. // Because USER doesn't know our codepage, it gives us the
  319. // raw OEM char and we convert it to a Unicode character.
  320. char chT = LOBYTE(Event.Event.KeyEvent.uChar.UnicodeChar);
  321. UINT uCodePage = Console->CP;
  322. //
  323. // FarEast hack for High ANSI OEM characters.
  324. //
  325. if (CONSOLE_IS_DBCS_CP(Console)) {
  326. if (IsDbcsExemptionForHighAnsi(uCodePage, chT)) {
  327. /*
  328. * FarEast hack:
  329. * treat characters in High ANSI area as if they are
  330. * the ones of Codepage 1252.
  331. */
  332. uCodePage = 1252;
  333. }
  334. }
  335. *Char = CharToWchar(Console, uCodePage, &chT);
  336. }
  337. } else {
  338. *Char = Event.Event.KeyEvent.uChar.UnicodeChar;
  339. }
  340. return STATUS_SUCCESS;
  341. }
  342. //
  343. // Ignore Escape and Newline chars
  344. //
  345. else if (Event.Event.KeyEvent.bKeyDown &&
  346. Event.Event.KeyEvent.wVirtualKeyCode != VK_ESCAPE &&
  347. Event.Event.KeyEvent.uChar.UnicodeChar != 0x0a) {
  348. *Char = Event.Event.KeyEvent.uChar.UnicodeChar;
  349. return STATUS_SUCCESS;
  350. }
  351. }
  352. if (Event.Event.KeyEvent.bKeyDown) {
  353. SHORT sTmp;
  354. if (ARGUMENT_PRESENT(CommandLineEditingKeys) &&
  355. fCommandLineEditKey) {
  356. *CommandLineEditingKeys = TRUE;
  357. *Char = (WCHAR) Event.Event.KeyEvent.wVirtualKeyCode;
  358. return STATUS_SUCCESS;
  359. }
  360. else if (ARGUMENT_PRESENT(CommandLinePopupKeys) &&
  361. fCommandLineEditKey) {
  362. *CommandLinePopupKeys = TRUE;
  363. *Char = (CHAR) Event.Event.KeyEvent.wVirtualKeyCode;
  364. return STATUS_SUCCESS;
  365. }
  366. sTmp = VkKeyScan(0);
  367. if ((LOBYTE(sTmp) == Event.Event.KeyEvent.wVirtualKeyCode) &&
  368. KEYEVENTSTATE_EQUAL_WINMODS(Event, HIBYTE(sTmp))) {
  369. /*
  370. * This really is the character 0x0000
  371. */
  372. *Char = Event.Event.KeyEvent.uChar.UnicodeChar;
  373. return STATUS_SUCCESS;
  374. }
  375. }
  376. }
  377. }
  378. }
  379. BOOLEAN
  380. RawReadWaitRoutine(
  381. IN PLIST_ENTRY WaitQueue,
  382. IN PCSR_THREAD WaitingThread,
  383. IN PCSR_API_MSG WaitReplyMessage,
  384. IN PVOID WaitParameter,
  385. IN PVOID SatisfyParameter1,
  386. IN PVOID SatisfyParameter2,
  387. IN ULONG WaitFlags
  388. )
  389. /*++
  390. Routine Description:
  391. This routine is called to complete a raw read that blocked in
  392. ReadInputBuffer. The context of the read was saved in the RawReadData
  393. structure. This routine is called when events have been written to
  394. the input buffer. It is called in the context of the writing thread.
  395. ?It will be called at most once per read.?
  396. Arguments:
  397. WaitQueue - pointer to queue containing wait block
  398. WaitingThread - pointer to waiting thread
  399. WaitReplyMessage - Pointer to reply message to return to dll when
  400. read is completed.
  401. RawReadData - pointer to data saved in ReadChars
  402. SatisfyParameter1 - not used
  403. SatisfyParameter2 - not used
  404. WaitFlags - Flags indicating status of wait.
  405. Return Value:
  406. --*/
  407. {
  408. NTSTATUS Status;
  409. PWCHAR lpBuffer;
  410. PCONSOLE_READCONSOLE_MSG a;
  411. PCONSOLE_INFORMATION Console;
  412. PRAW_READ_DATA RawReadData;
  413. PHANDLE_DATA HandleData;
  414. BOOLEAN RetVal = TRUE;
  415. #ifdef FE_SB
  416. DWORD NumBytes;
  417. BOOL fAddDbcsLead = FALSE;
  418. #endif
  419. a = (PCONSOLE_READCONSOLE_MSG)&WaitReplyMessage->u.ApiMessageData;
  420. RawReadData = (PRAW_READ_DATA)WaitParameter;
  421. Status = DereferenceIoHandleNoCheck(RawReadData->ProcessData,
  422. RawReadData->HandleIndex,
  423. &HandleData
  424. );
  425. ASSERT (NT_SUCCESS(Status));
  426. if (!NT_SUCCESS(Status)) {
  427. return TRUE;
  428. }
  429. //
  430. // see if this routine was called by CloseInputHandle. if it
  431. // was, see if this wait block corresponds to the dying handle.
  432. // if it doesn't, just return.
  433. //
  434. if (SatisfyParameter1 != NULL &&
  435. SatisfyParameter1 != HandleData) {
  436. return FALSE;
  437. }
  438. if ((ULONG_PTR)SatisfyParameter2 & CONSOLE_CTRL_C_SEEN) {
  439. return FALSE;
  440. }
  441. Console = RawReadData->Console;
  442. //
  443. // this routine should be called by a thread owning the same
  444. // lock on the same console as we're reading from.
  445. //
  446. a->NumBytes = 0;
  447. #ifdef FE_SB
  448. NumBytes = 0 ;
  449. #endif
  450. try {
  451. LockReadCount(HandleData);
  452. ASSERT(HandleData->InputReadData->ReadCount);
  453. HandleData->InputReadData->ReadCount -= 1;
  454. UnlockReadCount(HandleData);
  455. //
  456. // if a ctrl-c is seen, don't terminate read. if ctrl-break is seen,
  457. // terminate read.
  458. //
  459. if ((ULONG_PTR)SatisfyParameter2 & CONSOLE_CTRL_BREAK_SEEN) {
  460. WaitReplyMessage->ReturnValue = STATUS_ALERTED;
  461. leave;
  462. }
  463. //
  464. // see if called by CsrDestroyProcess or CsrDestroyThread
  465. // via CsrNotifyWaitBlock. if so, just decrement the ReadCount
  466. // and return.
  467. //
  468. if (WaitFlags & CSR_PROCESS_TERMINATING) {
  469. Status = STATUS_THREAD_IS_TERMINATING;
  470. leave;
  471. }
  472. //
  473. // We must see if we were woken up because the handle is being
  474. // closed. if so, we decrement the read count. if it goes to
  475. // zero, we wake up the close thread. otherwise, we wake up any
  476. // other thread waiting for data.
  477. //
  478. if (HandleData->InputReadData->InputHandleFlags & HANDLE_CLOSING) {
  479. ASSERT (SatisfyParameter1 == HandleData);
  480. Status = STATUS_ALERTED;
  481. leave;
  482. }
  483. //
  484. // if we get to here, this routine was called either by the input
  485. // thread or a write routine. both of these callers grab the
  486. // current console lock.
  487. //
  488. //
  489. // this routine should be called by a thread owning the same
  490. // lock on the same console as we're reading from.
  491. //
  492. ASSERT (ConsoleLocked(Console));
  493. if (a->CaptureBufferSize <= BUFFER_SIZE) {
  494. lpBuffer = a->Buffer;
  495. }
  496. else {
  497. lpBuffer = RawReadData->BufPtr;
  498. }
  499. //
  500. // this call to GetChar may block.
  501. //
  502. #ifdef FE_SB
  503. if (!a->Unicode && CONSOLE_IS_DBCS_CP(Console)) {
  504. if (HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar) {
  505. fAddDbcsLead = TRUE;
  506. *lpBuffer = HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar;
  507. RawReadData->BufferSize-=sizeof(WCHAR);
  508. RtlZeroMemory(&HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte,sizeof(INPUT_RECORD));
  509. Status = STATUS_SUCCESS;
  510. if (RawReadData->BufferSize == 0) {
  511. a->NumBytes = 1;
  512. return FALSE;
  513. }
  514. }
  515. else{
  516. Status = GetChar(RawReadData->InputInfo,
  517. lpBuffer,
  518. TRUE,
  519. Console,
  520. HandleData,
  521. WaitReplyMessage,
  522. RawReadWaitRoutine,
  523. RawReadData,
  524. sizeof(*RawReadData),
  525. TRUE,
  526. NULL,
  527. NULL,
  528. NULL,
  529. NULL
  530. );
  531. }
  532. }
  533. else
  534. #endif
  535. Status = GetChar(RawReadData->InputInfo,
  536. lpBuffer,
  537. TRUE,
  538. Console,
  539. HandleData,
  540. WaitReplyMessage,
  541. RawReadWaitRoutine,
  542. RawReadData,
  543. sizeof(*RawReadData),
  544. TRUE,
  545. NULL,
  546. NULL,
  547. NULL,
  548. NULL
  549. );
  550. if (!NT_SUCCESS(Status)) {
  551. if (Status == CONSOLE_STATUS_WAIT) {
  552. RetVal = FALSE;
  553. }
  554. leave;
  555. }
  556. #ifdef FE_SB
  557. IsConsoleFullWidth(Console->hDC,
  558. Console->CP,*lpBuffer) ? NumBytes+=2 : NumBytes++;
  559. #endif
  560. lpBuffer++;
  561. a->NumBytes += sizeof(WCHAR);
  562. while (a->NumBytes < RawReadData->BufferSize) {
  563. //
  564. // this call to GetChar won't block.
  565. //
  566. Status = GetChar(RawReadData->InputInfo,lpBuffer,FALSE,NULL,NULL,NULL,NULL,NULL,0,TRUE,NULL,NULL,NULL,NULL);
  567. if (!NT_SUCCESS(Status)) {
  568. Status = STATUS_SUCCESS;
  569. break;
  570. }
  571. #ifdef FE_SB
  572. IsConsoleFullWidth(Console->hDC,
  573. Console->CP,*lpBuffer) ? NumBytes+=2 : NumBytes++;
  574. #endif
  575. lpBuffer++;
  576. a->NumBytes += sizeof(WCHAR);
  577. }
  578. } finally {
  579. //
  580. // if the read was completed (status != wait), free the raw read
  581. // data.
  582. //
  583. if (Status != CONSOLE_STATUS_WAIT) {
  584. if (!a->Unicode) {
  585. //
  586. // if ansi, translate string.
  587. //
  588. PCHAR TransBuffer;
  589. #ifdef FE_SB
  590. TransBuffer = ConsoleHeapAlloc(TMP_DBCS_TAG, NumBytes);
  591. #else
  592. TransBuffer = ConsoleHeapAlloc(TMP_TAG, a->NumBytes / sizeof(WCHAR));
  593. #endif
  594. if (TransBuffer == NULL) {
  595. RetVal = TRUE;
  596. goto EndFinally;
  597. }
  598. if (a->CaptureBufferSize <= BUFFER_SIZE) {
  599. lpBuffer = a->Buffer;
  600. }
  601. else {
  602. lpBuffer = RawReadData->BufPtr;
  603. }
  604. #ifdef FE_SB
  605. if (CONSOLE_IS_DBCS_CP(Console))
  606. {
  607. a->NumBytes = TranslateUnicodeToOem(Console,
  608. lpBuffer,
  609. a->NumBytes / sizeof (WCHAR),
  610. TransBuffer,
  611. NumBytes,
  612. &HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte);
  613. }
  614. else
  615. #endif
  616. a->NumBytes = ConvertToOem(RawReadData->Console->CP,
  617. lpBuffer,
  618. a->NumBytes / sizeof (WCHAR),
  619. TransBuffer,
  620. a->NumBytes / sizeof (WCHAR)
  621. );
  622. RtlCopyMemory(lpBuffer,TransBuffer,a->NumBytes);
  623. #ifdef FE_SB
  624. if (fAddDbcsLead)
  625. a->NumBytes++;
  626. #endif
  627. ConsoleHeapFree(TransBuffer);
  628. }
  629. WaitReplyMessage->ReturnValue = Status;
  630. ConsoleHeapFree(RawReadData);
  631. }
  632. EndFinally:;
  633. }
  634. return RetVal;
  635. //
  636. // satisfy the unreferenced parameter warnings.
  637. //
  638. UNREFERENCED_PARAMETER(WaitQueue);
  639. UNREFERENCED_PARAMETER(WaitingThread);
  640. }
  641. ULONG
  642. RetrieveTotalNumberOfSpaces(
  643. IN SHORT OriginalCursorPositionX,
  644. IN PWCHAR Buffer,
  645. IN ULONG CurrentPosition
  646. #if defined(FE_SB)
  647. ,
  648. IN PCONSOLE_INFORMATION Console
  649. #endif
  650. )
  651. /*++
  652. This routine returns the total number of screen spaces the characters
  653. up to the specified character take up.
  654. --*/
  655. {
  656. WCHAR Char;
  657. ULONG i,NumSpacesForChar,NumSpaces;
  658. SHORT XPosition;
  659. XPosition=OriginalCursorPositionX;
  660. NumSpaces=0;
  661. for (i=0;i<CurrentPosition;i++) {
  662. Char = Buffer[i];
  663. if (Char == UNICODE_TAB) {
  664. NumSpacesForChar = NUMBER_OF_SPACES_IN_TAB(XPosition);
  665. } else if (IS_CONTROL_CHAR(Char)) {
  666. NumSpacesForChar = 2;
  667. #if defined(FE_SB)
  668. } else if (IsConsoleFullWidth(Console->hDC,Console->CP,Char)) {
  669. NumSpacesForChar = 2;
  670. #endif
  671. } else {
  672. NumSpacesForChar = 1;
  673. }
  674. XPosition = (SHORT)(XPosition+NumSpacesForChar);
  675. NumSpaces += NumSpacesForChar;
  676. }
  677. return NumSpaces;
  678. }
  679. ULONG
  680. RetrieveNumberOfSpaces(
  681. IN SHORT OriginalCursorPositionX,
  682. IN PWCHAR Buffer,
  683. IN ULONG CurrentPosition
  684. #if defined(FE_SB)
  685. ,
  686. IN PCONSOLE_INFORMATION Console,
  687. IN DWORD CodePage
  688. #endif
  689. )
  690. /*++
  691. This routine returns the number of screen spaces the specified character
  692. takes up.
  693. --*/
  694. {
  695. WCHAR Char;
  696. ULONG i,NumSpaces;
  697. SHORT XPosition;
  698. Char = Buffer[CurrentPosition];
  699. if (Char == UNICODE_TAB) {
  700. NumSpaces=0;
  701. XPosition=OriginalCursorPositionX;
  702. for (i=0;i<=CurrentPosition;i++) {
  703. Char = Buffer[i];
  704. if (Char == UNICODE_TAB) {
  705. NumSpaces = NUMBER_OF_SPACES_IN_TAB(XPosition);
  706. } else if (IS_CONTROL_CHAR(Char)) {
  707. NumSpaces = 2;
  708. #if defined(FE_SB)
  709. } else if (IsConsoleFullWidth(Console->hDC,CodePage,Char)) {
  710. NumSpaces = 2;
  711. #endif
  712. } else {
  713. NumSpaces = 1;
  714. }
  715. XPosition = (SHORT)(XPosition+NumSpaces);
  716. }
  717. return NumSpaces;
  718. }
  719. else if (IS_CONTROL_CHAR(Char)) {
  720. return 2;
  721. }
  722. #if defined(FE_SB)
  723. else if (IsConsoleFullWidth(Console->hDC,CodePage,Char)) {
  724. return 2;
  725. }
  726. #endif
  727. else {
  728. return 1;
  729. }
  730. }
  731. BOOL
  732. ProcessCookedReadInput(
  733. IN PCOOKED_READ_DATA CookedReadData,
  734. IN WCHAR Char,
  735. IN DWORD KeyState,
  736. OUT PNTSTATUS Status
  737. )
  738. /*++
  739. Return Value:
  740. TRUE if read is completed
  741. --*/
  742. {
  743. DWORD NumSpaces;
  744. SHORT ScrollY=0;
  745. ULONG NumToWrite;
  746. WCHAR wchOrig = Char;
  747. BOOL fStartFromDelim;
  748. *Status = STATUS_SUCCESS;
  749. if (CookedReadData->BytesRead >= (CookedReadData->BufferSize-(2*sizeof(WCHAR))) &&
  750. Char != UNICODE_CARRIAGERETURN &&
  751. Char != UNICODE_BACKSPACE) {
  752. return FALSE;
  753. }
  754. if (CookedReadData->CtrlWakeupMask != 0 &&
  755. Char < L' ' && (CookedReadData->CtrlWakeupMask & (1 << Char))) {
  756. *CookedReadData->BufPtr = Char;
  757. CookedReadData->BytesRead += sizeof(WCHAR);
  758. CookedReadData->BufPtr+=1;
  759. CookedReadData->CurrentPosition+=1;
  760. CookedReadData->ControlKeyState = KeyState;
  761. return TRUE;
  762. }
  763. if (Char == EXTKEY_ERASE_PREV_WORD) {
  764. Char = UNICODE_BACKSPACE;
  765. }
  766. if (AT_EOL(CookedReadData)) {
  767. //
  768. // if at end of line, processing is relatively simple. just store the
  769. // character and write it to the screen.
  770. //
  771. if (Char == UNICODE_BACKSPACE2) {
  772. Char = UNICODE_BACKSPACE;
  773. }
  774. if (Char != UNICODE_BACKSPACE ||
  775. CookedReadData->BufPtr != CookedReadData->BackupLimit) {
  776. fStartFromDelim = gExtendedEditKey && IS_WORD_DELIM(CookedReadData->BufPtr[-1]);
  777. eol_repeat:
  778. if (CookedReadData->Echo) {
  779. NumToWrite=sizeof(WCHAR);
  780. *Status = WriteCharsFromInput(CookedReadData->ScreenInfo,
  781. CookedReadData->BackupLimit,
  782. CookedReadData->BufPtr,
  783. &Char,
  784. &NumToWrite,
  785. (PLONG)&NumSpaces,
  786. CookedReadData->OriginalCursorPosition.X,
  787. WC_DESTRUCTIVE_BACKSPACE |
  788. WC_KEEP_CURSOR_VISIBLE | WC_ECHO,
  789. &ScrollY
  790. );
  791. if (NT_SUCCESS(*Status)) {
  792. CookedReadData->OriginalCursorPosition.Y += ScrollY;
  793. } else {
  794. RIPMSG1(RIP_WARNING, "WriteCharsFromInput failed %x", *Status);
  795. }
  796. }
  797. CookedReadData->NumberOfVisibleChars += NumSpaces;
  798. if (Char == UNICODE_BACKSPACE && CookedReadData->Processed) {
  799. CookedReadData->BytesRead -= sizeof(WCHAR);
  800. *CookedReadData->BufPtr=(WCHAR)' ';
  801. CookedReadData->BufPtr-=1;
  802. CookedReadData->CurrentPosition-=1;
  803. // Repeat until it hits the word boundary
  804. if (gExtendedEditKey &&
  805. wchOrig == EXTKEY_ERASE_PREV_WORD &&
  806. CookedReadData->BufPtr != CookedReadData->BackupLimit &&
  807. fStartFromDelim ^ !IS_WORD_DELIM(CookedReadData->BufPtr[-1])) {
  808. goto eol_repeat;
  809. }
  810. }
  811. else {
  812. *CookedReadData->BufPtr = Char;
  813. CookedReadData->BytesRead += sizeof(WCHAR);
  814. CookedReadData->BufPtr+=1;
  815. CookedReadData->CurrentPosition+=1;
  816. }
  817. }
  818. } else {
  819. BOOL CallWrite=TRUE;
  820. //
  821. // processing in the middle of the line is more complex:
  822. //
  823. //
  824. // calculate new cursor position
  825. // store new char
  826. // clear the current command line from the screen
  827. // write the new command line to the screen
  828. // update the cursor position
  829. //
  830. if (Char == UNICODE_BACKSPACE && CookedReadData->Processed) {
  831. //
  832. // for backspace, use writechars to calculate the new cursor position.
  833. // this call also sets the cursor to the right position for the
  834. // second call to writechars.
  835. //
  836. if (CookedReadData->BufPtr != CookedReadData->BackupLimit) {
  837. fStartFromDelim = gExtendedEditKey && IS_WORD_DELIM(CookedReadData->BufPtr[-1]);
  838. bs_repeat:
  839. //
  840. // we call writechar here so that cursor position gets updated
  841. // correctly. we also call it later if we're not at eol so
  842. // that the remainder of the string can be updated correctly.
  843. //
  844. if (CookedReadData->Echo) {
  845. NumToWrite=sizeof(WCHAR);
  846. *Status = WriteCharsFromInput(CookedReadData->ScreenInfo,
  847. CookedReadData->BackupLimit,
  848. CookedReadData->BufPtr,
  849. &Char,
  850. &NumToWrite,
  851. NULL,
  852. CookedReadData->OriginalCursorPosition.X,
  853. WC_DESTRUCTIVE_BACKSPACE |
  854. WC_KEEP_CURSOR_VISIBLE | WC_ECHO,
  855. NULL);
  856. if (!NT_SUCCESS(*Status)) {
  857. RIPMSG1(RIP_WARNING, "WriteCharsFromInput failed %x", *Status);
  858. }
  859. }
  860. CookedReadData->BytesRead -= sizeof(WCHAR);
  861. CookedReadData->BufPtr-=1;
  862. CookedReadData->CurrentPosition-=1;
  863. RtlCopyMemory(CookedReadData->BufPtr,
  864. CookedReadData->BufPtr+1,
  865. CookedReadData->BytesRead - (CookedReadData->CurrentPosition * sizeof(WCHAR))
  866. );
  867. #if defined(FE_SB)
  868. {
  869. PWCHAR buf = (PWCHAR)((PBYTE)CookedReadData->BackupLimit +
  870. CookedReadData->BytesRead );
  871. *buf = (WCHAR)' ';
  872. }
  873. #endif
  874. NumSpaces = 0;
  875. // Repeat until it hits the word boundary
  876. if (gExtendedEditKey &&
  877. wchOrig == EXTKEY_ERASE_PREV_WORD &&
  878. CookedReadData->BufPtr != CookedReadData->BackupLimit &&
  879. fStartFromDelim ^ !IS_WORD_DELIM(CookedReadData->BufPtr[-1])) {
  880. goto bs_repeat;
  881. }
  882. } else {
  883. CallWrite = FALSE;
  884. }
  885. } else {
  886. //
  887. // store the char
  888. //
  889. if (Char == UNICODE_CARRIAGERETURN) {
  890. CookedReadData->BufPtr = (PWCHAR)((PBYTE)CookedReadData->BackupLimit + CookedReadData->BytesRead);
  891. *CookedReadData->BufPtr = Char;
  892. CookedReadData->BufPtr+=1;
  893. CookedReadData->BytesRead += sizeof(WCHAR);
  894. CookedReadData->CurrentPosition += 1;
  895. } else {
  896. #if defined(FE_SB)
  897. BOOL fBisect = FALSE;
  898. if (CookedReadData->Echo) {
  899. if (CheckBisectProcessW(CookedReadData->ScreenInfo,
  900. CookedReadData->ScreenInfo->Console->CP,
  901. CookedReadData->BackupLimit,
  902. CookedReadData->CurrentPosition+1,
  903. CookedReadData->ScreenInfo->ScreenBufferSize.X
  904. -CookedReadData->OriginalCursorPosition.X,
  905. CookedReadData->OriginalCursorPosition.X,
  906. TRUE)) {
  907. fBisect = TRUE;
  908. }
  909. }
  910. #endif
  911. if (INSERT_MODE(CookedReadData)) {
  912. memmove(CookedReadData->BufPtr+1,
  913. CookedReadData->BufPtr,
  914. CookedReadData->BytesRead - (CookedReadData->CurrentPosition * sizeof(WCHAR))
  915. );
  916. CookedReadData->BytesRead += sizeof(WCHAR);
  917. }
  918. *CookedReadData->BufPtr = Char;
  919. CookedReadData->BufPtr+=1;
  920. CookedReadData->CurrentPosition += 1;
  921. //
  922. // calculate new cursor position
  923. //
  924. if (CookedReadData->Echo) {
  925. NumSpaces = RetrieveNumberOfSpaces(CookedReadData->OriginalCursorPosition.X,
  926. CookedReadData->BackupLimit,
  927. CookedReadData->CurrentPosition-1
  928. #if defined(FE_SB)
  929. ,
  930. CookedReadData->ScreenInfo->Console,
  931. CookedReadData->ScreenInfo->Console->CP
  932. #endif
  933. );
  934. #if defined(FE_SB)
  935. if (NumSpaces > 0 && fBisect)
  936. NumSpaces--;
  937. #endif
  938. }
  939. }
  940. }
  941. if (CookedReadData->Echo && CallWrite) {
  942. COORD CursorPosition;
  943. //
  944. // save cursor position
  945. //
  946. CursorPosition = CookedReadData->ScreenInfo->BufferInfo.TextInfo.CursorPosition;
  947. CursorPosition.X = (SHORT)(CursorPosition.X+NumSpaces);
  948. //
  949. // clear the current command line from the screen
  950. //
  951. DeleteCommandLine(CookedReadData,
  952. FALSE);
  953. //
  954. // write the new command line to the screen
  955. //
  956. NumToWrite = CookedReadData->BytesRead;
  957. *Status = WriteCharsFromInput(CookedReadData->ScreenInfo,
  958. CookedReadData->BackupLimit,
  959. CookedReadData->BackupLimit,
  960. CookedReadData->BackupLimit,
  961. &NumToWrite,
  962. (PLONG)&CookedReadData->NumberOfVisibleChars,
  963. CookedReadData->OriginalCursorPosition.X,
  964. (Char != UNICODE_CARRIAGERETURN) ?
  965. WC_DESTRUCTIVE_BACKSPACE | WC_ECHO :
  966. WC_DESTRUCTIVE_BACKSPACE | WC_KEEP_CURSOR_VISIBLE | WC_ECHO,
  967. &ScrollY
  968. );
  969. if (!NT_SUCCESS(*Status)) {
  970. RIPMSG1(RIP_WARNING, "WriteCharsFromInput failed %x", *Status);
  971. CookedReadData->BytesRead = 0;
  972. return TRUE;
  973. }
  974. //
  975. // update cursor position
  976. //
  977. if (Char != UNICODE_CARRIAGERETURN) {
  978. #if defined(FE_SB)
  979. if (CheckBisectProcessW(CookedReadData->ScreenInfo,
  980. CookedReadData->ScreenInfo->Console->CP,
  981. CookedReadData->BackupLimit,
  982. CookedReadData->CurrentPosition+1,
  983. CookedReadData->ScreenInfo->ScreenBufferSize.X
  984. -CookedReadData->OriginalCursorPosition.X,
  985. CookedReadData->OriginalCursorPosition.X,
  986. TRUE)) {
  987. if (CursorPosition.X == (CookedReadData->ScreenInfo->ScreenBufferSize.X-1))
  988. CursorPosition.X++;
  989. }
  990. #endif
  991. // adjust cursor position for WriteChars
  992. CookedReadData->OriginalCursorPosition.Y += ScrollY;
  993. CursorPosition.Y += ScrollY;
  994. *Status = AdjustCursorPosition(CookedReadData->ScreenInfo,
  995. CursorPosition,
  996. TRUE,
  997. NULL);
  998. ASSERT(NT_SUCCESS(*Status));
  999. if (!NT_SUCCESS(*Status)) {
  1000. CookedReadData->BytesRead = 0;
  1001. return TRUE;
  1002. }
  1003. }
  1004. }
  1005. }
  1006. //
  1007. // in cooked mode, enter (carriage return) is converted to
  1008. // carriage return linefeed (0xda). carriage return is always
  1009. // stored at the end of the buffer.
  1010. //
  1011. if (Char == UNICODE_CARRIAGERETURN) {
  1012. if (CookedReadData->Processed) {
  1013. if (CookedReadData->BytesRead < CookedReadData->BufferSize) {
  1014. *CookedReadData->BufPtr = UNICODE_LINEFEED;
  1015. if (CookedReadData->Echo) {
  1016. NumToWrite=sizeof(WCHAR);
  1017. *Status = WriteCharsFromInput(CookedReadData->ScreenInfo,
  1018. CookedReadData->BackupLimit,
  1019. CookedReadData->BufPtr,
  1020. CookedReadData->BufPtr,
  1021. &NumToWrite,
  1022. NULL,
  1023. CookedReadData->OriginalCursorPosition.X,
  1024. WC_DESTRUCTIVE_BACKSPACE |
  1025. WC_KEEP_CURSOR_VISIBLE | WC_ECHO,
  1026. NULL);
  1027. if (!NT_SUCCESS(*Status)) {
  1028. RIPMSG1(RIP_WARNING, "WriteCharsFromInput failed %x", *Status);
  1029. }
  1030. }
  1031. CookedReadData->BytesRead += sizeof(WCHAR);
  1032. CookedReadData->BufPtr++;
  1033. CookedReadData->CurrentPosition += 1;
  1034. }
  1035. }
  1036. //
  1037. // reset the cursor back to 25% if necessary
  1038. //
  1039. if (CookedReadData->Line) {
  1040. if (CookedReadData->InsertMode != CookedReadData->Console->InsertMode) {
  1041. ProcessCommandLine(CookedReadData,VK_INSERT,0,NULL,NULL,FALSE); // make cursor small
  1042. }
  1043. *Status = STATUS_SUCCESS;
  1044. return TRUE;
  1045. }
  1046. }
  1047. return FALSE;
  1048. }
  1049. NTSTATUS
  1050. CookedRead(
  1051. IN PCOOKED_READ_DATA CookedReadData,
  1052. IN PCSR_API_MSG WaitReplyMessage,
  1053. IN PCSR_THREAD WaitingThread,
  1054. IN BOOLEAN WaitRoutine
  1055. )
  1056. {
  1057. WCHAR Char;
  1058. BOOLEAN CommandLineEditingKeys,EnableScrollMode;
  1059. DWORD KeyState;
  1060. NTSTATUS Status=STATUS_SUCCESS;
  1061. PCONSOLE_READCONSOLE_MSG a;
  1062. PHANDLE_DATA HandleData;
  1063. #ifdef FE_SB
  1064. DWORD NumBytes;
  1065. ULONG NumToWrite;
  1066. BOOL fAddDbcsLead = FALSE;
  1067. #endif
  1068. Status = DereferenceIoHandleNoCheck(CookedReadData->ProcessData,
  1069. CookedReadData->HandleIndex,
  1070. &HandleData
  1071. );
  1072. if (!NT_SUCCESS(Status)) {
  1073. CookedReadData->BytesRead = 0;
  1074. ConsoleHeapFree(CookedReadData->BackupLimit);
  1075. return Status;
  1076. }
  1077. a = (PCONSOLE_READCONSOLE_MSG)&WaitReplyMessage->u.ApiMessageData;
  1078. while (CookedReadData->BytesRead < CookedReadData->BufferSize) {
  1079. //
  1080. // this call to GetChar may block.
  1081. //
  1082. Status = GetChar(CookedReadData->InputInfo,
  1083. &Char,
  1084. TRUE,
  1085. CookedReadData->Console,
  1086. HandleData,
  1087. WaitReplyMessage,
  1088. CookedReadWaitRoutine,
  1089. CookedReadData,
  1090. sizeof(*CookedReadData),
  1091. WaitRoutine,
  1092. &CommandLineEditingKeys,
  1093. NULL,
  1094. &EnableScrollMode,
  1095. &KeyState
  1096. );
  1097. if (!NT_SUCCESS(Status)) {
  1098. if (Status != CONSOLE_STATUS_WAIT) {
  1099. CookedReadData->BytesRead = 0;
  1100. }
  1101. break;
  1102. }
  1103. //
  1104. // we should probably set these up in GetChars, but we set them
  1105. // up here because the debugger is multi-threaded and calls
  1106. // read before outputting the prompt.
  1107. //
  1108. if (CookedReadData->OriginalCursorPosition.X == -1) {
  1109. CookedReadData->OriginalCursorPosition = CookedReadData->ScreenInfo->BufferInfo.TextInfo.CursorPosition;
  1110. }
  1111. if (CommandLineEditingKeys) {
  1112. Status = ProcessCommandLine(CookedReadData,Char,KeyState,WaitReplyMessage,WaitingThread,WaitRoutine);
  1113. if (Status == CONSOLE_STATUS_READ_COMPLETE ||
  1114. Status == CONSOLE_STATUS_WAIT) {
  1115. break;
  1116. }
  1117. if (!NT_SUCCESS(Status)) {
  1118. if (Status == CONSOLE_STATUS_WAIT_NO_BLOCK) {
  1119. Status = CONSOLE_STATUS_WAIT;
  1120. if (!WaitRoutine) {
  1121. //
  1122. // we have no wait block, so create one.
  1123. //
  1124. WaitForMoreToRead(CookedReadData->InputInfo,
  1125. WaitReplyMessage,
  1126. CookedReadWaitRoutine,
  1127. CookedReadData,
  1128. sizeof(*CookedReadData),
  1129. FALSE
  1130. );
  1131. }
  1132. } else {
  1133. CookedReadData->BytesRead = 0;
  1134. }
  1135. break;
  1136. }
  1137. } else {
  1138. if (ProcessCookedReadInput(CookedReadData,
  1139. Char,
  1140. KeyState,
  1141. &Status
  1142. )) {
  1143. CookedReadData->Console->Flags |= CONSOLE_IGNORE_NEXT_KEYUP;
  1144. break;
  1145. }
  1146. }
  1147. }
  1148. //
  1149. // if the read was completed (status != wait), free the cooked read
  1150. // data. also, close the temporary output handle that was opened to
  1151. // echo the characters read.
  1152. //
  1153. if (Status != CONSOLE_STATUS_WAIT) {
  1154. DWORD LineCount=1;
  1155. if (CookedReadData->Echo) {
  1156. BOOLEAN FoundCR;
  1157. ULONG i,StringLength;
  1158. PWCHAR StringPtr;
  1159. // figure out where real string ends (at carriage return
  1160. // or end of buffer)
  1161. StringPtr = CookedReadData->BackupLimit;
  1162. StringLength = CookedReadData->BytesRead;
  1163. FoundCR = FALSE;
  1164. for (i=0;i<(CookedReadData->BytesRead/sizeof(WCHAR));i++) {
  1165. if (*StringPtr++ == UNICODE_CARRIAGERETURN) {
  1166. StringLength = i*sizeof(WCHAR);
  1167. FoundCR = TRUE;
  1168. break;
  1169. }
  1170. }
  1171. if (FoundCR) {
  1172. //
  1173. // add to command line recall list
  1174. //
  1175. AddCommand(CookedReadData->CommandHistory,CookedReadData->BackupLimit,(USHORT)StringLength,CookedReadData->Console->Flags & CONSOLE_HISTORY_NODUP);
  1176. //
  1177. // check for alias
  1178. //
  1179. i = CookedReadData->BufferSize;
  1180. if (NT_SUCCESS(MatchandCopyAlias(CookedReadData->Console,
  1181. CookedReadData->BackupLimit,
  1182. (USHORT)StringLength,
  1183. CookedReadData->BackupLimit,
  1184. (PUSHORT)&i,
  1185. CookedReadData->ExeName,
  1186. CookedReadData->ExeNameLength,
  1187. &LineCount
  1188. ))) {
  1189. CookedReadData->BytesRead = i;
  1190. }
  1191. }
  1192. //
  1193. // Close the handle - unless ProcessCommandListInput already did it.
  1194. //
  1195. if (Status != CONSOLE_STATUS_READ_COMPLETE) {
  1196. CloseOutputHandle(CONSOLE_FROMTHREADPERPROCESSDATA(WaitingThread),
  1197. CookedReadData->Console,
  1198. &CookedReadData->TempHandle,
  1199. NULL,
  1200. FALSE
  1201. );
  1202. }
  1203. }
  1204. WaitReplyMessage->ReturnValue = Status;
  1205. //
  1206. // at this point, a->NumBytes contains the number of bytes in
  1207. // the UNICODE string read. UserBufferSize contains the converted
  1208. // size of the app's buffer.
  1209. //
  1210. if (CookedReadData->BytesRead > CookedReadData->UserBufferSize || LineCount > 1) {
  1211. if (LineCount > 1) {
  1212. PWSTR Tmp;
  1213. HandleData->InputReadData->InputHandleFlags |= HANDLE_MULTI_LINE_INPUT;
  1214. #ifdef FE_SB
  1215. if (!a->Unicode && CONSOLE_IS_DBCS_CP(CookedReadData->Console)) {
  1216. if (HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar) {
  1217. fAddDbcsLead = TRUE;
  1218. *CookedReadData->UserBuffer++ = HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar;
  1219. CookedReadData->UserBufferSize-=sizeof(WCHAR);
  1220. RtlZeroMemory(&HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte,sizeof(INPUT_RECORD));
  1221. }
  1222. NumBytes = 0;
  1223. for (Tmp=CookedReadData->BackupLimit;
  1224. *Tmp!=UNICODE_LINEFEED && CookedReadData->UserBufferSize/sizeof(WCHAR) > NumBytes;
  1225. (IsConsoleFullWidth(CookedReadData->Console->hDC,
  1226. CookedReadData->Console->CP,*Tmp) ? NumBytes+=2 : NumBytes++),Tmp++) ;
  1227. }
  1228. #endif
  1229. for (Tmp=CookedReadData->BackupLimit;*Tmp!=UNICODE_LINEFEED;Tmp++)
  1230. ASSERT(Tmp<(CookedReadData->BackupLimit+CookedReadData->BytesRead));
  1231. a->NumBytes = (ULONG)(Tmp-CookedReadData->BackupLimit+1)*sizeof(*Tmp);
  1232. } else {
  1233. #ifdef FE_SB
  1234. if (!a->Unicode && CONSOLE_IS_DBCS_CP(CookedReadData->Console)) {
  1235. PWSTR Tmp;
  1236. if (HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar) {
  1237. fAddDbcsLead = TRUE;
  1238. *CookedReadData->UserBuffer++ = HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar;
  1239. CookedReadData->UserBufferSize-=sizeof(WCHAR);
  1240. RtlZeroMemory(&HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte,sizeof(INPUT_RECORD));
  1241. }
  1242. NumBytes = 0;
  1243. NumToWrite = CookedReadData->BytesRead;
  1244. for (Tmp=CookedReadData->BackupLimit;
  1245. NumToWrite && CookedReadData->UserBufferSize/sizeof(WCHAR) > NumBytes;
  1246. (IsConsoleFullWidth(CookedReadData->Console->hDC,
  1247. CookedReadData->Console->CP,*Tmp) ? NumBytes+=2 : NumBytes++),Tmp++,NumToWrite-=sizeof(WCHAR)) ;
  1248. }
  1249. #endif
  1250. a->NumBytes = CookedReadData->UserBufferSize;
  1251. }
  1252. HandleData->InputReadData->InputHandleFlags |= HANDLE_INPUT_PENDING;
  1253. HandleData->InputReadData->BufPtr = CookedReadData->BackupLimit;
  1254. HandleData->InputReadData->BytesAvailable = CookedReadData->BytesRead - a->NumBytes;
  1255. HandleData->InputReadData->CurrentBufPtr=(PWCHAR)((PBYTE)CookedReadData->BackupLimit+a->NumBytes);
  1256. RtlCopyMemory(CookedReadData->UserBuffer,CookedReadData->BackupLimit,a->NumBytes);
  1257. }
  1258. else {
  1259. #ifdef FE_SB
  1260. if (!a->Unicode && CONSOLE_IS_DBCS_CP(CookedReadData->Console)) {
  1261. PWSTR Tmp;
  1262. if (HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar) {
  1263. fAddDbcsLead = TRUE;
  1264. *CookedReadData->UserBuffer++ = HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar;
  1265. CookedReadData->UserBufferSize-=sizeof(WCHAR);
  1266. RtlZeroMemory(&HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte,sizeof(INPUT_RECORD));
  1267. if (CookedReadData->UserBufferSize == 0) {
  1268. a->NumBytes = 1;
  1269. ConsoleHeapFree(CookedReadData->BackupLimit);
  1270. return STATUS_SUCCESS;
  1271. }
  1272. }
  1273. NumBytes = 0;
  1274. NumToWrite = CookedReadData->BytesRead;
  1275. for (Tmp=CookedReadData->BackupLimit;
  1276. NumToWrite && CookedReadData->UserBufferSize/sizeof(WCHAR) > NumBytes;
  1277. (IsConsoleFullWidth(CookedReadData->Console->hDC,
  1278. CookedReadData->Console->CP,*Tmp) ? NumBytes+=2 : NumBytes++),Tmp++,NumToWrite-=sizeof(WCHAR)) ;
  1279. }
  1280. #endif
  1281. a->NumBytes = CookedReadData->BytesRead;
  1282. RtlCopyMemory(CookedReadData->UserBuffer,CookedReadData->BackupLimit,a->NumBytes);
  1283. ConsoleHeapFree(CookedReadData->BackupLimit);
  1284. }
  1285. a->ControlKeyState = CookedReadData->ControlKeyState;
  1286. if (!a->Unicode) {
  1287. //
  1288. // if ansi, translate string.
  1289. //
  1290. PCHAR TransBuffer;
  1291. #ifdef FE_SB
  1292. if (CONSOLE_IS_DBCS_CP(CookedReadData->Console))
  1293. TransBuffer = ConsoleHeapAlloc(TMP_DBCS_TAG, NumBytes);
  1294. else
  1295. #endif
  1296. TransBuffer = ConsoleHeapAlloc(TMP_TAG, a->NumBytes / sizeof(WCHAR));
  1297. if (TransBuffer == NULL) {
  1298. return STATUS_NO_MEMORY;
  1299. }
  1300. #ifdef FE_SB
  1301. if (CONSOLE_IS_DBCS_CP(CookedReadData->Console)) {
  1302. a->NumBytes = TranslateUnicodeToOem(CookedReadData->Console,
  1303. CookedReadData->UserBuffer,
  1304. a->NumBytes / sizeof (WCHAR),
  1305. TransBuffer,
  1306. NumBytes,
  1307. &HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte);
  1308. }
  1309. else
  1310. #endif
  1311. a->NumBytes = ConvertToOem(CookedReadData->Console->CP,
  1312. CookedReadData->UserBuffer,
  1313. a->NumBytes / sizeof (WCHAR),
  1314. TransBuffer,
  1315. a->NumBytes / sizeof (WCHAR)
  1316. );
  1317. RtlCopyMemory(CookedReadData->UserBuffer,TransBuffer,a->NumBytes);
  1318. #ifdef FE_SB
  1319. if (fAddDbcsLead)
  1320. a->NumBytes++;
  1321. #endif
  1322. ConsoleHeapFree(TransBuffer);
  1323. }
  1324. ConsoleHeapFree(CookedReadData->ExeName);
  1325. if (WaitRoutine) {
  1326. #ifdef FE_SB
  1327. CookedReadData->Console->lpCookedReadData = NULL;
  1328. #endif
  1329. ConsoleHeapFree(CookedReadData);
  1330. }
  1331. }
  1332. return Status;
  1333. }
  1334. BOOLEAN
  1335. CookedReadWaitRoutine(
  1336. IN PLIST_ENTRY WaitQueue,
  1337. IN PCSR_THREAD WaitingThread,
  1338. IN PCSR_API_MSG WaitReplyMessage,
  1339. IN PVOID WaitParameter,
  1340. IN PVOID SatisfyParameter1,
  1341. IN PVOID SatisfyParameter2,
  1342. IN ULONG WaitFlags
  1343. )
  1344. /*++
  1345. Routine Description:
  1346. This routine is called to complete a cooked read that blocked in
  1347. ReadInputBuffer. The context of the read was saved in the CookedReadData
  1348. structure. This routine is called when events have been written to
  1349. the input buffer. It is called in the context of the writing thread.
  1350. It may be called more than once.
  1351. Arguments:
  1352. WaitQueue - pointer to queue containing wait block
  1353. WaitingThread - pointer to waiting thread
  1354. WaitReplyMessage - pointer to reply message
  1355. CookedReadData - pointer to data saved in ReadChars
  1356. SatisfyParameter1 - if this routine was called (indirectly) by
  1357. CloseInputHandle, this argument contains a HandleData pointer of
  1358. the dying handle. otherwise, it contains NULL.
  1359. SatisfyParameter2 - if this routine is called because a ctrl-c or
  1360. ctrl-break was seen, this argument contains CONSOLE_CTRL_SEEN.
  1361. otherwise it contains NULL.
  1362. WaitFlags - Flags indicating status of wait.
  1363. Return Value:
  1364. --*/
  1365. {
  1366. NTSTATUS Status;
  1367. PCONSOLE_INFORMATION Console;
  1368. PCOOKED_READ_DATA CookedReadData;
  1369. PCONSOLE_READCONSOLE_MSG a;
  1370. PHANDLE_DATA HandleData;
  1371. a = (PCONSOLE_READCONSOLE_MSG)&WaitReplyMessage->u.ApiMessageData;
  1372. CookedReadData = (PCOOKED_READ_DATA)WaitParameter;
  1373. Status = DereferenceIoHandleNoCheck(CookedReadData->ProcessData,
  1374. CookedReadData->HandleIndex,
  1375. &HandleData
  1376. );
  1377. ASSERT (NT_SUCCESS(Status));
  1378. if (!NT_SUCCESS(Status)) {
  1379. return TRUE;
  1380. }
  1381. ASSERT(!(HandleData->InputReadData->InputHandleFlags & HANDLE_INPUT_PENDING));
  1382. //
  1383. // see if this routine was called by CloseInputHandle. if it
  1384. // was, see if this wait block corresponds to the dying handle.
  1385. // if it doesn't, just return.
  1386. //
  1387. if (SatisfyParameter1 != NULL &&
  1388. SatisfyParameter1 != HandleData) {
  1389. //DbgPrint("CookedReadWaitRoutine exit 1\n");
  1390. return FALSE;
  1391. }
  1392. Console = CookedReadData->Console;
  1393. //
  1394. // this routine should be called by a thread owning the same
  1395. // lock on the same console as we're reading from.
  1396. //
  1397. LockReadCount(HandleData);
  1398. ASSERT(HandleData->InputReadData->ReadCount);
  1399. HandleData->InputReadData->ReadCount -= 1;
  1400. UnlockReadCount(HandleData);
  1401. //
  1402. // if ctrl-c or ctrl-break was seen, terminate read.
  1403. //
  1404. if ((ULONG_PTR)SatisfyParameter2 & (CONSOLE_CTRL_C_SEEN | CONSOLE_CTRL_BREAK_SEEN)) {
  1405. if (CookedReadData->Echo) {
  1406. CloseOutputHandle(CONSOLE_FROMTHREADPERPROCESSDATA(WaitingThread),
  1407. CookedReadData->Console,
  1408. &CookedReadData->TempHandle,
  1409. NULL,
  1410. FALSE
  1411. );
  1412. }
  1413. //DbgPrint("CookedReadWaitRoutine exit 2\n");
  1414. WaitReplyMessage->ReturnValue = STATUS_ALERTED;
  1415. ConsoleHeapFree(CookedReadData->BackupLimit);
  1416. ConsoleHeapFree(CookedReadData->ExeName);
  1417. #if defined(FE_SB)
  1418. CookedReadData->Console->lpCookedReadData = NULL;
  1419. #endif
  1420. ConsoleHeapFree(CookedReadData);
  1421. return TRUE;
  1422. }
  1423. //
  1424. // see if called by CsrDestroyProcess or CsrDestroyThread
  1425. // via CsrNotifyWaitBlock. if so, just decrement the ReadCount
  1426. // and return.
  1427. //
  1428. if (WaitFlags & CSR_PROCESS_TERMINATING) {
  1429. if (CookedReadData->Echo) {
  1430. CloseOutputHandle(CONSOLE_FROMTHREADPERPROCESSDATA(WaitingThread),
  1431. CookedReadData->Console,
  1432. &CookedReadData->TempHandle,
  1433. NULL,
  1434. FALSE
  1435. );
  1436. }
  1437. //DbgPrint("CookedReadWaitRoutine exit 3\n");
  1438. WaitReplyMessage->ReturnValue = (ULONG)STATUS_THREAD_IS_TERMINATING;
  1439. //
  1440. // clean up popup data structures
  1441. //
  1442. CleanUpPopups(CookedReadData);
  1443. ConsoleHeapFree(CookedReadData->BackupLimit);
  1444. ConsoleHeapFree(CookedReadData->ExeName);
  1445. #if defined(FE_SB)
  1446. CookedReadData->Console->lpCookedReadData = NULL;
  1447. #endif
  1448. ConsoleHeapFree(CookedReadData);
  1449. return TRUE;
  1450. }
  1451. //
  1452. // We must see if we were woken up because the handle is being
  1453. // closed. if so, we decrement the read count. if it goes to
  1454. // zero, we wake up the close thread. otherwise, we wake up any
  1455. // other thread waiting for data.
  1456. //
  1457. if (HandleData->InputReadData->InputHandleFlags & HANDLE_CLOSING) {
  1458. ASSERT (SatisfyParameter1 == HandleData);
  1459. if (CookedReadData->Echo) {
  1460. CloseOutputHandle(CONSOLE_FROMTHREADPERPROCESSDATA(WaitingThread),
  1461. CookedReadData->Console,
  1462. &CookedReadData->TempHandle,
  1463. NULL,
  1464. FALSE
  1465. );
  1466. }
  1467. //DbgPrint("CookedReadWaitRoutine exit 4\n");
  1468. WaitReplyMessage->ReturnValue = STATUS_ALERTED;
  1469. //
  1470. // clean up popup data structures
  1471. //
  1472. CleanUpPopups(CookedReadData);
  1473. ConsoleHeapFree(CookedReadData->BackupLimit);
  1474. ConsoleHeapFree(CookedReadData->ExeName);
  1475. #if defined(FE_SB)
  1476. CookedReadData->Console->lpCookedReadData = NULL;
  1477. #endif
  1478. ConsoleHeapFree(CookedReadData);
  1479. return TRUE;
  1480. }
  1481. //
  1482. // if we get to here, this routine was called either by the input
  1483. // thread or a write routine. both of these callers grab the
  1484. // current console lock.
  1485. //
  1486. //
  1487. // this routine should be called by a thread owning the same
  1488. // lock on the same console as we're reading from.
  1489. //
  1490. ASSERT (ConsoleLocked(Console));
  1491. if (CookedReadData->CommandHistory) {
  1492. PCLE_POPUP Popup;
  1493. if (!CLE_NO_POPUPS(CookedReadData->CommandHistory)) {
  1494. Popup = CONTAINING_RECORD( CookedReadData->CommandHistory->PopupList.Flink, CLE_POPUP, ListLink );
  1495. Status = (Popup->PopupInputRoutine)(CookedReadData,
  1496. WaitReplyMessage,
  1497. WaitingThread,
  1498. TRUE);
  1499. if (Status == CONSOLE_STATUS_READ_COMPLETE ||
  1500. (Status != CONSOLE_STATUS_WAIT &&
  1501. Status != CONSOLE_STATUS_WAIT_NO_BLOCK) ) {
  1502. ConsoleHeapFree(CookedReadData->BackupLimit);
  1503. ConsoleHeapFree(CookedReadData->ExeName);
  1504. #if defined(FE_SB)
  1505. CookedReadData->Console->lpCookedReadData = NULL;
  1506. #endif
  1507. ConsoleHeapFree(CookedReadData);
  1508. return TRUE;
  1509. }
  1510. return FALSE;
  1511. }
  1512. }
  1513. if (a->CaptureBufferSize <= BUFFER_SIZE &&
  1514. CookedReadData->BytesRead == 0) {
  1515. CookedReadData->UserBuffer = a->Buffer;
  1516. }
  1517. Status = CookedRead(CookedReadData,
  1518. WaitReplyMessage,
  1519. WaitingThread,
  1520. TRUE
  1521. );
  1522. if (Status != CONSOLE_STATUS_WAIT) {
  1523. return TRUE;
  1524. } else {
  1525. return FALSE;
  1526. }
  1527. //
  1528. // satisfy the unreferenced parameter warnings.
  1529. //
  1530. UNREFERENCED_PARAMETER(WaitQueue);
  1531. UNREFERENCED_PARAMETER(SatisfyParameter2);
  1532. }
  1533. NTSTATUS
  1534. ReadChars(
  1535. IN PINPUT_INFORMATION InputInfo,
  1536. IN PCONSOLE_INFORMATION Console,
  1537. IN PCONSOLE_PER_PROCESS_DATA ProcessData,
  1538. IN PSCREEN_INFORMATION ScreenInfo,
  1539. IN OUT PWCHAR lpBuffer,
  1540. IN OUT PDWORD NumBytes,
  1541. IN DWORD InitialNumBytes,
  1542. IN DWORD CtrlWakeupMask,
  1543. IN PHANDLE_DATA HandleData,
  1544. IN PCOMMAND_HISTORY CommandHistory,
  1545. IN PCSR_API_MSG Message OPTIONAL,
  1546. IN HANDLE HandleIndex,
  1547. IN USHORT ExeNameLength,
  1548. IN PWCHAR ExeName,
  1549. IN BOOLEAN Unicode
  1550. )
  1551. /*++
  1552. Routine Description:
  1553. This routine reads in characters for stream input and does the
  1554. required processing based on the input mode (line,char,echo).
  1555. This routine returns UNICODE characters.
  1556. Arguments:
  1557. InputInfo - Pointer to input buffer information.
  1558. Console - Pointer to console buffer information.
  1559. ScreenInfo - Pointer to screen buffer information.
  1560. lpBuffer - Pointer to buffer to read into.
  1561. NumBytes - On input, size of buffer. On output, number of bytes
  1562. read.
  1563. HandleData - Pointer to handle data structure.
  1564. Return Value:
  1565. --*/
  1566. {
  1567. DWORD BufferSize;
  1568. NTSTATUS Status;
  1569. HANDLE_DATA TempHandle;
  1570. BOOLEAN Echo = FALSE;
  1571. ULONG NumToWrite;
  1572. #ifdef FE_SB
  1573. PCONSOLE_READCONSOLE_MSG a = (PCONSOLE_READCONSOLE_MSG)&Message->u.ApiMessageData;
  1574. BOOL fAddDbcsLead = FALSE;
  1575. ULONG NumToBytes;
  1576. #endif
  1577. BufferSize = *NumBytes;
  1578. *NumBytes = 0;
  1579. if (HandleData->InputReadData->InputHandleFlags & HANDLE_INPUT_PENDING) {
  1580. //
  1581. // if we have leftover input, copy as much fits into the user's
  1582. // buffer and return. we may have multi line input, if a macro
  1583. // has been defined that contains the $T character.
  1584. //
  1585. if (HandleData->InputReadData->InputHandleFlags & HANDLE_MULTI_LINE_INPUT) {
  1586. PWSTR Tmp;
  1587. #ifdef FE_SB
  1588. if (!Unicode && CONSOLE_IS_DBCS_CP(Console)) {
  1589. if (HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar) {
  1590. fAddDbcsLead = TRUE;
  1591. *lpBuffer++ = HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar;
  1592. BufferSize--;
  1593. HandleData->InputReadData->BytesAvailable--;
  1594. RtlZeroMemory(&HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte,sizeof(INPUT_RECORD));
  1595. }
  1596. if (HandleData->InputReadData->BytesAvailable == 0 ||
  1597. BufferSize == 0) {
  1598. HandleData->InputReadData->InputHandleFlags &= ~(HANDLE_INPUT_PENDING | HANDLE_MULTI_LINE_INPUT);
  1599. ConsoleHeapFree(HandleData->InputReadData->BufPtr);
  1600. *NumBytes = 1;
  1601. return STATUS_SUCCESS;
  1602. }
  1603. else {
  1604. for (NumToWrite=0,Tmp=HandleData->InputReadData->CurrentBufPtr,NumToBytes=0;
  1605. NumToBytes < HandleData->InputReadData->BytesAvailable && NumToBytes < BufferSize/sizeof(WCHAR) && *Tmp!=UNICODE_LINEFEED;
  1606. (IsConsoleFullWidth(Console->hDC,
  1607. Console->CP,*Tmp) ? NumToBytes+=2 : NumToBytes++),Tmp++,NumToWrite+=sizeof(WCHAR)) ;
  1608. }
  1609. }
  1610. #endif
  1611. for (NumToWrite=0,Tmp=HandleData->InputReadData->CurrentBufPtr;
  1612. NumToWrite < HandleData->InputReadData->BytesAvailable && *Tmp!=UNICODE_LINEFEED;
  1613. Tmp++,NumToWrite+=sizeof(WCHAR)) ;
  1614. NumToWrite += sizeof(WCHAR);
  1615. if (NumToWrite > BufferSize) {
  1616. NumToWrite = BufferSize;
  1617. }
  1618. } else {
  1619. #ifdef FE_SB
  1620. if (!Unicode && CONSOLE_IS_DBCS_CP(Console)) {
  1621. PWSTR Tmp;
  1622. if (HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar) {
  1623. fAddDbcsLead = TRUE;
  1624. *lpBuffer++ = HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar;
  1625. BufferSize-=sizeof(WCHAR);
  1626. HandleData->InputReadData->BytesAvailable-=sizeof(WCHAR);
  1627. RtlZeroMemory(&HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte,sizeof(INPUT_RECORD));
  1628. }
  1629. if (HandleData->InputReadData->BytesAvailable == 0) {
  1630. HandleData->InputReadData->InputHandleFlags &= ~(HANDLE_INPUT_PENDING | HANDLE_MULTI_LINE_INPUT);
  1631. ConsoleHeapFree(HandleData->InputReadData->BufPtr);
  1632. *NumBytes = 1;
  1633. return STATUS_SUCCESS;
  1634. }
  1635. else {
  1636. for (NumToWrite=0,Tmp=HandleData->InputReadData->CurrentBufPtr,NumToBytes=0;
  1637. NumToBytes < HandleData->InputReadData->BytesAvailable && NumToBytes < BufferSize/sizeof(WCHAR);
  1638. (IsConsoleFullWidth(Console->hDC,
  1639. Console->CP,*Tmp) ? NumToBytes+=2 : NumToBytes++),Tmp++,NumToWrite+=sizeof(WCHAR)) ;
  1640. }
  1641. }
  1642. #endif
  1643. NumToWrite = (BufferSize < HandleData->InputReadData->BytesAvailable) ?
  1644. BufferSize : HandleData->InputReadData->BytesAvailable;
  1645. }
  1646. RtlCopyMemory(lpBuffer,HandleData->InputReadData->CurrentBufPtr,NumToWrite);
  1647. HandleData->InputReadData->BytesAvailable-= NumToWrite;
  1648. if (HandleData->InputReadData->BytesAvailable == 0) {
  1649. HandleData->InputReadData->InputHandleFlags &= ~(HANDLE_INPUT_PENDING | HANDLE_MULTI_LINE_INPUT);
  1650. ConsoleHeapFree(HandleData->InputReadData->BufPtr);
  1651. }
  1652. else {
  1653. HandleData->InputReadData->CurrentBufPtr=(PWCHAR)((PBYTE)HandleData->InputReadData->CurrentBufPtr+NumToWrite);
  1654. }
  1655. if (!Unicode) {
  1656. //
  1657. // if ansi, translate string. we allocated the capture buffer large
  1658. // enough to handle the translated string.
  1659. //
  1660. PCHAR TransBuffer;
  1661. #ifdef FE_SB
  1662. if (CONSOLE_IS_DBCS_CP(Console))
  1663. TransBuffer = ConsoleHeapAlloc(TMP_DBCS_TAG, NumToBytes);
  1664. else
  1665. #endif
  1666. TransBuffer = ConsoleHeapAlloc(TMP_TAG, NumToWrite / sizeof(WCHAR));
  1667. if (TransBuffer == NULL) {
  1668. return STATUS_NO_MEMORY;
  1669. }
  1670. #ifdef FE_SB
  1671. if (CONSOLE_IS_DBCS_CP(Console))
  1672. {
  1673. NumToWrite = TranslateUnicodeToOem(Console,
  1674. lpBuffer,
  1675. NumToWrite / sizeof (WCHAR),
  1676. TransBuffer,
  1677. NumToBytes,
  1678. &HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte);
  1679. }
  1680. else
  1681. #endif
  1682. NumToWrite = ConvertToOem(Console->CP,
  1683. lpBuffer,
  1684. NumToWrite / sizeof (WCHAR),
  1685. TransBuffer,
  1686. NumToWrite / sizeof (WCHAR)
  1687. );
  1688. RtlCopyMemory(lpBuffer,TransBuffer,NumToWrite);
  1689. #ifdef FE_SB
  1690. if (fAddDbcsLead)
  1691. NumToWrite++;
  1692. #endif
  1693. ConsoleHeapFree(TransBuffer);
  1694. }
  1695. *NumBytes = NumToWrite;
  1696. return STATUS_SUCCESS;
  1697. }
  1698. //
  1699. // we need to create a temporary handle to the current screen buffer
  1700. // if echo is on.
  1701. //
  1702. if ((InputInfo->InputMode & (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)) ==
  1703. (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)) {
  1704. HANDLE ActiveScreenHandle;
  1705. Echo = FALSE;
  1706. ActiveScreenHandle = FindActiveScreenBufferHandle(ProcessData,Console);
  1707. if (ActiveScreenHandle != INVALID_HANDLE_VALUE) {
  1708. TempHandle.HandleType = CONSOLE_OUTPUT_HANDLE;
  1709. TempHandle.Buffer.ScreenBuffer = Console->CurrentScreenBuffer;
  1710. if (TempHandle.Buffer.ScreenBuffer != NULL) {
  1711. Status = ConsoleAddShare(GENERIC_WRITE,
  1712. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1713. &TempHandle.Buffer.ScreenBuffer->ShareAccess,
  1714. &TempHandle
  1715. );
  1716. if (NT_SUCCESS(Status)) {
  1717. Echo = TRUE;
  1718. TempHandle.Buffer.ScreenBuffer->RefCount++;
  1719. }
  1720. }
  1721. }
  1722. }
  1723. if (InputInfo->InputMode & ENABLE_LINE_INPUT) {
  1724. //
  1725. // read in characters until the buffer is full or return is read.
  1726. // since we may wait inside this loop, store all important variables
  1727. // in the read data structure. if we do wait, a read data structure
  1728. // will be allocated from the heap and its pointer will be stored
  1729. // in the wait block. the CookedReadData will be copied into the
  1730. // structure. the data is freed when the read is completed.
  1731. //
  1732. COOKED_READ_DATA CookedReadData;
  1733. ULONG i;
  1734. PWCHAR TempBuffer;
  1735. ULONG TempBufferSize;
  1736. //
  1737. // to emulate OS/2 KbdStringIn, we read into our own big buffer
  1738. // (256 bytes) until the user types enter. then return as many
  1739. // chars as will fit in the user's buffer.
  1740. //
  1741. TempBufferSize = (BufferSize < LINE_INPUT_BUFFER_SIZE) ? LINE_INPUT_BUFFER_SIZE : BufferSize;
  1742. TempBuffer = ConsoleHeapAlloc(TMP_TAG, TempBufferSize);
  1743. if (TempBuffer==NULL) {
  1744. if (Echo) {
  1745. CloseOutputHandle(ProcessData,
  1746. Console,
  1747. &TempHandle,
  1748. NULL,
  1749. FALSE
  1750. );
  1751. }
  1752. return STATUS_NO_MEMORY;
  1753. }
  1754. //
  1755. // initialize the user's buffer to spaces. this is done so that
  1756. // moving in the buffer via cursor doesn't do strange things.
  1757. //
  1758. for (i=0;i<TempBufferSize/sizeof(WCHAR);i++) {
  1759. TempBuffer[i] = (WCHAR)' ';
  1760. }
  1761. CookedReadData.InputInfo = InputInfo;
  1762. CookedReadData.ScreenInfo = ScreenInfo;
  1763. CookedReadData.Console = Console;
  1764. CookedReadData.TempHandle.HandleType = TempHandle.HandleType;
  1765. CookedReadData.TempHandle.Buffer.ScreenBuffer = TempHandle.Buffer.ScreenBuffer;
  1766. CookedReadData.BufferSize = TempBufferSize;
  1767. CookedReadData.BytesRead = 0;
  1768. CookedReadData.CurrentPosition = 0;
  1769. CookedReadData.BufPtr = TempBuffer;
  1770. CookedReadData.BackupLimit = TempBuffer;
  1771. CookedReadData.UserBufferSize = BufferSize;
  1772. CookedReadData.UserBuffer = lpBuffer;
  1773. CookedReadData.OriginalCursorPosition.X = -1;
  1774. CookedReadData.OriginalCursorPosition.Y = -1;
  1775. CookedReadData.NumberOfVisibleChars = 0;
  1776. CookedReadData.CtrlWakeupMask = CtrlWakeupMask;
  1777. CookedReadData.CommandHistory = CommandHistory;
  1778. CookedReadData.Echo = Echo;
  1779. CookedReadData.InsertMode = Console->InsertMode;
  1780. CookedReadData.Processed = (InputInfo->InputMode & ENABLE_PROCESSED_INPUT) != 0;
  1781. CookedReadData.Line = (InputInfo->InputMode & ENABLE_LINE_INPUT) != 0;
  1782. CookedReadData.ProcessData = ProcessData;
  1783. CookedReadData.HandleIndex = HandleIndex;
  1784. CookedReadData.ExeName = ConsoleHeapAlloc(HISTORY_TAG, ExeNameLength);
  1785. if (InitialNumBytes != 0) {
  1786. RtlCopyMemory(CookedReadData.BufPtr, CookedReadData.UserBuffer, InitialNumBytes);
  1787. CookedReadData.BytesRead += InitialNumBytes;
  1788. CookedReadData.NumberOfVisibleChars = (InitialNumBytes / sizeof(WCHAR));
  1789. CookedReadData.BufPtr += (InitialNumBytes / sizeof(WCHAR));
  1790. CookedReadData.CurrentPosition = (InitialNumBytes / sizeof(WCHAR));
  1791. CookedReadData.OriginalCursorPosition = ScreenInfo->BufferInfo.TextInfo.CursorPosition;
  1792. CookedReadData.OriginalCursorPosition.X -= (SHORT)CookedReadData.CurrentPosition;
  1793. while (CookedReadData.OriginalCursorPosition.X < 0) {
  1794. CookedReadData.OriginalCursorPosition.X += ScreenInfo->ScreenBufferSize.X;
  1795. CookedReadData.OriginalCursorPosition.Y -= 1;
  1796. }
  1797. }
  1798. if (CookedReadData.ExeName) {
  1799. RtlCopyMemory(CookedReadData.ExeName,ExeName,ExeNameLength);
  1800. CookedReadData.ExeNameLength = ExeNameLength;
  1801. }
  1802. #ifdef FE_SB
  1803. Console->lpCookedReadData = (PVOID)&CookedReadData;
  1804. #endif
  1805. Status = CookedRead(&CookedReadData,
  1806. Message,
  1807. CSR_SERVER_QUERYCLIENTTHREAD(),
  1808. FALSE
  1809. );
  1810. #ifdef FE_SB
  1811. if (Status != CONSOLE_STATUS_WAIT) {
  1812. Console->lpCookedReadData = NULL;
  1813. }
  1814. #endif
  1815. return Status;
  1816. }
  1817. //
  1818. // character (raw) mode
  1819. //
  1820. else {
  1821. //
  1822. // read at least one character in. after one character has been
  1823. // read, get any more available characters and return. the first
  1824. // call to GetChar may wait. if we do wait, a read data structure
  1825. // will be allocated from the heap and its pointer will be stored
  1826. // in the wait block. the RawReadData will be copied into the
  1827. // structure. the data is freed when the read is completed.
  1828. //
  1829. RAW_READ_DATA RawReadData;
  1830. RawReadData.InputInfo = InputInfo;
  1831. RawReadData.Console = Console;
  1832. RawReadData.BufferSize = BufferSize;
  1833. RawReadData.BufPtr = lpBuffer;
  1834. RawReadData.ProcessData = ProcessData;
  1835. RawReadData.HandleIndex = HandleIndex;
  1836. if (*NumBytes < BufferSize) {
  1837. PWCHAR pwchT;
  1838. #ifdef FE_SB
  1839. PWCHAR lpBufferTmp = lpBuffer;
  1840. NumToWrite = 0;
  1841. if (!Unicode && CONSOLE_IS_DBCS_CP(Console)) {
  1842. if (HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar) {
  1843. fAddDbcsLead = TRUE;
  1844. *lpBuffer++ = HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte.Event.KeyEvent.uChar.AsciiChar;
  1845. BufferSize-=sizeof(WCHAR);
  1846. RtlZeroMemory(&HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte,sizeof(INPUT_RECORD));
  1847. Status = STATUS_SUCCESS;
  1848. if (BufferSize == 0) {
  1849. *NumBytes = 1;
  1850. return STATUS_SUCCESS;
  1851. }
  1852. }
  1853. else{
  1854. Status = GetChar(InputInfo,
  1855. lpBuffer,
  1856. TRUE,
  1857. Console,
  1858. HandleData,
  1859. Message,
  1860. RawReadWaitRoutine,
  1861. &RawReadData,
  1862. sizeof(RawReadData),
  1863. FALSE,
  1864. NULL,
  1865. NULL,
  1866. NULL,
  1867. NULL
  1868. );
  1869. }
  1870. }
  1871. else
  1872. #endif
  1873. Status = GetChar(InputInfo,
  1874. lpBuffer,
  1875. TRUE,
  1876. Console,
  1877. HandleData,
  1878. Message,
  1879. RawReadWaitRoutine,
  1880. &RawReadData,
  1881. sizeof(RawReadData),
  1882. FALSE,
  1883. NULL,
  1884. NULL,
  1885. NULL,
  1886. NULL
  1887. );
  1888. if (!NT_SUCCESS(Status)) {
  1889. *NumBytes = 0;
  1890. return Status;
  1891. }
  1892. #ifdef FE_SB
  1893. if (! fAddDbcsLead) {
  1894. IsConsoleFullWidth(Console->hDC,
  1895. Console->CP,*lpBuffer) ? *NumBytes+=2 : ++*NumBytes;
  1896. NumToWrite+=sizeof(WCHAR);
  1897. lpBuffer++;
  1898. }
  1899. if (CONSOLE_IS_DBCS_CP(Console)) {
  1900. while (NumToWrite < BufferSize) {
  1901. Status = GetChar(InputInfo,lpBuffer,FALSE,NULL,NULL,NULL,NULL,NULL,0,FALSE,NULL,NULL,NULL,NULL);
  1902. if (!NT_SUCCESS(Status)) {
  1903. return STATUS_SUCCESS;
  1904. }
  1905. IsConsoleFullWidth(Console->hDC,
  1906. Console->CP,*lpBuffer) ? *NumBytes+=2 : ++*NumBytes;
  1907. lpBuffer++;
  1908. NumToWrite+=sizeof(WCHAR);
  1909. }
  1910. }
  1911. else{
  1912. #endif
  1913. pwchT = lpBuffer + 1;
  1914. *NumBytes += sizeof(WCHAR);
  1915. while (*NumBytes < BufferSize) {
  1916. Status = GetChar(InputInfo,pwchT,FALSE,NULL,NULL,NULL,NULL,NULL,0,FALSE,NULL,NULL,NULL,NULL);
  1917. if (!NT_SUCCESS(Status)) {
  1918. break;
  1919. }
  1920. pwchT++;
  1921. *NumBytes += sizeof(WCHAR);
  1922. }
  1923. #ifdef FE_SB
  1924. }
  1925. #endif
  1926. //
  1927. // if ansi, translate string. we allocated the capture buffer large
  1928. // enough to handle the translated string.
  1929. //
  1930. if (!Unicode) {
  1931. PCHAR TransBuffer;
  1932. TransBuffer = ConsoleHeapAlloc(TMP_TAG, *NumBytes / sizeof(WCHAR));
  1933. if (TransBuffer == NULL) {
  1934. return STATUS_NO_MEMORY;
  1935. }
  1936. #ifdef FE_SB
  1937. lpBuffer = lpBufferTmp;
  1938. if (CONSOLE_IS_DBCS_CP(Console))
  1939. {
  1940. *NumBytes = TranslateUnicodeToOem(Console,
  1941. lpBuffer,
  1942. NumToWrite / sizeof (WCHAR),
  1943. TransBuffer,
  1944. *NumBytes,
  1945. &HandleData->Buffer.InputBuffer->ReadConInpDbcsLeadByte);
  1946. }
  1947. else
  1948. #endif
  1949. *NumBytes = ConvertToOem(Console->CP,
  1950. lpBuffer,
  1951. *NumBytes / sizeof (WCHAR),
  1952. TransBuffer,
  1953. *NumBytes / sizeof (WCHAR)
  1954. );
  1955. RtlCopyMemory(lpBuffer,TransBuffer,*NumBytes);
  1956. #ifdef FE_SB
  1957. if (fAddDbcsLead)
  1958. ++*NumBytes;
  1959. #endif
  1960. ConsoleHeapFree(TransBuffer);
  1961. }
  1962. }
  1963. }
  1964. return STATUS_SUCCESS;
  1965. }
  1966. ULONG
  1967. SrvReadConsole(
  1968. IN OUT PCSR_API_MSG m,
  1969. IN OUT PCSR_REPLY_STATUS ReplyStatus
  1970. )
  1971. /*++
  1972. Routine Description:
  1973. This routine reads characters from the input stream.
  1974. Arguments:
  1975. ApiMessageData - Points to parameter structure.
  1976. Return Value:
  1977. --*/
  1978. {
  1979. PCONSOLE_READCONSOLE_MSG a = (PCONSOLE_READCONSOLE_MSG)&m->u.ApiMessageData;
  1980. PCONSOLE_INFORMATION Console;
  1981. PHANDLE_DATA HandleData;
  1982. NTSTATUS Status;
  1983. PWCHAR Buffer;
  1984. PCONSOLE_PER_PROCESS_DATA ProcessData;
  1985. Status = ApiPreamble(a->ConsoleHandle,
  1986. &Console
  1987. );
  1988. if (!NT_SUCCESS(Status)) {
  1989. return Status;
  1990. }
  1991. ProcessData = CONSOLE_PERPROCESSDATA();
  1992. Status = DereferenceIoHandle(ProcessData,
  1993. a->InputHandle,
  1994. CONSOLE_INPUT_HANDLE,
  1995. GENERIC_READ,
  1996. &HandleData
  1997. );
  1998. if (!NT_SUCCESS(Status)) {
  1999. a->NumBytes = 0;
  2000. } else {
  2001. if (a->CaptureBufferSize <= BUFFER_SIZE) {
  2002. Buffer = a->Buffer;
  2003. }
  2004. else {
  2005. Buffer = a->BufPtr;
  2006. if (!CsrValidateMessageBuffer(m, &a->BufPtr, a->CaptureBufferSize, sizeof(BYTE))) {
  2007. UnlockConsole(Console);
  2008. return STATUS_INVALID_PARAMETER;
  2009. }
  2010. }
  2011. #if defined(FE_SB)
  2012. Console->ReadConInpNumBytesTemp = a->NumBytes / sizeof(WCHAR);
  2013. #endif
  2014. Status = ReadChars(HandleData->Buffer.InputBuffer,
  2015. Console,
  2016. ProcessData,
  2017. Console->CurrentScreenBuffer,
  2018. Buffer,
  2019. &a->NumBytes,
  2020. a->InitialNumBytes,
  2021. a->CtrlWakeupMask,
  2022. HandleData,
  2023. FindCommandHistory(Console,CONSOLE_CLIENTPROCESSHANDLE()),
  2024. m,
  2025. HANDLE_TO_INDEX(a->InputHandle),
  2026. a->ExeNameLength,
  2027. a->Buffer,
  2028. a->Unicode
  2029. );
  2030. if (Status == CONSOLE_STATUS_WAIT) {
  2031. *ReplyStatus = CsrReplyPending;
  2032. }
  2033. }
  2034. UnlockConsole(Console);
  2035. return Status;
  2036. }
  2037. VOID
  2038. MakeCursorVisible(
  2039. IN PSCREEN_INFORMATION ScreenInfo,
  2040. IN COORD CursorPosition
  2041. )
  2042. {
  2043. COORD WindowOrigin;
  2044. NTSTATUS Status;
  2045. WindowOrigin.X = 0;
  2046. WindowOrigin.Y = 0;
  2047. if (CursorPosition.X > ScreenInfo->Window.Right) {
  2048. WindowOrigin.X = CursorPosition.X - ScreenInfo->Window.Right;
  2049. } else if (CursorPosition.X < ScreenInfo->Window.Left) {
  2050. WindowOrigin.X = CursorPosition.X - ScreenInfo->Window.Left;
  2051. }
  2052. if (CursorPosition.Y > ScreenInfo->Window.Bottom) {
  2053. WindowOrigin.Y = CursorPosition.Y - ScreenInfo->Window.Bottom;
  2054. } else if (CursorPosition.Y < ScreenInfo->Window.Top) {
  2055. WindowOrigin.Y = CursorPosition.Y - ScreenInfo->Window.Top;
  2056. }
  2057. if (WindowOrigin.X != 0 || WindowOrigin.Y != 0) {
  2058. Status = SetWindowOrigin(ScreenInfo,
  2059. FALSE,
  2060. WindowOrigin
  2061. );
  2062. if (!NT_SUCCESS(Status)) {
  2063. return;
  2064. }
  2065. }
  2066. }
  2067. #define WRITE_NO_CR_LF 0
  2068. #define WRITE_CR 1
  2069. #define WRITE_CR_LF 2
  2070. #define WRITE_SPECIAL_CHARS 4
  2071. #define WRITE_UNICODE_CRLF 0x000a000d
  2072. DWORD
  2073. FastStreamWrite(
  2074. IN PWCHAR lpString,
  2075. IN DWORD NumChars
  2076. )
  2077. /*++
  2078. Routine Description:
  2079. This routine determines whether the text string contains characters
  2080. that require special processing. If it doesn't,
  2081. unicode characters. The string is also copied to the input buffer, if
  2082. the output mode is line mode.
  2083. Arguments:
  2084. lpString - Pointer to string to write.
  2085. NumChars - Number of chars in buffer.
  2086. Return Value:
  2087. WRITE_SPECIAL_CHARS - string contains characters requiring special processing
  2088. WRITE_NO_CR_LF - string contains no special chars and no CRLF
  2089. WRITE_CR_LF - string contains no special chars and is terminated by CRLF
  2090. WRITE_CR - string contains no special chars and is terminated by CR
  2091. --*/
  2092. {
  2093. DWORD UNALIGNED *Tmp;
  2094. register PWCHAR StrPtr=lpString;
  2095. while (NumChars) {
  2096. if (*StrPtr < UNICODE_SPACE) {
  2097. Tmp = (PDWORD)StrPtr;
  2098. if (NumChars == 2 &&
  2099. *Tmp == WRITE_UNICODE_CRLF) {
  2100. return WRITE_CR_LF;
  2101. } else if (NumChars == 1 &&
  2102. *StrPtr == (WCHAR)'\r') {
  2103. return WRITE_CR;
  2104. } else {
  2105. return WRITE_SPECIAL_CHARS;
  2106. }
  2107. }
  2108. StrPtr++;
  2109. NumChars--;
  2110. }
  2111. return WRITE_NO_CR_LF;
  2112. }
  2113. VOID UnblockWriteConsole(
  2114. IN PCONSOLE_INFORMATION Console,
  2115. IN DWORD Reason)
  2116. {
  2117. Console->Flags &= ~Reason;
  2118. if ((Console->Flags & (CONSOLE_SUSPENDED | CONSOLE_SELECTING | CONSOLE_SCROLLBAR_TRACKING)) == 0) {
  2119. /*
  2120. * no remain reason to suspend output, so unblock it.
  2121. */
  2122. if (CsrNotifyWait(&Console->OutputQueue, TRUE, NULL, NULL)) {
  2123. // #334370 under stress, WaitQueue may already hold the satisfied waits
  2124. ASSERT ((Console->WaitQueue == NULL) ||
  2125. (Console->WaitQueue == &Console->OutputQueue));
  2126. Console->WaitQueue = &Console->OutputQueue;
  2127. }
  2128. }
  2129. }
  2130. ULONG
  2131. SrvWriteConsole(
  2132. IN OUT PCSR_API_MSG m,
  2133. IN OUT PCSR_REPLY_STATUS ReplyStatus
  2134. )
  2135. /*++
  2136. Routine Description:
  2137. This routine writes characters to the output stream.
  2138. Arguments:
  2139. ApiMessageData - Points to parameter structure.
  2140. Return Value:
  2141. --*/
  2142. {
  2143. NTSTATUS Status;
  2144. PCONSOLE_WRITECONSOLE_MSG a = (PCONSOLE_WRITECONSOLE_MSG)&m->u.ApiMessageData;
  2145. PCONSOLE_INFORMATION Console;
  2146. PHANDLE_DATA HandleData;
  2147. Status = ApiPreamble(a->ConsoleHandle,
  2148. &Console
  2149. );
  2150. if (!NT_SUCCESS(Status)) {
  2151. return Status;
  2152. }
  2153. if (!a->BufferInMessage) {
  2154. if (!CsrValidateMessageBuffer(m, &a->BufPtr, a->NumBytes, sizeof(BYTE))) {
  2155. UnlockConsole(Console);
  2156. return STATUS_INVALID_PARAMETER;
  2157. }
  2158. }
  2159. else if (a->NumBytes > sizeof(a->Buffer)) {
  2160. UnlockConsole(Console);
  2161. return STATUS_INVALID_PARAMETER;
  2162. }
  2163. //
  2164. // Make sure we have a valid screen buffer.
  2165. //
  2166. Status = DereferenceIoHandle(CONSOLE_PERPROCESSDATA(),
  2167. a->OutputHandle,
  2168. CONSOLE_OUTPUT_HANDLE,
  2169. GENERIC_WRITE,
  2170. &HandleData
  2171. );
  2172. if (!NT_SUCCESS(Status)) {
  2173. UnlockConsole(Console);
  2174. return Status;
  2175. }
  2176. Status = DoSrvWriteConsole(m,ReplyStatus,Console,HandleData);
  2177. UnlockConsole(Console);
  2178. return Status;
  2179. }
  2180. BOOLEAN
  2181. WriteConsoleWaitRoutine(
  2182. IN PLIST_ENTRY WaitQueue,
  2183. IN PCSR_THREAD WaitingThread,
  2184. IN PCSR_API_MSG WaitReplyMessage,
  2185. IN PVOID WaitParameter,
  2186. IN PVOID SatisfyParameter1,
  2187. IN PVOID SatisfyParameter2,
  2188. IN ULONG WaitFlags
  2189. )
  2190. {
  2191. NTSTATUS Status;
  2192. PCONSOLE_WRITECONSOLE_MSG a = (PCONSOLE_WRITECONSOLE_MSG)&WaitReplyMessage->u.ApiMessageData;
  2193. PCONSOLE_INFORMATION Console;
  2194. if (WaitFlags & CSR_PROCESS_TERMINATING) {
  2195. WaitReplyMessage->ReturnValue = (ULONG)STATUS_THREAD_IS_TERMINATING;
  2196. return TRUE;
  2197. }
  2198. LockConsoleHandleTable();
  2199. Status = DereferenceConsoleHandle(a->ConsoleHandle,
  2200. &Console
  2201. );
  2202. UnlockConsoleHandleTable();
  2203. ASSERT (NT_SUCCESS(Status));
  2204. //
  2205. // if we get to here, this routine was called by the input
  2206. // thread, which grabs the current console lock.
  2207. //
  2208. //
  2209. // this routine should be called by a thread owning the same
  2210. // lock on the same console as we're reading from.
  2211. //
  2212. ASSERT (ConsoleLocked(Console));
  2213. //
  2214. // if we're unicode, the string may still be in the message buffer.
  2215. // since the message was reallocated and copied when the wait was
  2216. // created, we need to fix up a->TransBuffer here.
  2217. //
  2218. if (a->Unicode && a->BufferInMessage) {
  2219. a->TransBuffer = a->Buffer;
  2220. }
  2221. Status = DoWriteConsole(WaitReplyMessage,Console,WaitingThread);
  2222. if (Status == CONSOLE_STATUS_WAIT) {
  2223. return FALSE;
  2224. }
  2225. if (!a->Unicode) {
  2226. #ifdef FE_SB
  2227. if (CONSOLE_IS_DBCS_OUTPUTCP(Console))
  2228. {
  2229. if (a->NumBytes == Console->WriteConOutNumBytesUnicode)
  2230. a->NumBytes = Console->WriteConOutNumBytesTemp;
  2231. else
  2232. a->NumBytes /= sizeof(WCHAR);
  2233. }
  2234. else
  2235. #endif
  2236. a->NumBytes /= sizeof(WCHAR);
  2237. ConsoleHeapFree(a->TransBuffer);
  2238. }
  2239. WaitReplyMessage->ReturnValue = Status;
  2240. return TRUE;
  2241. UNREFERENCED_PARAMETER(WaitQueue);
  2242. UNREFERENCED_PARAMETER(WaitParameter);
  2243. UNREFERENCED_PARAMETER(SatisfyParameter1);
  2244. UNREFERENCED_PARAMETER(SatisfyParameter2);
  2245. }
  2246. ULONG
  2247. SrvDuplicateHandle(
  2248. IN OUT PCSR_API_MSG m,
  2249. IN OUT PCSR_REPLY_STATUS ReplyStatus
  2250. )
  2251. /*++
  2252. Routine Description:
  2253. This routine duplicates an input or output handle.
  2254. Arguments:
  2255. ApiMessageData - Points to parameter structure.
  2256. Return Value:
  2257. --*/
  2258. {
  2259. PCONSOLE_DUPHANDLE_MSG a = (PCONSOLE_DUPHANDLE_MSG)&m->u.ApiMessageData;
  2260. PCONSOLE_INFORMATION Console;
  2261. PHANDLE_DATA SourceHandleData,TargetHandleData;
  2262. PCONSOLE_SHARE_ACCESS ShareAccess;
  2263. NTSTATUS Status;
  2264. PCONSOLE_PER_PROCESS_DATA ProcessData;
  2265. Status = ApiPreamble(a->ConsoleHandle,
  2266. &Console
  2267. );
  2268. if (!NT_SUCCESS(Status)) {
  2269. return Status;
  2270. }
  2271. ProcessData = CONSOLE_PERPROCESSDATA();
  2272. Status = DereferenceIoHandleNoCheck(ProcessData,
  2273. HANDLE_TO_INDEX(a->SourceHandle),
  2274. &SourceHandleData
  2275. );
  2276. if (!NT_SUCCESS(Status)) {
  2277. goto exit;
  2278. }
  2279. if (a->Options & DUPLICATE_SAME_ACCESS) {
  2280. a->DesiredAccess = SourceHandleData->Access;
  2281. }
  2282. //
  2283. // make sure that requested access is a subset of source handle's access
  2284. //
  2285. else if ((a->DesiredAccess & SourceHandleData->Access) != a->DesiredAccess) {
  2286. Status = STATUS_INVALID_PARAMETER;
  2287. goto exit;
  2288. }
  2289. Status = AllocateIoHandle(ProcessData,
  2290. SourceHandleData->HandleType,
  2291. &a->TargetHandle
  2292. );
  2293. if (!NT_SUCCESS(Status)) {
  2294. goto exit;
  2295. }
  2296. //
  2297. // it's possible that AllocateIoHandle realloced the handle table,
  2298. // so deference SourceHandle again.
  2299. //
  2300. Status = DereferenceIoHandleNoCheck(ProcessData,
  2301. HANDLE_TO_INDEX(a->SourceHandle),
  2302. &SourceHandleData
  2303. );
  2304. ASSERT (NT_SUCCESS(Status));
  2305. if (!NT_SUCCESS(Status)) {
  2306. goto exit;
  2307. }
  2308. Status = DereferenceIoHandleNoCheck(ProcessData,
  2309. a->TargetHandle,
  2310. &TargetHandleData
  2311. );
  2312. ASSERT (NT_SUCCESS(Status));
  2313. if (!NT_SUCCESS(Status)) {
  2314. FreeIoHandle(ProcessData,
  2315. a->TargetHandle
  2316. );
  2317. goto exit;
  2318. }
  2319. if (SourceHandleData->HandleType & CONSOLE_INPUT_HANDLE) {
  2320. // grab input lock
  2321. if (!InitializeInputHandle(TargetHandleData,
  2322. SourceHandleData->Buffer.InputBuffer)) {
  2323. FreeIoHandle(ProcessData,
  2324. a->TargetHandle
  2325. );
  2326. Status = STATUS_NO_MEMORY;
  2327. goto exit;
  2328. }
  2329. ShareAccess = &SourceHandleData->Buffer.InputBuffer->ShareAccess;
  2330. }
  2331. else {
  2332. // grab output lock
  2333. InitializeOutputHandle(TargetHandleData,SourceHandleData->Buffer.ScreenBuffer);
  2334. ShareAccess = &SourceHandleData->Buffer.ScreenBuffer->ShareAccess;
  2335. }
  2336. TargetHandleData->HandleType = SourceHandleData->HandleType;
  2337. if (a->InheritHandle) {
  2338. TargetHandleData->HandleType |= CONSOLE_INHERITABLE;
  2339. } else {
  2340. TargetHandleData->HandleType &= ~CONSOLE_INHERITABLE;
  2341. }
  2342. Status = ConsoleDupShare(a->DesiredAccess,
  2343. SourceHandleData->ShareAccess,
  2344. ShareAccess,
  2345. TargetHandleData
  2346. );
  2347. if (!NT_SUCCESS(Status)) {
  2348. FreeIoHandle(ProcessData,
  2349. a->TargetHandle
  2350. );
  2351. if (SourceHandleData->HandleType & CONSOLE_INPUT_HANDLE) {
  2352. SourceHandleData->Buffer.InputBuffer->RefCount--;
  2353. }
  2354. else {
  2355. SourceHandleData->Buffer.ScreenBuffer->RefCount--;
  2356. }
  2357. }
  2358. else {
  2359. a->TargetHandle = INDEX_TO_HANDLE(a->TargetHandle);
  2360. }
  2361. if (a->Options & DUPLICATE_CLOSE_SOURCE) {
  2362. if (SourceHandleData->HandleType & CONSOLE_INPUT_HANDLE)
  2363. CloseInputHandle(ProcessData,Console,SourceHandleData,HANDLE_TO_INDEX(a->SourceHandle));
  2364. else {
  2365. CloseOutputHandle(ProcessData,Console,SourceHandleData,HANDLE_TO_INDEX(a->SourceHandle),TRUE);
  2366. }
  2367. }
  2368. exit:
  2369. UnlockConsole(Console);
  2370. return Status;
  2371. UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
  2372. }
  2373. ULONG
  2374. SrvGetHandleInformation(
  2375. IN OUT PCSR_API_MSG m,
  2376. IN OUT PCSR_REPLY_STATUS ReplyStatus
  2377. )
  2378. /*++
  2379. Routine Description:
  2380. This gets information about an input or output handle.
  2381. Arguments:
  2382. ApiMessageData - Points to parameter structure.
  2383. Return Value:
  2384. --*/
  2385. {
  2386. PCONSOLE_GETHANDLEINFORMATION_MSG a = (PCONSOLE_GETHANDLEINFORMATION_MSG)&m->u.ApiMessageData;
  2387. PCONSOLE_INFORMATION Console;
  2388. PHANDLE_DATA HandleData;
  2389. NTSTATUS Status;
  2390. Status = ApiPreamble(a->ConsoleHandle,
  2391. &Console
  2392. );
  2393. if (!NT_SUCCESS(Status)) {
  2394. return Status;
  2395. }
  2396. Status = DereferenceIoHandleNoCheck(CONSOLE_PERPROCESSDATA(),
  2397. HANDLE_TO_INDEX(a->Handle),
  2398. &HandleData
  2399. );
  2400. if (NT_SUCCESS(Status)) {
  2401. a->Flags = 0;
  2402. if (HandleData->HandleType & CONSOLE_INHERITABLE) {
  2403. a->Flags |= HANDLE_FLAG_INHERIT;
  2404. }
  2405. }
  2406. UnlockConsole(Console);
  2407. return Status;
  2408. UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
  2409. }
  2410. ULONG
  2411. SrvSetHandleInformation(
  2412. IN OUT PCSR_API_MSG m,
  2413. IN OUT PCSR_REPLY_STATUS ReplyStatus
  2414. )
  2415. /*++
  2416. Routine Description:
  2417. This sets information about an input or output handle.
  2418. Arguments:
  2419. ApiMessageData - Points to parameter structure.
  2420. Return Value:
  2421. --*/
  2422. {
  2423. PCONSOLE_SETHANDLEINFORMATION_MSG a = (PCONSOLE_SETHANDLEINFORMATION_MSG)&m->u.ApiMessageData;
  2424. PCONSOLE_INFORMATION Console;
  2425. PHANDLE_DATA HandleData;
  2426. NTSTATUS Status;
  2427. Status = ApiPreamble(a->ConsoleHandle,
  2428. &Console
  2429. );
  2430. if (!NT_SUCCESS(Status)) {
  2431. return Status;
  2432. }
  2433. Status = DereferenceIoHandleNoCheck(CONSOLE_PERPROCESSDATA(),
  2434. HANDLE_TO_INDEX(a->Handle),
  2435. &HandleData
  2436. );
  2437. if (NT_SUCCESS(Status)) {
  2438. if (a->Mask & HANDLE_FLAG_INHERIT) {
  2439. if (a->Flags & HANDLE_FLAG_INHERIT) {
  2440. HandleData->HandleType |= CONSOLE_INHERITABLE;
  2441. } else {
  2442. HandleData->HandleType &= ~CONSOLE_INHERITABLE;
  2443. }
  2444. }
  2445. }
  2446. UnlockConsole(Console);
  2447. return Status;
  2448. UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
  2449. }
  2450. NTSTATUS
  2451. CloseInputHandle(
  2452. IN PCONSOLE_PER_PROCESS_DATA ProcessData,
  2453. IN PCONSOLE_INFORMATION Console,
  2454. IN PHANDLE_DATA HandleData,
  2455. IN HANDLE Handle
  2456. )
  2457. /*++
  2458. Routine Description:
  2459. This routine closes an input handle. It decrements the input buffer's
  2460. reference count. If it goes to zero, the buffer is reinitialized.
  2461. Otherwise, the handle is removed from sharing.
  2462. Arguments:
  2463. ProcessData - Pointer to per process data.
  2464. HandleData - Pointer to handle data structure.
  2465. Handle - Handle to close.
  2466. Return Value:
  2467. Note:
  2468. The console lock must be held when calling this routine.
  2469. --*/
  2470. {
  2471. BOOLEAN WaitSatisfied = FALSE;
  2472. if (HandleData->InputReadData->InputHandleFlags & HANDLE_INPUT_PENDING) {
  2473. HandleData->InputReadData->InputHandleFlags &= ~HANDLE_INPUT_PENDING;
  2474. ConsoleHeapFree(HandleData->InputReadData->BufPtr);
  2475. }
  2476. //
  2477. // see if there are any reads waiting for data via this handle. if
  2478. // there are, wake them up. there aren't any other outstanding i/o
  2479. // operations via this handle because the console lock is held.
  2480. //
  2481. LockReadCount(HandleData);
  2482. if (HandleData->InputReadData->ReadCount != 0) {
  2483. UnlockReadCount(HandleData);
  2484. HandleData->InputReadData->InputHandleFlags |= HANDLE_CLOSING;
  2485. WaitSatisfied |= CsrNotifyWait(&HandleData->Buffer.InputBuffer->ReadWaitQueue,
  2486. TRUE,
  2487. (PVOID) HandleData,
  2488. NULL
  2489. );
  2490. LockReadCount(HandleData);
  2491. }
  2492. if (WaitSatisfied) {
  2493. // #334370 under stress, WaitQueue may already hold the satisfied waits
  2494. ASSERT ((Console->WaitQueue == NULL) ||
  2495. (Console->WaitQueue == &HandleData->Buffer.InputBuffer->ReadWaitQueue));
  2496. Console->WaitQueue = &HandleData->Buffer.InputBuffer->ReadWaitQueue;
  2497. }
  2498. if (HandleData->InputReadData->ReadCount != 0) {
  2499. KdPrint(("ReadCount is %lX\n",HandleData->InputReadData->ReadCount));
  2500. }
  2501. ASSERT (HandleData->InputReadData->ReadCount == 0);
  2502. UnlockReadCount(HandleData);
  2503. ASSERT (HandleData->Buffer.InputBuffer->RefCount);
  2504. HandleData->Buffer.InputBuffer->RefCount--;
  2505. if (HandleData->Buffer.InputBuffer->RefCount == 0) {
  2506. ReinitializeInputBuffer(HandleData->Buffer.InputBuffer);
  2507. }
  2508. else {
  2509. ConsoleRemoveShare(HandleData->Access,
  2510. HandleData->ShareAccess,
  2511. &HandleData->Buffer.InputBuffer->ShareAccess
  2512. );
  2513. }
  2514. return FreeIoHandle(ProcessData,Handle);
  2515. }
  2516. NTSTATUS
  2517. CloseOutputHandle(
  2518. IN PCONSOLE_PER_PROCESS_DATA ProcessData,
  2519. IN PCONSOLE_INFORMATION Console,
  2520. IN PHANDLE_DATA HandleData,
  2521. IN HANDLE Handle,
  2522. IN BOOLEAN FreeHandle
  2523. )
  2524. /*++
  2525. Routine Description:
  2526. This routine closes an output handle. It decrements the screen buffer's
  2527. reference count. If it goes to zero, the buffer is freed. Otherwise,
  2528. the handle is removed from sharing.
  2529. Arguments:
  2530. ProcessData - Pointer to per process data.
  2531. Console - Pointer to console information structure.
  2532. HandleData - Pointer to handle data structure.
  2533. Handle - Handle to close.
  2534. FreeHandle - if TRUE, free handle. used by ReadChars in echo mode
  2535. and by process cleanup.
  2536. Return Value:
  2537. Note:
  2538. The console lock must be held when calling this routine.
  2539. --*/
  2540. {
  2541. NTSTATUS Status;
  2542. ASSERT (HandleData->Buffer.ScreenBuffer->RefCount);
  2543. HandleData->Buffer.ScreenBuffer->RefCount--;
  2544. if (HandleData->Buffer.ScreenBuffer->RefCount == 0) {
  2545. RemoveScreenBuffer(Console,HandleData->Buffer.ScreenBuffer);
  2546. if (HandleData->Buffer.ScreenBuffer == Console->CurrentScreenBuffer &&
  2547. Console->ScreenBuffers != Console->CurrentScreenBuffer) {
  2548. if (Console->ScreenBuffers != NULL) {
  2549. SetActiveScreenBuffer(Console->ScreenBuffers);
  2550. } else {
  2551. Console->CurrentScreenBuffer = NULL;
  2552. }
  2553. }
  2554. Status = FreeScreenBuffer(HandleData->Buffer.ScreenBuffer);
  2555. }
  2556. else {
  2557. Status = ConsoleRemoveShare(HandleData->Access,
  2558. HandleData->ShareAccess,
  2559. &HandleData->Buffer.ScreenBuffer->ShareAccess
  2560. );
  2561. }
  2562. if (FreeHandle)
  2563. Status = FreeIoHandle(ProcessData,Handle);
  2564. return Status;
  2565. }
  2566. ULONG
  2567. SrvCloseHandle(
  2568. IN OUT PCSR_API_MSG m,
  2569. IN OUT PCSR_REPLY_STATUS ReplyStatus
  2570. )
  2571. /*++
  2572. Routine Description:
  2573. This routine closes an input or output handle.
  2574. Arguments:
  2575. ApiMessageData - Points to parameter structure.
  2576. Return Value:
  2577. --*/
  2578. {
  2579. PCONSOLE_CLOSEHANDLE_MSG a = (PCONSOLE_CLOSEHANDLE_MSG)&m->u.ApiMessageData;
  2580. PCONSOLE_INFORMATION Console;
  2581. PHANDLE_DATA HandleData;
  2582. NTSTATUS Status;
  2583. PCONSOLE_PER_PROCESS_DATA ProcessData;
  2584. Status = ApiPreamble(a->ConsoleHandle,
  2585. &Console
  2586. );
  2587. if (!NT_SUCCESS(Status)) {
  2588. return Status;
  2589. }
  2590. ProcessData = CONSOLE_PERPROCESSDATA();
  2591. Status = DereferenceIoHandleNoCheck(ProcessData,
  2592. HANDLE_TO_INDEX(a->Handle),
  2593. &HandleData
  2594. );
  2595. if (NT_SUCCESS(Status)) {
  2596. if (HandleData->HandleType & CONSOLE_INPUT_HANDLE)
  2597. Status = CloseInputHandle(ProcessData,Console,HandleData,HANDLE_TO_INDEX(a->Handle));
  2598. else {
  2599. Status = CloseOutputHandle(ProcessData,Console,HandleData,HANDLE_TO_INDEX(a->Handle),TRUE);
  2600. }
  2601. }
  2602. UnlockConsole(Console);
  2603. return Status;
  2604. UNREFERENCED_PARAMETER(ReplyStatus); // get rid of unreferenced parameter warning message
  2605. }
  2606. NTSTATUS
  2607. WriteCharsFromInput(
  2608. IN PSCREEN_INFORMATION ScreenInfo,
  2609. IN PWCHAR lpBufferBackupLimit,
  2610. IN PWCHAR lpBuffer,
  2611. IN PWCHAR lpString,
  2612. IN OUT PDWORD NumBytes,
  2613. OUT PLONG NumSpaces OPTIONAL,
  2614. IN SHORT OriginalXPosition,
  2615. IN DWORD dwFlags,
  2616. OUT PSHORT ScrollY OPTIONAL
  2617. )
  2618. /*++
  2619. Routine Description:
  2620. This routine converts chars from their true unicode representation
  2621. to the Unicode representation (UnicodeAnsi) that will generate
  2622. the correct glyph given an OEM font and an ANSI translation by GDI.
  2623. It then calls WriteChars.
  2624. Arguments:
  2625. ScreenInfo - Pointer to screen buffer information structure.
  2626. lpBufferBackupLimit - Pointer to beginning of buffer.
  2627. lpBuffer - Pointer to buffer to copy string to. assumed to be at least
  2628. as long as lpString. This pointer is updated to point to the next
  2629. position in the buffer.
  2630. lpString - Pointer to string to write.
  2631. NumBytes - On input, number of bytes to write. On output, number of
  2632. bytes written.
  2633. NumSpaces - On output, the number of spaces consumed by the written characters.
  2634. dwFlags -
  2635. WC_DESTRUCTIVE_BACKSPACE backspace overwrites characters.
  2636. WC_KEEP_CURSOR_VISIBLE change window origin desirable when hit rt. edge
  2637. WC_ECHO if called by Read (echoing characters)
  2638. WC_FALSIFY_UNICODE if RealUnicodeToFalseUnicode need be called.
  2639. Return Value:
  2640. Note:
  2641. This routine does not process tabs and backspace properly. That code
  2642. will be implemented as part of the line editing services.
  2643. --*/
  2644. {
  2645. DWORD Length,i;
  2646. if (ScreenInfo->Flags & CONSOLE_GRAPHICS_BUFFER) {
  2647. return STATUS_UNSUCCESSFUL;
  2648. }
  2649. if (!(ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY) ||
  2650. (ScreenInfo->Console->FullScreenFlags & CONSOLE_FULLSCREEN)) {
  2651. goto SimpleWrite;
  2652. }
  2653. Length = *NumBytes / sizeof(WCHAR);
  2654. for (i=0;i<Length;i++) {
  2655. if (lpString[i] > 0x7f) {
  2656. dwFlags |= WC_FALSIFY_UNICODE;
  2657. break;
  2658. }
  2659. }
  2660. SimpleWrite:
  2661. return WriteChars(ScreenInfo,
  2662. lpBufferBackupLimit,
  2663. lpBuffer,
  2664. lpString,
  2665. NumBytes,
  2666. NumSpaces,
  2667. OriginalXPosition,
  2668. dwFlags,
  2669. ScrollY
  2670. );
  2671. }
  2672. #if defined(FE_SB)
  2673. #define WWSB_NOFE
  2674. #include "dispatch.h"
  2675. #include "_stream.h"
  2676. #undef WWSB_NOFE
  2677. #define WWSB_FE
  2678. #include "dispatch.h"
  2679. #include "_stream.h"
  2680. #undef WWSB_FE
  2681. #endif // FE_SB