2 * LICENSE: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/lineinput.c
5 * PURPOSE: Console line input functions
6 * PROGRAMMERS: Jeffrey Morlan
9 /* INCLUDES *******************************************************************/
13 #include "include/conio.h"
19 typedef struct _HISTORY_BUFFER
25 PUNICODE_STRING Entries
;
26 UNICODE_STRING ExeName
;
27 } HISTORY_BUFFER
, *PHISTORY_BUFFER
;
30 /* PRIVATE FUNCTIONS **********************************************************/
32 static PHISTORY_BUFFER
33 HistoryCurrentBuffer(PCONSOLE Console
)
35 /* TODO: use actual EXE name sent from process that called ReadConsole */
36 UNICODE_STRING ExeName
= { 14, 14, L
"cmd.exe" };
37 PLIST_ENTRY Entry
= Console
->HistoryBuffers
.Flink
;
40 for (; Entry
!= &Console
->HistoryBuffers
; Entry
= Entry
->Flink
)
42 Hist
= CONTAINING_RECORD(Entry
, HISTORY_BUFFER
, ListEntry
);
43 if (RtlEqualUnicodeString(&ExeName
, &Hist
->ExeName
, FALSE
))
47 /* Couldn't find the buffer, create a new one */
48 Hist
= RtlAllocateHeap(ConSrvHeap
, 0, sizeof(HISTORY_BUFFER
) + ExeName
.Length
);
51 Hist
->MaxEntries
= Console
->HistoryBufferSize
;
53 Hist
->Entries
= RtlAllocateHeap(ConSrvHeap
, 0, Hist
->MaxEntries
* sizeof(UNICODE_STRING
));
56 RtlFreeHeap(ConSrvHeap
, 0, Hist
);
59 Hist
->ExeName
.Length
= Hist
->ExeName
.MaximumLength
= ExeName
.Length
;
60 Hist
->ExeName
.Buffer
= (PWCHAR
)(Hist
+ 1);
61 memcpy(Hist
->ExeName
.Buffer
, ExeName
.Buffer
, ExeName
.Length
);
62 InsertHeadList(&Console
->HistoryBuffers
, &Hist
->ListEntry
);
67 HistoryAddEntry(PCONSOLE Console
)
69 UNICODE_STRING NewEntry
;
70 PHISTORY_BUFFER Hist
= HistoryCurrentBuffer(Console
);
75 NewEntry
.Length
= NewEntry
.MaximumLength
= Console
->LineSize
* sizeof(WCHAR
);
76 NewEntry
.Buffer
= Console
->LineBuffer
;
78 /* Don't add blank or duplicate entries */
79 if (NewEntry
.Length
== 0 || Hist
->MaxEntries
== 0 ||
80 (Hist
->NumEntries
> 0 &&
81 RtlEqualUnicodeString(&Hist
->Entries
[Hist
->NumEntries
- 1], &NewEntry
, FALSE
)))
86 if (Console
->HistoryNoDup
)
88 /* Check if this line has been entered before */
89 for (i
= Hist
->NumEntries
- 1; i
>= 0; i
--)
91 if (RtlEqualUnicodeString(&Hist
->Entries
[i
], &NewEntry
, FALSE
))
93 /* Just rotate the list to bring this entry to the end */
94 NewEntry
= Hist
->Entries
[i
];
95 memmove(&Hist
->Entries
[i
], &Hist
->Entries
[i
+ 1],
96 (Hist
->NumEntries
- (i
+ 1)) * sizeof(UNICODE_STRING
));
97 Hist
->Entries
[Hist
->NumEntries
- 1] = NewEntry
;
98 Hist
->Position
= Hist
->NumEntries
- 1;
104 if (Hist
->NumEntries
== Hist
->MaxEntries
)
106 /* List is full, remove oldest entry */
107 RtlFreeUnicodeString(&Hist
->Entries
[0]);
108 memmove(&Hist
->Entries
[0], &Hist
->Entries
[1],
109 --Hist
->NumEntries
* sizeof(UNICODE_STRING
));
112 if (NT_SUCCESS(RtlDuplicateUnicodeString(0, &NewEntry
, &Hist
->Entries
[Hist
->NumEntries
])))
114 Hist
->Position
= Hist
->NumEntries
- 1;
118 HistoryGetCurrentEntry(PCONSOLE Console
, PUNICODE_STRING Entry
)
120 PHISTORY_BUFFER Hist
= HistoryCurrentBuffer(Console
);
122 if (!Hist
|| Hist
->NumEntries
== 0)
125 *Entry
= Hist
->Entries
[Hist
->Position
];
128 static PHISTORY_BUFFER
129 HistoryFindBuffer(PCONSOLE Console
, PUNICODE_STRING ExeName
)
131 PLIST_ENTRY Entry
= Console
->HistoryBuffers
.Flink
;
132 while (Entry
!= &Console
->HistoryBuffers
)
134 /* For the history APIs, the caller is allowed to give only part of the name */
135 PHISTORY_BUFFER Hist
= CONTAINING_RECORD(Entry
, HISTORY_BUFFER
, ListEntry
);
136 if (RtlPrefixUnicodeString(ExeName
, &Hist
->ExeName
, TRUE
))
138 Entry
= Entry
->Flink
;
144 HistoryDeleteBuffer(PHISTORY_BUFFER Hist
)
148 while (Hist
->NumEntries
!= 0)
149 RtlFreeUnicodeString(&Hist
->Entries
[--Hist
->NumEntries
]);
151 RtlFreeHeap(ConSrvHeap
, 0, Hist
->Entries
);
152 RemoveEntryList(&Hist
->ListEntry
);
153 RtlFreeHeap(ConSrvHeap
, 0, Hist
);
157 HistoryDeleteBuffers(PCONSOLE Console
)
159 PLIST_ENTRY CurrentEntry
;
160 PHISTORY_BUFFER HistoryBuffer
;
162 while (!IsListEmpty(&Console
->HistoryBuffers
))
164 CurrentEntry
= RemoveHeadList(&Console
->HistoryBuffers
);
165 HistoryBuffer
= CONTAINING_RECORD(CurrentEntry
, HISTORY_BUFFER
, ListEntry
);
166 HistoryDeleteBuffer(HistoryBuffer
);
171 LineInputSetPos(PCONSOLE Console
, UINT Pos
)
173 if (Pos
!= Console
->LinePos
&& Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
175 PCONSOLE_SCREEN_BUFFER Buffer
= Console
->ActiveBuffer
;
176 SHORT OldCursorX
= Buffer
->CursorPosition
.X
;
177 SHORT OldCursorY
= Buffer
->CursorPosition
.Y
;
178 INT XY
= OldCursorY
* Buffer
->ScreenBufferSize
.X
+ OldCursorX
;
180 XY
+= (Pos
- Console
->LinePos
);
183 else if (XY
>= Buffer
->ScreenBufferSize
.Y
* Buffer
->ScreenBufferSize
.X
)
184 XY
= Buffer
->ScreenBufferSize
.Y
* Buffer
->ScreenBufferSize
.X
- 1;
186 Buffer
->CursorPosition
.X
= XY
% Buffer
->ScreenBufferSize
.X
;
187 Buffer
->CursorPosition
.Y
= XY
/ Buffer
->ScreenBufferSize
.X
;
188 ConioSetScreenInfo(Console
, Buffer
, OldCursorX
, OldCursorY
);
191 Console
->LinePos
= Pos
;
195 LineInputEdit(PCONSOLE Console
, UINT NumToDelete
, UINT NumToInsert
, WCHAR
*Insertion
)
197 UINT Pos
= Console
->LinePos
;
198 UINT NewSize
= Console
->LineSize
- NumToDelete
+ NumToInsert
;
201 /* Make sure there's always enough room for ending \r\n */
202 if (NewSize
+ 2 > Console
->LineMaxSize
)
205 memmove(&Console
->LineBuffer
[Pos
+ NumToInsert
],
206 &Console
->LineBuffer
[Pos
+ NumToDelete
],
207 (Console
->LineSize
- (Pos
+ NumToDelete
)) * sizeof(WCHAR
));
208 memcpy(&Console
->LineBuffer
[Pos
], Insertion
, NumToInsert
* sizeof(WCHAR
));
210 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
212 for (i
= Pos
; i
< NewSize
; i
++)
215 WideCharToMultiByte(Console
->OutputCodePage
, 0,
216 &Console
->LineBuffer
[i
], 1,
217 &AsciiChar
, 1, NULL
, NULL
);
218 ConioWriteConsole(Console
, Console
->ActiveBuffer
, &AsciiChar
, 1, TRUE
);
220 for (; i
< Console
->LineSize
; i
++)
222 ConioWriteConsole(Console
, Console
->ActiveBuffer
, " ", 1, TRUE
);
224 Console
->LinePos
= i
;
227 Console
->LineSize
= NewSize
;
228 LineInputSetPos(Console
, Pos
+ NumToInsert
);
232 LineInputRecallHistory(PCONSOLE Console
, INT Offset
)
234 PHISTORY_BUFFER Hist
= HistoryCurrentBuffer(Console
);
237 if (!Hist
|| Hist
->NumEntries
== 0) return;
239 Position
= Hist
->Position
+ Offset
;
240 Position
= min(max(Position
, 0), Hist
->NumEntries
- 1);
241 Hist
->Position
= Position
;
243 LineInputSetPos(Console
, 0);
244 LineInputEdit(Console
, Console
->LineSize
,
245 Hist
->Entries
[Hist
->Position
].Length
/ sizeof(WCHAR
),
246 Hist
->Entries
[Hist
->Position
].Buffer
);
250 LineInputKeyDown(PCONSOLE Console
, KEY_EVENT_RECORD
*KeyEvent
)
252 UINT Pos
= Console
->LinePos
;
253 PHISTORY_BUFFER Hist
;
254 UNICODE_STRING Entry
;
257 switch (KeyEvent
->wVirtualKeyCode
)
260 /* Clear entire line */
261 LineInputSetPos(Console
, 0);
262 LineInputEdit(Console
, Console
->LineSize
, 0, NULL
);
265 /* Move to start of line. With ctrl, erase everything left of cursor */
266 LineInputSetPos(Console
, 0);
267 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
268 LineInputEdit(Console
, Pos
, 0, NULL
);
271 /* Move to end of line. With ctrl, erase everything right of cursor */
272 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
273 LineInputEdit(Console
, Console
->LineSize
- Pos
, 0, NULL
);
275 LineInputSetPos(Console
, Console
->LineSize
);
278 /* Move left. With ctrl, move to beginning of previous word */
279 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
281 while (Pos
> 0 && Console
->LineBuffer
[Pos
- 1] == L
' ') Pos
--;
282 while (Pos
> 0 && Console
->LineBuffer
[Pos
- 1] != L
' ') Pos
--;
288 LineInputSetPos(Console
, Pos
);
292 /* Move right. With ctrl, move to beginning of next word */
293 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
295 while (Pos
< Console
->LineSize
&& Console
->LineBuffer
[Pos
] != L
' ') Pos
++;
296 while (Pos
< Console
->LineSize
&& Console
->LineBuffer
[Pos
] == L
' ') Pos
++;
297 LineInputSetPos(Console
, Pos
);
302 /* Recall one character (but don't overwrite current line) */
303 HistoryGetCurrentEntry(Console
, &Entry
);
304 if (Pos
< Console
->LineSize
)
305 LineInputSetPos(Console
, Pos
+ 1);
306 else if (Pos
* sizeof(WCHAR
) < Entry
.Length
)
307 LineInputEdit(Console
, 0, 1, &Entry
.Buffer
[Pos
]);
311 /* Toggle between insert and overstrike */
312 Console
->LineInsertToggle
= !Console
->LineInsertToggle
;
313 ConioSetCursorInfo(Console
, Console
->ActiveBuffer
);
316 /* Remove character to right of cursor */
317 if (Pos
!= Console
->LineSize
)
318 LineInputEdit(Console
, 1, 0, NULL
);
321 /* Recall first history entry */
322 LineInputRecallHistory(Console
, -((WORD
)-1));
325 /* Recall last history entry */
326 LineInputRecallHistory(Console
, +((WORD
)-1));
330 /* Recall previous history entry. On first time, actually recall the
331 * current (usually last) entry; on subsequent times go back. */
332 LineInputRecallHistory(Console
, Console
->LineUpPressed
? -1 : 0);
333 Console
->LineUpPressed
= TRUE
;
336 /* Recall next history entry */
337 LineInputRecallHistory(Console
, +1);
340 /* Recall remainder of current history entry */
341 HistoryGetCurrentEntry(Console
, &Entry
);
342 if (Pos
* sizeof(WCHAR
) < Entry
.Length
)
344 UINT InsertSize
= (Entry
.Length
/ sizeof(WCHAR
) - Pos
);
345 UINT DeleteSize
= min(Console
->LineSize
- Pos
, InsertSize
);
346 LineInputEdit(Console
, DeleteSize
, InsertSize
, &Entry
.Buffer
[Pos
]);
350 /* Insert a ^Z character */
351 KeyEvent
->uChar
.UnicodeChar
= 26;
354 if (KeyEvent
->dwControlKeyState
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
))
355 HistoryDeleteBuffer(HistoryCurrentBuffer(Console
));
358 /* Search for history entries starting with input. */
359 Hist
= HistoryCurrentBuffer(Console
);
360 if (!Hist
|| Hist
->NumEntries
== 0) return;
362 /* Like Up/F5, on first time start from current (usually last) entry,
363 * but on subsequent times start at previous entry. */
364 if (Console
->LineUpPressed
)
365 Hist
->Position
= (Hist
->Position
? Hist
->Position
: Hist
->NumEntries
) - 1;
366 Console
->LineUpPressed
= TRUE
;
368 Entry
.Length
= Console
->LinePos
* sizeof(WCHAR
);
369 Entry
.Buffer
= Console
->LineBuffer
;
371 /* Keep going backwards, even wrapping around to the end,
372 * until we get back to starting point */
373 HistPos
= Hist
->Position
;
376 if (RtlPrefixUnicodeString(&Entry
, &Hist
->Entries
[HistPos
], FALSE
))
378 Hist
->Position
= HistPos
;
379 LineInputEdit(Console
, Console
->LineSize
- Pos
,
380 Hist
->Entries
[HistPos
].Length
/ sizeof(WCHAR
) - Pos
,
381 &Hist
->Entries
[HistPos
].Buffer
[Pos
]);
382 /* Cursor stays where it was */
383 LineInputSetPos(Console
, Pos
);
386 if (--HistPos
< 0) HistPos
+= Hist
->NumEntries
;
387 } while (HistPos
!= Hist
->Position
);
391 if (KeyEvent
->uChar
.UnicodeChar
== L
'\b' && Console
->InputBuffer
.Mode
& ENABLE_PROCESSED_INPUT
)
393 /* backspace handling - if processed input enabled then we handle it here
394 * otherwise we treat it like a normal char. */
397 LineInputSetPos(Console
, Pos
- 1);
398 LineInputEdit(Console
, 1, 0, NULL
);
401 else if (KeyEvent
->uChar
.UnicodeChar
== L
'\r')
403 HistoryAddEntry(Console
);
405 /* TODO: Expand aliases */
407 LineInputSetPos(Console
, Console
->LineSize
);
408 Console
->LineBuffer
[Console
->LineSize
++] = L
'\r';
409 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
410 ConioWriteConsole(Console
, Console
->ActiveBuffer
, "\r", 1, TRUE
);
412 /* Add \n if processed input. There should usually be room for it,
413 * but an exception to the rule exists: the buffer could have been
414 * pre-filled with LineMaxSize - 1 characters. */
415 if (Console
->InputBuffer
.Mode
& ENABLE_PROCESSED_INPUT
&&
416 Console
->LineSize
< Console
->LineMaxSize
)
418 Console
->LineBuffer
[Console
->LineSize
++] = L
'\n';
419 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
420 ConioWriteConsole(Console
, Console
->ActiveBuffer
, "\n", 1, TRUE
);
422 Console
->LineComplete
= TRUE
;
423 Console
->LinePos
= 0;
425 else if (KeyEvent
->uChar
.UnicodeChar
!= L
'\0')
427 if (KeyEvent
->uChar
.UnicodeChar
< 0x20 &&
428 Console
->LineWakeupMask
& (1 << KeyEvent
->uChar
.UnicodeChar
))
430 /* Control key client wants to handle itself (e.g. for tab completion) */
431 Console
->LineBuffer
[Console
->LineSize
++] = L
' ';
432 Console
->LineBuffer
[Console
->LinePos
] = KeyEvent
->uChar
.UnicodeChar
;
433 Console
->LineComplete
= TRUE
;
434 Console
->LinePos
= 0;
438 /* Normal character */
439 BOOL Overstrike
= Console
->LineInsertToggle
&& Console
->LinePos
!= Console
->LineSize
;
440 LineInputEdit(Console
, Overstrike
, 1, &KeyEvent
->uChar
.UnicodeChar
);
446 /* PUBLIC SERVER APIS *********************************************************/
448 CSR_API(SrvGetConsoleCommandHistory
)
450 PCONSOLE_GETCOMMANDHISTORY GetCommandHistoryRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetCommandHistoryRequest
;
451 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
454 PHISTORY_BUFFER Hist
;
455 PBYTE Buffer
= (PBYTE
)GetCommandHistoryRequest
->History
;
456 ULONG BufferSize
= GetCommandHistoryRequest
->Length
;
459 if ( !CsrValidateMessageBuffer(ApiMessage
,
460 (PVOID
*)&GetCommandHistoryRequest
->History
,
461 GetCommandHistoryRequest
->Length
,
463 !CsrValidateMessageBuffer(ApiMessage
,
464 (PVOID
*)&GetCommandHistoryRequest
->ExeName
.Buffer
,
465 GetCommandHistoryRequest
->ExeName
.Length
,
468 return STATUS_INVALID_PARAMETER
;
471 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
472 if (NT_SUCCESS(Status
))
474 Hist
= HistoryFindBuffer(Console
, &GetCommandHistoryRequest
->ExeName
);
477 for (i
= 0; i
< Hist
->NumEntries
; i
++)
479 if (BufferSize
< (Hist
->Entries
[i
].Length
+ sizeof(WCHAR
)))
481 Status
= STATUS_BUFFER_OVERFLOW
;
484 memcpy(Buffer
, Hist
->Entries
[i
].Buffer
, Hist
->Entries
[i
].Length
);
485 Buffer
+= Hist
->Entries
[i
].Length
;
486 *(PWCHAR
)Buffer
= L
'\0';
487 Buffer
+= sizeof(WCHAR
);
490 GetCommandHistoryRequest
->Length
= Buffer
- (PBYTE
)GetCommandHistoryRequest
->History
;
491 ConSrvReleaseConsole(Console
, TRUE
);
496 CSR_API(SrvGetConsoleCommandHistoryLength
)
498 PCONSOLE_GETCOMMANDHISTORYLENGTH GetCommandHistoryLengthRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetCommandHistoryLengthRequest
;
499 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
502 PHISTORY_BUFFER Hist
;
506 if (!CsrValidateMessageBuffer(ApiMessage
,
507 (PVOID
*)&GetCommandHistoryLengthRequest
->ExeName
.Buffer
,
508 GetCommandHistoryLengthRequest
->ExeName
.Length
,
511 return STATUS_INVALID_PARAMETER
;
514 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
515 if (NT_SUCCESS(Status
))
517 Hist
= HistoryFindBuffer(Console
, &GetCommandHistoryLengthRequest
->ExeName
);
520 for (i
= 0; i
< Hist
->NumEntries
; i
++)
521 Length
+= Hist
->Entries
[i
].Length
+ sizeof(WCHAR
);
523 GetCommandHistoryLengthRequest
->Length
= Length
;
524 ConSrvReleaseConsole(Console
, TRUE
);
529 CSR_API(SrvExpungeConsoleCommandHistory
)
531 PCONSOLE_EXPUNGECOMMANDHISTORY ExpungeCommandHistoryRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ExpungeCommandHistoryRequest
;
532 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
534 PHISTORY_BUFFER Hist
;
537 if (!CsrValidateMessageBuffer(ApiMessage
,
538 (PVOID
*)&ExpungeCommandHistoryRequest
->ExeName
.Buffer
,
539 ExpungeCommandHistoryRequest
->ExeName
.Length
,
542 return STATUS_INVALID_PARAMETER
;
545 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
546 if (NT_SUCCESS(Status
))
548 Hist
= HistoryFindBuffer(Console
, &ExpungeCommandHistoryRequest
->ExeName
);
549 HistoryDeleteBuffer(Hist
);
550 ConSrvReleaseConsole(Console
, TRUE
);
555 CSR_API(SrvSetConsoleNumberOfCommands
)
557 PCONSOLE_SETHISTORYNUMBERCOMMANDS SetHistoryNumberCommandsRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetHistoryNumberCommandsRequest
;
558 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
560 PHISTORY_BUFFER Hist
;
562 UINT MaxEntries
= SetHistoryNumberCommandsRequest
->NumCommands
;
563 PUNICODE_STRING OldEntryList
, NewEntryList
;
565 if (!CsrValidateMessageBuffer(ApiMessage
,
566 (PVOID
*)&SetHistoryNumberCommandsRequest
->ExeName
.Buffer
,
567 SetHistoryNumberCommandsRequest
->ExeName
.Length
,
570 return STATUS_INVALID_PARAMETER
;
573 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
574 if (NT_SUCCESS(Status
))
576 Hist
= HistoryFindBuffer(Console
, &SetHistoryNumberCommandsRequest
->ExeName
);
579 OldEntryList
= Hist
->Entries
;
580 NewEntryList
= RtlAllocateHeap(ConSrvHeap
, 0,
581 MaxEntries
* sizeof(UNICODE_STRING
));
584 Status
= STATUS_NO_MEMORY
;
588 /* If necessary, shrink by removing oldest entries */
589 for (; Hist
->NumEntries
> MaxEntries
; Hist
->NumEntries
--)
591 RtlFreeUnicodeString(Hist
->Entries
++);
592 Hist
->Position
+= (Hist
->Position
== 0);
595 Hist
->MaxEntries
= MaxEntries
;
596 Hist
->Entries
= memcpy(NewEntryList
, Hist
->Entries
,
597 Hist
->NumEntries
* sizeof(UNICODE_STRING
));
598 RtlFreeHeap(ConSrvHeap
, 0, OldEntryList
);
601 ConSrvReleaseConsole(Console
, TRUE
);
606 CSR_API(SrvGetConsoleHistory
)
608 PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HistoryInfoRequest
;
610 NTSTATUS Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
611 if (NT_SUCCESS(Status
))
613 HistoryInfoRequest
->HistoryBufferSize
= Console
->HistoryBufferSize
;
614 HistoryInfoRequest
->NumberOfHistoryBuffers
= Console
->NumberOfHistoryBuffers
;
615 HistoryInfoRequest
->dwFlags
= Console
->HistoryNoDup
;
616 ConSrvReleaseConsole(Console
, TRUE
);
621 CSR_API(SrvSetConsoleHistory
)
623 PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HistoryInfoRequest
;
625 NTSTATUS Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
626 if (NT_SUCCESS(Status
))
628 Console
->HistoryBufferSize
= HistoryInfoRequest
->HistoryBufferSize
;
629 Console
->NumberOfHistoryBuffers
= HistoryInfoRequest
->NumberOfHistoryBuffers
;
630 Console
->HistoryNoDup
= HistoryInfoRequest
->dwFlags
& HISTORY_NO_DUP_FLAG
;
631 ConSrvReleaseConsole(Console
, TRUE
);