1 /*
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
7  *                  Marty Dill
8  *                  Filip Navara (xnavara@volny.cz)
9  *                  Thomas Weidenmueller (w3seek@reactos.org)
10  *                  Jeffrey Morlan
11  */
12 
13 /* INCLUDES *******************************************************************/
14 
15 #include <k32.h>
16 
17 #define NDEBUG
18 #include <debug.h>
19 
20 
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)
26 
27 
28 /* PRIVATE FUNCTIONS **********************************************************/
29 
30 /******************
31  * Read functions *
32  ******************/
33 
34 static
35 BOOL
36 IntReadConsole(IN HANDLE hConsoleInput,
37                OUT PVOID lpBuffer,
38                IN DWORD nNumberOfCharsToRead,
39                OUT LPDWORD lpNumberOfCharsRead,
40                IN PCONSOLE_READCONSOLE_CONTROL pInputControl OPTIONAL,
41                IN BOOLEAN bUnicode)
42 {
43     BOOL Success;
44     CONSOLE_API_MESSAGE ApiMessage;
45     PCONSOLE_READCONSOLE ReadConsoleRequest = &ApiMessage.Data.ReadConsoleRequest;
46     PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
47     ULONG CharSize, SizeBytes;
48 
49     DPRINT("IntReadConsole\n");
50 
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;
55 
56     /*
57      * Retrieve the (current) Input EXE name string and length,
58      * not NULL-terminated (always in UNICODE format).
59      */
60     ReadConsoleRequest->ExeLength =
61         GetCurrentExeName((PWCHAR)ReadConsoleRequest->StaticBuffer,
62                           sizeof(ReadConsoleRequest->StaticBuffer));
63 
64     /*** For DEBUGGING purposes ***/
65     {
66         UNICODE_STRING ExeName;
67         ExeName.Length = ExeName.MaximumLength = ReadConsoleRequest->ExeLength;
68         ExeName.Buffer = (PWCHAR)ReadConsoleRequest->StaticBuffer;
69         DPRINT("IntReadConsole(ExeName = %wZ)\n", &ExeName);
70     }
71     /******************************/
72 
73     /* Determine the needed size */
74     CharSize  = (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
75     SizeBytes = nNumberOfCharsToRead * CharSize;
76 
77     ReadConsoleRequest->CaptureBufferSize =
78     ReadConsoleRequest->NumBytes          = SizeBytes;
79 
80     /*
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.
85      */
86     if (SizeBytes <= sizeof(ReadConsoleRequest->StaticBuffer))
87     {
88         ReadConsoleRequest->Buffer = ReadConsoleRequest->StaticBuffer;
89         // CaptureBuffer = NULL;
90     }
91     else
92     {
93         /* Allocate a Capture Buffer */
94         CaptureBuffer = CsrAllocateCaptureBuffer(1, SizeBytes);
95         if (CaptureBuffer == NULL)
96         {
97             DPRINT1("CsrAllocateCaptureBuffer failed!\n");
98             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
99             return FALSE;
100         }
101 
102         /* Allocate space in the Buffer */
103         CsrAllocateMessagePointer(CaptureBuffer,
104                                   SizeBytes,
105                                   (PVOID*)&ReadConsoleRequest->Buffer);
106     }
107 
108     ReadConsoleRequest->InitialNumBytes = 0;
109     ReadConsoleRequest->CtrlWakeupMask  = 0;
110     ReadConsoleRequest->ControlKeyState = 0;
111 
112     /*
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."
117      */
118     _SEH2_TRY
119     {
120         if (bUnicode && pInputControl &&
121             pInputControl->nLength == sizeof(CONSOLE_READCONSOLE_CONTROL))
122         {
123             /* Sanity check */
124             if (pInputControl->nInitialChars <= nNumberOfCharsToRead)
125             {
126                 ReadConsoleRequest->InitialNumBytes =
127                     pInputControl->nInitialChars * sizeof(WCHAR); // CharSize
128 
129                 if (pInputControl->nInitialChars != 0)
130                 {
131                     /*
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.
138                      */
139                     RtlCopyMemory(ReadConsoleRequest->Buffer,
140                                   lpBuffer,
141                                   ReadConsoleRequest->InitialNumBytes);
142                 }
143 
144                 ReadConsoleRequest->CtrlWakeupMask = pInputControl->dwCtrlWakeupMask;
145             }
146             else
147             {
148                 // Status = STATUS_INVALID_PARAMETER;
149             }
150         }
151         else
152         {
153             /* We are in a situation where pInputControl has no meaning */
154             pInputControl = NULL;
155         }
156     }
157     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
158     {
159         // HACK
160         if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
161         SetLastError(ERROR_INVALID_ACCESS);
162         _SEH2_YIELD(return FALSE);
163     }
164     _SEH2_END;
165 
166     /* FIXME: Check for sanity */
167 /*
168     if (!NT_SUCCESS(Status) && pInputControl)
169     {
170         // Free CaptureBuffer if needed
171         // Set last error to last status
172         // Return FALSE
173     }
174 */
175 
176     /* Call the server */
177     CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
178                         CaptureBuffer,
179                         CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepReadConsole),
180                         sizeof(*ReadConsoleRequest));
181 
182     /* Check for success */
183     Success = NT_SUCCESS(ApiMessage.Status);
184 
185     /* Retrieve the results */
186     if (Success)
187     {
188         _SEH2_TRY
189         {
190             *lpNumberOfCharsRead = ReadConsoleRequest->NumBytes / CharSize;
191 
192             if (bUnicode && pInputControl)
193                 pInputControl->dwControlKeyState = ReadConsoleRequest->ControlKeyState;
194 
195             RtlCopyMemory(lpBuffer,
196                           ReadConsoleRequest->Buffer,
197                           ReadConsoleRequest->NumBytes);
198         }
199         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
200         {
201             SetLastError(ERROR_INVALID_ACCESS);
202             Success = FALSE;
203         }
204         _SEH2_END;
205     }
206     else
207     {
208         BaseSetLastNTError(ApiMessage.Status);
209     }
210 
211     /* Release the capture buffer if needed */
212     if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
213 
214     if (Success)
215     {
216         /* Yield execution to another thread if Ctrl-C or Ctrl-Break happened */
217         if (ApiMessage.Status == STATUS_ALERTED /* || ApiMessage.Status == STATUS_CANCELLED */)
218         {
219             NtYieldExecution();
220             SetLastError(ERROR_OPERATION_ABORTED); // STATUS_CANCELLED
221         }
222     }
223 
224     /* Return success status */
225     return Success;
226 }
227 
228 
229 static
230 BOOL
231 IntGetConsoleInput(IN HANDLE hConsoleInput,
232                    OUT PINPUT_RECORD lpBuffer,
233                    IN DWORD nLength,
234                    OUT LPDWORD lpNumberOfEventsRead,
235                    IN WORD wFlags,
236                    IN BOOLEAN bUnicode)
237 {
238     BOOL Success;
239     CONSOLE_API_MESSAGE ApiMessage;
240     PCONSOLE_GETINPUT GetInputRequest = &ApiMessage.Data.GetInputRequest;
241     PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
242 
243     if (!IsConsoleHandle(hConsoleInput))
244     {
245         _SEH2_TRY
246         {
247             *lpNumberOfEventsRead = 0;
248             SetLastError(ERROR_INVALID_HANDLE);
249         }
250         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
251         {
252             SetLastError(ERROR_INVALID_ACCESS);
253         }
254         _SEH2_END;
255 
256         return FALSE;
257     }
258 
259     DPRINT("IntGetConsoleInput: %lx %p\n", nLength, lpNumberOfEventsRead);
260 
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;
267 
268     /*
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.
273      */
274     if (nLength <= sizeof(GetInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
275     {
276         GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer;
277         // CaptureBuffer = NULL;
278     }
279     else
280     {
281         ULONG Size = nLength * sizeof(INPUT_RECORD);
282 
283         /* Allocate a Capture Buffer */
284         CaptureBuffer = CsrAllocateCaptureBuffer(1, Size);
285         if (CaptureBuffer == NULL)
286         {
287             DPRINT1("CsrAllocateCaptureBuffer failed!\n");
288             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
289             return FALSE;
290         }
291 
292         /* Allocate space in the Buffer */
293         CsrAllocateMessagePointer(CaptureBuffer,
294                                   Size,
295                                   (PVOID*)&GetInputRequest->RecordBufPtr);
296     }
297 
298     /* Call the server */
299     CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
300                         CaptureBuffer,
301                         CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepGetConsoleInput),
302                         sizeof(*GetInputRequest));
303 
304     /* Check for success */
305     Success = NT_SUCCESS(ApiMessage.Status);
306 
307     /* Retrieve the results */
308     _SEH2_TRY
309     {
310         DPRINT("Events read: %lx\n", GetInputRequest->NumRecords);
311         *lpNumberOfEventsRead = GetInputRequest->NumRecords;
312 
313         if (Success)
314         {
315             RtlCopyMemory(lpBuffer,
316                           GetInputRequest->RecordBufPtr,
317                           GetInputRequest->NumRecords * sizeof(INPUT_RECORD));
318         }
319         else
320         {
321             BaseSetLastNTError(ApiMessage.Status);
322         }
323     }
324     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
325     {
326         SetLastError(ERROR_INVALID_ACCESS);
327         Success = FALSE;
328     }
329     _SEH2_END;
330 
331     /* Release the capture buffer if needed */
332     if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
333 
334     /* Return success status */
335     return Success;
336 }
337 
338 
339 static
340 BOOL
341 IntReadConsoleOutput(IN HANDLE hConsoleOutput,
342                      OUT PCHAR_INFO lpBuffer,
343                      IN COORD dwBufferSize,
344                      IN COORD dwBufferCoord,
345                      IN OUT PSMALL_RECT lpReadRegion,
346                      IN BOOLEAN bUnicode)
347 {
348     BOOL Success;
349     CONSOLE_API_MESSAGE ApiMessage;
350     PCONSOLE_READOUTPUT ReadOutputRequest = &ApiMessage.Data.ReadOutputRequest;
351     PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
352 
353     SHORT SizeX, SizeY;
354     ULONG NumCells;
355 
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;
360 
361     /* Update lpReadRegion */
362     _SEH2_TRY
363     {
364         SizeX = min(dwBufferSize.X - dwBufferCoord.X, ConioRectWidth(lpReadRegion));
365         SizeY = min(dwBufferSize.Y - dwBufferCoord.Y, ConioRectHeight(lpReadRegion));
366         if (SizeX <= 0 || SizeY <= 0)
367         {
368             SetLastError(ERROR_INVALID_PARAMETER);
369             _SEH2_YIELD(return FALSE);
370         }
371         lpReadRegion->Right  = lpReadRegion->Left + SizeX - 1;
372         lpReadRegion->Bottom = lpReadRegion->Top  + SizeY - 1;
373 
374         ReadOutputRequest->ReadRegion = *lpReadRegion;
375     }
376     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
377     {
378         SetLastError(ERROR_INVALID_ACCESS);
379         _SEH2_YIELD(return FALSE);
380     }
381     _SEH2_END;
382 
383     NumCells = SizeX * SizeY;
384     DPRINT("IntReadConsoleOutput: (%d x %d)\n", SizeX, SizeY);
385 
386     /*
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.
391      */
392     if (NumCells <= 1)
393     {
394         ReadOutputRequest->CharInfo = &ReadOutputRequest->StaticBuffer;
395         // CaptureBuffer = NULL;
396     }
397     else
398     {
399         ULONG Size = NumCells * sizeof(CHAR_INFO);
400 
401         /* Allocate a Capture Buffer */
402         CaptureBuffer = CsrAllocateCaptureBuffer(1, Size);
403         if (CaptureBuffer == NULL)
404         {
405             DPRINT1("CsrAllocateCaptureBuffer failed with size %ld!\n", Size);
406             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
407             return FALSE;
408         }
409 
410         /* Allocate space in the Buffer */
411         CsrAllocateMessagePointer(CaptureBuffer,
412                                   Size,
413                                   (PVOID*)&ReadOutputRequest->CharInfo);
414     }
415 
416     /* Call the server */
417     CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
418                         CaptureBuffer,
419                         CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepReadConsoleOutput),
420                         sizeof(*ReadOutputRequest));
421 
422     /* Check for success */
423     Success = NT_SUCCESS(ApiMessage.Status);
424 
425     /* Retrieve the results */
426     _SEH2_TRY
427     {
428         *lpReadRegion = ReadOutputRequest->ReadRegion;
429 
430         if (Success)
431         {
432 #if 0
433             SHORT x, X;
434 #endif
435             SHORT y, Y;
436 
437             /* Copy into the buffer */
438 
439             SizeX = ReadOutputRequest->ReadRegion.Right -
440                     ReadOutputRequest->ReadRegion.Left + 1;
441 
442             for (y = 0, Y = ReadOutputRequest->ReadRegion.Top; Y <= ReadOutputRequest->ReadRegion.Bottom; ++y, ++Y)
443             {
444                 RtlCopyMemory(lpBuffer + (y + dwBufferCoord.Y) * dwBufferSize.X + dwBufferCoord.X,
445                               ReadOutputRequest->CharInfo + y * SizeX,
446                               SizeX * sizeof(CHAR_INFO));
447 #if 0
448                 for (x = 0, X = ReadOutputRequest->ReadRegion.Left; X <= ReadOutputRequest->ReadRegion.Right; ++x, ++X)
449                 {
450                     *(lpBuffer + (y + dwBufferCoord.Y) * dwBufferSize.X + (x + dwBufferCoord.X)) =
451                     *(ReadOutputRequest->CharInfo + y * SizeX + x);
452                 }
453 #endif
454             }
455         }
456         else
457         {
458             BaseSetLastNTError(ApiMessage.Status);
459         }
460     }
461     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
462     {
463         SetLastError(ERROR_INVALID_ACCESS);
464         Success = FALSE;
465     }
466     _SEH2_END;
467 
468     /* Release the capture buffer if needed */
469     if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
470 
471     /* Return success status */
472     return Success;
473 }
474 
475 
476 static
477 BOOL
478 IntReadConsoleOutputCode(IN HANDLE hConsoleOutput,
479                          IN CODE_TYPE CodeType,
480                          OUT PVOID pCode,
481                          IN DWORD nLength,
482                          IN COORD dwReadCoord,
483                          OUT LPDWORD lpNumberOfCodesRead)
484 {
485     BOOL Success;
486     CONSOLE_API_MESSAGE ApiMessage;
487     PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest = &ApiMessage.Data.ReadOutputCodeRequest;
488     PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
489     ULONG CodeSize, SizeBytes;
490 
491     DPRINT("IntReadConsoleOutputCode\n");
492 
493     if ( (CodeType != CODE_ASCII    ) &&
494          (CodeType != CODE_UNICODE  ) &&
495          (CodeType != CODE_ATTRIBUTE) )
496     {
497         SetLastError(ERROR_INVALID_PARAMETER);
498         return FALSE;
499     }
500 
501     /* Set up the data to send to the Console Server */
502     ReadOutputCodeRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
503     ReadOutputCodeRequest->OutputHandle  = hConsoleOutput;
504     ReadOutputCodeRequest->Coord         = dwReadCoord;
505     ReadOutputCodeRequest->NumCodes      = nLength;
506 
507     /* Determine the needed size */
508     ReadOutputCodeRequest->CodeType = CodeType;
509     switch (CodeType)
510     {
511         case CODE_ASCII:
512             CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
513             break;
514 
515         case CODE_UNICODE:
516             CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
517             break;
518 
519         case CODE_ATTRIBUTE:
520             CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
521             break;
522     }
523     SizeBytes = nLength * CodeSize;
524 
525     /*
526      * For optimization purposes, Windows (and hence ReactOS, too, for
527      * compatibility reasons) uses a static buffer if no more than eighty
528      * bytes are read. Otherwise a new buffer is allocated.
529      * This behaviour is also expected in the server-side.
530      */
531     if (SizeBytes <= sizeof(ReadOutputCodeRequest->CodeStaticBuffer))
532     {
533         ReadOutputCodeRequest->pCode = ReadOutputCodeRequest->CodeStaticBuffer;
534         // CaptureBuffer = NULL;
535     }
536     else
537     {
538         /* Allocate a Capture Buffer */
539         CaptureBuffer = CsrAllocateCaptureBuffer(1, SizeBytes);
540         if (CaptureBuffer == NULL)
541         {
542             DPRINT1("CsrAllocateCaptureBuffer failed!\n");
543             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
544             return FALSE;
545         }
546 
547         /* Allocate space in the Buffer */
548         CsrAllocateMessagePointer(CaptureBuffer,
549                                   SizeBytes,
550                                   (PVOID*)&ReadOutputCodeRequest->pCode);
551     }
552 
553     /* Call the server */
554     CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
555                         CaptureBuffer,
556                         CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepReadConsoleOutputString),
557                         sizeof(*ReadOutputCodeRequest));
558 
559     /* Check for success */
560     Success = NT_SUCCESS(ApiMessage.Status);
561 
562     /* Retrieve the results */
563     _SEH2_TRY
564     {
565         *lpNumberOfCodesRead = ReadOutputCodeRequest->NumCodes;
566 
567         if (Success)
568         {
569             RtlCopyMemory(pCode,
570                           ReadOutputCodeRequest->pCode,
571                           ReadOutputCodeRequest->NumCodes * CodeSize);
572         }
573         else
574         {
575             BaseSetLastNTError(ApiMessage.Status);
576         }
577     }
578     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
579     {
580         SetLastError(ERROR_INVALID_ACCESS);
581         Success = FALSE;
582     }
583     _SEH2_END;
584 
585     /* Release the capture buffer if needed */
586     if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
587 
588     /* Return success status */
589     return Success;
590 }
591 
592 
593 /*******************
594  * Write functions *
595  *******************/
596 
597 static
598 BOOL
599 IntWriteConsole(IN HANDLE hConsoleOutput,
600                 IN PVOID lpBuffer,
601                 IN DWORD nNumberOfCharsToWrite,
602                 OUT LPDWORD lpNumberOfCharsWritten,
603                 LPVOID lpReserved,
604                 IN BOOLEAN bUnicode)
605 {
606     BOOL Success;
607     CONSOLE_API_MESSAGE ApiMessage;
608     PCONSOLE_WRITECONSOLE WriteConsoleRequest = &ApiMessage.Data.WriteConsoleRequest;
609     PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
610     ULONG CharSize, SizeBytes;
611 
612     DPRINT("IntWriteConsole\n");
613 
614     /* Set up the data to send to the Console Server */
615     WriteConsoleRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
616     WriteConsoleRequest->OutputHandle  = hConsoleOutput;
617     WriteConsoleRequest->Unicode       = bUnicode;
618 
619     /* Those members are unused by the client, on Windows */
620     WriteConsoleRequest->Reserved1 = 0;
621     // WriteConsoleRequest->Reserved2 = {0};
622 
623     /* Determine the needed size */
624     CharSize  = (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
625     SizeBytes = nNumberOfCharsToWrite * CharSize;
626 
627     WriteConsoleRequest->NumBytes = SizeBytes;
628 
629     /*
630      * For optimization purposes, Windows (and hence ReactOS, too, for
631      * compatibility reasons) uses a static buffer if no more than eighty
632      * bytes are written. Otherwise a new buffer is allocated.
633      * This behaviour is also expected in the server-side.
634      */
635     if (SizeBytes <= sizeof(WriteConsoleRequest->StaticBuffer))
636     {
637         WriteConsoleRequest->Buffer = WriteConsoleRequest->StaticBuffer;
638         // CaptureBuffer = NULL;
639         WriteConsoleRequest->UsingStaticBuffer = TRUE;
640 
641         _SEH2_TRY
642         {
643             RtlCopyMemory(WriteConsoleRequest->Buffer,
644                           lpBuffer,
645                           SizeBytes);
646         }
647         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
648         {
649             SetLastError(ERROR_INVALID_ACCESS);
650             _SEH2_YIELD(return FALSE);
651         }
652         _SEH2_END;
653     }
654     else
655     {
656         /* Allocate a Capture Buffer */
657         CaptureBuffer = CsrAllocateCaptureBuffer(1, SizeBytes);
658         if (CaptureBuffer == NULL)
659         {
660             DPRINT1("CsrAllocateCaptureBuffer failed!\n");
661             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
662             return FALSE;
663         }
664 
665         /* Capture the buffer to write */
666         CsrCaptureMessageBuffer(CaptureBuffer,
667                                 (PVOID)lpBuffer,
668                                 SizeBytes,
669                                 (PVOID*)&WriteConsoleRequest->Buffer);
670         WriteConsoleRequest->UsingStaticBuffer = FALSE;
671     }
672 
673     /* Call the server */
674     CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
675                         CaptureBuffer,
676                         CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepWriteConsole),
677                         sizeof(*WriteConsoleRequest));
678 
679     /* Check for success */
680     Success = NT_SUCCESS(ApiMessage.Status);
681 
682     /* Release the capture buffer if needed */
683     if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
684 
685     /* Retrieve the results */
686     if (Success)
687     {
688         _SEH2_TRY
689         {
690             *lpNumberOfCharsWritten = WriteConsoleRequest->NumBytes / CharSize;
691         }
692         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
693         {
694             SetLastError(ERROR_INVALID_ACCESS);
695             Success = FALSE;
696         }
697         _SEH2_END;
698     }
699     else
700     {
701         BaseSetLastNTError(ApiMessage.Status);
702     }
703 
704     /* Return success status */
705     return Success;
706 }
707 
708 
709 static
710 BOOL
711 IntWriteConsoleInput(IN HANDLE hConsoleInput,
712                      IN PINPUT_RECORD lpBuffer,
713                      IN DWORD nLength,
714                      OUT LPDWORD lpNumberOfEventsWritten,
715                      IN BOOLEAN bUnicode,
716                      IN BOOLEAN bAppendToEnd)
717 {
718     BOOL Success;
719     CONSOLE_API_MESSAGE ApiMessage;
720     PCONSOLE_WRITEINPUT WriteInputRequest = &ApiMessage.Data.WriteInputRequest;
721     PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
722 
723     DPRINT("IntWriteConsoleInput: %lx %p\n", nLength, lpNumberOfEventsWritten);
724 
725     /* Set up the data to send to the Console Server */
726     WriteInputRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
727     WriteInputRequest->InputHandle   = hConsoleInput;
728     WriteInputRequest->NumRecords    = nLength;
729     WriteInputRequest->Unicode       = bUnicode;
730     WriteInputRequest->AppendToEnd   = bAppendToEnd;
731 
732     /*
733      * For optimization purposes, Windows (and hence ReactOS, too, for
734      * compatibility reasons) uses a static buffer if no more than five
735      * input records are written. Otherwise a new buffer is allocated.
736      * This behaviour is also expected in the server-side.
737      */
738     if (nLength <= sizeof(WriteInputRequest->RecordStaticBuffer)/sizeof(INPUT_RECORD))
739     {
740         WriteInputRequest->RecordBufPtr = WriteInputRequest->RecordStaticBuffer;
741         // CaptureBuffer = NULL;
742 
743         _SEH2_TRY
744         {
745             RtlCopyMemory(WriteInputRequest->RecordBufPtr,
746                           lpBuffer,
747                           nLength * sizeof(INPUT_RECORD));
748         }
749         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
750         {
751             SetLastError(ERROR_INVALID_ACCESS);
752             _SEH2_YIELD(return FALSE);
753         }
754         _SEH2_END;
755     }
756     else
757     {
758         ULONG Size = nLength * sizeof(INPUT_RECORD);
759 
760         /* Allocate a Capture Buffer */
761         CaptureBuffer = CsrAllocateCaptureBuffer(1, Size);
762         if (CaptureBuffer == NULL)
763         {
764             DPRINT1("CsrAllocateCaptureBuffer failed!\n");
765             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
766             return FALSE;
767         }
768 
769         /* Capture the user buffer */
770         CsrCaptureMessageBuffer(CaptureBuffer,
771                                 lpBuffer,
772                                 Size,
773                                 (PVOID*)&WriteInputRequest->RecordBufPtr);
774     }
775 
776     /* Call the server */
777     CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
778                         CaptureBuffer,
779                         CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepWriteConsoleInput),
780                         sizeof(*WriteInputRequest));
781 
782     /* Check for success */
783     Success = NT_SUCCESS(ApiMessage.Status);
784 
785     /* Release the capture buffer if needed */
786     if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
787 
788     /* Retrieve the results */
789     _SEH2_TRY
790     {
791         DPRINT("Events written: %lx\n", WriteInputRequest->NumRecords);
792         *lpNumberOfEventsWritten = WriteInputRequest->NumRecords;
793 
794         if (!Success)
795             BaseSetLastNTError(ApiMessage.Status);
796     }
797     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
798     {
799         SetLastError(ERROR_INVALID_ACCESS);
800         Success = FALSE;
801     }
802     _SEH2_END;
803 
804     /* Return success status */
805     return Success;
806 }
807 
808 
809 static
810 BOOL
811 IntWriteConsoleOutput(IN HANDLE hConsoleOutput,
812                       IN CONST CHAR_INFO *lpBuffer,
813                       IN COORD dwBufferSize,
814                       IN COORD dwBufferCoord,
815                       IN OUT PSMALL_RECT lpWriteRegion,
816                       IN BOOLEAN bUnicode)
817 {
818     BOOL Success;
819     CONSOLE_API_MESSAGE ApiMessage;
820     PCONSOLE_WRITEOUTPUT WriteOutputRequest = &ApiMessage.Data.WriteOutputRequest;
821     PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
822 
823     SHORT SizeX, SizeY;
824     ULONG NumCells;
825 
826     /* Set up the data to send to the Console Server */
827     WriteOutputRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
828     WriteOutputRequest->OutputHandle  = hConsoleOutput;
829     WriteOutputRequest->Unicode       = bUnicode;
830 
831     /* Update lpWriteRegion */
832     _SEH2_TRY
833     {
834         SizeX = min(dwBufferSize.X - dwBufferCoord.X, ConioRectWidth(lpWriteRegion));
835         SizeY = min(dwBufferSize.Y - dwBufferCoord.Y, ConioRectHeight(lpWriteRegion));
836         if (SizeX <= 0 || SizeY <= 0)
837         {
838             SetLastError(ERROR_INVALID_PARAMETER);
839             _SEH2_YIELD(return FALSE);
840         }
841         lpWriteRegion->Right  = lpWriteRegion->Left + SizeX - 1;
842         lpWriteRegion->Bottom = lpWriteRegion->Top  + SizeY - 1;
843 
844         WriteOutputRequest->WriteRegion = *lpWriteRegion;
845     }
846     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
847     {
848         SetLastError(ERROR_INVALID_ACCESS);
849         _SEH2_YIELD(return FALSE);
850     }
851     _SEH2_END;
852 
853     NumCells = SizeX * SizeY;
854     DPRINT("IntWriteConsoleOutput: (%d x %d)\n", SizeX, SizeY);
855 
856     /*
857      * For optimization purposes, Windows (and hence ReactOS, too, for
858      * compatibility reasons) uses a static buffer if no more than one
859      * cell is written. Otherwise a new buffer is allocated.
860      * This behaviour is also expected in the server-side.
861      */
862     if (NumCells <= 1)
863     {
864         WriteOutputRequest->CharInfo = &WriteOutputRequest->StaticBuffer;
865         // CaptureBuffer = NULL;
866         WriteOutputRequest->UseVirtualMemory = FALSE;
867     }
868     else
869     {
870         ULONG Size = NumCells * sizeof(CHAR_INFO);
871 
872         /* Allocate a Capture Buffer */
873         CaptureBuffer = CsrAllocateCaptureBuffer(1, Size);
874         if (CaptureBuffer)
875         {
876             /* Allocate space in the Buffer */
877             CsrAllocateMessagePointer(CaptureBuffer,
878                                       Size,
879                                       (PVOID*)&WriteOutputRequest->CharInfo);
880             WriteOutputRequest->UseVirtualMemory = FALSE;
881         }
882         else
883         {
884             /*
885              * CsrAllocateCaptureBuffer failed because we tried to allocate
886              * a too large (>= 64 kB, size of the CSR heap) data buffer.
887              * To circumvent this, Windows uses a trick (that we reproduce for
888              * compatibility reasons): we allocate a heap buffer in the process'
889              * memory, and CSR will read it via NtReadVirtualMemory.
890              */
891             DPRINT1("CsrAllocateCaptureBuffer failed with size %ld, let's use local heap buffer...\n", Size);
892 
893             WriteOutputRequest->CharInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
894             WriteOutputRequest->UseVirtualMemory = TRUE;
895 
896             /* Bail out if we still cannot allocate memory */
897             if (WriteOutputRequest->CharInfo == NULL)
898             {
899                 DPRINT1("Failed to allocate heap buffer with size %ld!\n", Size);
900                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
901                 return FALSE;
902             }
903         }
904     }
905 
906     /* Capture the user buffer contents */
907     _SEH2_TRY
908     {
909 #if 0
910         SHORT x, X;
911 #endif
912         SHORT y, Y;
913 
914         /* Copy into the buffer */
915 
916         SizeX = WriteOutputRequest->WriteRegion.Right -
917                 WriteOutputRequest->WriteRegion.Left + 1;
918 
919         for (y = 0, Y = WriteOutputRequest->WriteRegion.Top; Y <= WriteOutputRequest->WriteRegion.Bottom; ++y, ++Y)
920         {
921             RtlCopyMemory(WriteOutputRequest->CharInfo + y * SizeX,
922                           lpBuffer + (y + dwBufferCoord.Y) * dwBufferSize.X + dwBufferCoord.X,
923                           SizeX * sizeof(CHAR_INFO));
924 #if 0
925             for (x = 0, X = WriteOutputRequest->WriteRegion.Left; X <= WriteOutputRequest->WriteRegion.Right; ++x, ++X)
926             {
927                 *(WriteOutputRequest->CharInfo + y * SizeX + x) =
928                 *(lpBuffer + (y + dwBufferCoord.Y) * dwBufferSize.X + (x + dwBufferCoord.X));
929             }
930 #endif
931         }
932     }
933     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
934     {
935         SetLastError(ERROR_INVALID_ACCESS);
936         _SEH2_YIELD(return FALSE);
937     }
938     _SEH2_END;
939 
940     /* Call the server */
941     CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
942                         CaptureBuffer,
943                         CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepWriteConsoleOutput),
944                         sizeof(*WriteOutputRequest));
945 
946     /* Check for success */
947     Success = NT_SUCCESS(ApiMessage.Status);
948 
949     /* Release the capture buffer if needed */
950     if (CaptureBuffer)
951     {
952         CsrFreeCaptureBuffer(CaptureBuffer);
953     }
954     else
955     {
956         /* If we used a heap buffer, free it */
957         if (WriteOutputRequest->UseVirtualMemory)
958             RtlFreeHeap(RtlGetProcessHeap(), 0, WriteOutputRequest->CharInfo);
959     }
960 
961     /* Retrieve the results */
962     _SEH2_TRY
963     {
964         *lpWriteRegion = WriteOutputRequest->WriteRegion;
965 
966         if (!Success)
967             BaseSetLastNTError(ApiMessage.Status);
968     }
969     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
970     {
971         SetLastError(ERROR_INVALID_ACCESS);
972         Success = FALSE;
973     }
974     _SEH2_END;
975 
976     /* Return success status */
977     return Success;
978 }
979 
980 
981 static
982 BOOL
983 IntWriteConsoleOutputCode(IN HANDLE hConsoleOutput,
984                           IN CODE_TYPE CodeType,
985                           IN CONST VOID *pCode,
986                           IN DWORD nLength,
987                           IN COORD dwWriteCoord,
988                           OUT LPDWORD lpNumberOfCodesWritten)
989 {
990     BOOL Success;
991     CONSOLE_API_MESSAGE ApiMessage;
992     PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest = &ApiMessage.Data.WriteOutputCodeRequest;
993     PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
994     ULONG CodeSize, SizeBytes;
995 
996     if ( (CodeType != CODE_ASCII    ) &&
997          (CodeType != CODE_UNICODE  ) &&
998          (CodeType != CODE_ATTRIBUTE) )
999     {
1000         SetLastError(ERROR_INVALID_PARAMETER);
1001         return FALSE;
1002     }
1003 
1004     DPRINT("IntWriteConsoleOutputCode\n");
1005 
1006     /* Set up the data to send to the Console Server */
1007     WriteOutputCodeRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1008     WriteOutputCodeRequest->OutputHandle  = hConsoleOutput;
1009     WriteOutputCodeRequest->Coord         = dwWriteCoord;
1010     WriteOutputCodeRequest->NumCodes      = nLength;
1011 
1012     /* Determine the needed size */
1013     WriteOutputCodeRequest->CodeType = CodeType;
1014     switch (CodeType)
1015     {
1016         case CODE_ASCII:
1017             CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
1018             break;
1019 
1020         case CODE_UNICODE:
1021             CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
1022             break;
1023 
1024         case CODE_ATTRIBUTE:
1025             CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
1026             break;
1027     }
1028     SizeBytes = nLength * CodeSize;
1029 
1030     /*
1031      * For optimization purposes, Windows (and hence ReactOS, too, for
1032      * compatibility reasons) uses a static buffer if no more than eighty
1033      * bytes are written. Otherwise a new buffer is allocated.
1034      * This behaviour is also expected in the server-side.
1035      */
1036     if (SizeBytes <= sizeof(WriteOutputCodeRequest->CodeStaticBuffer))
1037     {
1038         WriteOutputCodeRequest->pCode = WriteOutputCodeRequest->CodeStaticBuffer;
1039         // CaptureBuffer = NULL;
1040 
1041         _SEH2_TRY
1042         {
1043             RtlCopyMemory(WriteOutputCodeRequest->pCode,
1044                           pCode,
1045                           SizeBytes);
1046         }
1047         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1048         {
1049             SetLastError(ERROR_INVALID_ACCESS);
1050             _SEH2_YIELD(return FALSE);
1051         }
1052         _SEH2_END;
1053     }
1054     else
1055     {
1056         /* Allocate a Capture Buffer */
1057         CaptureBuffer = CsrAllocateCaptureBuffer(1, SizeBytes);
1058         if (CaptureBuffer == NULL)
1059         {
1060             DPRINT1("CsrAllocateCaptureBuffer failed!\n");
1061             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1062             return FALSE;
1063         }
1064 
1065         /* Capture the buffer to write */
1066         CsrCaptureMessageBuffer(CaptureBuffer,
1067                                 (PVOID)pCode,
1068                                 SizeBytes,
1069                                 (PVOID*)&WriteOutputCodeRequest->pCode);
1070     }
1071 
1072     /* Call the server */
1073     CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1074                         CaptureBuffer,
1075                         CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepWriteConsoleOutputString),
1076                         sizeof(*WriteOutputCodeRequest));
1077 
1078     /* Check for success */
1079     Success = NT_SUCCESS(ApiMessage.Status);
1080 
1081     /* Release the capture buffer if needed */
1082     if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer);
1083 
1084     /* Retrieve the results */
1085     _SEH2_TRY
1086     {
1087         *lpNumberOfCodesWritten = WriteOutputCodeRequest->NumCodes;
1088 
1089         if (!Success)
1090             BaseSetLastNTError(ApiMessage.Status);
1091     }
1092     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1093     {
1094         SetLastError(ERROR_INVALID_ACCESS);
1095         Success = FALSE;
1096     }
1097     _SEH2_END;
1098 
1099     /* Return success status */
1100     return Success;
1101 }
1102 
1103 
1104 static
1105 BOOL
1106 IntFillConsoleOutputCode(IN HANDLE hConsoleOutput,
1107                          IN CODE_TYPE CodeType,
1108                          IN CODE_ELEMENT Code,
1109                          IN DWORD nLength,
1110                          IN COORD dwWriteCoord,
1111                          OUT LPDWORD lpNumberOfCodesWritten)
1112 {
1113     BOOL Success;
1114     CONSOLE_API_MESSAGE ApiMessage;
1115     PCONSOLE_FILLOUTPUTCODE FillOutputRequest = &ApiMessage.Data.FillOutputRequest;
1116 
1117     DPRINT("IntFillConsoleOutputCode\n");
1118 
1119     if ( (CodeType != CODE_ASCII    ) &&
1120          (CodeType != CODE_UNICODE  ) &&
1121          (CodeType != CODE_ATTRIBUTE) )
1122     {
1123         SetLastError(ERROR_INVALID_PARAMETER);
1124         return FALSE;
1125     }
1126 
1127     /* Set up the data to send to the Console Server */
1128     FillOutputRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1129     FillOutputRequest->OutputHandle  = hConsoleOutput;
1130     FillOutputRequest->WriteCoord    = dwWriteCoord;
1131     FillOutputRequest->CodeType = CodeType;
1132     FillOutputRequest->Code     = Code;
1133     FillOutputRequest->NumCodes = nLength;
1134 
1135     /* Call the server */
1136     CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1137                         NULL,
1138                         CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepFillConsoleOutput),
1139                         sizeof(*FillOutputRequest));
1140 
1141     /* Check for success */
1142     Success = NT_SUCCESS(ApiMessage.Status);
1143 
1144     /* Retrieve the results */
1145     _SEH2_TRY
1146     {
1147         *lpNumberOfCodesWritten = FillOutputRequest->NumCodes;
1148 
1149         if (!Success)
1150             BaseSetLastNTError(ApiMessage.Status);
1151     }
1152     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1153     {
1154         SetLastError(ERROR_INVALID_ACCESS);
1155         Success = FALSE;
1156     }
1157     _SEH2_END;
1158 
1159     /* Return success status */
1160     return Success;
1161 }
1162 
1163 
1164 /* FUNCTIONS ******************************************************************/
1165 
1166 /******************
1167  * Read functions *
1168  ******************/
1169 
1170 /*
1171  * @implemented
1172  */
1173 BOOL
1174 WINAPI
1175 DECLSPEC_HOTPATCH
1176 ReadConsoleW(IN HANDLE hConsoleInput,
1177              OUT LPVOID lpBuffer,
1178              IN DWORD nNumberOfCharsToRead,
1179              OUT LPDWORD lpNumberOfCharsRead,
1180              IN PCONSOLE_READCONSOLE_CONTROL pInputControl OPTIONAL)
1181 {
1182     return IntReadConsole(hConsoleInput,
1183                           lpBuffer,
1184                           nNumberOfCharsToRead,
1185                           lpNumberOfCharsRead,
1186                           pInputControl,
1187                           TRUE);
1188 }
1189 
1190 
1191 /*
1192  * @implemented
1193  */
1194 BOOL
1195 WINAPI
1196 DECLSPEC_HOTPATCH
1197 ReadConsoleA(IN HANDLE hConsoleInput,
1198              OUT LPVOID lpBuffer,
1199              IN DWORD nNumberOfCharsToRead,
1200              OUT LPDWORD lpNumberOfCharsRead,
1201              IN PCONSOLE_READCONSOLE_CONTROL pInputControl OPTIONAL)
1202 {
1203     return IntReadConsole(hConsoleInput,
1204                           lpBuffer,
1205                           nNumberOfCharsToRead,
1206                           lpNumberOfCharsRead,
1207                           NULL,
1208                           FALSE);
1209 }
1210 
1211 
1212 /*
1213  * @implemented
1214  */
1215 BOOL
1216 WINAPI
1217 DECLSPEC_HOTPATCH
1218 PeekConsoleInputW(IN HANDLE hConsoleInput,
1219                   OUT PINPUT_RECORD lpBuffer,
1220                   IN DWORD nLength,
1221                   OUT LPDWORD lpNumberOfEventsRead)
1222 {
1223     return IntGetConsoleInput(hConsoleInput,
1224                               lpBuffer,
1225                               nLength,
1226                               lpNumberOfEventsRead,
1227                               CONSOLE_READ_KEEPEVENT | CONSOLE_READ_CONTINUE,
1228                               TRUE);
1229 }
1230 
1231 
1232 /*
1233  * @implemented
1234  */
1235 BOOL
1236 WINAPI
1237 DECLSPEC_HOTPATCH
1238 PeekConsoleInputA(IN HANDLE hConsoleInput,
1239                   OUT PINPUT_RECORD lpBuffer,
1240                   IN DWORD nLength,
1241                   OUT LPDWORD lpNumberOfEventsRead)
1242 {
1243     return IntGetConsoleInput(hConsoleInput,
1244                               lpBuffer,
1245                               nLength,
1246                               lpNumberOfEventsRead,
1247                               CONSOLE_READ_KEEPEVENT | CONSOLE_READ_CONTINUE,
1248                               FALSE);
1249 }
1250 
1251 
1252 /*
1253  * @implemented
1254  */
1255 BOOL
1256 WINAPI
1257 DECLSPEC_HOTPATCH
1258 ReadConsoleInputW(IN HANDLE hConsoleInput,
1259                   OUT PINPUT_RECORD lpBuffer,
1260                   IN DWORD nLength,
1261                   OUT LPDWORD lpNumberOfEventsRead)
1262 {
1263     return IntGetConsoleInput(hConsoleInput,
1264                               lpBuffer,
1265                               nLength,
1266                               lpNumberOfEventsRead,
1267                               0,
1268                               TRUE);
1269 }
1270 
1271 
1272 /*
1273  * @implemented
1274  */
1275 BOOL
1276 WINAPI
1277 DECLSPEC_HOTPATCH
1278 ReadConsoleInputA(IN HANDLE hConsoleInput,
1279                   OUT PINPUT_RECORD lpBuffer,
1280                   IN DWORD nLength,
1281                   OUT LPDWORD lpNumberOfEventsRead)
1282 {
1283     return IntGetConsoleInput(hConsoleInput,
1284                               lpBuffer,
1285                               nLength,
1286                               lpNumberOfEventsRead,
1287                               0,
1288                               FALSE);
1289 }
1290 
1291 
1292 /*
1293  * @implemented
1294  */
1295 BOOL
1296 WINAPI
1297 DECLSPEC_HOTPATCH
1298 ReadConsoleInputExW(IN HANDLE hConsoleInput,
1299                     OUT PINPUT_RECORD lpBuffer,
1300                     IN DWORD nLength,
1301                     OUT LPDWORD lpNumberOfEventsRead,
1302                     IN WORD wFlags)
1303 {
1304     return IntGetConsoleInput(hConsoleInput,
1305                               lpBuffer,
1306                               nLength,
1307                               lpNumberOfEventsRead,
1308                               wFlags,
1309                               TRUE);
1310 }
1311 
1312 
1313 /*
1314  * @implemented
1315  */
1316 BOOL
1317 WINAPI
1318 DECLSPEC_HOTPATCH
1319 ReadConsoleInputExA(IN HANDLE hConsoleInput,
1320                     OUT PINPUT_RECORD lpBuffer,
1321                     IN DWORD nLength,
1322                     OUT LPDWORD lpNumberOfEventsRead,
1323                     IN WORD wFlags)
1324 {
1325     return IntGetConsoleInput(hConsoleInput,
1326                               lpBuffer,
1327                               nLength,
1328                               lpNumberOfEventsRead,
1329                               wFlags,
1330                               FALSE);
1331 }
1332 
1333 
1334 /*
1335  * @implemented
1336  */
1337 BOOL
1338 WINAPI
1339 DECLSPEC_HOTPATCH
1340 ReadConsoleOutputW(IN HANDLE hConsoleOutput,
1341                    OUT PCHAR_INFO lpBuffer,
1342                    IN COORD dwBufferSize,
1343                    IN COORD dwBufferCoord,
1344                    IN OUT PSMALL_RECT lpReadRegion)
1345 {
1346     return IntReadConsoleOutput(hConsoleOutput,
1347                                 lpBuffer,
1348                                 dwBufferSize,
1349                                 dwBufferCoord,
1350                                 lpReadRegion,
1351                                 TRUE);
1352 }
1353 
1354 
1355 /*
1356  * @implemented
1357  */
1358 BOOL
1359 WINAPI
1360 DECLSPEC_HOTPATCH
1361 ReadConsoleOutputA(IN HANDLE hConsoleOutput,
1362                    OUT PCHAR_INFO lpBuffer,
1363                    IN COORD dwBufferSize,
1364                    IN COORD dwBufferCoord,
1365                    IN OUT PSMALL_RECT lpReadRegion)
1366 {
1367     return IntReadConsoleOutput(hConsoleOutput,
1368                                 lpBuffer,
1369                                 dwBufferSize,
1370                                 dwBufferCoord,
1371                                 lpReadRegion,
1372                                 FALSE);
1373 }
1374 
1375 
1376 /*
1377  * @implemented
1378  */
1379 BOOL
1380 WINAPI
1381 DECLSPEC_HOTPATCH
1382 ReadConsoleOutputCharacterW(IN HANDLE hConsoleOutput,
1383                             OUT LPWSTR lpCharacter,
1384                             IN DWORD nLength,
1385                             IN COORD dwReadCoord,
1386                             OUT LPDWORD lpNumberOfCharsRead)
1387 {
1388     return IntReadConsoleOutputCode(hConsoleOutput,
1389                                     CODE_UNICODE,
1390                                     lpCharacter,
1391                                     nLength,
1392                                     dwReadCoord,
1393                                     lpNumberOfCharsRead);
1394 }
1395 
1396 
1397 /*
1398  * @implemented
1399  */
1400 BOOL
1401 WINAPI
1402 DECLSPEC_HOTPATCH
1403 ReadConsoleOutputCharacterA(IN HANDLE hConsoleOutput,
1404                             OUT LPSTR lpCharacter,
1405                             IN DWORD nLength,
1406                             IN COORD dwReadCoord,
1407                             OUT LPDWORD lpNumberOfCharsRead)
1408 {
1409     return IntReadConsoleOutputCode(hConsoleOutput,
1410                                     CODE_ASCII,
1411                                     lpCharacter,
1412                                     nLength,
1413                                     dwReadCoord,
1414                                     lpNumberOfCharsRead);
1415 }
1416 
1417 
1418 /*
1419  * @implemented
1420  */
1421 BOOL
1422 WINAPI
1423 DECLSPEC_HOTPATCH
1424 ReadConsoleOutputAttribute(IN HANDLE hConsoleOutput,
1425                            OUT LPWORD lpAttribute,
1426                            IN DWORD nLength,
1427                            IN COORD dwReadCoord,
1428                            OUT LPDWORD lpNumberOfAttrsRead)
1429 {
1430     return IntReadConsoleOutputCode(hConsoleOutput,
1431                                     CODE_ATTRIBUTE,
1432                                     lpAttribute,
1433                                     nLength,
1434                                     dwReadCoord,
1435                                     lpNumberOfAttrsRead);
1436 }
1437 
1438 
1439 /*******************
1440  * Write functions *
1441  *******************/
1442 
1443 /*
1444  * @implemented
1445  */
1446 BOOL
1447 WINAPI
1448 DECLSPEC_HOTPATCH
1449 WriteConsoleW(IN HANDLE hConsoleOutput,
1450               IN CONST VOID *lpBuffer,
1451               IN DWORD nNumberOfCharsToWrite,
1452               OUT LPDWORD lpNumberOfCharsWritten,
1453               LPVOID lpReserved)
1454 {
1455     return IntWriteConsole(hConsoleOutput,
1456                            (PVOID)lpBuffer,
1457                            nNumberOfCharsToWrite,
1458                            lpNumberOfCharsWritten,
1459                            lpReserved,
1460                            TRUE);
1461 }
1462 
1463 
1464 /*
1465  * @implemented
1466  */
1467 BOOL
1468 WINAPI
1469 DECLSPEC_HOTPATCH
1470 WriteConsoleA(IN HANDLE hConsoleOutput,
1471               IN CONST VOID *lpBuffer,
1472               IN DWORD nNumberOfCharsToWrite,
1473               OUT LPDWORD lpNumberOfCharsWritten,
1474               LPVOID lpReserved)
1475 {
1476     return IntWriteConsole(hConsoleOutput,
1477                            (PVOID)lpBuffer,
1478                            nNumberOfCharsToWrite,
1479                            lpNumberOfCharsWritten,
1480                            lpReserved,
1481                            FALSE);
1482 }
1483 
1484 
1485 /*
1486  * @implemented
1487  */
1488 BOOL
1489 WINAPI
1490 DECLSPEC_HOTPATCH
1491 WriteConsoleInputW(IN HANDLE hConsoleInput,
1492                    IN CONST INPUT_RECORD *lpBuffer,
1493                    IN DWORD nLength,
1494                    OUT LPDWORD lpNumberOfEventsWritten)
1495 {
1496     return IntWriteConsoleInput(hConsoleInput,
1497                                 (PINPUT_RECORD)lpBuffer,
1498                                 nLength,
1499                                 lpNumberOfEventsWritten,
1500                                 TRUE,
1501                                 TRUE);
1502 }
1503 
1504 
1505 /*
1506  * @implemented
1507  */
1508 BOOL
1509 WINAPI
1510 DECLSPEC_HOTPATCH
1511 WriteConsoleInputA(IN HANDLE hConsoleInput,
1512                    IN CONST INPUT_RECORD *lpBuffer,
1513                    IN DWORD nLength,
1514                    OUT LPDWORD lpNumberOfEventsWritten)
1515 {
1516     return IntWriteConsoleInput(hConsoleInput,
1517                                 (PINPUT_RECORD)lpBuffer,
1518                                 nLength,
1519                                 lpNumberOfEventsWritten,
1520                                 FALSE,
1521                                 TRUE);
1522 }
1523 
1524 
1525 /*
1526  * @implemented
1527  */
1528 BOOL
1529 WINAPI
1530 DECLSPEC_HOTPATCH
1531 WriteConsoleInputVDMW(IN HANDLE hConsoleInput,
1532                       IN CONST INPUT_RECORD *lpBuffer,
1533                       IN DWORD nLength,
1534                       OUT LPDWORD lpNumberOfEventsWritten)
1535 {
1536     return IntWriteConsoleInput(hConsoleInput,
1537                                 (PINPUT_RECORD)lpBuffer,
1538                                 nLength,
1539                                 lpNumberOfEventsWritten,
1540                                 TRUE,
1541                                 FALSE);
1542 }
1543 
1544 
1545 /*
1546  * @implemented
1547  */
1548 BOOL
1549 WINAPI
1550 DECLSPEC_HOTPATCH
1551 WriteConsoleInputVDMA(IN HANDLE hConsoleInput,
1552                       IN CONST INPUT_RECORD *lpBuffer,
1553                       IN DWORD nLength,
1554                       OUT LPDWORD lpNumberOfEventsWritten)
1555 {
1556     return IntWriteConsoleInput(hConsoleInput,
1557                                 (PINPUT_RECORD)lpBuffer,
1558                                 nLength,
1559                                 lpNumberOfEventsWritten,
1560                                 FALSE,
1561                                 FALSE);
1562 }
1563 
1564 
1565 /*
1566  * @implemented
1567  */
1568 BOOL
1569 WINAPI
1570 DECLSPEC_HOTPATCH
1571 WriteConsoleOutputW(IN HANDLE hConsoleOutput,
1572                     IN CONST CHAR_INFO *lpBuffer,
1573                     IN COORD dwBufferSize,
1574                     IN COORD dwBufferCoord,
1575                     IN OUT PSMALL_RECT lpWriteRegion)
1576 {
1577     return IntWriteConsoleOutput(hConsoleOutput,
1578                                  lpBuffer,
1579                                  dwBufferSize,
1580                                  dwBufferCoord,
1581                                  lpWriteRegion,
1582                                  TRUE);
1583 }
1584 
1585 
1586 /*
1587  * @implemented
1588  */
1589 BOOL
1590 WINAPI
1591 DECLSPEC_HOTPATCH
1592 WriteConsoleOutputA(IN HANDLE hConsoleOutput,
1593                     IN CONST CHAR_INFO *lpBuffer,
1594                     IN COORD dwBufferSize,
1595                     IN COORD dwBufferCoord,
1596                     IN OUT PSMALL_RECT lpWriteRegion)
1597 {
1598     return IntWriteConsoleOutput(hConsoleOutput,
1599                                  lpBuffer,
1600                                  dwBufferSize,
1601                                  dwBufferCoord,
1602                                  lpWriteRegion,
1603                                  FALSE);
1604 }
1605 
1606 
1607 /*
1608  * @implemented
1609  */
1610 BOOL
1611 WINAPI
1612 DECLSPEC_HOTPATCH
1613 WriteConsoleOutputCharacterW(IN HANDLE hConsoleOutput,
1614                              IN LPCWSTR lpCharacter,
1615                              IN DWORD nLength,
1616                              IN COORD dwWriteCoord,
1617                              OUT LPDWORD lpNumberOfCharsWritten)
1618 {
1619     return IntWriteConsoleOutputCode(hConsoleOutput,
1620                                      CODE_UNICODE,
1621                                      lpCharacter,
1622                                      nLength,
1623                                      dwWriteCoord,
1624                                      lpNumberOfCharsWritten);
1625 }
1626 
1627 
1628 /*
1629  * @implemented
1630  */
1631 BOOL
1632 WINAPI
1633 DECLSPEC_HOTPATCH
1634 WriteConsoleOutputCharacterA(IN HANDLE hConsoleOutput,
1635                              IN LPCSTR lpCharacter,
1636                              IN DWORD nLength,
1637                              IN COORD dwWriteCoord,
1638                              OUT LPDWORD lpNumberOfCharsWritten)
1639 {
1640     return IntWriteConsoleOutputCode(hConsoleOutput,
1641                                      CODE_ASCII,
1642                                      lpCharacter,
1643                                      nLength,
1644                                      dwWriteCoord,
1645                                      lpNumberOfCharsWritten);
1646 }
1647 
1648 
1649 /*
1650  * @implemented
1651  */
1652 BOOL
1653 WINAPI
1654 DECLSPEC_HOTPATCH
1655 WriteConsoleOutputAttribute(IN HANDLE hConsoleOutput,
1656                             IN CONST WORD *lpAttribute,
1657                             IN DWORD nLength,
1658                             IN COORD dwWriteCoord,
1659                             OUT LPDWORD lpNumberOfAttrsWritten)
1660 {
1661     return IntWriteConsoleOutputCode(hConsoleOutput,
1662                                      CODE_ATTRIBUTE,
1663                                      lpAttribute,
1664                                      nLength,
1665                                      dwWriteCoord,
1666                                      lpNumberOfAttrsWritten);
1667 }
1668 
1669 
1670 /*
1671  * @implemented
1672  */
1673 BOOL
1674 WINAPI
1675 DECLSPEC_HOTPATCH
1676 FillConsoleOutputCharacterW(IN HANDLE hConsoleOutput,
1677                             IN WCHAR cCharacter,
1678                             IN DWORD nLength,
1679                             IN COORD dwWriteCoord,
1680                             OUT LPDWORD lpNumberOfCharsWritten)
1681 {
1682     CODE_ELEMENT Code;
1683     Code.UnicodeChar = cCharacter;
1684     return IntFillConsoleOutputCode(hConsoleOutput,
1685                                     CODE_UNICODE,
1686                                     Code,
1687                                     nLength,
1688                                     dwWriteCoord,
1689                                     lpNumberOfCharsWritten);
1690 }
1691 
1692 
1693 /*
1694  * @implemented
1695  */
1696 BOOL
1697 WINAPI
1698 DECLSPEC_HOTPATCH
1699 FillConsoleOutputCharacterA(IN HANDLE hConsoleOutput,
1700                             IN CHAR cCharacter,
1701                             IN DWORD nLength,
1702                             IN COORD dwWriteCoord,
1703                             LPDWORD lpNumberOfCharsWritten)
1704 {
1705     CODE_ELEMENT Code;
1706     Code.AsciiChar = cCharacter;
1707     return IntFillConsoleOutputCode(hConsoleOutput,
1708                                     CODE_ASCII,
1709                                     Code,
1710                                     nLength,
1711                                     dwWriteCoord,
1712                                     lpNumberOfCharsWritten);
1713 }
1714 
1715 
1716 /*
1717  * @implemented
1718  */
1719 BOOL
1720 WINAPI
1721 DECLSPEC_HOTPATCH
1722 FillConsoleOutputAttribute(IN HANDLE hConsoleOutput,
1723                            IN WORD wAttribute,
1724                            IN DWORD nLength,
1725                            IN COORD dwWriteCoord,
1726                            OUT LPDWORD lpNumberOfAttrsWritten)
1727 {
1728     CODE_ELEMENT Code;
1729     Code.Attribute = wAttribute;
1730     return IntFillConsoleOutputCode(hConsoleOutput,
1731                                     CODE_ATTRIBUTE,
1732                                     Code,
1733                                     nLength,
1734                                     dwWriteCoord,
1735                                     lpNumberOfAttrsWritten);
1736 }
1737 
1738 /* EOF */
1739