2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/kernel32/client/console/readwrite.c
5 * PURPOSE: Win32 Console Client read-write functions
6 * PROGRAMMERS: Emanuele Aliberti
8 * Filip Navara (xnavara@volny.cz)
9 * Thomas Weidenmueller (w3seek@reactos.org)
13 /* INCLUDES *******************************************************************/
21 /* See consrv/include/rect.h */
22 #define ConioRectHeight(Rect) \
23 (((Rect)->Top > (Rect)->Bottom) ? 0 : ((Rect)->Bottom - (Rect)->Top + 1))
24 #define ConioRectWidth(Rect) \
25 (((Rect)->Left > (Rect)->Right) ? 0 : ((Rect)->Right - (Rect)->Left + 1))
28 /* PRIVATE FUNCTIONS **********************************************************/
36 IntReadConsole(IN HANDLE hConsoleInput
,
38 IN DWORD nNumberOfCharsToRead
,
39 OUT LPDWORD lpNumberOfCharsRead
,
40 IN PCONSOLE_READCONSOLE_CONTROL pInputControl OPTIONAL
,
44 CONSOLE_API_MESSAGE ApiMessage
;
45 PCONSOLE_READCONSOLE ReadConsoleRequest
= &ApiMessage
.Data
.ReadConsoleRequest
;
46 PCSR_CAPTURE_BUFFER CaptureBuffer
= NULL
;
47 ULONG CharSize
, SizeBytes
;
49 DPRINT("IntReadConsole\n");
51 /* Set up the data to send to the Console Server */
52 ReadConsoleRequest
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
53 ReadConsoleRequest
->InputHandle
= hConsoleInput
;
54 ReadConsoleRequest
->Unicode
= bUnicode
;
57 * Retrieve the (current) Input EXE name string and length,
58 * not NULL-terminated (always in UNICODE format).
60 ReadConsoleRequest
->ExeLength
=
61 GetCurrentExeName((PWCHAR
)ReadConsoleRequest
->StaticBuffer
,
62 sizeof(ReadConsoleRequest
->StaticBuffer
));
64 /*** For DEBUGGING purposes ***/
66 UNICODE_STRING ExeName
;
67 ExeName
.Length
= ExeName
.MaximumLength
= ReadConsoleRequest
->ExeLength
;
68 ExeName
.Buffer
= (PWCHAR
)ReadConsoleRequest
->StaticBuffer
;
69 DPRINT("IntReadConsole(ExeName = %wZ)\n", &ExeName
);
71 /******************************/
73 /* Determine the needed size */
74 CharSize
= (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
75 SizeBytes
= nNumberOfCharsToRead
* CharSize
;
77 ReadConsoleRequest
->CaptureBufferSize
=
78 ReadConsoleRequest
->NumBytes
= SizeBytes
;
81 * For optimization purposes, Windows (and hence ReactOS, too, for
82 * compatibility reasons) uses a static buffer if no more than eighty
83 * bytes are read. Otherwise a new buffer is allocated.
84 * This behaviour is also expected in the server-side.
86 if (SizeBytes
<= sizeof(ReadConsoleRequest
->StaticBuffer
))
88 ReadConsoleRequest
->Buffer
= ReadConsoleRequest
->StaticBuffer
;
89 // CaptureBuffer = NULL;
93 /* Allocate a Capture Buffer */
94 CaptureBuffer
= CsrAllocateCaptureBuffer(1, SizeBytes
);
95 if (CaptureBuffer
== NULL
)
97 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
98 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
102 /* Allocate space in the Buffer */
103 CsrAllocateMessagePointer(CaptureBuffer
,
105 (PVOID
*)&ReadConsoleRequest
->Buffer
);
108 ReadConsoleRequest
->InitialNumBytes
= 0;
109 ReadConsoleRequest
->CtrlWakeupMask
= 0;
110 ReadConsoleRequest
->ControlKeyState
= 0;
113 * From MSDN (ReadConsole function), the description
114 * for pInputControl says:
115 * "This parameter requires Unicode input by default.
116 * For ANSI mode, set this parameter to NULL."
120 if (bUnicode
&& pInputControl
&&
121 pInputControl
->nLength
== sizeof(CONSOLE_READCONSOLE_CONTROL
))
124 if (pInputControl
->nInitialChars
<= nNumberOfCharsToRead
)
126 ReadConsoleRequest
->InitialNumBytes
=
127 pInputControl
->nInitialChars
* sizeof(WCHAR
); // CharSize
129 if (pInputControl
->nInitialChars
!= 0)
132 * It is possible here to overwrite the static buffer, in case
133 * the number of bytes to read was smaller than the static buffer.
134 * In this case, this means we are continuing a pending read,
135 * and we do not need in fact the executable name that was
136 * stored in the static buffer because it was first grabbed when
137 * we started the first read.
139 RtlCopyMemory(ReadConsoleRequest
->Buffer
,
141 ReadConsoleRequest
->InitialNumBytes
);
144 ReadConsoleRequest
->CtrlWakeupMask
= pInputControl
->dwCtrlWakeupMask
;
148 // Status = STATUS_INVALID_PARAMETER;
153 /* We are in a situation where pInputControl has no meaning */
154 pInputControl
= NULL
;
157 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
160 if (CaptureBuffer
) CsrFreeCaptureBuffer(CaptureBuffer
);
161 SetLastError(ERROR_INVALID_ACCESS
);
162 _SEH2_YIELD(return FALSE
);
166 /* FIXME: Check for sanity */
168 if (!NT_SUCCESS(Status) && pInputControl)
170 // Free CaptureBuffer if needed
171 // Set last error to last status
176 /* Call the server */
177 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
179 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX
, ConsolepReadConsole
),
180 sizeof(*ReadConsoleRequest
));
182 /* Check for success */
183 Success
= NT_SUCCESS(ApiMessage
.Status
);
185 /* Retrieve the results */
190 *lpNumberOfCharsRead
= ReadConsoleRequest
->NumBytes
/ CharSize
;
192 if (bUnicode
&& pInputControl
)
193 pInputControl
->dwControlKeyState
= ReadConsoleRequest
->ControlKeyState
;
195 RtlCopyMemory(lpBuffer
,
196 ReadConsoleRequest
->Buffer
,
197 ReadConsoleRequest
->NumBytes
);
199 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
201 SetLastError(ERROR_INVALID_ACCESS
);
208 BaseSetLastNTError(ApiMessage
.Status
);
211 /* Release the capture buffer if needed */
212 if (CaptureBuffer
) CsrFreeCaptureBuffer(CaptureBuffer
);
216 /* Yield execution to another thread if Ctrl-C or Ctrl-Break happened */
217 if (ApiMessage
.Status
== STATUS_ALERTED
/* || ApiMessage.Status == STATUS_CANCELLED */)
220 SetLastError(ERROR_OPERATION_ABORTED
); // STATUS_CANCELLED
224 /* Return success status */
231 IntGetConsoleInput(IN HANDLE hConsoleInput
,
232 OUT PINPUT_RECORD lpBuffer
,
234 OUT LPDWORD lpNumberOfEventsRead
,
239 CONSOLE_API_MESSAGE ApiMessage
;
240 PCONSOLE_GETINPUT GetInputRequest
= &ApiMessage
.Data
.GetInputRequest
;
241 PCSR_CAPTURE_BUFFER CaptureBuffer
= NULL
;
243 if (!IsConsoleHandle(hConsoleInput
))
247 *lpNumberOfEventsRead
= 0;
248 SetLastError(ERROR_INVALID_HANDLE
);
250 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
252 SetLastError(ERROR_INVALID_ACCESS
);
259 DPRINT("IntGetConsoleInput: %lx %p\n", nLength
, lpNumberOfEventsRead
);
261 /* Set up the data to send to the Console Server */
262 GetInputRequest
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
263 GetInputRequest
->InputHandle
= hConsoleInput
;
264 GetInputRequest
->NumRecords
= nLength
;
265 GetInputRequest
->Flags
= wFlags
;
266 GetInputRequest
->Unicode
= bUnicode
;
269 * For optimization purposes, Windows (and hence ReactOS, too, for
270 * compatibility reasons) uses a static buffer if no more than five
271 * input records are read. Otherwise a new buffer is allocated.
272 * This behaviour is also expected in the server-side.
274 if (nLength
<= sizeof(GetInputRequest
->RecordStaticBuffer
)/sizeof(INPUT_RECORD
))
276 GetInputRequest
->RecordBufPtr
= GetInputRequest
->RecordStaticBuffer
;
277 // CaptureBuffer = NULL;
281 ULONG Size
= nLength
* sizeof(INPUT_RECORD
);
283 /* Allocate a Capture Buffer */
284 CaptureBuffer
= CsrAllocateCaptureBuffer(1, Size
);
285 if (CaptureBuffer
== NULL
)
287 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
288 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
292 /* Allocate space in the Buffer */
293 CsrAllocateMessagePointer(CaptureBuffer
,
295 (PVOID
*)&GetInputRequest
->RecordBufPtr
);
298 /* Call the server */
299 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
301 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX
, ConsolepGetConsoleInput
),
302 sizeof(*GetInputRequest
));
304 /* Check for success */
305 Success
= NT_SUCCESS(ApiMessage
.Status
);
307 /* Retrieve the results */
310 DPRINT("Events read: %lx\n", GetInputRequest
->NumRecords
);
311 *lpNumberOfEventsRead
= GetInputRequest
->NumRecords
;
315 RtlCopyMemory(lpBuffer
,
316 GetInputRequest
->RecordBufPtr
,
317 GetInputRequest
->NumRecords
* sizeof(INPUT_RECORD
));
321 BaseSetLastNTError(ApiMessage
.Status
);
324 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
326 SetLastError(ERROR_INVALID_ACCESS
);
331 /* Release the capture buffer if needed */
332 if (CaptureBuffer
) CsrFreeCaptureBuffer(CaptureBuffer
);
334 /* Return success status */
341 IntReadConsoleOutput(IN HANDLE hConsoleOutput
,
342 OUT PCHAR_INFO lpBuffer
,
343 IN COORD dwBufferSize
,
344 IN COORD dwBufferCoord
,
345 IN OUT PSMALL_RECT lpReadRegion
,
349 CONSOLE_API_MESSAGE ApiMessage
;
350 PCONSOLE_READOUTPUT ReadOutputRequest
= &ApiMessage
.Data
.ReadOutputRequest
;
351 PCSR_CAPTURE_BUFFER CaptureBuffer
= NULL
;
356 /* Set up the data to send to the Console Server */
357 ReadOutputRequest
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
358 ReadOutputRequest
->OutputHandle
= hConsoleOutput
;
359 ReadOutputRequest
->Unicode
= bUnicode
;
361 /* Update lpReadRegion */
364 SizeX
= min(dwBufferSize
.X
- dwBufferCoord
.X
, ConioRectWidth(lpReadRegion
));
365 SizeY
= min(dwBufferSize
.Y
- dwBufferCoord
.Y
, ConioRectHeight(lpReadRegion
));
366 if (SizeX
<= 0 || SizeY
<= 0)
368 SetLastError(ERROR_INVALID_PARAMETER
);
369 _SEH2_YIELD(return FALSE
);
371 lpReadRegion
->Right
= lpReadRegion
->Left
+ SizeX
- 1;
372 lpReadRegion
->Bottom
= lpReadRegion
->Top
+ SizeY
- 1;
374 ReadOutputRequest
->ReadRegion
= *lpReadRegion
;
376 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
378 SetLastError(ERROR_INVALID_ACCESS
);
379 _SEH2_YIELD(return FALSE
);
383 NumCells
= SizeX
* SizeY
;
384 DPRINT("IntReadConsoleOutput: (%d x %d)\n", SizeX
, SizeY
);
387 * For optimization purposes, Windows (and hence ReactOS, too, for
388 * compatibility reasons) uses a static buffer if no more than one
389 * cell is read. Otherwise a new buffer is allocated.
390 * This behaviour is also expected in the server-side.
394 ReadOutputRequest
->CharInfo
= &ReadOutputRequest
->StaticBuffer
;
395 // CaptureBuffer = NULL;
399 ULONG Size
= NumCells
* sizeof(CHAR_INFO
);
401 /* Allocate a Capture Buffer */
402 CaptureBuffer
= CsrAllocateCaptureBuffer(1, Size
);
403 if (CaptureBuffer
== NULL
)
405 DPRINT1("CsrAllocateCaptureBuffer failed with size %ld!\n", Size
);
406 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
410 /* Allocate space in the Buffer */
411 CsrAllocateMessagePointer(CaptureBuffer
,
413 (PVOID
*)&ReadOutputRequest
->CharInfo
);
416 /* Call the server */
417 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
419 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX
, ConsolepReadConsoleOutput
),
420 sizeof(*ReadOutputRequest
));
422 /* Check for success */
423 Success
= NT_SUCCESS(ApiMessage
.Status
);
425 /* Retrieve the results */
428 *lpReadRegion
= ReadOutputRequest
->ReadRegion
;
437 /* Copy into the buffer */
439 SizeX
= ConioRectWidth(&ReadOutputRequest
->ReadRegion
);
441 for (y
= 0, Y
= ReadOutputRequest
->ReadRegion
.Top
; Y
<= ReadOutputRequest
->ReadRegion
.Bottom
; ++y
, ++Y
)
443 RtlCopyMemory(lpBuffer
+ (y
+ dwBufferCoord
.Y
) * dwBufferSize
.X
+ dwBufferCoord
.X
,
444 ReadOutputRequest
->CharInfo
+ y
* SizeX
,
445 SizeX
* sizeof(CHAR_INFO
));
447 for (x
= 0, X
= ReadOutputRequest
->ReadRegion
.Left
; X
<= ReadOutputRequest
->ReadRegion
.Right
; ++x
, ++X
)
449 *(lpBuffer
+ (y
+ dwBufferCoord
.Y
) * dwBufferSize
.X
+ (x
+ dwBufferCoord
.X
)) =
450 *(ReadOutputRequest
->CharInfo
+ y
* SizeX
+ x
);
457 BaseSetLastNTError(ApiMessage
.Status
);
460 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
462 SetLastError(ERROR_INVALID_ACCESS
);
467 /* Release the capture buffer if needed */
468 if (CaptureBuffer
) CsrFreeCaptureBuffer(CaptureBuffer
);
470 /* Return success status */
477 IntReadConsoleOutputCode(IN HANDLE hConsoleOutput
,
478 IN CODE_TYPE CodeType
,
481 IN COORD dwReadCoord
,
482 OUT LPDWORD lpNumberOfCodesRead
)
485 CONSOLE_API_MESSAGE ApiMessage
;
486 PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest
= &ApiMessage
.Data
.ReadOutputCodeRequest
;
487 PCSR_CAPTURE_BUFFER CaptureBuffer
= NULL
;
488 ULONG CodeSize
, SizeBytes
;
490 DPRINT("IntReadConsoleOutputCode\n");
492 if ( (CodeType
!= CODE_ASCII
) &&
493 (CodeType
!= CODE_UNICODE
) &&
494 (CodeType
!= CODE_ATTRIBUTE
) )
496 SetLastError(ERROR_INVALID_PARAMETER
);
500 /* Set up the data to send to the Console Server */
501 ReadOutputCodeRequest
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
502 ReadOutputCodeRequest
->OutputHandle
= hConsoleOutput
;
503 ReadOutputCodeRequest
->Coord
= dwReadCoord
;
504 ReadOutputCodeRequest
->NumCodes
= nLength
;
506 /* Determine the needed size */
507 ReadOutputCodeRequest
->CodeType
= CodeType
;
511 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, AsciiChar
);
515 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
519 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, Attribute
);
522 SizeBytes
= nLength
* CodeSize
;
525 * For optimization purposes, Windows (and hence ReactOS, too, for
526 * compatibility reasons) uses a static buffer if no more than eighty
527 * bytes are read. Otherwise a new buffer is allocated.
528 * This behaviour is also expected in the server-side.
530 if (SizeBytes
<= sizeof(ReadOutputCodeRequest
->CodeStaticBuffer
))
532 ReadOutputCodeRequest
->pCode
= ReadOutputCodeRequest
->CodeStaticBuffer
;
533 // CaptureBuffer = NULL;
537 /* Allocate a Capture Buffer */
538 CaptureBuffer
= CsrAllocateCaptureBuffer(1, SizeBytes
);
539 if (CaptureBuffer
== NULL
)
541 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
542 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
546 /* Allocate space in the Buffer */
547 CsrAllocateMessagePointer(CaptureBuffer
,
549 (PVOID
*)&ReadOutputCodeRequest
->pCode
);
552 /* Call the server */
553 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
555 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX
, ConsolepReadConsoleOutputString
),
556 sizeof(*ReadOutputCodeRequest
));
558 /* Check for success */
559 Success
= NT_SUCCESS(ApiMessage
.Status
);
561 /* Retrieve the results */
564 *lpNumberOfCodesRead
= ReadOutputCodeRequest
->NumCodes
;
569 ReadOutputCodeRequest
->pCode
,
570 ReadOutputCodeRequest
->NumCodes
* CodeSize
);
574 BaseSetLastNTError(ApiMessage
.Status
);
577 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
579 SetLastError(ERROR_INVALID_ACCESS
);
584 /* Release the capture buffer if needed */
585 if (CaptureBuffer
) CsrFreeCaptureBuffer(CaptureBuffer
);
587 /* Return success status */
598 IntWriteConsole(IN HANDLE hConsoleOutput
,
600 IN DWORD nNumberOfCharsToWrite
,
601 OUT LPDWORD lpNumberOfCharsWritten
,
606 CONSOLE_API_MESSAGE ApiMessage
;
607 PCONSOLE_WRITECONSOLE WriteConsoleRequest
= &ApiMessage
.Data
.WriteConsoleRequest
;
608 PCSR_CAPTURE_BUFFER CaptureBuffer
= NULL
;
609 ULONG CharSize
, SizeBytes
;
611 DPRINT("IntWriteConsole\n");
613 /* Set up the data to send to the Console Server */
614 WriteConsoleRequest
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
615 WriteConsoleRequest
->OutputHandle
= hConsoleOutput
;
616 WriteConsoleRequest
->Unicode
= bUnicode
;
618 /* Those members are unused by the client, on Windows */
619 WriteConsoleRequest
->Reserved1
= 0;
620 // WriteConsoleRequest->Reserved2 = {0};
622 /* Determine the needed size */
623 CharSize
= (bUnicode
? sizeof(WCHAR
) : sizeof(CHAR
));
624 SizeBytes
= nNumberOfCharsToWrite
* CharSize
;
626 WriteConsoleRequest
->NumBytes
= SizeBytes
;
629 * For optimization purposes, Windows (and hence ReactOS, too, for
630 * compatibility reasons) uses a static buffer if no more than eighty
631 * bytes are written. Otherwise a new buffer is allocated.
632 * This behaviour is also expected in the server-side.
634 if (SizeBytes
<= sizeof(WriteConsoleRequest
->StaticBuffer
))
636 WriteConsoleRequest
->Buffer
= WriteConsoleRequest
->StaticBuffer
;
637 // CaptureBuffer = NULL;
638 WriteConsoleRequest
->UsingStaticBuffer
= TRUE
;
642 RtlCopyMemory(WriteConsoleRequest
->Buffer
,
646 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
648 SetLastError(ERROR_INVALID_ACCESS
);
649 _SEH2_YIELD(return FALSE
);
655 /* Allocate a Capture Buffer */
656 CaptureBuffer
= CsrAllocateCaptureBuffer(1, SizeBytes
);
657 if (CaptureBuffer
== NULL
)
659 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
660 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
664 /* Capture the buffer to write */
665 CsrCaptureMessageBuffer(CaptureBuffer
,
668 (PVOID
*)&WriteConsoleRequest
->Buffer
);
669 WriteConsoleRequest
->UsingStaticBuffer
= FALSE
;
672 /* Call the server */
673 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
675 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX
, ConsolepWriteConsole
),
676 sizeof(*WriteConsoleRequest
));
678 /* Check for success */
679 Success
= NT_SUCCESS(ApiMessage
.Status
);
681 /* Release the capture buffer if needed */
682 if (CaptureBuffer
) CsrFreeCaptureBuffer(CaptureBuffer
);
684 /* Retrieve the results. NOTE: lpNumberOfCharsWritten optional since Vista+ */
685 if (Success
&& lpNumberOfCharsWritten
)
689 *lpNumberOfCharsWritten
= WriteConsoleRequest
->NumBytes
/ CharSize
;
691 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
693 SetLastError(ERROR_INVALID_ACCESS
);
700 BaseSetLastNTError(ApiMessage
.Status
);
703 /* Return success status */
710 IntWriteConsoleInput(IN HANDLE hConsoleInput
,
711 IN PINPUT_RECORD lpBuffer
,
713 OUT LPDWORD lpNumberOfEventsWritten
,
715 IN BOOLEAN bAppendToEnd
)
718 CONSOLE_API_MESSAGE ApiMessage
;
719 PCONSOLE_WRITEINPUT WriteInputRequest
= &ApiMessage
.Data
.WriteInputRequest
;
720 PCSR_CAPTURE_BUFFER CaptureBuffer
= NULL
;
722 DPRINT("IntWriteConsoleInput: %lx %p\n", nLength
, lpNumberOfEventsWritten
);
724 /* Set up the data to send to the Console Server */
725 WriteInputRequest
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
726 WriteInputRequest
->InputHandle
= hConsoleInput
;
727 WriteInputRequest
->NumRecords
= nLength
;
728 WriteInputRequest
->Unicode
= bUnicode
;
729 WriteInputRequest
->AppendToEnd
= bAppendToEnd
;
732 * For optimization purposes, Windows (and hence ReactOS, too, for
733 * compatibility reasons) uses a static buffer if no more than five
734 * input records are written. Otherwise a new buffer is allocated.
735 * This behaviour is also expected in the server-side.
737 if (nLength
<= sizeof(WriteInputRequest
->RecordStaticBuffer
)/sizeof(INPUT_RECORD
))
739 WriteInputRequest
->RecordBufPtr
= WriteInputRequest
->RecordStaticBuffer
;
740 // CaptureBuffer = NULL;
744 RtlCopyMemory(WriteInputRequest
->RecordBufPtr
,
746 nLength
* sizeof(INPUT_RECORD
));
748 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
750 SetLastError(ERROR_INVALID_ACCESS
);
751 _SEH2_YIELD(return FALSE
);
757 ULONG Size
= nLength
* sizeof(INPUT_RECORD
);
759 /* Allocate a Capture Buffer */
760 CaptureBuffer
= CsrAllocateCaptureBuffer(1, Size
);
761 if (CaptureBuffer
== NULL
)
763 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
764 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
768 /* Capture the user buffer */
769 CsrCaptureMessageBuffer(CaptureBuffer
,
772 (PVOID
*)&WriteInputRequest
->RecordBufPtr
);
775 /* Call the server */
776 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
778 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX
, ConsolepWriteConsoleInput
),
779 sizeof(*WriteInputRequest
));
781 /* Check for success */
782 Success
= NT_SUCCESS(ApiMessage
.Status
);
784 /* Release the capture buffer if needed */
785 if (CaptureBuffer
) CsrFreeCaptureBuffer(CaptureBuffer
);
787 /* Retrieve the results */
790 DPRINT("Events written: %lx\n", WriteInputRequest
->NumRecords
);
791 *lpNumberOfEventsWritten
= WriteInputRequest
->NumRecords
;
794 BaseSetLastNTError(ApiMessage
.Status
);
796 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
798 SetLastError(ERROR_INVALID_ACCESS
);
803 /* Return success status */
810 IntWriteConsoleOutput(IN HANDLE hConsoleOutput
,
811 IN CONST CHAR_INFO
*lpBuffer
,
812 IN COORD dwBufferSize
,
813 IN COORD dwBufferCoord
,
814 IN OUT PSMALL_RECT lpWriteRegion
,
818 CONSOLE_API_MESSAGE ApiMessage
;
819 PCONSOLE_WRITEOUTPUT WriteOutputRequest
= &ApiMessage
.Data
.WriteOutputRequest
;
820 PCSR_CAPTURE_BUFFER CaptureBuffer
= NULL
;
825 /* Set up the data to send to the Console Server */
826 WriteOutputRequest
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
827 WriteOutputRequest
->OutputHandle
= hConsoleOutput
;
828 WriteOutputRequest
->Unicode
= bUnicode
;
830 /* Update lpWriteRegion */
833 SizeX
= min(dwBufferSize
.X
- dwBufferCoord
.X
, ConioRectWidth(lpWriteRegion
));
834 SizeY
= min(dwBufferSize
.Y
- dwBufferCoord
.Y
, ConioRectHeight(lpWriteRegion
));
835 if (SizeX
<= 0 || SizeY
<= 0)
837 SetLastError(ERROR_INVALID_PARAMETER
);
838 _SEH2_YIELD(return FALSE
);
840 lpWriteRegion
->Right
= lpWriteRegion
->Left
+ SizeX
- 1;
841 lpWriteRegion
->Bottom
= lpWriteRegion
->Top
+ SizeY
- 1;
843 WriteOutputRequest
->WriteRegion
= *lpWriteRegion
;
845 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
847 SetLastError(ERROR_INVALID_ACCESS
);
848 _SEH2_YIELD(return FALSE
);
852 NumCells
= SizeX
* SizeY
;
853 DPRINT("IntWriteConsoleOutput: (%d x %d)\n", SizeX
, SizeY
);
856 * For optimization purposes, Windows (and hence ReactOS, too, for
857 * compatibility reasons) uses a static buffer if no more than one
858 * cell is written. Otherwise a new buffer is allocated.
859 * This behaviour is also expected in the server-side.
863 WriteOutputRequest
->CharInfo
= &WriteOutputRequest
->StaticBuffer
;
864 // CaptureBuffer = NULL;
865 WriteOutputRequest
->UseVirtualMemory
= FALSE
;
869 ULONG Size
= NumCells
* sizeof(CHAR_INFO
);
871 /* Allocate a Capture Buffer */
872 CaptureBuffer
= CsrAllocateCaptureBuffer(1, Size
);
875 /* Allocate space in the Buffer */
876 CsrAllocateMessagePointer(CaptureBuffer
,
878 (PVOID
*)&WriteOutputRequest
->CharInfo
);
879 WriteOutputRequest
->UseVirtualMemory
= FALSE
;
884 * CsrAllocateCaptureBuffer failed because we tried to allocate
885 * a too large (>= 64 kB, size of the CSR heap) data buffer.
886 * To circumvent this, Windows uses a trick (that we reproduce for
887 * compatibility reasons): we allocate a heap buffer in the process'
888 * memory, and CSR will read it via NtReadVirtualMemory.
890 DPRINT1("CsrAllocateCaptureBuffer failed with size %ld, let's use local heap buffer...\n", Size
);
892 WriteOutputRequest
->CharInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, Size
);
893 WriteOutputRequest
->UseVirtualMemory
= TRUE
;
895 /* Bail out if we still cannot allocate memory */
896 if (WriteOutputRequest
->CharInfo
== NULL
)
898 DPRINT1("Failed to allocate heap buffer with size %ld!\n", Size
);
899 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
905 /* Capture the user buffer contents */
913 /* Copy into the buffer */
915 SizeX
= ConioRectWidth(&WriteOutputRequest
->WriteRegion
);
917 for (y
= 0, Y
= WriteOutputRequest
->WriteRegion
.Top
; Y
<= WriteOutputRequest
->WriteRegion
.Bottom
; ++y
, ++Y
)
919 RtlCopyMemory(WriteOutputRequest
->CharInfo
+ y
* SizeX
,
920 lpBuffer
+ (y
+ dwBufferCoord
.Y
) * dwBufferSize
.X
+ dwBufferCoord
.X
,
921 SizeX
* sizeof(CHAR_INFO
));
923 for (x
= 0, X
= WriteOutputRequest
->WriteRegion
.Left
; X
<= WriteOutputRequest
->WriteRegion
.Right
; ++x
, ++X
)
925 *(WriteOutputRequest
->CharInfo
+ y
* SizeX
+ x
) =
926 *(lpBuffer
+ (y
+ dwBufferCoord
.Y
) * dwBufferSize
.X
+ (x
+ dwBufferCoord
.X
));
931 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
933 SetLastError(ERROR_INVALID_ACCESS
);
934 _SEH2_YIELD(return FALSE
);
938 /* Call the server */
939 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
941 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX
, ConsolepWriteConsoleOutput
),
942 sizeof(*WriteOutputRequest
));
944 /* Check for success */
945 Success
= NT_SUCCESS(ApiMessage
.Status
);
947 /* Release the capture buffer if needed */
950 CsrFreeCaptureBuffer(CaptureBuffer
);
954 /* If we used a heap buffer, free it */
955 if (WriteOutputRequest
->UseVirtualMemory
)
956 RtlFreeHeap(RtlGetProcessHeap(), 0, WriteOutputRequest
->CharInfo
);
959 /* Retrieve the results */
962 *lpWriteRegion
= WriteOutputRequest
->WriteRegion
;
965 BaseSetLastNTError(ApiMessage
.Status
);
967 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
969 SetLastError(ERROR_INVALID_ACCESS
);
974 /* Return success status */
981 IntWriteConsoleOutputCode(IN HANDLE hConsoleOutput
,
982 IN CODE_TYPE CodeType
,
983 IN CONST VOID
*pCode
,
985 IN COORD dwWriteCoord
,
986 OUT LPDWORD lpNumberOfCodesWritten
)
989 CONSOLE_API_MESSAGE ApiMessage
;
990 PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest
= &ApiMessage
.Data
.WriteOutputCodeRequest
;
991 PCSR_CAPTURE_BUFFER CaptureBuffer
= NULL
;
992 ULONG CodeSize
, SizeBytes
;
994 if ( (CodeType
!= CODE_ASCII
) &&
995 (CodeType
!= CODE_UNICODE
) &&
996 (CodeType
!= CODE_ATTRIBUTE
) )
998 SetLastError(ERROR_INVALID_PARAMETER
);
1002 DPRINT("IntWriteConsoleOutputCode\n");
1004 /* Set up the data to send to the Console Server */
1005 WriteOutputCodeRequest
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
1006 WriteOutputCodeRequest
->OutputHandle
= hConsoleOutput
;
1007 WriteOutputCodeRequest
->Coord
= dwWriteCoord
;
1008 WriteOutputCodeRequest
->NumCodes
= nLength
;
1010 /* Determine the needed size */
1011 WriteOutputCodeRequest
->CodeType
= CodeType
;
1015 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, AsciiChar
);
1019 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, UnicodeChar
);
1022 case CODE_ATTRIBUTE
:
1023 CodeSize
= RTL_FIELD_SIZE(CODE_ELEMENT
, Attribute
);
1026 SizeBytes
= nLength
* CodeSize
;
1029 * For optimization purposes, Windows (and hence ReactOS, too, for
1030 * compatibility reasons) uses a static buffer if no more than eighty
1031 * bytes are written. Otherwise a new buffer is allocated.
1032 * This behaviour is also expected in the server-side.
1034 if (SizeBytes
<= sizeof(WriteOutputCodeRequest
->CodeStaticBuffer
))
1036 WriteOutputCodeRequest
->pCode
= WriteOutputCodeRequest
->CodeStaticBuffer
;
1037 // CaptureBuffer = NULL;
1041 RtlCopyMemory(WriteOutputCodeRequest
->pCode
,
1045 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1047 SetLastError(ERROR_INVALID_ACCESS
);
1048 _SEH2_YIELD(return FALSE
);
1054 /* Allocate a Capture Buffer */
1055 CaptureBuffer
= CsrAllocateCaptureBuffer(1, SizeBytes
);
1056 if (CaptureBuffer
== NULL
)
1058 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
1059 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1063 /* Capture the buffer to write */
1064 CsrCaptureMessageBuffer(CaptureBuffer
,
1067 (PVOID
*)&WriteOutputCodeRequest
->pCode
);
1070 /* Call the server */
1071 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1073 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX
, ConsolepWriteConsoleOutputString
),
1074 sizeof(*WriteOutputCodeRequest
));
1076 /* Check for success */
1077 Success
= NT_SUCCESS(ApiMessage
.Status
);
1079 /* Release the capture buffer if needed */
1080 if (CaptureBuffer
) CsrFreeCaptureBuffer(CaptureBuffer
);
1082 /* Retrieve the results */
1085 *lpNumberOfCodesWritten
= WriteOutputCodeRequest
->NumCodes
;
1088 BaseSetLastNTError(ApiMessage
.Status
);
1090 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1092 SetLastError(ERROR_INVALID_ACCESS
);
1097 /* Return success status */
1104 IntFillConsoleOutputCode(IN HANDLE hConsoleOutput
,
1105 IN CODE_TYPE CodeType
,
1106 IN CODE_ELEMENT Code
,
1108 IN COORD dwWriteCoord
,
1109 OUT LPDWORD lpNumberOfCodesWritten
)
1112 CONSOLE_API_MESSAGE ApiMessage
;
1113 PCONSOLE_FILLOUTPUTCODE FillOutputRequest
= &ApiMessage
.Data
.FillOutputRequest
;
1115 DPRINT("IntFillConsoleOutputCode\n");
1117 if ( (CodeType
!= CODE_ASCII
) &&
1118 (CodeType
!= CODE_UNICODE
) &&
1119 (CodeType
!= CODE_ATTRIBUTE
) )
1121 SetLastError(ERROR_INVALID_PARAMETER
);
1125 /* Set up the data to send to the Console Server */
1126 FillOutputRequest
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
1127 FillOutputRequest
->OutputHandle
= hConsoleOutput
;
1128 FillOutputRequest
->WriteCoord
= dwWriteCoord
;
1129 FillOutputRequest
->CodeType
= CodeType
;
1130 FillOutputRequest
->Code
= Code
;
1131 FillOutputRequest
->NumCodes
= nLength
;
1133 /* Call the server */
1134 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1136 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX
, ConsolepFillConsoleOutput
),
1137 sizeof(*FillOutputRequest
));
1139 /* Check for success */
1140 Success
= NT_SUCCESS(ApiMessage
.Status
);
1142 /* Retrieve the results */
1145 *lpNumberOfCodesWritten
= FillOutputRequest
->NumCodes
;
1148 BaseSetLastNTError(ApiMessage
.Status
);
1150 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1152 SetLastError(ERROR_INVALID_ACCESS
);
1157 /* Return success status */
1162 /* FUNCTIONS ******************************************************************/
1174 ReadConsoleW(IN HANDLE hConsoleInput
,
1175 OUT LPVOID lpBuffer
,
1176 IN DWORD nNumberOfCharsToRead
,
1177 OUT LPDWORD lpNumberOfCharsRead
,
1178 IN PCONSOLE_READCONSOLE_CONTROL pInputControl OPTIONAL
)
1180 return IntReadConsole(hConsoleInput
,
1182 nNumberOfCharsToRead
,
1183 lpNumberOfCharsRead
,
1195 ReadConsoleA(IN HANDLE hConsoleInput
,
1196 OUT LPVOID lpBuffer
,
1197 IN DWORD nNumberOfCharsToRead
,
1198 OUT LPDWORD lpNumberOfCharsRead
,
1199 IN PCONSOLE_READCONSOLE_CONTROL pInputControl OPTIONAL
)
1201 return IntReadConsole(hConsoleInput
,
1203 nNumberOfCharsToRead
,
1204 lpNumberOfCharsRead
,
1216 PeekConsoleInputW(IN HANDLE hConsoleInput
,
1217 OUT PINPUT_RECORD lpBuffer
,
1219 OUT LPDWORD lpNumberOfEventsRead
)
1221 return IntGetConsoleInput(hConsoleInput
,
1224 lpNumberOfEventsRead
,
1225 CONSOLE_READ_KEEPEVENT
| CONSOLE_READ_CONTINUE
,
1236 PeekConsoleInputA(IN HANDLE hConsoleInput
,
1237 OUT PINPUT_RECORD lpBuffer
,
1239 OUT LPDWORD lpNumberOfEventsRead
)
1241 return IntGetConsoleInput(hConsoleInput
,
1244 lpNumberOfEventsRead
,
1245 CONSOLE_READ_KEEPEVENT
| CONSOLE_READ_CONTINUE
,
1256 ReadConsoleInputW(IN HANDLE hConsoleInput
,
1257 OUT PINPUT_RECORD lpBuffer
,
1259 OUT LPDWORD lpNumberOfEventsRead
)
1261 return IntGetConsoleInput(hConsoleInput
,
1264 lpNumberOfEventsRead
,
1276 ReadConsoleInputA(IN HANDLE hConsoleInput
,
1277 OUT PINPUT_RECORD lpBuffer
,
1279 OUT LPDWORD lpNumberOfEventsRead
)
1281 return IntGetConsoleInput(hConsoleInput
,
1284 lpNumberOfEventsRead
,
1296 ReadConsoleInputExW(IN HANDLE hConsoleInput
,
1297 OUT PINPUT_RECORD lpBuffer
,
1299 OUT LPDWORD lpNumberOfEventsRead
,
1302 return IntGetConsoleInput(hConsoleInput
,
1305 lpNumberOfEventsRead
,
1317 ReadConsoleInputExA(IN HANDLE hConsoleInput
,
1318 OUT PINPUT_RECORD lpBuffer
,
1320 OUT LPDWORD lpNumberOfEventsRead
,
1323 return IntGetConsoleInput(hConsoleInput
,
1326 lpNumberOfEventsRead
,
1338 ReadConsoleOutputW(IN HANDLE hConsoleOutput
,
1339 OUT PCHAR_INFO lpBuffer
,
1340 IN COORD dwBufferSize
,
1341 IN COORD dwBufferCoord
,
1342 IN OUT PSMALL_RECT lpReadRegion
)
1344 return IntReadConsoleOutput(hConsoleOutput
,
1359 ReadConsoleOutputA(IN HANDLE hConsoleOutput
,
1360 OUT PCHAR_INFO lpBuffer
,
1361 IN COORD dwBufferSize
,
1362 IN COORD dwBufferCoord
,
1363 IN OUT PSMALL_RECT lpReadRegion
)
1365 return IntReadConsoleOutput(hConsoleOutput
,
1380 ReadConsoleOutputCharacterW(IN HANDLE hConsoleOutput
,
1381 OUT LPWSTR lpCharacter
,
1383 IN COORD dwReadCoord
,
1384 OUT LPDWORD lpNumberOfCharsRead
)
1386 return IntReadConsoleOutputCode(hConsoleOutput
,
1391 lpNumberOfCharsRead
);
1401 ReadConsoleOutputCharacterA(IN HANDLE hConsoleOutput
,
1402 OUT LPSTR lpCharacter
,
1404 IN COORD dwReadCoord
,
1405 OUT LPDWORD lpNumberOfCharsRead
)
1407 return IntReadConsoleOutputCode(hConsoleOutput
,
1412 lpNumberOfCharsRead
);
1422 ReadConsoleOutputAttribute(IN HANDLE hConsoleOutput
,
1423 OUT LPWORD lpAttribute
,
1425 IN COORD dwReadCoord
,
1426 OUT LPDWORD lpNumberOfAttrsRead
)
1428 return IntReadConsoleOutputCode(hConsoleOutput
,
1433 lpNumberOfAttrsRead
);
1437 /*******************
1439 *******************/
1447 WriteConsoleW(IN HANDLE hConsoleOutput
,
1448 IN CONST VOID
*lpBuffer
,
1449 IN DWORD nNumberOfCharsToWrite
,
1450 OUT LPDWORD lpNumberOfCharsWritten
,
1453 return IntWriteConsole(hConsoleOutput
,
1455 nNumberOfCharsToWrite
,
1456 lpNumberOfCharsWritten
,
1468 WriteConsoleA(IN HANDLE hConsoleOutput
,
1469 IN CONST VOID
*lpBuffer
,
1470 IN DWORD nNumberOfCharsToWrite
,
1471 OUT LPDWORD lpNumberOfCharsWritten
,
1474 return IntWriteConsole(hConsoleOutput
,
1476 nNumberOfCharsToWrite
,
1477 lpNumberOfCharsWritten
,
1489 WriteConsoleInputW(IN HANDLE hConsoleInput
,
1490 IN CONST INPUT_RECORD
*lpBuffer
,
1492 OUT LPDWORD lpNumberOfEventsWritten
)
1494 return IntWriteConsoleInput(hConsoleInput
,
1495 (PINPUT_RECORD
)lpBuffer
,
1497 lpNumberOfEventsWritten
,
1509 WriteConsoleInputA(IN HANDLE hConsoleInput
,
1510 IN CONST INPUT_RECORD
*lpBuffer
,
1512 OUT LPDWORD lpNumberOfEventsWritten
)
1514 return IntWriteConsoleInput(hConsoleInput
,
1515 (PINPUT_RECORD
)lpBuffer
,
1517 lpNumberOfEventsWritten
,
1529 WriteConsoleInputVDMW(IN HANDLE hConsoleInput
,
1530 IN CONST INPUT_RECORD
*lpBuffer
,
1532 OUT LPDWORD lpNumberOfEventsWritten
)
1534 return IntWriteConsoleInput(hConsoleInput
,
1535 (PINPUT_RECORD
)lpBuffer
,
1537 lpNumberOfEventsWritten
,
1549 WriteConsoleInputVDMA(IN HANDLE hConsoleInput
,
1550 IN CONST INPUT_RECORD
*lpBuffer
,
1552 OUT LPDWORD lpNumberOfEventsWritten
)
1554 return IntWriteConsoleInput(hConsoleInput
,
1555 (PINPUT_RECORD
)lpBuffer
,
1557 lpNumberOfEventsWritten
,
1569 WriteConsoleOutputW(IN HANDLE hConsoleOutput
,
1570 IN CONST CHAR_INFO
*lpBuffer
,
1571 IN COORD dwBufferSize
,
1572 IN COORD dwBufferCoord
,
1573 IN OUT PSMALL_RECT lpWriteRegion
)
1575 return IntWriteConsoleOutput(hConsoleOutput
,
1590 WriteConsoleOutputA(IN HANDLE hConsoleOutput
,
1591 IN CONST CHAR_INFO
*lpBuffer
,
1592 IN COORD dwBufferSize
,
1593 IN COORD dwBufferCoord
,
1594 IN OUT PSMALL_RECT lpWriteRegion
)
1596 return IntWriteConsoleOutput(hConsoleOutput
,
1611 WriteConsoleOutputCharacterW(IN HANDLE hConsoleOutput
,
1612 IN LPCWSTR lpCharacter
,
1614 IN COORD dwWriteCoord
,
1615 OUT LPDWORD lpNumberOfCharsWritten
)
1617 return IntWriteConsoleOutputCode(hConsoleOutput
,
1622 lpNumberOfCharsWritten
);
1632 WriteConsoleOutputCharacterA(IN HANDLE hConsoleOutput
,
1633 IN LPCSTR lpCharacter
,
1635 IN COORD dwWriteCoord
,
1636 OUT LPDWORD lpNumberOfCharsWritten
)
1638 return IntWriteConsoleOutputCode(hConsoleOutput
,
1643 lpNumberOfCharsWritten
);
1653 WriteConsoleOutputAttribute(IN HANDLE hConsoleOutput
,
1654 IN CONST WORD
*lpAttribute
,
1656 IN COORD dwWriteCoord
,
1657 OUT LPDWORD lpNumberOfAttrsWritten
)
1659 return IntWriteConsoleOutputCode(hConsoleOutput
,
1664 lpNumberOfAttrsWritten
);
1674 FillConsoleOutputCharacterW(IN HANDLE hConsoleOutput
,
1675 IN WCHAR cCharacter
,
1677 IN COORD dwWriteCoord
,
1678 OUT LPDWORD lpNumberOfCharsWritten
)
1681 Code
.UnicodeChar
= cCharacter
;
1682 return IntFillConsoleOutputCode(hConsoleOutput
,
1687 lpNumberOfCharsWritten
);
1697 FillConsoleOutputCharacterA(IN HANDLE hConsoleOutput
,
1700 IN COORD dwWriteCoord
,
1701 LPDWORD lpNumberOfCharsWritten
)
1704 Code
.AsciiChar
= cCharacter
;
1705 return IntFillConsoleOutputCode(hConsoleOutput
,
1710 lpNumberOfCharsWritten
);
1720 FillConsoleOutputAttribute(IN HANDLE hConsoleOutput
,
1723 IN COORD dwWriteCoord
,
1724 OUT LPDWORD lpNumberOfAttrsWritten
)
1727 Code
.Attribute
= wAttribute
;
1728 return IntFillConsoleOutputCode(hConsoleOutput
,
1733 lpNumberOfAttrsWritten
);