ReactOS 0.4.15-dev-5666-gc548b97
pager.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Console Utilities Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Console/terminal paging functionality.
5 * COPYRIGHT: Copyright 2017-2021 Hermes Belusca-Maito
6 * Copyright 2021 Katayama Hirofumi MZ
7 */
8
16/* FIXME: Temporary HACK before we cleanly support UNICODE functions */
17#define UNICODE
18#define _UNICODE
19
20#include <windef.h>
21#include <winbase.h>
22// #include <winnls.h>
23#include <wincon.h> // Console APIs (only if kernel32 support included)
24#include <winnls.h> // for WideCharToMultiByte
25#include <strsafe.h>
26
27#include "conutils.h"
28#include "stream.h"
29#include "screen.h"
30#include "pager.h"
31
32// Temporary HACK
33#define CON_STREAM_WRITE ConStreamWrite
34
35#define CP_SHIFTJIS 932 // Japanese Shift-JIS
36#define CP_HANGUL 949 // Korean Hangul/Wansung
37#define CP_JOHAB 1361 // Korean Johab
38#define CP_GB2312 936 // Chinese Simplified (GB2312)
39#define CP_BIG5 950 // Chinese Traditional (Big5)
40
41/* IsFarEastCP(CodePage) */
42#define IsCJKCodePage(CodePage) \
43 ((CodePage) == CP_SHIFTJIS || (CodePage) == CP_HANGUL || \
44 /* (CodePage) == CP_JOHAB || */ \
45 (CodePage) == CP_BIG5 || (CodePage) == CP_GB2312)
46
47static inline INT
49 IN UINT nCodePage,
50 IN WCHAR ch)
51{
52 INT ret = WideCharToMultiByte(nCodePage, 0, &ch, 1, NULL, 0, NULL, NULL);
53 if (ret == 0)
54 ret = 1;
55 else if (ret > 2)
56 ret = 2;
57 return ret;
58}
59
67static BOOL
69 IN OUT PCON_PAGER Pager,
70 IN PCTCH TextBuff,
72{
73 SIZE_T ich = Pager->ich;
74 SIZE_T ichStart;
75 SIZE_T cchLine;
76 BOOL bCacheLine;
77
78 Pager->ichCurr = 0;
79 Pager->iEndLine = 0;
80
81 /*
82 * If we already had an existing line, then we can safely start a new one
83 * and getting rid of any current cached line. Otherwise, we don't have
84 * a current line and we may be caching a new one, in which case, continue
85 * caching it until it becomes complete.
86 */
87 // INVESTIGATE: Do that only if (ichStart >= iEndLine) ??
88 if (Pager->CurrentLine)
89 {
90 // ASSERT(Pager->CurrentLine == Pager->CachedLine);
91 if (Pager->CachedLine)
92 {
93 HeapFree(GetProcessHeap(), 0, (PVOID)Pager->CachedLine);
94 Pager->CachedLine = NULL;
95 Pager->cchCachedLine = 0;
96 }
97
98 Pager->CurrentLine = NULL;
99 }
100
101 /* Nothing else to read if we are past the end of the buffer */
102 if (ich >= cch)
103 {
104 /* If we have a pending cached line, terminate it now */
105 if (Pager->CachedLine)
106 goto TerminateLine;
107
108 /* Otherwise, bail out */
109 return FALSE;
110 }
111
112 /* Start a new line, or continue an existing one */
113 ichStart = ich;
114
115 /* Find where this line ends, looking for a NEWLINE character.
116 * (NOTE: We cannot use strchr because the buffer is not NULL-terminated) */
117 for (; ich < cch; ++ich)
118 {
119 if (TextBuff[ich] == TEXT('\n'))
120 {
121 ++ich;
122 break;
123 }
124 }
125 Pager->ich = ich;
126
127 cchLine = (ich - ichStart);
128
129 //
130 // FIXME: Impose a maximum string limit when the line is cached, in order
131 // not to potentially grow memory indefinitely. When the limit is reached,
132 // terminate the line.
133 //
134
135 /*
136 * If we have stopped because we have exhausted the text buffer
137 * and we have not found an end-of-line character, this may mean
138 * that the text line spans across different text buffers. If we
139 * have been told so, cache this line: we will complete it during
140 * the next call(s) and only then, display it.
141 * Otherwise, consider the line to be terminated now.
142 */
143 bCacheLine = ((Pager->dwFlags & CON_PAGER_CACHE_INCOMPLETE_LINE) &&
144 (ich >= cch) && (TextBuff[ich - 1] != TEXT('\n')));
145
146 /* Allocate, or re-allocate, the cached line buffer */
147 if (bCacheLine && !Pager->CachedLine)
148 {
149 /* We start caching, allocate the cached line buffer */
150 Pager->CachedLine = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
151 cchLine * sizeof(TCHAR));
152 Pager->cchCachedLine = 0;
153
154 if (!Pager->CachedLine)
155 {
157 return FALSE;
158 }
159 }
160 else if (Pager->CachedLine)
161 {
162 /* We continue caching, re-allocate the cached line buffer */
164 (PVOID)Pager->CachedLine,
165 (Pager->cchCachedLine + cchLine) * sizeof(TCHAR));
166 if (!ptr)
167 {
168 HeapFree(GetProcessHeap(), 0, (PVOID)Pager->CachedLine);
169 Pager->CachedLine = NULL;
170 Pager->cchCachedLine = 0;
171
173 return FALSE;
174 }
175 Pager->CachedLine = ptr;
176 }
177 if (Pager->CachedLine)
178 {
179 /* Copy/append the text to the cached line buffer */
180 RtlCopyMemory((PVOID)&Pager->CachedLine[Pager->cchCachedLine],
181 &TextBuff[ichStart],
182 cchLine * sizeof(TCHAR));
183 Pager->cchCachedLine += cchLine;
184 }
185 if (bCacheLine)
186 {
187 /* The line is currently incomplete, don't proceed further for now */
188 return FALSE;
189 }
190
191TerminateLine:
192 /* The line should be complete now. If we have an existing cached line,
193 * it has been completed by appending the remaining text to it. */
194
195 /* We are starting a new line */
196 Pager->ichCurr = 0;
197 if (Pager->CachedLine)
198 {
199 Pager->iEndLine = Pager->cchCachedLine;
200 Pager->CurrentLine = Pager->CachedLine;
201 }
202 else
203 {
204 Pager->iEndLine = cchLine;
205 Pager->CurrentLine = &TextBuff[ichStart];
206 }
207
208 /* Increase only when we have got a NEWLINE */
209 if ((Pager->iEndLine > 0) && (Pager->CurrentLine[Pager->iEndLine - 1] == TEXT('\n')))
210 Pager->lineno++;
211
212 return TRUE;
213}
214
218static BOOL
220 IN PCON_PAGER Pager,
221 IN PCTCH TextBuff,
222 IN DWORD cch)
223{
224 const DWORD PageColumns = Pager->PageColumns;
225 const DWORD ScrollRows = Pager->ScrollRows;
226
227 BOOL bFinitePaging = ((PageColumns > 0) && (Pager->PageRows > 0));
228 LONG nTabWidth = Pager->nTabWidth;
229
230 PCTCH Line;
231 SIZE_T ich;
232 SIZE_T ichStart;
233 SIZE_T iEndLine;
234 DWORD iColumn = Pager->iColumn;
235
236 UINT nCodePage = GetConsoleOutputCP();
237 BOOL IsCJK = IsCJKCodePage(nCodePage);
238 UINT nWidthOfChar = 1;
239 BOOL IsDoubleWidthCharTrailing = FALSE;
240
241 /* Normalize the tab width: if negative or too large,
242 * cap it to the number of columns. */
243 if (PageColumns > 0) // if (bFinitePaging)
244 {
245 if (nTabWidth < 0)
246 nTabWidth = PageColumns - 1;
247 else
248 nTabWidth = min(nTabWidth, PageColumns - 1);
249 }
250 else
251 {
252 /* If no column width is known, default to 8 spaces if the
253 * original value is negative; otherwise keep the current one. */
254 if (nTabWidth < 0)
255 nTabWidth = 8;
256 }
257
258
259 /* Continue displaying the previous line, if any, or start a new one */
260 Line = Pager->CurrentLine;
261 ichStart = Pager->ichCurr;
262 iEndLine = Pager->iEndLine;
263
264ProcessLine:
265
266 /* Stop now if we have displayed more page lines than requested */
267 if (bFinitePaging && (Pager->iLine >= ScrollRows))
268 goto End;
269
270 if (!Line || (ichStart >= iEndLine))
271 {
272 /* Start a new line */
273 if (!GetNextLine(Pager, TextBuff, cch))
274 goto End;
275
276 Line = Pager->CurrentLine;
277 ichStart = Pager->ichCurr;
278 iEndLine = Pager->iEndLine;
279 }
280 else
281 {
282 /* Continue displaying the current line */
283 }
284
285 // ASSERT(Line && ((ichStart < iEndLine) || (ichStart == iEndLine && iEndLine == 0)));
286
287 /* Determine whether this line segment (from the current position till the end) should be displayed */
288 Pager->iColumn = iColumn;
289 if (Pager->PagerLine && Pager->PagerLine(Pager, &Line[ichStart], iEndLine - ichStart))
290 {
291 iColumn = Pager->iColumn;
292
293 /* Done with this line; start a new one */
294 Pager->nSpacePending = 0; // And reset any pending space.
295 ichStart = iEndLine;
296 goto ProcessLine;
297 }
298 // else: Continue displaying the line.
299
300
301 /* Print out any pending TAB expansion */
302 if (Pager->nSpacePending > 0)
303 {
305 while (Pager->nSpacePending > 0)
306 {
307 /* Print filling spaces */
308 CON_STREAM_WRITE(Pager->Screen->Stream, TEXT(" "), 1);
309 --(Pager->nSpacePending);
310 ++iColumn;
311
312 /* Check whether we are going across the column */
313 if ((PageColumns > 0) && (iColumn % PageColumns == 0))
314 {
315 // Pager->nSpacePending = 0; // <-- This is the mode of most text editors...
316
317 /* Reposition the cursor to the next line, first column */
318 if (!bFinitePaging || (PageColumns < Pager->Screen->csbi.dwSize.X))
319 CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\n"), 1);
320
321 Pager->iLine++;
322
323 /* Restart at the character */
324 // ASSERT(ichStart == ich);
325 goto ProcessLine;
326 }
327 }
328 }
329
330
331 /* Find, within this line segment (starting from its
332 * beginning), until where we can print to the page. */
333 for (ich = ichStart; ich < iEndLine; ++ich)
334 {
335 /* NEWLINE character */
336 if (Line[ich] == TEXT('\n'))
337 {
338 /* We should stop now */
339 // ASSERT(ich == iEndLine - 1);
340 break;
341 }
342
343 /* TAB character */
344 if (Line[ich] == TEXT('\t') &&
345 (Pager->dwFlags & CON_PAGER_EXPAND_TABS))
346 {
347 /* We should stop now */
348 break;
349 }
350
351 /* FORM-FEED character */
352 if (Line[ich] == TEXT('\f') &&
353 (Pager->dwFlags & CON_PAGER_EXPAND_FF))
354 {
355 /* We should stop now */
356 break;
357 }
358
359 /* Other character - Handle double-width for CJK */
360
361 if (IsCJK)
362 nWidthOfChar = GetWidthOfCharCJK(nCodePage, Line[ich]);
363
364 /* Care about CJK character presentation only when outputting
365 * to a device where the number of columns is known. */
366 if ((PageColumns > 0) && IsCJK)
367 {
368 IsDoubleWidthCharTrailing = (nWidthOfChar == 2) &&
369 ((iColumn + 1) % PageColumns == 0);
370 if (IsDoubleWidthCharTrailing)
371 {
372 /* Reserve this character for the next line */
373 ++iColumn; // Count a blank instead.
374 /* We should stop now */
375 break;
376 }
377 }
378
379 iColumn += nWidthOfChar;
380
381 /* Check whether we are going across the column */
382 if ((PageColumns > 0) && (iColumn % PageColumns == 0))
383 {
384 ++ich;
385 break;
386 }
387 }
388
389 /* Output the pending line segment */
390 if (ich - ichStart > 0)
391 CON_STREAM_WRITE(Pager->Screen->Stream, &Line[ichStart], ich - ichStart);
392
393 /* Have we finished the line segment? */
394 if (ich >= iEndLine)
395 {
396 /* Restart at the character */
397 ichStart = ich;
398 goto ProcessLine;
399 }
400
401 /* Handle special characters */
402
403 /* NEWLINE character */
404 if (Line[ich] == TEXT('\n'))
405 {
406 // ASSERT(ich == iEndLine - 1);
407
408 /* Reposition the cursor to the next line, first column */
409 CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\n"), 1);
410
411 Pager->iLine++;
412 iColumn = 0;
413
414 /* Done with this line; start a new one */
415 Pager->nSpacePending = 0; // And reset any pending space.
416 ichStart = iEndLine;
417 goto ProcessLine;
418 }
419
420 /* TAB character */
421 if (Line[ich] == TEXT('\t') &&
422 (Pager->dwFlags & CON_PAGER_EXPAND_TABS))
423 {
424 /* Perform TAB expansion, unless the tab width is zero */
425 if (nTabWidth == 0)
426 {
427 ichStart = ++ich;
428 goto ProcessLine;
429 }
430
431 ichStart = ++ich;
432 /* Reset the number of spaces needed to develop this TAB character */
433 Pager->nSpacePending = nTabWidth - (iColumn % nTabWidth);
434 goto ExpandTab;
435 }
436
437 /* FORM-FEED character */
438 if (Line[ich] == TEXT('\f') &&
439 (Pager->dwFlags & CON_PAGER_EXPAND_FF))
440 {
441 if (bFinitePaging)
442 {
443 /* Clear until the end of the page */
444 while (Pager->iLine < ScrollRows)
445 {
446 /* Call the user paging function in order to know
447 * whether we need to output the blank lines. */
448 Pager->iColumn = iColumn;
449 if (Pager->PagerLine && Pager->PagerLine(Pager, TEXT("\n"), 1))
450 {
451 /* Only one blank line displayed, that counts in the line count */
452 Pager->iLine++;
453 break;
454 }
455 else
456 {
457 CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\n"), 1);
458 Pager->iLine++;
459 }
460 }
461 }
462 else
463 {
464 /* Just output a FORM-FEED and a NEWLINE */
465 CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\f\n"), 2);
466 Pager->iLine++;
467 }
468
469 iColumn = 0;
470 Pager->nSpacePending = 0; // And reset any pending space.
471
472 /* Skip and restart past the character */
473 ichStart = ++ich;
474 goto ProcessLine;
475 }
476
477 /* If we output a double-width character that goes across the column,
478 * fill with blank and display the character on the next line. */
479 if (IsDoubleWidthCharTrailing)
480 {
481 IsDoubleWidthCharTrailing = FALSE; // Reset the flag.
482 CON_STREAM_WRITE(Pager->Screen->Stream, TEXT(" "), 1);
483 /* Fall back below */
484 }
485
486 /* Are we wrapping the line? */
487 if ((PageColumns > 0) && (iColumn % PageColumns == 0))
488 {
489 /* Reposition the cursor to the next line, first column */
490 if (!bFinitePaging || (PageColumns < Pager->Screen->csbi.dwSize.X))
491 CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\n"), 1);
492
493 Pager->iLine++;
494 }
495
496 /* Restart at the character */
497 ichStart = ich;
498 goto ProcessLine;
499
500
501End:
502 /*
503 * We are exiting, either because we displayed all the required lines
504 * (iLine >= ScrollRows), or, because we don't have more data to display.
505 */
506
507 Pager->ichCurr = ichStart;
508 Pager->iColumn = iColumn;
509 // INVESTIGATE: Can we get rid of CurrentLine here? // if (ichStart >= iEndLine) ...
510
511 /* Return TRUE if we displayed all the required lines; FALSE otherwise */
512 if (bFinitePaging && (Pager->iLine >= ScrollRows))
513 {
514 Pager->iLine = 0; /* Reset the count of lines being printed */
515 return TRUE;
516 }
517 else
518 {
519 return FALSE;
520 }
521}
522
523
548BOOL
550 IN PCON_PAGER Pager,
552 IN BOOL StartPaging,
553 IN PCTCH szStr,
554 IN DWORD len)
555{
557 BOOL bIsConsole;
558
559 /* Parameters validation */
560 if (!Pager)
561 return FALSE;
562
563 /* Get the size of the visual screen that can be printed to */
564 bIsConsole = ConGetScreenInfo(Pager->Screen, &csbi);
565 if (bIsConsole)
566 {
567 /* Calculate the console screen extent */
568 Pager->PageColumns = csbi.dwSize.X;
569 Pager->PageRows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
570 }
571 else
572 {
573 /* We assume it's a file handle */
574 Pager->PageColumns = 0;
575 Pager->PageRows = 0;
576 }
577
578 if (StartPaging)
579 {
580 if (bIsConsole && (Pager->PageRows >= 2))
581 {
582 /* Reset to display one page by default */
583 Pager->ScrollRows = Pager->PageRows - 1;
584 }
585 else
586 {
587 /* File output, or single line: all lines are displayed at once; reset to a default value */
588 Pager->ScrollRows = 0;
589 }
590
591 /* Reset the internal data buffer */
592 Pager->CachedLine = NULL;
593 Pager->cchCachedLine = 0;
594
595 /* Reset the paging state */
596 Pager->CurrentLine = NULL;
597 Pager->ichCurr = 0;
598 Pager->iEndLine = 0;
599 Pager->nSpacePending = 0;
600 Pager->iColumn = 0;
601 Pager->iLine = 0;
602 Pager->lineno = 0;
603 }
604
605 /* Reset the reading index in the user-provided source buffer */
606 Pager->ich = 0;
607
608 /* Run the pager even when the user-provided source buffer is
609 * empty, in case we need to flush any remaining cached line. */
610 if (!Pager->CachedLine)
611 {
612 /* No cached line, bail out now */
613 if (len == 0 || szStr == NULL)
614 return TRUE;
615 }
616
617 while (ConPagerWorker(Pager, szStr, len))
618 {
619 /* Prompt the user only when we display to a console and the screen
620 * is not too small: at least one line for the actual paged text and
621 * one line for the prompt. */
622 if (bIsConsole && (Pager->PageRows >= 2))
623 {
624 /* Reset to display one page by default */
625 Pager->ScrollRows = Pager->PageRows - 1;
626
627 /* Prompt the user; give him some values for statistics */
628 // FIXME: Doesn't reflect what's currently being displayed.
629 if (!PagePrompt(Pager, Pager->ich, len))
630 return FALSE;
631 }
632
633 /* If we display to a console, recalculate its screen extent
634 * in case the user has redimensioned it during the prompt. */
635 if (bIsConsole && ConGetScreenInfo(Pager->Screen, &csbi))
636 {
637 Pager->PageColumns = csbi.dwSize.X;
638 Pager->PageRows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
639 }
640 }
641
642 return TRUE;
643}
644
645BOOL
647 IN PCON_PAGER Pager,
649 IN BOOL StartPaging,
650 IN PCTSTR szStr)
651{
652 DWORD len;
653
654 /* Return if no string has been given */
655 if (szStr == NULL)
656 return TRUE;
657
658 len = wcslen(szStr);
659 return ConWritePaging(Pager, PagePrompt, StartPaging, szStr, len);
660}
661
662BOOL
664 IN PCON_PAGER Pager,
666 IN BOOL StartPaging,
668 IN UINT uID)
669{
670 INT Len;
671 PCWSTR szStr = NULL;
672
673 Len = K32LoadStringW(hInstance, uID, (PWSTR)&szStr, 0);
674 if (szStr && Len)
675 return ConWritePaging(Pager, PagePrompt, StartPaging, szStr, Len);
676 else
677 return TRUE;
678}
679
680BOOL
682 IN PCON_PAGER Pager,
684 IN BOOL StartPaging,
685 IN UINT uID)
686{
687 return ConResPagingEx(Pager, PagePrompt, StartPaging,
688 NULL /*GetModuleHandleW(NULL)*/, uID);
689}
690
691/* EOF */
static LPTSTR ExpandTab(LPCTSTR line)
Definition: text.h:141
HINSTANCE hInstance
Definition: charmap.c:19
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define Len
Definition: deflate.h:82
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
@ Screen
Definition: console.h:34
#define GetProcessHeap()
Definition: compat.h:736
#define SetLastError(x)
Definition: compat.h:752
#define HeapAlloc
Definition: compat.h:733
#define HeapReAlloc
Definition: compat.h:734
#define HeapFree(x, y, z)
Definition: compat.h:735
#define WideCharToMultiByte
Definition: compat.h:111
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
UINT WINAPI DECLSPEC_HOTPATCH GetConsoleOutputCP(VOID)
Definition: console.c:2451
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLenum GLsizei len
Definition: glext.h:6722
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define TEXT(s)
Definition: k32.h:26
static PVOID ptr
Definition: dispmode.c:27
static DWORD DWORD void LPSTR DWORD cch
Definition: str.c:202
#define min(a, b)
Definition: monoChain.cc:55
static BOOL __stdcall PagePrompt(PCON_PAGER Pager, DWORD Done, DWORD Total)
Definition: more.c:160
unsigned int UINT
Definition: ndis.h:50
LPCSTR PCTSTR
Definition: ntbasedef.h:488
LPCCH PCTCH
Definition: ntbasedef.h:486
Console/terminal paging functionality.
#define CON_PAGER_EXPAND_TABS
Definition: pager.h:40
BOOL(__stdcall * PAGE_PROMPT)(IN PCON_PAGER Pager, IN DWORD Done, IN DWORD Total)
Definition: pager.h:83
#define CON_PAGER_CACHE_INCOMPLETE_LINE
Definition: pager.h:43
#define CON_PAGER_EXPAND_FF
Definition: pager.h:41
long LONG
Definition: pedump.c:60
Console/terminal screen management.
static BOOL GetNextLine(IN OUT PCON_PAGER Pager, IN PCTCH TextBuff, IN SIZE_T cch)
Retrieves a new text line, or continue fetching the current one.
Definition: pager.c:68
BOOL ConResPagingEx(IN PCON_PAGER Pager, IN PAGE_PROMPT PagePrompt, IN BOOL StartPaging, IN HINSTANCE hInstance OPTIONAL, IN UINT uID)
Definition: pager.c:663
#define IsCJKCodePage(CodePage)
Definition: pager.c:42
static INT GetWidthOfCharCJK(IN UINT nCodePage, IN WCHAR ch)
Definition: pager.c:48
BOOL ConPutsPaging(IN PCON_PAGER Pager, IN PAGE_PROMPT PagePrompt, IN BOOL StartPaging, IN PCTSTR szStr)
Definition: pager.c:646
static BOOL ConPagerWorker(IN PCON_PAGER Pager, IN PCTCH TextBuff, IN DWORD cch)
Does the main paging work: fetching text lines and displaying them.
Definition: pager.c:219
#define CON_STREAM_WRITE
Definition: pager.c:33
BOOL ConResPaging(IN PCON_PAGER Pager, IN PAGE_PROMPT PagePrompt, IN BOOL StartPaging, IN UINT uID)
Definition: pager.c:681
BOOL ConWritePaging(IN PCON_PAGER Pager, IN PAGE_PROMPT PagePrompt, IN BOOL StartPaging, IN PCTCH szStr, IN DWORD len)
Definition: pager.c:549
BOOL ConGetScreenInfo(IN PCON_SCREEN Screen, OUT PCONSOLE_SCREEN_BUFFER_INFO pcsbi)
Definition: screen.c:73
Console I/O streams.
INT WINAPI K32LoadStringW(IN HINSTANCE hInstance OPTIONAL, IN UINT uID, OUT LPWSTR lpBuffer, IN INT nBufferMax)
Definition: utils.c:173
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
Definition: ncftp.h:79
SHORT X
Definition: blue.h:26
SHORT Top
Definition: blue.h:33
SHORT Bottom
Definition: blue.h:35
uint16_t * PWSTR
Definition: typedefs.h:56
const uint16_t * PCWSTR
Definition: typedefs.h:57
ULONG_PTR SIZE_T
Definition: typedefs.h:80
int32_t INT
Definition: typedefs.h:58
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define IN
Definition: typedefs.h:39
#define OUT
Definition: typedefs.h:40
int ret
char TCHAR
Definition: xmlstorage.h:189
__wchar_t WCHAR
Definition: xmlstorage.h:180