5cda80672ce17284b6a940aa4424938efb696625
[reactos.git] / dll / win32 / kernel32 / client / console / readwrite.c
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 /* PRIVATE FUNCTIONS **********************************************************/
22
23 /******************
24 * Read functions *
25 ******************/
26
27 static
28 BOOL
29 IntReadConsole(HANDLE hConsoleInput,
30 PVOID lpBuffer,
31 DWORD nNumberOfCharsToRead,
32 LPDWORD lpNumberOfCharsRead,
33 PCONSOLE_READCONSOLE_CONTROL pInputControl,
34 BOOL bUnicode)
35 {
36 NTSTATUS Status;
37 CONSOLE_API_MESSAGE ApiMessage;
38 PCSRSS_READ_CONSOLE ReadConsoleRequest = &ApiMessage.Data.ReadConsoleRequest;
39 PCSR_CAPTURE_BUFFER CaptureBuffer;
40 ULONG CharSize;
41
42 /* Determine the needed size */
43 CharSize = (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
44 ReadConsoleRequest->BufferSize = nNumberOfCharsToRead * CharSize;
45
46 /* Allocate a Capture Buffer */
47 CaptureBuffer = CsrAllocateCaptureBuffer(1, ReadConsoleRequest->BufferSize);
48 if (CaptureBuffer == NULL)
49 {
50 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
51 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
52 return FALSE;
53 }
54
55 /* Allocate space in the Buffer */
56 CsrAllocateMessagePointer(CaptureBuffer,
57 ReadConsoleRequest->BufferSize,
58 (PVOID*)&ReadConsoleRequest->Buffer);
59
60 ReadConsoleRequest->ConsoleHandle = hConsoleInput;
61 ReadConsoleRequest->Unicode = bUnicode;
62 ReadConsoleRequest->NrCharactersToRead = (WORD)nNumberOfCharsToRead;
63 ReadConsoleRequest->NrCharactersRead = 0;
64 ReadConsoleRequest->CtrlWakeupMask = 0;
65 if (pInputControl && pInputControl->nLength == sizeof(CONSOLE_READCONSOLE_CONTROL))
66 {
67 ReadConsoleRequest->NrCharactersRead = pInputControl->nInitialChars;
68 memcpy(ReadConsoleRequest->Buffer,
69 lpBuffer,
70 pInputControl->nInitialChars * sizeof(WCHAR));
71 ReadConsoleRequest->CtrlWakeupMask = pInputControl->dwCtrlWakeupMask;
72 }
73
74 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
75 CaptureBuffer,
76 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepReadConsole),
77 sizeof(CSRSS_READ_CONSOLE));
78 if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = ApiMessage.Status))
79 {
80 DPRINT1("CSR returned error in ReadConsole\n");
81 CsrFreeCaptureBuffer(CaptureBuffer);
82 BaseSetLastNTError(Status);
83 return FALSE;
84 }
85
86 memcpy(lpBuffer,
87 ReadConsoleRequest->Buffer,
88 ReadConsoleRequest->NrCharactersRead * CharSize);
89
90 if (lpNumberOfCharsRead != NULL)
91 *lpNumberOfCharsRead = ReadConsoleRequest->NrCharactersRead;
92
93 if (pInputControl && pInputControl->nLength == sizeof(CONSOLE_READCONSOLE_CONTROL))
94 pInputControl->dwControlKeyState = ReadConsoleRequest->ControlKeyState;
95
96 CsrFreeCaptureBuffer(CaptureBuffer);
97
98 return TRUE;
99 }
100
101
102 static
103 BOOL
104 IntGetConsoleInput(HANDLE hConsoleInput,
105 BOOL bRead,
106 PINPUT_RECORD lpBuffer,
107 DWORD nLength,
108 LPDWORD lpNumberOfEventsRead,
109 BOOL bUnicode)
110 {
111 NTSTATUS Status;
112 CONSOLE_API_MESSAGE ApiMessage;
113 PCSRSS_GET_CONSOLE_INPUT GetConsoleInputRequest = &ApiMessage.Data.GetConsoleInputRequest;
114 PCSR_CAPTURE_BUFFER CaptureBuffer;
115 ULONG Size;
116
117 if (lpBuffer == NULL)
118 {
119 SetLastError(ERROR_INVALID_PARAMETER);
120 return FALSE;
121 }
122
123 Size = nLength * sizeof(INPUT_RECORD);
124
125 DPRINT("IntGetConsoleInput: %lx %p\n", Size, lpNumberOfEventsRead);
126
127 /* Allocate a Capture Buffer */
128 CaptureBuffer = CsrAllocateCaptureBuffer(1, Size);
129 if (CaptureBuffer == NULL)
130 {
131 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
132 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
133 return FALSE;
134 }
135
136 /* Allocate space in the Buffer */
137 CsrAllocateMessagePointer(CaptureBuffer,
138 Size,
139 (PVOID*)&GetConsoleInputRequest->InputRecord);
140
141 /* Set up the data to send to the Console Server */
142 GetConsoleInputRequest->ConsoleHandle = hConsoleInput;
143 GetConsoleInputRequest->Unicode = bUnicode;
144 GetConsoleInputRequest->bRead = bRead;
145 if (bRead == TRUE)
146 {
147 GetConsoleInputRequest->InputsRead = 0;
148 }
149 GetConsoleInputRequest->Length = nLength;
150
151 /* Call the server */
152 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
153 CaptureBuffer,
154 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepGetConsoleInput),
155 sizeof(CSRSS_GET_CONSOLE_INPUT));
156 DPRINT("Server returned: %x\n", ApiMessage.Status);
157
158 /** For Read only **
159 if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = ApiMessage.Status))
160 {
161 // BaseSetLastNTError(Status); ????
162 if (GetConsoleInputRequest->InputsRead == 0)
163 {
164 /\* we couldn't read a single record, fail *\/
165 BaseSetLastNTError(Status);
166 return FALSE;
167 }
168 else
169 {
170 /\* FIXME - fail gracefully in case we already read at least one record? *\/
171 // break;
172 }
173 }
174 **/
175
176 /**
177 ** TODO: !! Simplify the function !!
178 **/
179 if (bRead == TRUE) // ReadConsoleInput call.
180 {
181 /* Check for success */
182 if (NT_SUCCESS(Status) || NT_SUCCESS(Status = ApiMessage.Status))
183 {
184 /* Return the number of events read */
185 DPRINT("Events read: %lx\n", GetConsoleInputRequest->InputsRead/*Length*/);
186
187 if (lpNumberOfEventsRead != NULL)
188 *lpNumberOfEventsRead = GetConsoleInputRequest->InputsRead/*Length*/;
189
190 /* Copy into the buffer */
191 DPRINT("Copying to buffer\n");
192 RtlCopyMemory(lpBuffer,
193 GetConsoleInputRequest->InputRecord,
194 sizeof(INPUT_RECORD) * GetConsoleInputRequest->InputsRead/*Length*/);
195 }
196 else
197 {
198 if (lpNumberOfEventsRead != NULL)
199 *lpNumberOfEventsRead = 0;
200
201 /* Error out */
202 BaseSetLastNTError(ApiMessage.Status);
203 }
204
205 /* Release the capture buffer */
206 CsrFreeCaptureBuffer(CaptureBuffer);
207
208 return (GetConsoleInputRequest->InputsRead > 0);
209 }
210 else // PeekConsoleInput call.
211 {
212 /* Check for success */
213 if (NT_SUCCESS(Status) || NT_SUCCESS(ApiMessage.Status))
214 {
215 /* Return the number of events read */
216 DPRINT("Events read: %lx\n", GetConsoleInputRequest->Length);
217
218 if (lpNumberOfEventsRead != NULL)
219 *lpNumberOfEventsRead = GetConsoleInputRequest->Length;
220
221 /* Copy into the buffer */
222 DPRINT("Copying to buffer\n");
223 RtlCopyMemory(lpBuffer,
224 GetConsoleInputRequest->InputRecord,
225 sizeof(INPUT_RECORD) * GetConsoleInputRequest->Length);
226 }
227 else
228 {
229 if (lpNumberOfEventsRead != NULL)
230 *lpNumberOfEventsRead = 0;
231
232 /* Error out */
233 BaseSetLastNTError(ApiMessage.Status);
234 }
235
236 /* Release the capture buffer */
237 CsrFreeCaptureBuffer(CaptureBuffer);
238
239 /* Return TRUE or FALSE */
240 return NT_SUCCESS(ApiMessage.Status);
241 }
242 }
243
244
245 static
246 BOOL
247 IntReadConsoleOutput(HANDLE hConsoleOutput,
248 PCHAR_INFO lpBuffer,
249 COORD dwBufferSize,
250 COORD dwBufferCoord,
251 PSMALL_RECT lpReadRegion,
252 BOOL bUnicode)
253 {
254 CONSOLE_API_MESSAGE ApiMessage;
255 PCSRSS_READ_CONSOLE_OUTPUT ReadConsoleOutputRequest = &ApiMessage.Data.ReadConsoleOutputRequest;
256 PCSR_CAPTURE_BUFFER CaptureBuffer;
257 DWORD Size, SizeX, SizeY;
258
259 if (lpBuffer == NULL)
260 {
261 SetLastError(ERROR_INVALID_PARAMETER);
262 return FALSE;
263 }
264
265 Size = dwBufferSize.X * dwBufferSize.Y * sizeof(CHAR_INFO);
266
267 DPRINT("IntReadConsoleOutput: %lx %p\n", Size, lpReadRegion);
268
269 /* Allocate a Capture Buffer */
270 CaptureBuffer = CsrAllocateCaptureBuffer(1, Size);
271 if (CaptureBuffer == NULL)
272 {
273 DPRINT1("CsrAllocateCaptureBuffer failed with size 0x%x!\n", Size);
274 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
275 return FALSE;
276 }
277
278 /* Allocate space in the Buffer */
279 CsrAllocateMessagePointer(CaptureBuffer,
280 Size,
281 (PVOID*)&ReadConsoleOutputRequest->CharInfo);
282
283 /* Set up the data to send to the Console Server */
284 ReadConsoleOutputRequest->ConsoleHandle = hConsoleOutput;
285 ReadConsoleOutputRequest->Unicode = bUnicode;
286 ReadConsoleOutputRequest->BufferSize = dwBufferSize;
287 ReadConsoleOutputRequest->BufferCoord = dwBufferCoord;
288 ReadConsoleOutputRequest->ReadRegion = *lpReadRegion;
289
290 /* Call the server */
291 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
292 CaptureBuffer,
293 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepReadConsoleOutput),
294 sizeof(CSRSS_READ_CONSOLE_OUTPUT));
295 DPRINT("Server returned: %x\n", ApiMessage.Status);
296
297 /* Check for success*/
298 if (NT_SUCCESS(ApiMessage.Status))
299 {
300 /* Copy into the buffer */
301 DPRINT("Copying to buffer\n");
302 SizeX = ReadConsoleOutputRequest->ReadRegion.Right -
303 ReadConsoleOutputRequest->ReadRegion.Left + 1;
304 SizeY = ReadConsoleOutputRequest->ReadRegion.Bottom -
305 ReadConsoleOutputRequest->ReadRegion.Top + 1;
306 RtlCopyMemory(lpBuffer,
307 ReadConsoleOutputRequest->CharInfo,
308 sizeof(CHAR_INFO) * SizeX * SizeY);
309 }
310 else
311 {
312 /* Error out */
313 BaseSetLastNTError(ApiMessage.Status);
314 }
315
316 /* Return the read region */
317 DPRINT("read region: %lx\n", ReadConsoleOutputRequest->ReadRegion);
318 *lpReadRegion = ReadConsoleOutputRequest->ReadRegion;
319
320 /* Release the capture buffer */
321 CsrFreeCaptureBuffer(CaptureBuffer);
322
323 /* Return TRUE or FALSE */
324 return NT_SUCCESS(ApiMessage.Status);
325 }
326
327
328 static
329 BOOL
330 IntReadConsoleOutputCode(HANDLE hConsoleOutput,
331 CODE_TYPE CodeType,
332 PVOID pCode,
333 DWORD nLength,
334 COORD dwReadCoord,
335 LPDWORD lpNumberOfCodesRead)
336 {
337 NTSTATUS Status;
338 CONSOLE_API_MESSAGE ApiMessage;
339 PCSRSS_READ_CONSOLE_OUTPUT_CODE ReadConsoleOutputCodeRequest = &ApiMessage.Data.ReadConsoleOutputCodeRequest;
340 PCSR_CAPTURE_BUFFER CaptureBuffer;
341 ULONG SizeBytes, CodeSize;
342 DWORD /*CodesRead = 0,*/ BytesRead;
343
344 /* Determine the needed size */
345 switch (CodeType)
346 {
347 case CODE_ASCII:
348 CodeSize = sizeof(CHAR);
349 break;
350
351 case CODE_UNICODE:
352 CodeSize = sizeof(WCHAR);
353 break;
354
355 case CODE_ATTRIBUTE:
356 CodeSize = sizeof(WORD);
357 break;
358
359 default:
360 SetLastError(ERROR_INVALID_PARAMETER);
361 return FALSE;
362 }
363 SizeBytes = nLength * CodeSize;
364
365 /* Allocate a Capture Buffer */
366 CaptureBuffer = CsrAllocateCaptureBuffer(1, SizeBytes);
367 if (CaptureBuffer == NULL)
368 {
369 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
370 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
371 return FALSE;
372 }
373
374 /* Allocate space in the Buffer */
375 CsrAllocateMessagePointer(CaptureBuffer,
376 SizeBytes,
377 (PVOID*)&ReadConsoleOutputCodeRequest->pCode.pCode);
378
379 /* Start reading */
380 ReadConsoleOutputCodeRequest->ConsoleHandle = hConsoleOutput;
381 ReadConsoleOutputCodeRequest->CodeType = CodeType;
382 ReadConsoleOutputCodeRequest->ReadCoord = dwReadCoord;
383
384 // while (nLength > 0)
385 {
386 ReadConsoleOutputCodeRequest->NumCodesToRead = nLength;
387 // SizeBytes = ReadConsoleOutputCodeRequest->NumCodesToRead * CodeSize;
388
389 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
390 CaptureBuffer,
391 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepReadConsoleOutputString),
392 sizeof(CSRSS_READ_CONSOLE_OUTPUT_CODE));
393 if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = ApiMessage.Status))
394 {
395 BaseSetLastNTError(Status);
396 CsrFreeCaptureBuffer(CaptureBuffer);
397 return FALSE;
398 }
399
400 BytesRead = ReadConsoleOutputCodeRequest->CodesRead * CodeSize;
401 memcpy(pCode, ReadConsoleOutputCodeRequest->pCode.pCode, BytesRead);
402 // pCode = (PVOID)((ULONG_PTR)pCode + /*(ULONG_PTR)*/BytesRead);
403 // nLength -= ReadConsoleOutputCodeRequest->CodesRead;
404 // CodesRead += ReadConsoleOutputCodeRequest->CodesRead;
405
406 ReadConsoleOutputCodeRequest->ReadCoord = ReadConsoleOutputCodeRequest->EndCoord;
407 }
408
409 if (lpNumberOfCodesRead != NULL)
410 *lpNumberOfCodesRead = /*CodesRead;*/ ReadConsoleOutputCodeRequest->CodesRead;
411
412 CsrFreeCaptureBuffer(CaptureBuffer);
413
414 return TRUE;
415 }
416
417
418 /*******************
419 * Write functions *
420 *******************/
421
422 static
423 BOOL
424 IntWriteConsole(HANDLE hConsoleOutput,
425 PVOID lpBuffer,
426 DWORD nNumberOfCharsToWrite,
427 LPDWORD lpNumberOfCharsWritten,
428 LPVOID lpReserved,
429 BOOL bUnicode)
430 {
431 NTSTATUS Status;
432 CONSOLE_API_MESSAGE ApiMessage;
433 PCSRSS_WRITE_CONSOLE WriteConsoleRequest = &ApiMessage.Data.WriteConsoleRequest;
434 PCSR_CAPTURE_BUFFER CaptureBuffer;
435 // USHORT nChars;
436 ULONG /* SizeBytes, */ CharSize;
437 // DWORD Written = 0;
438
439 /* Determine the needed size */
440 CharSize = (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
441 WriteConsoleRequest->BufferSize = nNumberOfCharsToWrite * CharSize;
442
443 /* Allocate a Capture Buffer */
444 CaptureBuffer = CsrAllocateCaptureBuffer(1, WriteConsoleRequest->BufferSize);
445 if (CaptureBuffer == NULL)
446 {
447 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
448 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
449 return FALSE;
450 }
451
452 /* Capture the buffer to write */
453 CsrCaptureMessageBuffer(CaptureBuffer,
454 (PVOID)lpBuffer,
455 WriteConsoleRequest->BufferSize,
456 (PVOID*)&WriteConsoleRequest->Buffer);
457
458 /* Start writing */
459 WriteConsoleRequest->NrCharactersToWrite = nNumberOfCharsToWrite;
460 WriteConsoleRequest->ConsoleHandle = hConsoleOutput;
461 WriteConsoleRequest->Unicode = bUnicode;
462
463 // while (nNumberOfCharsToWrite > 0)
464 {
465 //// nChars = (USHORT)min(nNumberOfCharsToWrite, CSRSS_MAX_WRITE_CONSOLE / CharSize);
466 // nChars = nNumberOfCharsToWrite;
467 // WriteConsoleRequest->NrCharactersToWrite = nChars;
468
469 // SizeBytes = nChars * CharSize;
470
471 // memcpy(WriteConsoleRequest->Buffer, lpBuffer, SizeBytes);
472
473 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
474 CaptureBuffer,
475 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepWriteConsole),
476 sizeof(CSRSS_WRITE_CONSOLE));
477 /** FIXME: Added in 47359 for pausing
478
479 if (Status == STATUS_PENDING)
480 {
481 WaitForSingleObject(WriteConsoleRequest->UnpauseEvent, INFINITE);
482 CloseHandle(WriteConsoleRequest->UnpauseEvent);
483 continue;
484 }
485 **/
486 if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = ApiMessage.Status))
487 {
488 CsrFreeCaptureBuffer(CaptureBuffer);
489 BaseSetLastNTError(Status);
490 return FALSE;
491 }
492
493 // nNumberOfCharsToWrite -= nChars;
494 // lpBuffer = (PVOID)((ULONG_PTR)lpBuffer + (ULONG_PTR)SizeBytes);
495 // Written += WriteConsoleRequest->NrCharactersWritten;
496 }
497
498 if (lpNumberOfCharsWritten != NULL)
499 // *lpNumberOfCharsWritten = Written;
500 *lpNumberOfCharsWritten = WriteConsoleRequest->NrCharactersWritten;
501
502 CsrFreeCaptureBuffer(CaptureBuffer);
503
504 return TRUE;
505 }
506
507
508 static
509 BOOL
510 IntWriteConsoleInput(HANDLE hConsoleInput,
511 PINPUT_RECORD lpBuffer,
512 DWORD nLength,
513 LPDWORD lpNumberOfEventsWritten,
514 BOOL bUnicode)
515 {
516 CONSOLE_API_MESSAGE ApiMessage;
517 PCSRSS_WRITE_CONSOLE_INPUT WriteConsoleInputRequest = &ApiMessage.Data.WriteConsoleInputRequest;
518 PCSR_CAPTURE_BUFFER CaptureBuffer;
519 DWORD Size;
520
521 if (lpBuffer == NULL)
522 {
523 SetLastError(ERROR_INVALID_PARAMETER);
524 return FALSE;
525 }
526
527 Size = nLength * sizeof(INPUT_RECORD);
528
529 DPRINT("IntWriteConsoleInput: %lx %p\n", Size, lpNumberOfEventsWritten);
530
531 /* Allocate a Capture Buffer */
532 CaptureBuffer = CsrAllocateCaptureBuffer(1, Size);
533 if (CaptureBuffer == NULL)
534 {
535 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
536 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
537 return FALSE;
538 }
539
540 /* Capture the user buffer */
541 CsrCaptureMessageBuffer(CaptureBuffer,
542 lpBuffer,
543 Size,
544 (PVOID*)&WriteConsoleInputRequest->InputRecord);
545
546 /* Set up the data to send to the Console Server */
547 WriteConsoleInputRequest->ConsoleHandle = hConsoleInput;
548 WriteConsoleInputRequest->Unicode = bUnicode;
549 WriteConsoleInputRequest->Length = nLength;
550
551 /* Call the server */
552 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
553 CaptureBuffer,
554 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepWriteConsoleInput),
555 sizeof(CSRSS_WRITE_CONSOLE_INPUT));
556 DPRINT("Server returned: %x\n", ApiMessage.Status);
557
558 /* Check for success*/
559 if (NT_SUCCESS(ApiMessage.Status))
560 {
561 /* Return the number of events read */
562 DPRINT("Events read: %lx\n", WriteConsoleInputRequest->Length);
563
564 if (lpNumberOfEventsWritten != NULL)
565 *lpNumberOfEventsWritten = WriteConsoleInputRequest->Length;
566 }
567 else
568 {
569 if (lpNumberOfEventsWritten != NULL)
570 *lpNumberOfEventsWritten = 0;
571
572 /* Error out */
573 BaseSetLastNTError(ApiMessage.Status);
574 }
575
576 /* Release the capture buffer */
577 CsrFreeCaptureBuffer(CaptureBuffer);
578
579 /* Return TRUE or FALSE */
580 return NT_SUCCESS(ApiMessage.Status);
581 }
582
583
584 static
585 BOOL
586 IntWriteConsoleOutput(HANDLE hConsoleOutput,
587 CONST CHAR_INFO *lpBuffer,
588 COORD dwBufferSize,
589 COORD dwBufferCoord,
590 PSMALL_RECT lpWriteRegion,
591 BOOL bUnicode)
592 {
593 CONSOLE_API_MESSAGE ApiMessage;
594 PCSRSS_WRITE_CONSOLE_OUTPUT WriteConsoleOutputRequest = &ApiMessage.Data.WriteConsoleOutputRequest;
595 PCSR_CAPTURE_BUFFER CaptureBuffer;
596 ULONG Size;
597
598 if ((lpBuffer == NULL) || (lpWriteRegion == NULL))
599 {
600 SetLastError(ERROR_INVALID_PARAMETER);
601 return FALSE;
602 }
603
604 Size = dwBufferSize.Y * dwBufferSize.X * sizeof(CHAR_INFO);
605
606 DPRINT("IntWriteConsoleOutput: %lx %p\n", Size, lpWriteRegion);
607
608 /* Allocate a Capture Buffer */
609 CaptureBuffer = CsrAllocateCaptureBuffer(1, Size);
610 if (CaptureBuffer == NULL)
611 {
612 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
613 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
614 return FALSE;
615 }
616
617 /* Capture the user buffer */
618 CsrCaptureMessageBuffer(CaptureBuffer,
619 (PVOID)lpBuffer,
620 Size,
621 (PVOID*)&WriteConsoleOutputRequest->CharInfo);
622
623 /* Set up the data to send to the Console Server */
624 WriteConsoleOutputRequest->ConsoleHandle = hConsoleOutput;
625 WriteConsoleOutputRequest->Unicode = bUnicode;
626 WriteConsoleOutputRequest->BufferSize = dwBufferSize;
627 WriteConsoleOutputRequest->BufferCoord = dwBufferCoord;
628 WriteConsoleOutputRequest->WriteRegion = *lpWriteRegion;
629
630 /* Call the server */
631 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
632 CaptureBuffer,
633 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepWriteConsoleOutput),
634 sizeof(CSRSS_WRITE_CONSOLE_OUTPUT));
635 DPRINT("Server returned: %x\n", ApiMessage.Status);
636
637 /* Check for success*/
638 if (!NT_SUCCESS(ApiMessage.Status))
639 {
640 /* Error out */
641 BaseSetLastNTError(ApiMessage.Status);
642 }
643
644 /* Return the read region */
645 DPRINT("read region: %lx\n", WriteConsoleOutputRequest->WriteRegion);
646 *lpWriteRegion = WriteConsoleOutputRequest->WriteRegion;
647
648 /* Release the capture buffer */
649 CsrFreeCaptureBuffer(CaptureBuffer);
650
651 /* Return TRUE or FALSE */
652 return NT_SUCCESS(ApiMessage.Status);
653 }
654
655
656 static
657 BOOL
658 IntWriteConsoleOutputCode(HANDLE hConsoleOutput,
659 CODE_TYPE CodeType,
660 CONST VOID *pCode,
661 DWORD nLength,
662 COORD dwWriteCoord,
663 LPDWORD lpNumberOfCodesWritten)
664 {
665 NTSTATUS Status;
666 CONSOLE_API_MESSAGE ApiMessage;
667 PCSRSS_WRITE_CONSOLE_OUTPUT_CODE WriteConsoleOutputCodeRequest = &ApiMessage.Data.WriteConsoleOutputCodeRequest;
668 PCSR_CAPTURE_BUFFER CaptureBuffer;
669 ULONG CodeSize; //, nChars;
670 // ULONG SizeBytes;
671 // DWORD Written = 0;
672
673 /* Determine the needed size */
674 /*
675 CodeSize = (bUnicode ? sizeof(WCHAR) : sizeof(CHAR));
676 nChars = min(nLength, CSRSS_MAX_WRITE_CONSOLE_OUTPUT_CHAR / CodeSize);
677 SizeBytes = nChars * CodeSize;
678 */
679 switch (CodeType)
680 {
681 case CODE_ASCII:
682 CodeSize = sizeof(CHAR);
683 break;
684
685 case CODE_UNICODE:
686 CodeSize = sizeof(WCHAR);
687 break;
688
689 case CODE_ATTRIBUTE:
690 CodeSize = sizeof(WORD);
691 break;
692
693 default:
694 SetLastError(ERROR_INVALID_PARAMETER);
695 return FALSE;
696 }
697 WriteConsoleOutputCodeRequest->BufferSize = nLength * CodeSize;
698
699 /* Allocate a Capture Buffer */
700 CaptureBuffer = CsrAllocateCaptureBuffer(1, WriteConsoleOutputCodeRequest->BufferSize);
701 if (CaptureBuffer == NULL)
702 {
703 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
704 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
705 return FALSE;
706 }
707
708 /*
709 /\* Allocate space in the Buffer *\/
710 CsrAllocateMessagePointer(CaptureBuffer,
711 SizeBytes,
712 (PVOID*)&WriteConsoleOutputCodeRequest->pCode.pCode);
713 */
714 /* Capture the buffer to write */
715 CsrCaptureMessageBuffer(CaptureBuffer,
716 (PVOID)pCode,
717 WriteConsoleOutputCodeRequest->BufferSize,
718 (PVOID*)&WriteConsoleOutputCodeRequest->pCode.pCode);
719
720 /* Start writing */
721 WriteConsoleOutputCodeRequest->ConsoleHandle = hConsoleOutput;
722 WriteConsoleOutputCodeRequest->CodeType = CodeType;
723 WriteConsoleOutputCodeRequest->Coord = dwWriteCoord;
724
725 /**
726 ** TODO: HACK: Surely it has to go into CONSRV !!
727 **/
728 // while (nLength > 0)
729 {
730 // DWORD BytesWrite;
731
732 WriteConsoleOutputCodeRequest->Length = nLength; // (WORD)min(nLength, nChars);
733 // BytesWrite = WriteConsoleOutputCodeRequest->Length * CodeSize;
734
735 // memcpy(WriteConsoleOutputCodeRequest->pCode.pCode, pCode, BytesWrite);
736
737 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
738 CaptureBuffer,
739 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepWriteConsoleOutputString),
740 sizeof(CSRSS_WRITE_CONSOLE_OUTPUT_CODE));
741 if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = ApiMessage.Status))
742 {
743 CsrFreeCaptureBuffer(CaptureBuffer);
744 BaseSetLastNTError(Status);
745 return FALSE;
746 }
747
748 // nLength -= WriteConsoleOutputCodeRequest->NrCharactersWritten;
749 // pCode = (PVOID)((ULONG_PTR)pCode + /*(ULONG_PTR)(*/WriteConsoleOutputCodeRequest->NrCharactersWritten * CodeSize/*)*/);
750 // Written += WriteConsoleOutputCodeRequest->NrCharactersWritten;
751
752 WriteConsoleOutputCodeRequest->Coord = WriteConsoleOutputCodeRequest->EndCoord;
753 }
754
755 if (lpNumberOfCodesWritten != NULL)
756 // *lpNumberOfCodesWritten = Written;
757 // *lpNumberOfCodesWritten = WriteConsoleOutputCodeRequest->NrCharactersWritten;
758 *lpNumberOfCodesWritten = WriteConsoleOutputCodeRequest->Length;
759
760 CsrFreeCaptureBuffer(CaptureBuffer);
761
762 return TRUE;
763 }
764
765
766 static
767 BOOL
768 IntFillConsoleOutputCode(HANDLE hConsoleOutput,
769 CODE_TYPE CodeType,
770 PVOID pCode,
771 DWORD nLength,
772 COORD dwWriteCoord,
773 LPDWORD lpNumberOfCodesWritten)
774 {
775 NTSTATUS Status;
776 CONSOLE_API_MESSAGE ApiMessage;
777 PCSRSS_FILL_OUTPUT FillOutputRequest = &ApiMessage.Data.FillOutputRequest;
778
779 FillOutputRequest->ConsoleHandle = hConsoleOutput;
780 FillOutputRequest->CodeType = CodeType;
781
782 switch (CodeType)
783 {
784 case CODE_ASCII:
785 FillOutputRequest->Code.AsciiChar = *(PCHAR)pCode;
786 break;
787
788 case CODE_UNICODE:
789 FillOutputRequest->Code.UnicodeChar = *(PWCHAR)pCode;
790 break;
791
792 case CODE_ATTRIBUTE:
793 FillOutputRequest->Code.Attribute = *(PWORD)pCode;
794 break;
795
796 default:
797 SetLastError(ERROR_INVALID_PARAMETER);
798 return FALSE;
799 }
800
801 FillOutputRequest->Coord = dwWriteCoord;
802 FillOutputRequest->Length = nLength;
803
804 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
805 NULL,
806 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepFillConsoleOutput),
807 sizeof(CSRSS_FILL_OUTPUT));
808 if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = ApiMessage.Status))
809 {
810 BaseSetLastNTError(Status);
811 return FALSE;
812 }
813
814 if (lpNumberOfCodesWritten)
815 *lpNumberOfCodesWritten = FillOutputRequest->Length;
816 // *lpNumberOfCodesWritten = Request.Data.FillOutputRequest.NrCharactersWritten;
817
818 return TRUE;
819 }
820
821
822 /* FUNCTIONS ******************************************************************/
823
824 /******************
825 * Read functions *
826 ******************/
827
828 /*--------------------------------------------------------------
829 * ReadConsoleW
830 *
831 * @implemented
832 */
833 BOOL
834 WINAPI
835 ReadConsoleW(HANDLE hConsoleInput,
836 LPVOID lpBuffer,
837 DWORD nNumberOfCharsToRead,
838 LPDWORD lpNumberOfCharsRead,
839 PCONSOLE_READCONSOLE_CONTROL pInputControl)
840 {
841 return IntReadConsole(hConsoleInput,
842 lpBuffer,
843 nNumberOfCharsToRead,
844 lpNumberOfCharsRead,
845 pInputControl,
846 TRUE);
847 }
848
849
850 /*--------------------------------------------------------------
851 * ReadConsoleA
852 *
853 * @implemented
854 */
855 BOOL
856 WINAPI
857 ReadConsoleA(HANDLE hConsoleInput,
858 LPVOID lpBuffer,
859 DWORD nNumberOfCharsToRead,
860 LPDWORD lpNumberOfCharsRead,
861 PCONSOLE_READCONSOLE_CONTROL pInputControl)
862 {
863 return IntReadConsole(hConsoleInput,
864 lpBuffer,
865 nNumberOfCharsToRead,
866 lpNumberOfCharsRead,
867 NULL,
868 FALSE);
869 }
870
871
872 /*--------------------------------------------------------------
873 * PeekConsoleInputW
874 *
875 * @implemented
876 */
877 BOOL
878 WINAPI
879 PeekConsoleInputW(HANDLE hConsoleInput,
880 PINPUT_RECORD lpBuffer,
881 DWORD nLength,
882 LPDWORD lpNumberOfEventsRead)
883 {
884 return IntGetConsoleInput(hConsoleInput,
885 FALSE,
886 lpBuffer,
887 nLength,
888 lpNumberOfEventsRead,
889 TRUE);
890 }
891
892
893 /*--------------------------------------------------------------
894 * PeekConsoleInputA
895 *
896 * @implemented
897 */
898 BOOL
899 WINAPI
900 PeekConsoleInputA(HANDLE hConsoleInput,
901 PINPUT_RECORD lpBuffer,
902 DWORD nLength,
903 LPDWORD lpNumberOfEventsRead)
904 {
905 return IntGetConsoleInput(hConsoleInput,
906 FALSE,
907 lpBuffer,
908 nLength,
909 lpNumberOfEventsRead,
910 FALSE);
911 }
912
913
914 /*--------------------------------------------------------------
915 * ReadConsoleInputW
916 *
917 * @implemented
918 */
919 BOOL
920 WINAPI
921 ReadConsoleInputW(HANDLE hConsoleInput,
922 PINPUT_RECORD lpBuffer,
923 DWORD nLength,
924 LPDWORD lpNumberOfEventsRead)
925 {
926 return IntGetConsoleInput(hConsoleInput,
927 TRUE,
928 lpBuffer,
929 nLength,
930 lpNumberOfEventsRead,
931 TRUE);
932 }
933
934
935 /*--------------------------------------------------------------
936 * ReadConsoleInputA
937 *
938 * @implemented
939 */
940 BOOL
941 WINAPI
942 ReadConsoleInputA(HANDLE hConsoleInput,
943 PINPUT_RECORD lpBuffer,
944 DWORD nLength,
945 LPDWORD lpNumberOfEventsRead)
946 {
947 return IntGetConsoleInput(hConsoleInput,
948 TRUE,
949 lpBuffer,
950 nLength,
951 lpNumberOfEventsRead,
952 FALSE);
953 }
954
955
956 BOOL
957 WINAPI
958 ReadConsoleInputExW(HANDLE hConsole, LPVOID lpBuffer, DWORD dwLen, LPDWORD Unknown1, DWORD Unknown2)
959 {
960 STUB;
961 return FALSE;
962 }
963
964
965 BOOL
966 WINAPI
967 ReadConsoleInputExA(HANDLE hConsole, LPVOID lpBuffer, DWORD dwLen, LPDWORD Unknown1, DWORD Unknown2)
968 {
969 STUB;
970 return FALSE;
971 }
972
973
974 /*--------------------------------------------------------------
975 * ReadConsoleOutputW
976 *
977 * @implemented
978 */
979 BOOL
980 WINAPI
981 ReadConsoleOutputW(HANDLE hConsoleOutput,
982 PCHAR_INFO lpBuffer,
983 COORD dwBufferSize,
984 COORD dwBufferCoord,
985 PSMALL_RECT lpReadRegion)
986 {
987 return IntReadConsoleOutput(hConsoleOutput,
988 lpBuffer,
989 dwBufferSize,
990 dwBufferCoord,
991 lpReadRegion,
992 TRUE);
993 }
994
995
996 /*--------------------------------------------------------------
997 * ReadConsoleOutputA
998 *
999 * @implemented
1000 */
1001 BOOL
1002 WINAPI
1003 ReadConsoleOutputA(HANDLE hConsoleOutput,
1004 PCHAR_INFO lpBuffer,
1005 COORD dwBufferSize,
1006 COORD dwBufferCoord,
1007 PSMALL_RECT lpReadRegion)
1008 {
1009 return IntReadConsoleOutput(hConsoleOutput,
1010 lpBuffer,
1011 dwBufferSize,
1012 dwBufferCoord,
1013 lpReadRegion,
1014 FALSE);
1015 }
1016
1017
1018 /*--------------------------------------------------------------
1019 * ReadConsoleOutputCharacterW
1020 *
1021 * @implemented
1022 */
1023 BOOL
1024 WINAPI
1025 ReadConsoleOutputCharacterW(HANDLE hConsoleOutput,
1026 LPWSTR lpCharacter,
1027 DWORD nLength,
1028 COORD dwReadCoord,
1029 LPDWORD lpNumberOfCharsRead)
1030 {
1031 return IntReadConsoleOutputCode(hConsoleOutput,
1032 CODE_UNICODE,
1033 lpCharacter,
1034 nLength,
1035 dwReadCoord,
1036 lpNumberOfCharsRead);
1037 }
1038
1039
1040 /*--------------------------------------------------------------
1041 * ReadConsoleOutputCharacterA
1042 *
1043 * @implemented
1044 */
1045 BOOL
1046 WINAPI
1047 ReadConsoleOutputCharacterA(HANDLE hConsoleOutput,
1048 LPSTR lpCharacter,
1049 DWORD nLength,
1050 COORD dwReadCoord,
1051 LPDWORD lpNumberOfCharsRead)
1052 {
1053 return IntReadConsoleOutputCode(hConsoleOutput,
1054 CODE_ASCII,
1055 lpCharacter,
1056 nLength,
1057 dwReadCoord,
1058 lpNumberOfCharsRead);
1059 }
1060
1061
1062 /*--------------------------------------------------------------
1063 * ReadConsoleOutputAttribute
1064 *
1065 * @implemented
1066 */
1067 BOOL
1068 WINAPI
1069 ReadConsoleOutputAttribute(HANDLE hConsoleOutput,
1070 LPWORD lpAttribute,
1071 DWORD nLength,
1072 COORD dwReadCoord,
1073 LPDWORD lpNumberOfAttrsRead)
1074 {
1075 return IntReadConsoleOutputCode(hConsoleOutput,
1076 CODE_ATTRIBUTE,
1077 lpAttribute,
1078 nLength,
1079 dwReadCoord,
1080 lpNumberOfAttrsRead);
1081 }
1082
1083
1084 /*******************
1085 * Write functions *
1086 *******************/
1087
1088 /*--------------------------------------------------------------
1089 * WriteConsoleW
1090 *
1091 * @implemented
1092 */
1093 BOOL
1094 WINAPI
1095 WriteConsoleW(HANDLE hConsoleOutput,
1096 CONST VOID *lpBuffer,
1097 DWORD nNumberOfCharsToWrite,
1098 LPDWORD lpNumberOfCharsWritten,
1099 LPVOID lpReserved)
1100 {
1101 return IntWriteConsole(hConsoleOutput,
1102 (PVOID)lpBuffer,
1103 nNumberOfCharsToWrite,
1104 lpNumberOfCharsWritten,
1105 lpReserved,
1106 TRUE);
1107 }
1108
1109
1110 /*--------------------------------------------------------------
1111 * WriteConsoleA
1112 *
1113 * @implemented
1114 */
1115 BOOL
1116 WINAPI
1117 WriteConsoleA(HANDLE hConsoleOutput,
1118 CONST VOID *lpBuffer,
1119 DWORD nNumberOfCharsToWrite,
1120 LPDWORD lpNumberOfCharsWritten,
1121 LPVOID lpReserved)
1122 {
1123 return IntWriteConsole(hConsoleOutput,
1124 (PVOID)lpBuffer,
1125 nNumberOfCharsToWrite,
1126 lpNumberOfCharsWritten,
1127 lpReserved,
1128 FALSE);
1129 }
1130
1131
1132 /*--------------------------------------------------------------
1133 * WriteConsoleInputW
1134 *
1135 * @implemented
1136 */
1137 BOOL
1138 WINAPI
1139 WriteConsoleInputW(HANDLE hConsoleInput,
1140 CONST INPUT_RECORD *lpBuffer,
1141 DWORD nLength,
1142 LPDWORD lpNumberOfEventsWritten)
1143 {
1144 return IntWriteConsoleInput(hConsoleInput,
1145 (PINPUT_RECORD)lpBuffer,
1146 nLength,
1147 lpNumberOfEventsWritten,
1148 TRUE);
1149 }
1150
1151
1152 /*--------------------------------------------------------------
1153 * WriteConsoleInputA
1154 *
1155 * @implemented
1156 */
1157 BOOL
1158 WINAPI
1159 WriteConsoleInputA(HANDLE hConsoleInput,
1160 CONST INPUT_RECORD *lpBuffer,
1161 DWORD nLength,
1162 LPDWORD lpNumberOfEventsWritten)
1163 {
1164 return IntWriteConsoleInput(hConsoleInput,
1165 (PINPUT_RECORD)lpBuffer,
1166 nLength,
1167 lpNumberOfEventsWritten,
1168 FALSE);
1169 }
1170
1171
1172 /*--------------------------------------------------------------
1173 * WriteConsoleOutputW
1174 *
1175 * @implemented
1176 */
1177 BOOL
1178 WINAPI
1179 WriteConsoleOutputW(HANDLE hConsoleOutput,
1180 CONST CHAR_INFO *lpBuffer,
1181 COORD dwBufferSize,
1182 COORD dwBufferCoord,
1183 PSMALL_RECT lpWriteRegion)
1184 {
1185 return IntWriteConsoleOutput(hConsoleOutput,
1186 lpBuffer,
1187 dwBufferSize,
1188 dwBufferCoord,
1189 lpWriteRegion,
1190 TRUE);
1191 }
1192
1193
1194 /*--------------------------------------------------------------
1195 * WriteConsoleOutputA
1196 *
1197 * @implemented
1198 */
1199 BOOL
1200 WINAPI
1201 WriteConsoleOutputA(HANDLE hConsoleOutput,
1202 CONST CHAR_INFO *lpBuffer,
1203 COORD dwBufferSize,
1204 COORD dwBufferCoord,
1205 PSMALL_RECT lpWriteRegion)
1206 {
1207 return IntWriteConsoleOutput(hConsoleOutput,
1208 lpBuffer,
1209 dwBufferSize,
1210 dwBufferCoord,
1211 lpWriteRegion,
1212 FALSE);
1213 }
1214
1215
1216 /*--------------------------------------------------------------
1217 * WriteConsoleOutputCharacterW
1218 *
1219 * @implemented
1220 */
1221 BOOL
1222 WINAPI
1223 WriteConsoleOutputCharacterW(HANDLE hConsoleOutput,
1224 LPCWSTR lpCharacter,
1225 DWORD nLength,
1226 COORD dwWriteCoord,
1227 LPDWORD lpNumberOfCharsWritten)
1228 {
1229 return IntWriteConsoleOutputCode(hConsoleOutput,
1230 CODE_UNICODE,
1231 lpCharacter,
1232 nLength,
1233 dwWriteCoord,
1234 lpNumberOfCharsWritten);
1235 }
1236
1237
1238 /*--------------------------------------------------------------
1239 * WriteConsoleOutputCharacterA
1240 *
1241 * @implemented
1242 */
1243 BOOL
1244 WINAPI
1245 WriteConsoleOutputCharacterA(HANDLE hConsoleOutput,
1246 LPCSTR lpCharacter,
1247 DWORD nLength,
1248 COORD dwWriteCoord,
1249 LPDWORD lpNumberOfCharsWritten)
1250 {
1251 return IntWriteConsoleOutputCode(hConsoleOutput,
1252 CODE_ASCII,
1253 lpCharacter,
1254 nLength,
1255 dwWriteCoord,
1256 lpNumberOfCharsWritten);
1257 }
1258
1259
1260 /*--------------------------------------------------------------
1261 * WriteConsoleOutputAttribute
1262 *
1263 * @implemented
1264 */
1265 BOOL
1266 WINAPI
1267 WriteConsoleOutputAttribute(HANDLE hConsoleOutput,
1268 CONST WORD *lpAttribute,
1269 DWORD nLength,
1270 COORD dwWriteCoord,
1271 LPDWORD lpNumberOfAttrsWritten)
1272 {
1273 return IntWriteConsoleOutputCode(hConsoleOutput,
1274 CODE_ATTRIBUTE,
1275 lpAttribute,
1276 nLength,
1277 dwWriteCoord,
1278 lpNumberOfAttrsWritten);
1279 }
1280
1281
1282 /*--------------------------------------------------------------
1283 * FillConsoleOutputCharacterW
1284 *
1285 * @implemented
1286 */
1287 BOOL
1288 WINAPI
1289 FillConsoleOutputCharacterW(HANDLE hConsoleOutput,
1290 WCHAR cCharacter,
1291 DWORD nLength,
1292 COORD dwWriteCoord,
1293 LPDWORD lpNumberOfCharsWritten)
1294 {
1295 return IntFillConsoleOutputCode(hConsoleOutput,
1296 CODE_UNICODE,
1297 &cCharacter,
1298 nLength,
1299 dwWriteCoord,
1300 lpNumberOfCharsWritten);
1301 }
1302
1303
1304 /*--------------------------------------------------------------
1305 * FillConsoleOutputCharacterA
1306 *
1307 * @implemented
1308 */
1309 BOOL
1310 WINAPI
1311 FillConsoleOutputCharacterA(HANDLE hConsoleOutput,
1312 CHAR cCharacter,
1313 DWORD nLength,
1314 COORD dwWriteCoord,
1315 LPDWORD lpNumberOfCharsWritten)
1316 {
1317 return IntFillConsoleOutputCode(hConsoleOutput,
1318 CODE_ASCII,
1319 &cCharacter,
1320 nLength,
1321 dwWriteCoord,
1322 lpNumberOfCharsWritten);
1323 }
1324
1325
1326 /*--------------------------------------------------------------
1327 * FillConsoleOutputAttribute
1328 *
1329 * @implemented
1330 */
1331 BOOL
1332 WINAPI
1333 FillConsoleOutputAttribute(HANDLE hConsoleOutput,
1334 WORD wAttribute,
1335 DWORD nLength,
1336 COORD dwWriteCoord,
1337 LPDWORD lpNumberOfAttrsWritten)
1338 {
1339 return IntFillConsoleOutputCode(hConsoleOutput,
1340 CODE_ATTRIBUTE,
1341 &wAttribute,
1342 nLength,
1343 dwWriteCoord,
1344 lpNumberOfAttrsWritten);
1345 }
1346
1347 /* EOF */