Release 970112
[wine.git] / misc / lstr.c
blobe8a683df9a39864eeeee8a98d9ee7d919b2e43bf
1 /*
2 * String functions
4 * Copyright 1993 Yngvi Sigurjonsson (yngvi@hafro.is)
5 * Copyright 1996 Marcus Meissner
6 */
8 #include <stdio.h>
9 #include <stdarg.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
14 #include "windows.h"
15 #include "winnt.h" /* HEAP_ macros */
16 #include "heap.h"
17 #include "ldt.h"
18 #include "module.h"
19 #include "stddebug.h"
20 #include "debug.h"
22 #define ToUpper(c) toupper(c)
23 #define ToLower(c) tolower(c)
26 /* Funny to divide them between user and kernel. */
28 /* IsCharAlpha USER 433 */
29 BOOL16 IsCharAlpha16(CHAR ch)
31 return isalpha(ch); /* This is probably not right for NLS */
34 /* IsCharAlphanumeric USER 434 */
35 BOOL16 IsCharAlphanumeric16(CHAR ch)
37 return isalnum(ch);
40 /* IsCharUpper USER 435 */
41 BOOL16 IsCharUpper16(CHAR ch)
43 return isupper(ch);
46 /* IsCharLower USER 436 */
47 BOOL16 IsCharLower16(CHAR ch)
49 return islower(ch);
52 /***********************************************************************
53 * AnsiUpper16 (USER.431)
55 SEGPTR AnsiUpper16( SEGPTR strOrChar )
57 /* I am not sure if the locale stuff works with toupper, but then again
58 I am not sure if the Linux libc locale stuffs works at all */
60 /* uppercase only one char if strOrChar < 0x10000 */
61 if (HIWORD(strOrChar))
63 char *s;
64 for (s = PTR_SEG_TO_LIN(strOrChar); *s; s++) *s = toupper(*s);
65 return strOrChar;
67 else return (SEGPTR)ToUpper( (int)strOrChar );
71 /***********************************************************************
72 * AnsiUpperBuff16 (USER.437)
74 UINT16 AnsiUpperBuff16( LPSTR str, UINT16 len )
76 UINT32 count = len ? len : 65536;
77 for (; count; count--, str++) *str = toupper(*str);
78 return len;
81 /***********************************************************************
82 * AnsiLower16 (USER.432)
84 SEGPTR AnsiLower16( SEGPTR strOrChar )
86 /* I am not sure if the locale stuff works with toupper, but then again
87 I am not sure if the Linux libc locale stuffs works at all */
89 /* lowercase only one char if strOrChar < 0x10000 */
90 if (HIWORD(strOrChar))
92 char *s;
93 for (s = PTR_SEG_TO_LIN( strOrChar ); *s; s++) *s = tolower( *s );
94 return strOrChar;
96 else return (SEGPTR)tolower( (int)strOrChar );
100 /***********************************************************************
101 * AnsiLowerBuff16 (USER.438)
103 UINT16 AnsiLowerBuff16( LPSTR str, UINT16 len )
105 UINT32 count = len ? len : 65536;
106 for (; count; count--, str++) *str = tolower(*str);
107 return len;
111 /***********************************************************************
112 * AnsiNext16 (USER.472)
114 SEGPTR AnsiNext16(SEGPTR current)
116 return (*(char *)PTR_SEG_TO_LIN(current)) ? current + 1 : current;
120 /***********************************************************************
121 * AnsiPrev16 (USER.473)
123 SEGPTR AnsiPrev16( SEGPTR start, SEGPTR current )
125 return (current == start) ? start : current - 1;
129 /***********************************************************************
130 * OutputDebugString (KERNEL.115)
132 void OutputDebugString( LPCSTR str )
134 char *module;
135 char *p, *buffer = HeapAlloc( GetProcessHeap(), 0, strlen(str)+1 );
136 /* Remove CRs */
137 for (p = buffer; *str; str++) if (*str != '\r') *p++ = *str;
138 *p = '\0';
139 if ((p > buffer) && (p[-1] == '\n')) p[1] = '\0'; /* Remove trailing \n */
140 module = MODULE_GetModuleName( GetExePtr(GetCurrentTask()) );
141 fprintf( stderr, "OutputDebugString: %s says '%s'\n",
142 module ? module : "???", buffer );
143 HeapFree( GetProcessHeap(), 0, buffer );
147 /***********************************************************************
148 * CharNext32A (USER32.28)
150 LPSTR CharNext32A( LPCSTR ptr )
152 if (!*ptr) return (LPSTR)ptr;
153 if (IsDBCSLeadByte32( *ptr )) return (LPSTR)(ptr + 2);
154 return (LPSTR)(ptr + 1);
158 /***********************************************************************
159 * CharNextEx32A (USER32.29)
161 LPSTR CharNextEx32A( WORD codepage, LPCSTR ptr, DWORD flags )
163 if (!*ptr) return (LPSTR)ptr;
164 if (IsDBCSLeadByteEx( codepage, *ptr )) return (LPSTR)(ptr + 2);
165 return (LPSTR)(ptr + 1);
169 /***********************************************************************
170 * CharNextExW (USER32.30)
172 LPWSTR CharNextEx32W(WORD codepage,LPCWSTR x,DWORD flags)
174 /* FIXME: add DBCS / codepage stuff */
175 if (*x) return (LPWSTR)(x+1);
176 else return (LPWSTR)x;
179 /***********************************************************************
180 * CharNextW (USER32.31)
182 LPWSTR CharNext32W(LPCWSTR x)
184 if (*x) return (LPWSTR)(x+1);
185 else return (LPWSTR)x;
188 /***********************************************************************
189 * CharPrev32A (USER32.32)
191 LPSTR CharPrev32A( LPCSTR start, LPCSTR ptr )
193 while (*start && (start < ptr))
195 LPCSTR next = CharNext32A( start );
196 if (next > ptr) break;
197 start = next;
199 return (LPSTR)start;
203 /***********************************************************************
204 * CharPrevEx32A (USER32.33)
206 LPSTR CharPrevEx32A( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
208 while (*start && (start < ptr))
210 LPCSTR next = CharNextEx32A( codepage, start, flags );
211 if (next > ptr) break;
212 start = next;
214 return (LPSTR)start;
218 /***********************************************************************
219 * CharPrevExW (USER32.34)
221 LPWSTR CharPrevEx32W(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
223 /* FIXME: add DBCS / codepage stuff */
224 if (x>start) return (LPWSTR)(x-1);
225 else return (LPWSTR)x;
228 /***********************************************************************
229 * CharPrevW (USER32.35)
231 LPWSTR CharPrev32W(LPCWSTR start,LPCWSTR x)
233 if (x>start) return (LPWSTR)(x-1);
234 else return (LPWSTR)x;
237 /***********************************************************************
238 * CharLowerA (USER32.24)
239 * FIXME: handle current locale
241 LPSTR CharLower32A(LPSTR x)
243 LPSTR s;
245 if (HIWORD(x))
247 s=x;
248 while (*s)
250 *s=tolower(*s);
251 s++;
253 return x;
255 else return (LPSTR)tolower(LOWORD(x));
258 /***********************************************************************
259 * CharLowerBuffA (USER32.25)
260 * FIXME: handle current locale
262 DWORD CharLowerBuff32A(LPSTR x,DWORD buflen)
264 DWORD done=0;
266 while (*x && (buflen--))
268 *x=tolower(*x);
269 x++;
270 done++;
272 return done;
275 /***********************************************************************
276 * CharLowerBuffW (USER32.26)
277 * FIXME: handle current locale
279 DWORD CharLowerBuff32W(LPWSTR x,DWORD buflen)
281 DWORD done=0;
283 while (*x && (buflen--))
285 *x=tolower(*x);
286 x++;
287 done++;
289 return done;
292 /***********************************************************************
293 * CharLowerW (USER32.27)
294 * FIXME: handle current locale
296 LPWSTR CharLower32W(LPWSTR x)
298 if (HIWORD(x))
300 LPWSTR s = x;
301 while (*s)
303 *s=tolower(*s);
304 s++;
306 return x;
308 else return (LPWSTR)tolower(LOWORD(x));
311 /***********************************************************************
312 * CharUpper32A (USER32.40)
313 * FIXME: handle current locale
315 LPSTR CharUpper32A(LPSTR x)
317 if (HIWORD(x))
319 LPSTR s = x;
320 while (*s)
322 *s=toupper(*s);
323 s++;
325 return x;
327 else return (LPSTR)toupper(LOWORD(x));
330 /***********************************************************************
331 * CharUpperBuffA (USER32.41)
332 * FIXME: handle current locale
334 DWORD CharUpperBuff32A(LPSTR x,DWORD buflen)
336 DWORD done=0;
338 while (*x && (buflen--))
340 *x=toupper(*x);
341 x++;
342 done++;
344 return done;
347 /***********************************************************************
348 * CharUpperBuffW (USER32.42)
349 * FIXME: handle current locale
351 DWORD CharUpperBuff32W(LPWSTR x,DWORD buflen)
353 DWORD done=0;
355 while (*x && (buflen--))
357 *x=toupper(*x);
358 x++;
359 done++;
361 return done;
364 /***********************************************************************
365 * CharUpperW (USER32.43)
366 * FIXME: handle current locale
368 LPWSTR CharUpper32W(LPWSTR x)
370 if (HIWORD(x))
372 LPWSTR s = x;
373 while (*s)
375 *s=toupper(*s);
376 s++;
378 return x;
380 else return (LPWSTR)toupper(LOWORD(x));
383 /***********************************************************************
384 * IsCharAlphaA (USER32.330)
385 * FIXME: handle current locale
387 BOOL32 IsCharAlpha32A(CHAR x)
389 return isalpha(x);
392 /***********************************************************************
393 * IsCharAlphaNumericA (USER32.331)
394 * FIXME: handle current locale
396 BOOL32 IsCharAlphaNumeric32A(CHAR x)
398 return isalnum(x);
401 /***********************************************************************
402 * IsCharAlphaNumericW (USER32.332)
403 * FIXME: handle current locale
405 BOOL32 IsCharAlphaNumeric32W(WCHAR x)
407 return isalnum(x);
410 /***********************************************************************
411 * IsCharAlphaW (USER32.333)
412 * FIXME: handle current locale
414 BOOL32 IsCharAlpha32W(WCHAR x)
416 return isalpha(x);
419 /***********************************************************************
420 * IsCharLower32A (USER32.334)
421 * FIXME: handle current locale
423 BOOL32 IsCharLower32A(CHAR x)
425 return islower(x);
428 /***********************************************************************
429 * IsCharLower32W (USER32.335)
430 * FIXME: handle current locale
432 BOOL32 IsCharLower32W(WCHAR x)
434 return islower(x);
437 /***********************************************************************
438 * IsCharUpper32A (USER32.336)
439 * FIXME: handle current locale
441 BOOL32 IsCharUpper32A(CHAR x)
443 return isupper(x);
446 /***********************************************************************
447 * IsCharUpper32W (USER32.337)
448 * FIXME: handle current locale
450 BOOL32 IsCharUpper32W(WCHAR x)
452 return isupper(x);
455 /***********************************************************************
456 * FormatMessageA (KERNEL32.138) Library Version
457 * FIXME: missing wrap,FROM_SYSTEM message-loading,
459 DWORD
460 FormatMessage32A(
461 DWORD dwFlags,
462 LPCVOID lpSource,
463 DWORD dwMessageId,
464 DWORD dwLanguageId,
465 LPSTR lpBuffer,
466 DWORD nSize,
467 LPDWORD args /* va_list *args */
469 LPSTR target,t;
470 DWORD talloced;
471 LPSTR from,f;
472 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
473 DWORD nolinefeed = 0;
475 dprintf_resource(stddeb,
476 "FormatMessage32A(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
477 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args
479 if (width)
480 fprintf(stdnimp," - line wrapping not supported.\n");
481 from = NULL;
482 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
483 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
484 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
485 /* gather information from system message tables ... */
486 fprintf(stdnimp," - FORMAT_MESSAGE_FROM_SYSTEM not implemented.\n");
488 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
489 INT32 bufsize;
491 dwMessageId &= 0xFFFF;
492 bufsize=LoadMessage32A(0,dwMessageId,dwLanguageId,NULL,100);
493 if (bufsize) {
494 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
495 LoadMessage32A(0,dwMessageId,dwLanguageId,from,bufsize+1);
498 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
499 t = target;
500 talloced= 100;
502 #define ADD_TO_T(c) \
503 *t++=c;\
504 if (t-target == talloced) {\
505 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
506 t = target+talloced;\
507 talloced*=2;\
510 if (from) {
511 f=from;
512 while (*f) {
513 if (*f=='%') {
514 int insertnr;
515 char *fmtstr,*sprintfbuf,*x;
516 DWORD *argliststart;
518 fmtstr = NULL;
519 f++;
520 if (!*f) {
521 ADD_TO_T('%');
522 continue;
524 switch (*f) {
525 case '1':case '2':case '3':case '4':case '5':
526 case '6':case '7':case '8':case '9':
527 insertnr=*f-'0';
528 switch (f[1]) {
529 case '0':case '1':case '2':case '3':
530 case '4':case '5':case '6':case '7':
531 case '8':case '9':
532 f++;
533 insertnr=insertnr*10+*f-'0';
534 f++;
535 break;
536 default:
537 f++;
538 break;
540 if (*f=='!') {
541 f++;
542 if (NULL!=(x=strchr(f,'!'))) {
543 *x='\0';
544 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
545 sprintf(fmtstr,"%%%s",f);
546 f=x+1;
548 } else
549 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
550 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
551 argliststart=args+insertnr-1;
552 else
553 /* FIXME: not sure that this is
554 * correct for unix-c-varargs.
556 argliststart=((DWORD*)&args)+insertnr-1;
558 if (fmtstr[strlen(fmtstr)]=='s')
559 sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
560 else
561 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
562 vsprintf(sprintfbuf,fmtstr,argliststart);
563 x=sprintfbuf;
564 while (*x) {
565 ADD_TO_T(*x++);
567 HeapFree(GetProcessHeap(),0,sprintfbuf);
568 HeapFree(GetProcessHeap(),0,fmtstr);
569 break;
570 case '0':
571 nolinefeed=1;
572 f++;
573 break;
574 default:ADD_TO_T(*f++)
575 break;
578 } else {
579 ADD_TO_T(*f++)
582 *t='\0';
584 if (!nolinefeed && t[-1]!='\n')
585 ADD_TO_T('\n');
586 talloced = strlen(target)+1;
587 if (nSize && talloced<nSize) {
588 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
590 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
591 /* nSize is the MINIMUM size */
592 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced);
593 memcpy(*(LPSTR*)lpBuffer,target,talloced);
594 } else
595 strncpy(lpBuffer,target,nSize);
596 HeapFree(GetProcessHeap(),0,target);
597 if (from) HeapFree(GetProcessHeap(),0,from);
598 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
599 strlen(*(LPSTR*)lpBuffer):
600 strlen(lpBuffer);
602 #undef ADD_TO_T
604 /***********************************************************************
605 * FormatMessageA (KERNEL32.138) Emulator Version
607 DWORD
608 WIN32_FormatMessage32A(DWORD *args) {
609 DWORD dwFlags = args[0];
610 LPCVOID lpSource = (LPCVOID)args[1];
611 DWORD dwMessageId = args[2];
612 DWORD dwLanguageId = args[3];
613 LPSTR lpBuffer = (LPSTR)args[4];
614 DWORD nSize = args[5];
615 DWORD *xargs;
617 /* convert possible varargs to an argument array look-a-like */
619 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) {
620 xargs=(DWORD*)args[6];
621 } else {
622 /* args[6] is a pointer to a pointer to the start of
623 * a list of arguments.
625 if (args[6])
626 xargs=(DWORD*)(((DWORD*)args[6])[0]);
627 else
628 xargs=NULL;
629 dwFlags|=FORMAT_MESSAGE_ARGUMENT_ARRAY;
631 return FormatMessage32A(
632 dwFlags,
633 lpSource,
634 dwMessageId,
635 dwLanguageId,
636 lpBuffer,
637 nSize,
638 xargs
642 DWORD
643 FormatMessage32W(
644 DWORD dwFlags,
645 LPCVOID lpSource,
646 DWORD dwMessageId,
647 DWORD dwLanguageId,
648 LPWSTR lpBuffer,
649 DWORD nSize,
650 LPDWORD args /* va_list *args */
652 LPSTR target,t;
653 DWORD talloced;
654 LPSTR from,f;
655 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
656 DWORD nolinefeed = 0;
658 dprintf_resource(stddeb,
659 "FormatMessage32A(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
660 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args
662 if (width)
663 fprintf(stdnimp," - line wrapping not supported.\n");
664 from = NULL;
665 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
666 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
667 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
668 /* gather information from system message tables ... */
669 fprintf(stdnimp," - FORMAT_MESSAGE_FROM_SYSTEM not implemented.\n");
671 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
672 INT32 bufsize;
674 dwMessageId &= 0xFFFF;
675 bufsize=LoadMessage32A(0,dwMessageId,dwLanguageId,NULL,100);
676 if (bufsize)
678 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
679 LoadMessage32A(0,dwMessageId,dwLanguageId,from,bufsize+1);
682 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
683 t = target;
684 talloced= 100;
686 #define ADD_TO_T(c) \
687 *t++=c;\
688 if (t-target == talloced) {\
689 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
690 t = target+talloced;\
691 talloced*=2;\
694 if (from) {
695 f=from;
696 while (*f) {
697 if (*f=='%') {
698 int insertnr;
699 char *fmtstr,*sprintfbuf,*x;
700 DWORD *argliststart;
702 fmtstr = NULL;
703 f++;
704 if (!*f) {
705 ADD_TO_T('%');
706 continue;
708 switch (*f) {
709 case '1':case '2':case '3':case '4':case '5':
710 case '6':case '7':case '8':case '9':
711 insertnr=*f-'0';
712 switch (f[1]) {
713 case '0':case '1':case '2':case '3':
714 case '4':case '5':case '6':case '7':
715 case '8':case '9':
716 f++;
717 insertnr=insertnr*10+*f-'0';
718 f++;
719 break;
720 default:
721 f++;
722 break;
724 if (*f=='!') {
725 f++;
726 if (NULL!=(x=strchr(f,'!')))
728 *x='\0';
729 fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
730 sprintf(fmtstr,"%%%s",f);
731 f=x+1;
733 } else
734 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
735 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
736 argliststart=args+insertnr-1;
737 else
738 /* FIXME: not sure that this is
739 * correct for unix-c-varargs.
741 argliststart=((DWORD*)&args)+insertnr-1;
743 if (fmtstr[strlen(fmtstr)]=='s') {
744 DWORD xarr[3];
746 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
747 /* possible invalid pointers */
748 xarr[1]=*(argliststart+1);
749 xarr[2]=*(argliststart+2);
750 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlen32W((LPWSTR)argliststart[0])*2+1);
751 vsprintf(sprintfbuf,fmtstr,xarr);
752 } else {
753 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
754 vsprintf(sprintfbuf,fmtstr,argliststart);
756 x=sprintfbuf;
757 while (*x) {
758 ADD_TO_T(*x++);
760 HeapFree(GetProcessHeap(),0,sprintfbuf);
761 HeapFree(GetProcessHeap(),0,fmtstr);
762 break;
763 case '0':
764 nolinefeed=1;
765 f++;
766 break;
767 default:ADD_TO_T(*f++)
768 break;
771 } else {
772 ADD_TO_T(*f++)
775 *t='\0';
777 if (!nolinefeed && t[-1]!='\n')
778 ADD_TO_T('\n');
779 talloced = strlen(target)+1;
780 if (nSize && talloced<nSize)
781 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
782 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
783 /* nSize is the MINIMUM size */
784 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced*2+2);
785 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
786 } else
787 lstrcpynAtoW(lpBuffer,target,nSize);
788 HeapFree(GetProcessHeap(),0,target);
789 if (from) HeapFree(GetProcessHeap(),0,from);
790 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
791 lstrlen32W(*(LPWSTR*)lpBuffer):
792 lstrlen32W(lpBuffer);
794 #undef ADD_TO_T
796 /***********************************************************************
797 * FormatMessageA (KERNEL32.138) Emulator Version
799 DWORD
800 WIN32_FormatMessage32W(DWORD *args) {
801 DWORD dwFlags = args[0];
802 LPCVOID lpSource = (LPCVOID)args[1];
803 DWORD dwMessageId = args[2];
804 DWORD dwLanguageId = args[3];
805 LPWSTR lpBuffer = (LPWSTR)args[4];
806 DWORD nSize = args[5];
807 DWORD *xargs;
809 /* convert possible varargs to an argument array look-a-like */
811 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) {
812 xargs=(DWORD*)args[6];
813 } else {
814 /* args[6] is a pointer to a pointer to the start of
815 * a list of arguments.
817 if (args[6])
818 xargs=(DWORD*)(((DWORD*)args[6])[0]);
819 else
820 xargs=NULL;
821 dwFlags|=FORMAT_MESSAGE_ARGUMENT_ARRAY;
823 return FormatMessage32W(
824 dwFlags,
825 lpSource,
826 dwMessageId,
827 dwLanguageId,
828 lpBuffer,
829 nSize,
830 xargs