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
;
73 NewEntry
.Length
= NewEntry
.MaximumLength
= Console
->LineSize
* sizeof(WCHAR
);
74 NewEntry
.Buffer
= Console
->LineBuffer
;
76 if (!(Hist
= HistoryCurrentBuffer(Console
)))
79 /* Don't add blank or duplicate entries */
80 if (NewEntry
.Length
== 0 || Hist
->MaxEntries
== 0 ||
81 (Hist
->NumEntries
> 0 &&
82 RtlEqualUnicodeString(&Hist
->Entries
[Hist
->NumEntries
- 1], &NewEntry
, FALSE
)))
87 if (Console
->HistoryNoDup
)
89 /* Check if this line has been entered before */
90 for (i
= Hist
->NumEntries
- 1; i
>= 0; i
--)
92 if (RtlEqualUnicodeString(&Hist
->Entries
[i
], &NewEntry
, FALSE
))
94 /* Just rotate the list to bring this entry to the end */
95 NewEntry
= Hist
->Entries
[i
];
96 memmove(&Hist
->Entries
[i
], &Hist
->Entries
[i
+ 1],
97 (Hist
->NumEntries
- (i
+ 1)) * sizeof(UNICODE_STRING
));
98 Hist
->Entries
[Hist
->NumEntries
- 1] = NewEntry
;
99 Hist
->Position
= Hist
->NumEntries
- 1;
105 if (Hist
->NumEntries
== Hist
->MaxEntries
)
107 /* List is full, remove oldest entry */
108 RtlFreeUnicodeString(&Hist
->Entries
[0]);
109 memmove(&Hist
->Entries
[0], &Hist
->Entries
[1],
110 --Hist
->NumEntries
* sizeof(UNICODE_STRING
));
113 if (NT_SUCCESS(RtlDuplicateUnicodeString(0, &NewEntry
, &Hist
->Entries
[Hist
->NumEntries
])))
115 Hist
->Position
= Hist
->NumEntries
- 1;
119 HistoryGetCurrentEntry(PCONSOLE Console
, PUNICODE_STRING Entry
)
121 PHISTORY_BUFFER Hist
;
122 if (!(Hist
= HistoryCurrentBuffer(Console
)) || 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 UINT OldCursorX
= Buffer
->CursorPosition
.X
;
177 UINT 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
;
236 if (!(Hist
= HistoryCurrentBuffer(Console
)) || Hist
->NumEntries
== 0)
239 Offset
+= Hist
->Position
;
240 Offset
= max(Offset
, 0);
241 Offset
= min(Offset
, Hist
->NumEntries
- 1);
242 Hist
->Position
= Offset
;
244 LineInputSetPos(Console
, 0);
245 LineInputEdit(Console
, Console
->LineSize
,
246 Hist
->Entries
[Offset
].Length
/ sizeof(WCHAR
),
247 Hist
->Entries
[Offset
].Buffer
);
251 LineInputKeyDown(PCONSOLE Console
, KEY_EVENT_RECORD
*KeyEvent
)
253 UINT Pos
= Console
->LinePos
;
254 PHISTORY_BUFFER Hist
;
255 UNICODE_STRING Entry
;
258 switch (KeyEvent
->wVirtualKeyCode
)
261 /* Clear entire line */
262 LineInputSetPos(Console
, 0);
263 LineInputEdit(Console
, Console
->LineSize
, 0, NULL
);
266 /* Move to start of line. With ctrl, erase everything left of cursor */
267 LineInputSetPos(Console
, 0);
268 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
269 LineInputEdit(Console
, Pos
, 0, NULL
);
272 /* Move to end of line. With ctrl, erase everything right of cursor */
273 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
274 LineInputEdit(Console
, Console
->LineSize
- Pos
, 0, NULL
);
276 LineInputSetPos(Console
, Console
->LineSize
);
279 /* Move left. With ctrl, move to beginning of previous word */
280 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
282 while (Pos
> 0 && Console
->LineBuffer
[Pos
- 1] == L
' ') Pos
--;
283 while (Pos
> 0 && Console
->LineBuffer
[Pos
- 1] != L
' ') Pos
--;
289 LineInputSetPos(Console
, Pos
);
293 /* Move right. With ctrl, move to beginning of next word */
294 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
296 while (Pos
< Console
->LineSize
&& Console
->LineBuffer
[Pos
] != L
' ') Pos
++;
297 while (Pos
< Console
->LineSize
&& Console
->LineBuffer
[Pos
] == L
' ') Pos
++;
298 LineInputSetPos(Console
, Pos
);
303 /* Recall one character (but don't overwrite current line) */
304 HistoryGetCurrentEntry(Console
, &Entry
);
305 if (Pos
< Console
->LineSize
)
306 LineInputSetPos(Console
, Pos
+ 1);
307 else if (Pos
* sizeof(WCHAR
) < Entry
.Length
)
308 LineInputEdit(Console
, 0, 1, &Entry
.Buffer
[Pos
]);
312 /* Toggle between insert and overstrike */
313 Console
->LineInsertToggle
= !Console
->LineInsertToggle
;
314 ConioSetCursorInfo(Console
, Console
->ActiveBuffer
);
317 /* Remove character to right of cursor */
318 if (Pos
!= Console
->LineSize
)
319 LineInputEdit(Console
, 1, 0, NULL
);
322 /* Recall first history entry */
323 LineInputRecallHistory(Console
, -((WORD
)-1));
326 /* Recall last history entry */
327 LineInputRecallHistory(Console
, +((WORD
)-1));
331 /* Recall previous history entry. On first time, actually recall the
332 * current (usually last) entry; on subsequent times go back. */
333 LineInputRecallHistory(Console
, Console
->LineUpPressed
? -1 : 0);
334 Console
->LineUpPressed
= TRUE
;
337 /* Recall next history entry */
338 LineInputRecallHistory(Console
, +1);
341 /* Recall remainder of current history entry */
342 HistoryGetCurrentEntry(Console
, &Entry
);
343 if (Pos
* sizeof(WCHAR
) < Entry
.Length
)
345 UINT InsertSize
= (Entry
.Length
/ sizeof(WCHAR
) - Pos
);
346 UINT DeleteSize
= min(Console
->LineSize
- Pos
, InsertSize
);
347 LineInputEdit(Console
, DeleteSize
, InsertSize
, &Entry
.Buffer
[Pos
]);
351 /* Insert a ^Z character */
352 KeyEvent
->uChar
.UnicodeChar
= 26;
355 if (KeyEvent
->dwControlKeyState
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
))
356 HistoryDeleteBuffer(HistoryCurrentBuffer(Console
));
359 /* Search for history entries starting with input. */
360 if (!(Hist
= HistoryCurrentBuffer(Console
)) || Hist
->NumEntries
== 0)
363 /* Like Up/F5, on first time start from current (usually last) entry,
364 * but on subsequent times start at previous entry. */
365 if (Console
->LineUpPressed
)
366 Hist
->Position
= (Hist
->Position
? Hist
->Position
: Hist
->NumEntries
) - 1;
367 Console
->LineUpPressed
= TRUE
;
369 Entry
.Length
= Console
->LinePos
* sizeof(WCHAR
);
370 Entry
.Buffer
= Console
->LineBuffer
;
372 /* Keep going backwards, even wrapping around to the end,
373 * until we get back to starting point */
374 HistPos
= Hist
->Position
;
377 if (RtlPrefixUnicodeString(&Entry
, &Hist
->Entries
[HistPos
], FALSE
))
379 Hist
->Position
= HistPos
;
380 LineInputEdit(Console
, Console
->LineSize
- Pos
,
381 Hist
->Entries
[HistPos
].Length
/ sizeof(WCHAR
) - Pos
,
382 &Hist
->Entries
[HistPos
].Buffer
[Pos
]);
383 /* Cursor stays where it was */
384 LineInputSetPos(Console
, Pos
);
387 if (--HistPos
< 0) HistPos
+= Hist
->NumEntries
;
388 } while (HistPos
!= Hist
->Position
);
392 if (KeyEvent
->uChar
.UnicodeChar
== L
'\b' && Console
->InputBuffer
.Mode
& ENABLE_PROCESSED_INPUT
)
394 /* backspace handling - if processed input enabled then we handle it here
395 * otherwise we treat it like a normal char. */
398 LineInputSetPos(Console
, Pos
- 1);
399 LineInputEdit(Console
, 1, 0, NULL
);
402 else if (KeyEvent
->uChar
.UnicodeChar
== L
'\r')
404 HistoryAddEntry(Console
);
406 /* TODO: Expand aliases */
408 LineInputSetPos(Console
, Console
->LineSize
);
409 Console
->LineBuffer
[Console
->LineSize
++] = L
'\r';
410 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
411 ConioWriteConsole(Console
, Console
->ActiveBuffer
, "\r", 1, TRUE
);
413 /* Add \n if processed input. There should usually be room for it,
414 * but an exception to the rule exists: the buffer could have been
415 * pre-filled with LineMaxSize - 1 characters. */
416 if (Console
->InputBuffer
.Mode
& ENABLE_PROCESSED_INPUT
&&
417 Console
->LineSize
< Console
->LineMaxSize
)
419 Console
->LineBuffer
[Console
->LineSize
++] = L
'\n';
420 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
421 ConioWriteConsole(Console
, Console
->ActiveBuffer
, "\n", 1, TRUE
);
423 Console
->LineComplete
= TRUE
;
424 Console
->LinePos
= 0;
426 else if (KeyEvent
->uChar
.UnicodeChar
!= L
'\0')
428 if (KeyEvent
->uChar
.UnicodeChar
< 0x20 &&
429 Console
->LineWakeupMask
& (1 << KeyEvent
->uChar
.UnicodeChar
))
431 /* Control key client wants to handle itself (e.g. for tab completion) */
432 Console
->LineBuffer
[Console
->LineSize
++] = L
' ';
433 Console
->LineBuffer
[Console
->LinePos
] = KeyEvent
->uChar
.UnicodeChar
;
434 Console
->LineComplete
= TRUE
;
435 Console
->LinePos
= 0;
439 /* Normal character */
440 BOOL Overstrike
= Console
->LineInsertToggle
&& Console
->LinePos
!= Console
->LineSize
;
441 LineInputEdit(Console
, Overstrike
, 1, &KeyEvent
->uChar
.UnicodeChar
);
447 /* PUBLIC SERVER APIS *********************************************************/
449 CSR_API(SrvGetConsoleCommandHistory
)
451 PCONSOLE_GETCOMMANDHISTORY GetCommandHistoryRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetCommandHistoryRequest
;
452 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
455 PHISTORY_BUFFER Hist
;
456 PBYTE Buffer
= (PBYTE
)GetCommandHistoryRequest
->History
;
457 ULONG BufferSize
= GetCommandHistoryRequest
->Length
;
460 if ( !CsrValidateMessageBuffer(ApiMessage
,
461 (PVOID
*)&GetCommandHistoryRequest
->History
,
462 GetCommandHistoryRequest
->Length
,
464 !CsrValidateMessageBuffer(ApiMessage
,
465 (PVOID
*)&GetCommandHistoryRequest
->ExeName
.Buffer
,
466 GetCommandHistoryRequest
->ExeName
.Length
,
469 return STATUS_INVALID_PARAMETER
;
472 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
473 if (NT_SUCCESS(Status
))
475 Hist
= HistoryFindBuffer(Console
, &GetCommandHistoryRequest
->ExeName
);
478 for (i
= 0; i
< Hist
->NumEntries
; i
++)
480 if (BufferSize
< (Hist
->Entries
[i
].Length
+ sizeof(WCHAR
)))
482 Status
= STATUS_BUFFER_OVERFLOW
;
485 memcpy(Buffer
, Hist
->Entries
[i
].Buffer
, Hist
->Entries
[i
].Length
);
486 Buffer
+= Hist
->Entries
[i
].Length
;
487 *(PWCHAR
)Buffer
= L
'\0';
488 Buffer
+= sizeof(WCHAR
);
491 GetCommandHistoryRequest
->Length
= Buffer
- (PBYTE
)GetCommandHistoryRequest
->History
;
492 ConSrvReleaseConsole(Console
, TRUE
);
497 CSR_API(SrvGetConsoleCommandHistoryLength
)
499 PCONSOLE_GETCOMMANDHISTORYLENGTH GetCommandHistoryLengthRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetCommandHistoryLengthRequest
;
500 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
503 PHISTORY_BUFFER Hist
;
507 if (!CsrValidateMessageBuffer(ApiMessage
,
508 (PVOID
*)&GetCommandHistoryLengthRequest
->ExeName
.Buffer
,
509 GetCommandHistoryLengthRequest
->ExeName
.Length
,
512 return STATUS_INVALID_PARAMETER
;
515 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
516 if (NT_SUCCESS(Status
))
518 Hist
= HistoryFindBuffer(Console
, &GetCommandHistoryLengthRequest
->ExeName
);
521 for (i
= 0; i
< Hist
->NumEntries
; i
++)
522 Length
+= Hist
->Entries
[i
].Length
+ sizeof(WCHAR
);
524 GetCommandHistoryLengthRequest
->Length
= Length
;
525 ConSrvReleaseConsole(Console
, TRUE
);
530 CSR_API(SrvExpungeConsoleCommandHistory
)
532 PCONSOLE_EXPUNGECOMMANDHISTORY ExpungeCommandHistoryRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ExpungeCommandHistoryRequest
;
533 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
535 PHISTORY_BUFFER Hist
;
538 if (!CsrValidateMessageBuffer(ApiMessage
,
539 (PVOID
*)&ExpungeCommandHistoryRequest
->ExeName
.Buffer
,
540 ExpungeCommandHistoryRequest
->ExeName
.Length
,
543 return STATUS_INVALID_PARAMETER
;
546 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
547 if (NT_SUCCESS(Status
))
549 Hist
= HistoryFindBuffer(Console
, &ExpungeCommandHistoryRequest
->ExeName
);
550 HistoryDeleteBuffer(Hist
);
551 ConSrvReleaseConsole(Console
, TRUE
);
556 CSR_API(SrvSetConsoleNumberOfCommands
)
558 PCONSOLE_SETHISTORYNUMBERCOMMANDS SetHistoryNumberCommandsRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetHistoryNumberCommandsRequest
;
559 PCONSOLE_PROCESS_DATA ProcessData
= ConsoleGetPerProcessData(CsrGetClientThread()->Process
);
561 PHISTORY_BUFFER Hist
;
563 UINT MaxEntries
= SetHistoryNumberCommandsRequest
->NumCommands
;
564 PUNICODE_STRING OldEntryList
, NewEntryList
;
566 if (!CsrValidateMessageBuffer(ApiMessage
,
567 (PVOID
*)&SetHistoryNumberCommandsRequest
->ExeName
.Buffer
,
568 SetHistoryNumberCommandsRequest
->ExeName
.Length
,
571 return STATUS_INVALID_PARAMETER
;
574 Status
= ConSrvGetConsole(ProcessData
, &Console
, TRUE
);
575 if (NT_SUCCESS(Status
))
577 Hist
= HistoryFindBuffer(Console
, &SetHistoryNumberCommandsRequest
->ExeName
);
580 OldEntryList
= Hist
->Entries
;
581 NewEntryList
= RtlAllocateHeap(ConSrvHeap
, 0,
582 MaxEntries
* sizeof(UNICODE_STRING
));
585 Status
= STATUS_NO_MEMORY
;
589 /* If necessary, shrink by removing oldest entries */
590 for (; Hist
->NumEntries
> MaxEntries
; Hist
->NumEntries
--)
592 RtlFreeUnicodeString(Hist
->Entries
++);
593 Hist
->Position
+= (Hist
->Position
== 0);
596 Hist
->MaxEntries
= MaxEntries
;
597 Hist
->Entries
= memcpy(NewEntryList
, Hist
->Entries
,
598 Hist
->NumEntries
* sizeof(UNICODE_STRING
));
599 RtlFreeHeap(ConSrvHeap
, 0, OldEntryList
);
602 ConSrvReleaseConsole(Console
, TRUE
);
607 CSR_API(SrvGetConsoleHistory
)
609 PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HistoryInfoRequest
;
611 NTSTATUS Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
612 if (NT_SUCCESS(Status
))
614 HistoryInfoRequest
->HistoryBufferSize
= Console
->HistoryBufferSize
;
615 HistoryInfoRequest
->NumberOfHistoryBuffers
= Console
->NumberOfHistoryBuffers
;
616 HistoryInfoRequest
->dwFlags
= Console
->HistoryNoDup
;
617 ConSrvReleaseConsole(Console
, TRUE
);
622 CSR_API(SrvSetConsoleHistory
)
624 PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HistoryInfoRequest
;
626 NTSTATUS Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
627 if (NT_SUCCESS(Status
))
629 Console
->HistoryBufferSize
= HistoryInfoRequest
->HistoryBufferSize
;
630 Console
->NumberOfHistoryBuffers
= HistoryInfoRequest
->NumberOfHistoryBuffers
;
631 Console
->HistoryNoDup
= HistoryInfoRequest
->dwFlags
& HISTORY_NO_DUP_FLAG
;
632 ConSrvReleaseConsole(Console
, TRUE
);