Author: hbelusca Date: Tue Jul 29 00:00:21 2014 New Revision: 63755
URL: http://svn.reactos.org/svn/reactos?rev=63755&view=rev Log: [KERNEL32][CONSRV] - Make kernel32 / winsrv console CSR structures Win2k3-compliant for Read/WriteConsoleCharacter/Attribute and FillConsoleOutputCharacter/Attribute functions. The underlying CONSOLE_READOUTPUTCODE and CONSOLE_WRITEOUTPUTCODE structures are the same. It should be noticed, as for the Read/WriteConsoleInput functions of r63754 and the other Read/WriteConsole*** functions, that for performance purposes Windows uses a local buffer for "small" sizes; we should do the same too because both the client and the server use the number of elements to actually read/write in order to determine which buffer one should use (local or some shared buffer). - Some memcpy --> RtlCopyMemory.
Part 7/X
CORE-7931
Modified: branches/condrv_restructure/dll/win32/kernel32/client/console/readwrite.c branches/condrv_restructure/include/reactos/subsys/win/conmsg.h branches/condrv_restructure/win32ss/user/winsrv/consrv/condrv/text.c branches/condrv_restructure/win32ss/user/winsrv/consrv/coninput.c branches/condrv_restructure/win32ss/user/winsrv/consrv/conoutput.c
Modified: branches/condrv_restructure/dll/win32/kernel32/client/console/readwrite.c URL: http://svn.reactos.org/svn/reactos/branches/condrv_restructure/dll/win32/ker... ============================================================================== --- branches/condrv_restructure/dll/win32/kernel32/client/console/readwrite.c [iso-8859-1] (original) +++ branches/condrv_restructure/dll/win32/kernel32/client/console/readwrite.c [iso-8859-1] Tue Jul 29 00:00:21 2014 @@ -71,9 +71,9 @@ * For ANSI mode, set this parameter to NULL." */ ReadConsoleRequest->NrCharactersRead = pInputControl->nInitialChars; - memcpy(ReadConsoleRequest->Buffer, - lpBuffer, - pInputControl->nInitialChars * sizeof(WCHAR)); + RtlCopyMemory(ReadConsoleRequest->Buffer, + lpBuffer, + pInputControl->nInitialChars * sizeof(WCHAR)); ReadConsoleRequest->CtrlWakeupMask = pInputControl->dwCtrlWakeupMask; }
@@ -86,9 +86,9 @@ /* Check for success */ if (NT_SUCCESS(ApiMessage.Status)) { - memcpy(lpBuffer, - ReadConsoleRequest->Buffer, - ReadConsoleRequest->NrCharactersRead * CharSize); + RtlCopyMemory(lpBuffer, + ReadConsoleRequest->Buffer, + ReadConsoleRequest->NrCharactersRead * CharSize);
if (lpNumberOfCharsRead != NULL) *lpNumberOfCharsRead = ReadConsoleRequest->NrCharactersRead; @@ -312,14 +312,21 @@ COORD dwReadCoord, LPDWORD lpNumberOfCodesRead) { - BOOL bRet = TRUE; CONSOLE_API_MESSAGE ApiMessage; PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest = &ApiMessage.Data.ReadOutputCodeRequest; - PCSR_CAPTURE_BUFFER CaptureBuffer; + PCSR_CAPTURE_BUFFER CaptureBuffer = NULL; ULONG SizeBytes, CodeSize; - DWORD CodesRead; + + DPRINT("IntReadConsoleOutputCode\n"); + + /* Set up the data to send to the Console Server */ + ReadOutputCodeRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; + ReadOutputCodeRequest->OutputHandle = hConsoleOutput; + ReadOutputCodeRequest->Coord = dwReadCoord; + ReadOutputCodeRequest->NumCodes = nLength;
/* Determine the needed size */ + ReadOutputCodeRequest->CodeType = CodeType; switch (CodeType) { case CODE_ASCII: @@ -340,26 +347,33 @@ } SizeBytes = nLength * CodeSize;
- /* Allocate a Capture Buffer */ - CaptureBuffer = CsrAllocateCaptureBuffer(1, SizeBytes); - if (CaptureBuffer == NULL) - { - DPRINT1("CsrAllocateCaptureBuffer failed!\n"); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - - /* Allocate space in the Buffer */ - CsrAllocateMessagePointer(CaptureBuffer, - SizeBytes, - (PVOID*)&ReadOutputCodeRequest->pCode.pCode); - - /* Start reading */ - ReadOutputCodeRequest->OutputHandle = hConsoleOutput; - ReadOutputCodeRequest->CodeType = CodeType; - ReadOutputCodeRequest->ReadCoord = dwReadCoord; - - ReadOutputCodeRequest->NumCodesToRead = nLength; + /* + * For optimization purposes, Windows (and hence ReactOS, too, for + * compatibility reasons) uses a static buffer if no more than eighty + * bytes are read. Otherwise a new buffer is allocated. + * This behaviour is also expected in the server-side. + */ + if (SizeBytes <= sizeof(ReadOutputCodeRequest->CodeStaticBuffer)) + { + ReadOutputCodeRequest->pCode.pCode = ReadOutputCodeRequest->CodeStaticBuffer; + // CaptureBuffer = NULL; + } + else + { + /* Allocate a Capture Buffer */ + CaptureBuffer = CsrAllocateCaptureBuffer(1, SizeBytes); + if (CaptureBuffer == NULL) + { + DPRINT1("CsrAllocateCaptureBuffer failed!\n"); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + /* Allocate space in the Buffer */ + CsrAllocateMessagePointer(CaptureBuffer, + SizeBytes, + (PVOID*)&ReadOutputCodeRequest->pCode.pCode); + }
/* Call the server */ CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, @@ -370,15 +384,13 @@ /* Check for success */ if (NT_SUCCESS(ApiMessage.Status)) { - CodesRead = ReadOutputCodeRequest->CodesRead; - memcpy(pCode, ReadOutputCodeRequest->pCode.pCode, CodesRead * CodeSize); - - // ReadOutputCodeRequest->ReadCoord = ReadOutputCodeRequest->EndCoord; + DWORD NumCodes = ReadOutputCodeRequest->NumCodes; + RtlCopyMemory(pCode, + ReadOutputCodeRequest->pCode.pCode, + NumCodes * CodeSize);
if (lpNumberOfCodesRead != NULL) - *lpNumberOfCodesRead = CodesRead; - - bRet = TRUE; + *lpNumberOfCodesRead = NumCodes; } else { @@ -387,12 +399,13 @@
/* Error out */ BaseSetLastNTError(ApiMessage.Status); - bRet = FALSE; - } - - CsrFreeCaptureBuffer(CaptureBuffer); - - return bRet; + } + + /* Release the capture buffer if needed */ + if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer); + + /* Return TRUE or FALSE */ + return NT_SUCCESS(ApiMessage.Status); }
@@ -651,13 +664,27 @@ COORD dwWriteCoord, LPDWORD lpNumberOfCodesWritten) { - BOOL bRet = TRUE; CONSOLE_API_MESSAGE ApiMessage; PCONSOLE_WRITEOUTPUTCODE WriteOutputCodeRequest = &ApiMessage.Data.WriteOutputCodeRequest; - PCSR_CAPTURE_BUFFER CaptureBuffer; - ULONG CodeSize; + PCSR_CAPTURE_BUFFER CaptureBuffer = NULL; + ULONG SizeBytes, CodeSize; + + if (pCode == NULL) + { + SetLastError(ERROR_INVALID_ACCESS); + return FALSE; + } + + DPRINT("IntWriteConsoleOutputCode\n"); + + /* Set up the data to send to the Console Server */ + WriteOutputCodeRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; + WriteOutputCodeRequest->OutputHandle = hConsoleOutput; + WriteOutputCodeRequest->Coord = dwWriteCoord; + WriteOutputCodeRequest->NumCodes = nLength;
/* Determine the needed size */ + WriteOutputCodeRequest->CodeType = CodeType; switch (CodeType) { case CODE_ASCII: @@ -676,29 +703,40 @@ SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - WriteOutputCodeRequest->BufferSize = nLength * CodeSize; - - /* Allocate a Capture Buffer */ - CaptureBuffer = CsrAllocateCaptureBuffer(1, WriteOutputCodeRequest->BufferSize); - if (CaptureBuffer == NULL) - { - DPRINT1("CsrAllocateCaptureBuffer failed!\n"); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - - /* Capture the buffer to write */ - CsrCaptureMessageBuffer(CaptureBuffer, - (PVOID)pCode, - WriteOutputCodeRequest->BufferSize, - (PVOID*)&WriteOutputCodeRequest->pCode.pCode); - - /* Start writing */ - WriteOutputCodeRequest->OutputHandle = hConsoleOutput; - WriteOutputCodeRequest->CodeType = CodeType; - WriteOutputCodeRequest->Coord = dwWriteCoord; - - WriteOutputCodeRequest->Length = (USHORT)nLength; + SizeBytes = nLength * CodeSize; + + /* + * For optimization purposes, Windows (and hence ReactOS, too, for + * compatibility reasons) uses a static buffer if no more than eighty + * bytes are written. Otherwise a new buffer is allocated. + * This behaviour is also expected in the server-side. + */ + if (SizeBytes <= sizeof(WriteOutputCodeRequest->CodeStaticBuffer)) + { + WriteOutputCodeRequest->pCode.pCode = WriteOutputCodeRequest->CodeStaticBuffer; + // CaptureBuffer = NULL; + + RtlCopyMemory(WriteOutputCodeRequest->pCode.pCode, + pCode, + SizeBytes); + } + else + { + /* Allocate a Capture Buffer */ + CaptureBuffer = CsrAllocateCaptureBuffer(1, SizeBytes); + if (CaptureBuffer == NULL) + { + DPRINT1("CsrAllocateCaptureBuffer failed!\n"); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + /* Capture the buffer to write */ + CsrCaptureMessageBuffer(CaptureBuffer, + (PVOID)pCode, + SizeBytes, + (PVOID*)&WriteOutputCodeRequest->pCode.pCode); + }
/* Call the server */ CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, @@ -706,16 +744,14 @@ CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepWriteConsoleOutputString), sizeof(*WriteOutputCodeRequest));
+ /* Release the capture buffer if needed */ + if (CaptureBuffer) CsrFreeCaptureBuffer(CaptureBuffer); + /* Check for success */ if (NT_SUCCESS(ApiMessage.Status)) { - // WriteOutputCodeRequest->Coord = WriteOutputCodeRequest->EndCoord; - if (lpNumberOfCodesWritten != NULL) - // *lpNumberOfCodesWritten = WriteOutputCodeRequest->NrCharactersWritten; - *lpNumberOfCodesWritten = WriteOutputCodeRequest->Length; - - bRet = TRUE; + *lpNumberOfCodesWritten = WriteOutputCodeRequest->NumCodes; } else { @@ -724,12 +760,10 @@
/* Error out */ BaseSetLastNTError(ApiMessage.Status); - bRet = FALSE; - } - - CsrFreeCaptureBuffer(CaptureBuffer); - - return bRet; + } + + /* Return TRUE or FALSE */ + return NT_SUCCESS(ApiMessage.Status); }
@@ -745,9 +779,13 @@ CONSOLE_API_MESSAGE ApiMessage; PCONSOLE_FILLOUTPUTCODE FillOutputRequest = &ApiMessage.Data.FillOutputRequest;
- FillOutputRequest->OutputHandle = hConsoleOutput; + /* Set up the data to send to the Console Server */ + FillOutputRequest->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; + FillOutputRequest->OutputHandle = hConsoleOutput; + FillOutputRequest->WriteCoord = dwWriteCoord; + FillOutputRequest->NumCodes = nLength; + FillOutputRequest->CodeType = CodeType; - switch (CodeType) { case CODE_ASCII: @@ -766,10 +804,6 @@ SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - - /* Set up the data to send to the Console Server */ - FillOutputRequest->Coord = dwWriteCoord; - FillOutputRequest->Length = nLength;
/* Call the server */ CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, @@ -781,10 +815,7 @@ if (NT_SUCCESS(ApiMessage.Status)) { if (lpNumberOfCodesWritten != NULL) - *lpNumberOfCodesWritten = FillOutputRequest->Length; - // *lpNumberOfCodesWritten = Request.Data.FillOutputRequest.NrCharactersWritten; - - return TRUE; + *lpNumberOfCodesWritten = FillOutputRequest->NumCodes; } else { @@ -792,8 +823,10 @@ *lpNumberOfCodesWritten = 0;
BaseSetLastNTError(ApiMessage.Status); - return FALSE; - } + } + + /* Return TRUE or FALSE */ + return NT_SUCCESS(ApiMessage.Status); }
Modified: branches/condrv_restructure/include/reactos/subsys/win/conmsg.h URL: http://svn.reactos.org/svn/reactos/branches/condrv_restructure/include/react... ============================================================================== --- branches/condrv_restructure/include/reactos/subsys/win/conmsg.h [iso-8859-1] (original) +++ branches/condrv_restructure/include/reactos/subsys/win/conmsg.h [iso-8859-1] Tue Jul 29 00:00:21 2014 @@ -423,7 +423,7 @@
BOOL Unicode; COORD BufferSize; - COORD BufferCoord; + COORD BufferCoord; // WriteCoord SMALL_RECT WriteRegion; PCHAR_INFO CharInfo; } CONSOLE_WRITEOUTPUT, *PCONSOLE_WRITEOUTPUT; @@ -461,15 +461,12 @@
typedef struct { - HANDLE OutputHandle; - - DWORD NumCodesToRead; - COORD ReadCoord; - COORD EndCoord; - - DWORD CodesRead; + HANDLE ConsoleHandle; + HANDLE OutputHandle; + COORD Coord;
CODE_TYPE CodeType; + CHAR CodeStaticBuffer[80]; union { PVOID pCode; @@ -477,32 +474,16 @@ PWCHAR UnicodeChar; PWORD Attribute; } pCode; // Either a pointer to a character or to an attribute. -} CONSOLE_READOUTPUTCODE, *PCONSOLE_READOUTPUTCODE; - -typedef struct -{ - HANDLE OutputHandle; - - ULONG BufferSize; // Seems unusued - WORD Length; - COORD Coord; - COORD EndCoord; - - ULONG NrCharactersWritten; // Seems unusued - - CODE_TYPE CodeType; - union - { - PVOID pCode; - PCHAR AsciiChar; - PWCHAR UnicodeChar; - PWORD Attribute; - } pCode; // Either a pointer to a character or to an attribute. -} CONSOLE_WRITEOUTPUTCODE, *PCONSOLE_WRITEOUTPUTCODE; - -typedef struct -{ - HANDLE OutputHandle; + + ULONG NumCodes; +} CONSOLE_READOUTPUTCODE , *PCONSOLE_READOUTPUTCODE, + CONSOLE_WRITEOUTPUTCODE, *PCONSOLE_WRITEOUTPUTCODE; + +typedef struct +{ + HANDLE ConsoleHandle; + HANDLE OutputHandle; + COORD WriteCoord;
CODE_TYPE CodeType; union @@ -512,10 +493,7 @@ WORD Attribute; } Code; // Either a character or an attribute.
- COORD Coord; - ULONG Length; - - ULONG NrCharactersWritten; // FIXME: Only for chars, is it removable ? + ULONG NumCodes; } CONSOLE_FILLOUTPUTCODE, *PCONSOLE_FILLOUTPUTCODE;
typedef struct
Modified: branches/condrv_restructure/win32ss/user/winsrv/consrv/condrv/text.c URL: http://svn.reactos.org/svn/reactos/branches/condrv_restructure/win32ss/user/... ============================================================================== --- branches/condrv_restructure/win32ss/user/winsrv/consrv/condrv/text.c [iso-8859-1] (original) +++ branches/condrv_restructure/win32ss/user/winsrv/consrv/condrv/text.c [iso-8859-1] Tue Jul 29 00:00:21 2014 @@ -891,7 +891,7 @@ OUT PVOID StringBuffer, IN ULONG NumCodesToRead, IN PCOORD ReadCoord, - OUT PCOORD EndCoord, + // OUT PCOORD EndCoord, OUT PULONG CodesRead) { SHORT Xpos, Ypos; @@ -901,7 +901,7 @@ PCHAR_INFO Ptr;
if (Console == NULL || Buffer == NULL || - ReadCoord == NULL || EndCoord == NULL || CodesRead == NULL) + ReadCoord == NULL || /* EndCoord == NULL || */ CodesRead == NULL) { return STATUS_INVALID_PARAMETER; } @@ -997,8 +997,8 @@ // break; // }
- EndCoord->X = Xpos; - EndCoord->Y = (Ypos - Buffer->VirtualY + Buffer->ScreenBufferSize.Y) % Buffer->ScreenBufferSize.Y; + // EndCoord->X = Xpos; + // EndCoord->Y = (Ypos - Buffer->VirtualY + Buffer->ScreenBufferSize.Y) % Buffer->ScreenBufferSize.Y;
*CodesRead = (ULONG)((ULONG_PTR)ReadBuffer - (ULONG_PTR)StringBuffer) / CodeSize; // <= NumCodesToRead
Modified: branches/condrv_restructure/win32ss/user/winsrv/consrv/coninput.c URL: http://svn.reactos.org/svn/reactos/branches/condrv_restructure/win32ss/user/... ============================================================================== --- branches/condrv_restructure/win32ss/user/winsrv/consrv/coninput.c [iso-8859-1] (original) +++ branches/condrv_restructure/win32ss/user/winsrv/consrv/coninput.c [iso-8859-1] Tue Jul 29 00:00:21 2014 @@ -383,7 +383,7 @@ * Adjust the internal pointer, because its old value points to * the static buffer in the original ApiMessage structure. */ - // GetInputRequest->RecordBufPtr = &GetInputRequest->RecordStaticBuffer; + // GetInputRequest->RecordBufPtr = GetInputRequest->RecordStaticBuffer; } else {
Modified: branches/condrv_restructure/win32ss/user/winsrv/consrv/conoutput.c URL: http://svn.reactos.org/svn/reactos/branches/condrv_restructure/win32ss/user/... ============================================================================== --- branches/condrv_restructure/win32ss/user/winsrv/consrv/conoutput.c [iso-8859-1] (original) +++ branches/condrv_restructure/win32ss/user/winsrv/consrv/conoutput.c [iso-8859-1] Tue Jul 29 00:00:21 2014 @@ -524,7 +524,7 @@ OUT PVOID StringBuffer, IN ULONG NumCodesToRead, IN PCOORD ReadCoord, - OUT PCOORD EndCoord, + // OUT PCOORD EndCoord, OUT PULONG CodesRead); CSR_API(SrvReadConsoleOutputString) { @@ -532,6 +532,8 @@ PCONSOLE_READOUTPUTCODE ReadOutputCodeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ReadOutputCodeRequest; PTEXTMODE_SCREEN_BUFFER Buffer; ULONG CodeSize; + + PVOID pCode;
DPRINT("SrvReadConsoleOutputString\n");
@@ -553,12 +555,32 @@ return STATUS_INVALID_PARAMETER; }
- if (!CsrValidateMessageBuffer(ApiMessage, - (PVOID*)&ReadOutputCodeRequest->pCode.pCode, - ReadOutputCodeRequest->NumCodesToRead, - CodeSize)) - { - return STATUS_INVALID_PARAMETER; + /* + * For optimization purposes, Windows (and hence ReactOS, too, for + * compatibility reasons) uses a static buffer if no more than eighty + * bytes are read. Otherwise a new buffer is used. + * The client-side expects that we know this behaviour. + */ + if (ReadOutputCodeRequest->NumCodes * CodeSize <= sizeof(ReadOutputCodeRequest->CodeStaticBuffer)) + { + /* + * Adjust the internal pointer, because its old value points to + * the static buffer in the original ApiMessage structure. + */ + // ReadOutputCodeRequest->pCode.pCode = ReadOutputCodeRequest->CodeStaticBuffer; + pCode = ReadOutputCodeRequest->CodeStaticBuffer; + } + else + { + if (!CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&ReadOutputCodeRequest->pCode.pCode, + ReadOutputCodeRequest->NumCodes, + CodeSize)) + { + return STATUS_INVALID_PARAMETER; + } + + pCode = ReadOutputCodeRequest->pCode.pCode; }
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), @@ -569,11 +591,11 @@ Status = ConDrvReadConsoleOutputString(Buffer->Header.Console, Buffer, ReadOutputCodeRequest->CodeType, - ReadOutputCodeRequest->pCode.pCode, - ReadOutputCodeRequest->NumCodesToRead, - &ReadOutputCodeRequest->ReadCoord, - &ReadOutputCodeRequest->EndCoord, - &ReadOutputCodeRequest->CodesRead); + pCode, + ReadOutputCodeRequest->NumCodes, + &ReadOutputCodeRequest->Coord, + // &ReadOutputCodeRequest->EndCoord, + &ReadOutputCodeRequest->NumCodes);
ConSrvReleaseScreenBuffer(Buffer, TRUE); return Status; @@ -595,6 +617,8 @@ PTEXTMODE_SCREEN_BUFFER Buffer; ULONG CodeSize;
+ PVOID pCode; + DPRINT("SrvWriteConsoleOutputString\n");
switch (WriteOutputCodeRequest->CodeType) @@ -615,12 +639,32 @@ return STATUS_INVALID_PARAMETER; }
- if (!CsrValidateMessageBuffer(ApiMessage, - (PVOID*)&WriteOutputCodeRequest->pCode.pCode, - WriteOutputCodeRequest->Length, - CodeSize)) - { - return STATUS_INVALID_PARAMETER; + /* + * For optimization purposes, Windows (and hence ReactOS, too, for + * compatibility reasons) uses a static buffer if no more than eighty + * bytes are written. Otherwise a new buffer is used. + * The client-side expects that we know this behaviour. + */ + if (WriteOutputCodeRequest->NumCodes * CodeSize <= sizeof(WriteOutputCodeRequest->CodeStaticBuffer)) + { + /* + * Adjust the internal pointer, because its old value points to + * the static buffer in the original ApiMessage structure. + */ + // WriteOutputCodeRequest->pCode.pCode = WriteOutputCodeRequest->CodeStaticBuffer; + pCode = WriteOutputCodeRequest->CodeStaticBuffer; + } + else + { + if (!CsrValidateMessageBuffer(ApiMessage, + (PVOID*)&WriteOutputCodeRequest->pCode.pCode, + WriteOutputCodeRequest->NumCodes, + CodeSize)) + { + return STATUS_INVALID_PARAMETER; + } + + pCode = WriteOutputCodeRequest->pCode.pCode; }
Status = ConSrvGetTextModeBuffer(ConsoleGetPerProcessData(CsrGetClientThread()->Process), @@ -631,9 +675,9 @@ Status = ConDrvWriteConsoleOutputString(Buffer->Header.Console, Buffer, WriteOutputCodeRequest->CodeType, - WriteOutputCodeRequest->pCode.pCode, - WriteOutputCodeRequest->Length, // NumCodesToWrite, - &WriteOutputCodeRequest->Coord /*, // WriteCoord, + pCode, + WriteOutputCodeRequest->NumCodes, + &WriteOutputCodeRequest->Coord /*, &WriteOutputCodeRequest->EndCoord, &WriteOutputCodeRequest->NrCharactersWritten */);
@@ -676,8 +720,8 @@ Buffer, CodeType, &FillOutputRequest->Code, - FillOutputRequest->Length, // NumCodesToWrite, - &FillOutputRequest->Coord /*, // WriteCoord, + FillOutputRequest->NumCodes, + &FillOutputRequest->WriteCoord /*, &FillOutputRequest->NrCharactersWritten */);
// FillOutputRequest->NrCharactersWritten = Written;