Release 980315
[wine/multimedia.git] / misc / lstr.c
blobff3576a8bd2da73f645aeda5c918a74183f4a164
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>
13 #include "config.h"
15 #ifdef HAVE_WCTYPE_H
16 # include <wctype.h>
17 #else
18 # define towlower(c) tolower(c)
19 # define towupper(c) toupper(c)
20 # define iswalnum(c) isalnum(c)
21 # define iswalpha(c) isalpha(c)
22 # define iswupper(c) isupper(c)
23 # define iswlower(c) islower(c)
24 #endif /* HAVE_WCTYPE_H */
27 #include "windows.h"
28 #include "winnt.h" /* HEAP_ macros */
29 #include "task.h"
30 #include "heap.h"
31 #include "ldt.h"
32 #include "stackframe.h"
33 #include "module.h"
34 #include "debug.h"
36 /* Funny to divide them between user and kernel. */
38 /* be careful: always use functions from wctype.h if character > 255 */
40 /***********************************************************************
41 * IsCharAlpha (USER.433)
43 BOOL16 WINAPI IsCharAlpha16(CHAR ch)
45 return isalpha(ch); /* This is probably not right for NLS */
48 /***********************************************************************
49 * IsCharAlphanumeric (USER.434)
51 BOOL16 WINAPI IsCharAlphaNumeric16(CHAR ch)
53 return isalnum(ch);
56 /***********************************************************************
57 * IsCharUpper (USER.435)
59 BOOL16 WINAPI IsCharUpper16(CHAR ch)
61 return isupper(ch);
64 /***********************************************************************
65 * IsCharLower (USER.436)
67 BOOL16 WINAPI IsCharLower16(CHAR ch)
69 return islower(ch);
72 /***********************************************************************
73 * AnsiUpper16 (USER.431)
75 SEGPTR WINAPI AnsiUpper16( SEGPTR strOrChar )
77 /* I am not sure if the locale stuff works with toupper, but then again
78 I am not sure if the Linux libc locale stuffs works at all */
80 /* uppercase only one char if strOrChar < 0x10000 */
81 if (HIWORD(strOrChar))
83 char *s;
84 for (s = PTR_SEG_TO_LIN(strOrChar); *s; s++) *s = toupper(*s);
85 return strOrChar;
87 else return toupper((char)strOrChar);
91 /***********************************************************************
92 * AnsiUpperBuff16 (USER.437)
94 UINT16 WINAPI AnsiUpperBuff16( LPSTR str, UINT16 len )
96 UINT32 count = len ? len : 65536;
97 for (; count; count--, str++) *str = toupper(*str);
98 return len;
101 /***********************************************************************
102 * AnsiLower16 (USER.432)
104 SEGPTR WINAPI AnsiLower16( SEGPTR strOrChar )
106 /* I am not sure if the locale stuff works with toupper, but then again
107 I am not sure if the Linux libc locale stuffs works at all */
109 /* lowercase only one char if strOrChar < 0x10000 */
110 if (HIWORD(strOrChar))
112 char *s;
113 for (s = PTR_SEG_TO_LIN( strOrChar ); *s; s++) *s = tolower( *s );
114 return strOrChar;
116 else return tolower((char)strOrChar);
120 /***********************************************************************
121 * AnsiLowerBuff16 (USER.438)
123 UINT16 WINAPI AnsiLowerBuff16( LPSTR str, UINT16 len )
125 UINT32 count = len ? len : 65536;
126 for (; count; count--, str++) *str = tolower(*str);
127 return len;
131 /***********************************************************************
132 * AnsiNext16 (USER.472)
134 SEGPTR WINAPI AnsiNext16(SEGPTR current)
136 return (*(char *)PTR_SEG_TO_LIN(current)) ? current + 1 : current;
140 /***********************************************************************
141 * AnsiPrev16 (USER.473)
143 SEGPTR WINAPI AnsiPrev16( SEGPTR start, SEGPTR current )
145 return (current == start) ? start : current - 1;
149 /***********************************************************************
150 * OutputDebugString16 (KERNEL.115)
152 void WINAPI OutputDebugString16( LPCSTR str )
154 char *module;
155 char *p, *buffer = HeapAlloc( GetProcessHeap(), 0, strlen(str)+2 );
156 /* Remove CRs */
157 for (p = buffer; *str; str++) if (*str != '\r') *p++ = *str;
158 *p = '\0';
159 if ((p > buffer) && (p[-1] == '\n')) p[1] = '\0'; /* Remove trailing \n */
160 module = MODULE_GetModuleName( GetCurrentTask() );
161 fprintf( stderr, "OutputDebugString: %s says '%s'\n",
162 module ? module : "???", buffer );
163 HeapFree( GetProcessHeap(), 0, buffer );
167 /***********************************************************************
168 * OutputDebugString32A (KERNEL32
170 void WINAPI OutputDebugString32A( LPCSTR str )
172 OutputDebugString16( str );
177 /***********************************************************************
178 * OutputDebugString32W (KERNEL32
180 void WINAPI OutputDebugString32W( LPCWSTR str )
182 LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, str );
183 OutputDebugString32A( p );
184 HeapFree( GetProcessHeap(), 0, p );
189 /***********************************************************************
190 * CharNext32A (USER32.28)
192 LPSTR WINAPI CharNext32A( LPCSTR ptr )
194 if (!*ptr) return (LPSTR)ptr;
195 if (IsDBCSLeadByte32( *ptr )) return (LPSTR)(ptr + 2);
196 return (LPSTR)(ptr + 1);
200 /***********************************************************************
201 * CharNextEx32A (USER32.29)
203 LPSTR WINAPI CharNextEx32A( WORD codepage, LPCSTR ptr, DWORD flags )
205 if (!*ptr) return (LPSTR)ptr;
206 if (IsDBCSLeadByteEx( codepage, *ptr )) return (LPSTR)(ptr + 2);
207 return (LPSTR)(ptr + 1);
211 /***********************************************************************
212 * CharNextExW (USER32.30)
214 LPWSTR WINAPI CharNextEx32W(WORD codepage,LPCWSTR x,DWORD flags)
216 /* FIXME: add DBCS / codepage stuff */
217 if (*x) return (LPWSTR)(x+1);
218 else return (LPWSTR)x;
221 /***********************************************************************
222 * CharNextW (USER32.31)
224 LPWSTR WINAPI CharNext32W(LPCWSTR x)
226 if (*x) return (LPWSTR)(x+1);
227 else return (LPWSTR)x;
230 /***********************************************************************
231 * CharPrev32A (USER32.32)
233 LPSTR WINAPI CharPrev32A( LPCSTR start, LPCSTR ptr )
235 while (*start && (start < ptr))
237 LPCSTR next = CharNext32A( start );
238 if (next >= ptr) break;
239 start = next;
241 return (LPSTR)start;
245 /***********************************************************************
246 * CharPrevEx32A (USER32.33)
248 LPSTR WINAPI CharPrevEx32A( WORD codepage, LPCSTR start, LPCSTR ptr, DWORD flags )
250 while (*start && (start < ptr))
252 LPCSTR next = CharNextEx32A( codepage, start, flags );
253 if (next > ptr) break;
254 start = next;
256 return (LPSTR)start;
260 /***********************************************************************
261 * CharPrevExW (USER32.34)
263 LPWSTR WINAPI CharPrevEx32W(WORD codepage,LPCWSTR start,LPCWSTR x,DWORD flags)
265 /* FIXME: add DBCS / codepage stuff */
266 if (x>start) return (LPWSTR)(x-1);
267 else return (LPWSTR)x;
270 /***********************************************************************
271 * CharPrevW (USER32.35)
273 LPWSTR WINAPI CharPrev32W(LPCWSTR start,LPCWSTR x)
275 if (x>start) return (LPWSTR)(x-1);
276 else return (LPWSTR)x;
279 /***********************************************************************
280 * CharLowerA (USER32.24)
281 * FIXME: handle current locale
283 LPSTR WINAPI CharLower32A(LPSTR x)
285 LPSTR s;
287 if (HIWORD(x))
289 s=x;
290 while (*s)
292 *s=tolower(*s);
293 s++;
295 return x;
297 else return (LPSTR)tolower((char)(int)x);
300 /***********************************************************************
301 * CharLowerBuffA (USER32.25)
302 * FIXME: handle current locale
304 DWORD WINAPI CharLowerBuff32A(LPSTR x,DWORD buflen)
306 DWORD done=0;
308 if (!x) return 0; /* YES */
309 while (*x && (buflen--))
311 *x=tolower(*x);
312 x++;
313 done++;
315 return done;
318 /***********************************************************************
319 * CharLowerBuffW (USER32.26)
320 * FIXME: handle current locale
322 DWORD WINAPI CharLowerBuff32W(LPWSTR x,DWORD buflen)
324 DWORD done=0;
326 if (!x) return 0; /* YES */
327 while (*x && (buflen--))
329 *x=towlower(*x);
330 x++;
331 done++;
333 return done;
336 /***********************************************************************
337 * CharLowerW (USER32.27)
338 * FIXME: handle current locale
340 LPWSTR WINAPI CharLower32W(LPWSTR x)
342 if (HIWORD(x))
344 LPWSTR s = x;
345 while (*s)
347 *s=towlower(*s);
348 s++;
350 return x;
352 else return (LPWSTR)towlower(LOWORD(x));
355 /***********************************************************************
356 * CharUpper32A (USER32.40)
357 * FIXME: handle current locale
359 LPSTR WINAPI CharUpper32A(LPSTR x)
361 if (HIWORD(x))
363 LPSTR s = x;
364 while (*s)
366 *s=toupper(*s);
367 s++;
369 return x;
371 return (LPSTR)toupper((char)(int)x);
374 /***********************************************************************
375 * CharUpperBuffA (USER32.41)
376 * FIXME: handle current locale
378 DWORD WINAPI CharUpperBuff32A(LPSTR x,DWORD buflen)
380 DWORD done=0;
382 if (!x) return 0; /* YES */
383 while (*x && (buflen--))
385 *x=toupper(*x);
386 x++;
387 done++;
389 return done;
392 /***********************************************************************
393 * CharUpperBuffW (USER32.42)
394 * FIXME: handle current locale
396 DWORD WINAPI CharUpperBuff32W(LPWSTR x,DWORD buflen)
398 DWORD done=0;
400 if (!x) return 0; /* YES */
401 while (*x && (buflen--))
403 *x=towupper(*x);
404 x++;
405 done++;
407 return done;
410 /***********************************************************************
411 * CharUpperW (USER32.43)
412 * FIXME: handle current locale
414 LPWSTR WINAPI CharUpper32W(LPWSTR x)
416 if (HIWORD(x))
418 LPWSTR s = x;
419 while (*s)
421 *s=towupper(*s);
422 s++;
424 return x;
426 else return (LPWSTR)towupper(LOWORD(x));
429 /***********************************************************************
430 * IsCharAlphaA (USER32.330)
431 * FIXME: handle current locale
433 BOOL32 WINAPI IsCharAlpha32A(CHAR x)
435 return isalpha(x);
438 /***********************************************************************
439 * IsCharAlphaNumericA (USER32.331)
440 * FIXME: handle current locale
442 BOOL32 WINAPI IsCharAlphaNumeric32A(CHAR x)
444 return isalnum(x);
447 /***********************************************************************
448 * IsCharAlphaNumericW (USER32.332)
449 * FIXME: handle current locale
451 BOOL32 WINAPI IsCharAlphaNumeric32W(WCHAR x)
453 return iswalnum(x);
456 /***********************************************************************
457 * IsCharAlphaW (USER32.333)
458 * FIXME: handle current locale
460 BOOL32 WINAPI IsCharAlpha32W(WCHAR x)
462 return iswalpha(x);
465 /***********************************************************************
466 * IsCharLower32A (USER32.334)
467 * FIXME: handle current locale
469 BOOL32 WINAPI IsCharLower32A(CHAR x)
471 return islower(x);
474 /***********************************************************************
475 * IsCharLower32W (USER32.335)
476 * FIXME: handle current locale
478 BOOL32 WINAPI IsCharLower32W(WCHAR x)
480 return iswlower(x);
483 /***********************************************************************
484 * IsCharUpper32A (USER32.336)
485 * FIXME: handle current locale
487 BOOL32 WINAPI IsCharUpper32A(CHAR x)
489 return isupper(x);
492 /***********************************************************************
493 * IsCharUpper32W (USER32.337)
494 * FIXME: handle current locale
496 BOOL32 WINAPI IsCharUpper32W(WCHAR x)
498 return iswupper(x);
501 /***********************************************************************
502 * FormatMessage32A (KERNEL32.138)
503 * FIXME: missing wrap,FROM_SYSTEM message-loading,
505 DWORD WINAPI FormatMessage32A(
506 DWORD dwFlags,
507 LPCVOID lpSource,
508 DWORD dwMessageId,
509 DWORD dwLanguageId,
510 LPSTR lpBuffer,
511 DWORD nSize,
512 LPDWORD args /* va_list *args */
514 LPSTR target,t;
515 DWORD talloced;
516 LPSTR from,f;
517 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
518 DWORD nolinefeed = 0;
520 TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
521 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
522 if (width)
523 FIXME(resource,"line wrapping not supported.\n");
524 from = NULL;
525 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
526 from = HEAP_strdupA( GetProcessHeap(), 0, (LPSTR)lpSource);
527 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
528 from = HeapAlloc( GetProcessHeap(),0,200 );
529 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
531 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
532 INT32 bufsize;
534 dwMessageId &= 0xFFFF;
535 bufsize=LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,NULL,100);
536 if (bufsize) {
537 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
538 LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
541 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
542 t = target;
543 talloced= 100;
545 #define ADD_TO_T(c) \
546 *t++=c;\
547 if (t-target == talloced) {\
548 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
549 t = target+talloced;\
550 talloced*=2;\
553 if (from) {
554 f=from;
555 while (*f) {
556 if (*f=='%') {
557 int insertnr;
558 char *fmtstr,*sprintfbuf,*x,*lastf;
559 DWORD *argliststart;
561 fmtstr = NULL;
562 lastf = f;
563 f++;
564 if (!*f) {
565 ADD_TO_T('%');
566 continue;
568 switch (*f) {
569 case '1':case '2':case '3':case '4':case '5':
570 case '6':case '7':case '8':case '9':
571 insertnr=*f-'0';
572 switch (f[1]) {
573 case '0':case '1':case '2':case '3':
574 case '4':case '5':case '6':case '7':
575 case '8':case '9':
576 f++;
577 insertnr=insertnr*10+*f-'0';
578 f++;
579 break;
580 default:
581 f++;
582 break;
584 if (*f=='!') {
585 f++;
586 if (NULL!=(x=strchr(f,'!'))) {
587 *x='\0';
588 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
589 sprintf(fmtstr,"%%%s",f);
590 f=x+1;
591 } else {
592 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
593 sprintf(fmtstr,"%%%s",f);
594 f+=strlen(f); /*at \0*/
596 } else
597 if(!args)
598 break;
599 else
600 fmtstr=HEAP_strdupA(GetProcessHeap(),0,"%s");
601 if (args) {
602 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
603 argliststart=args+insertnr-1;
604 else
605 argliststart=(*(DWORD**)args)+insertnr-1;
607 if (fmtstr[strlen(fmtstr)-1]=='s')
608 sprintfbuf=HeapAlloc(GetProcessHeap(),0,strlen((LPSTR)argliststart[0])+1);
609 else
610 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
612 /* CMF - This makes a BIG assumption about va_list */
613 vsprintf(sprintfbuf, fmtstr, (va_list) argliststart);
614 x=sprintfbuf;
615 while (*x) {
616 ADD_TO_T(*x++);
618 HeapFree(GetProcessHeap(),0,sprintfbuf);
619 } else {
620 /* NULL args - copy formatstr
621 * (probably wrong)
623 while (lastf<f) {
624 ADD_TO_T(*lastf++);
627 HeapFree(GetProcessHeap(),0,fmtstr);
628 break;
629 case 'n':
630 /* FIXME: perhaps add \r too? */
631 ADD_TO_T('\n');
632 f++;
633 break;
634 case '0':
635 nolinefeed=1;
636 f++;
637 break;
638 default:ADD_TO_T(*f++)
639 break;
642 } else {
643 ADD_TO_T(*f++)
646 *t='\0';
648 if (!nolinefeed && t[-1]!='\n')
649 ADD_TO_T('\n');
650 talloced = strlen(target)+1;
651 if (nSize && talloced<nSize) {
652 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
654 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
655 /* nSize is the MINIMUM size */
656 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced);
657 memcpy(*(LPSTR*)lpBuffer,target,talloced);
658 } else
659 strncpy(lpBuffer,target,nSize);
660 HeapFree(GetProcessHeap(),0,target);
661 if (from) HeapFree(GetProcessHeap(),0,from);
662 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
663 strlen(*(LPSTR*)lpBuffer):
664 strlen(lpBuffer);
666 #undef ADD_TO_T
669 /***********************************************************************
670 * FormatMessage32W (KERNEL32.138)
672 DWORD WINAPI FormatMessage32W(
673 DWORD dwFlags,
674 LPCVOID lpSource,
675 DWORD dwMessageId,
676 DWORD dwLanguageId,
677 LPWSTR lpBuffer,
678 DWORD nSize,
679 LPDWORD args /* va_list *args */
681 LPSTR target,t;
682 DWORD talloced;
683 LPSTR from,f;
684 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
685 DWORD nolinefeed = 0;
687 TRACE(resource, "(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
688 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
689 if (width)
690 FIXME(resource,"line wrapping not supported.\n");
691 from = NULL;
692 if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
693 from = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lpSource);
694 if (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) {
695 /* gather information from system message tables ... */
696 from = HeapAlloc( GetProcessHeap(),0,200 );
697 sprintf(from,"Systemmessage, messageid = 0x%08lx\n",dwMessageId);
699 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) {
700 INT32 bufsize;
702 dwMessageId &= 0xFFFF;
703 bufsize=LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,NULL,100);
704 if (bufsize)
706 from = HeapAlloc( GetProcessHeap(), 0, bufsize + 1 );
707 LoadMessage32A((HMODULE32)lpSource,dwMessageId,dwLanguageId,from,bufsize+1);
710 target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 );
711 t = target;
712 talloced= 100;
714 #define ADD_TO_T(c) \
715 *t++=c;\
716 if (t-target == talloced) {\
717 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
718 t = target+talloced;\
719 talloced*=2;\
722 if (from) {
723 f=from;
724 while (*f) {
725 if (*f=='%') {
726 int insertnr;
727 char *fmtstr,*sprintfbuf,*x;
728 DWORD *argliststart;
730 fmtstr = NULL;
731 f++;
732 if (!*f) {
733 ADD_TO_T('%');
734 continue;
736 switch (*f) {
737 case '1':case '2':case '3':case '4':case '5':
738 case '6':case '7':case '8':case '9':
739 insertnr=*f-'0';
740 switch (f[1]) {
741 case '0':case '1':case '2':case '3':
742 case '4':case '5':case '6':case '7':
743 case '8':case '9':
744 f++;
745 insertnr=insertnr*10+*f-'0';
746 f++;
747 break;
748 default:
749 f++;
750 break;
752 if (*f=='!') {
753 f++;
754 if (NULL!=(x=strchr(f,'!')))
756 *x='\0';
757 fmtstr=HeapAlloc( GetProcessHeap(), 0, strlen(f)+2);
758 sprintf(fmtstr,"%%%s",f);
759 f=x+1;
760 } else {
761 fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f));
762 sprintf(fmtstr,"%%%s",f);
763 f+=strlen(f); /*at \0*/
765 } else
766 if(!args)
767 break;
768 else
769 fmtstr=HEAP_strdupA( GetProcessHeap(),0,"%s");
770 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
771 argliststart=args+insertnr-1;
772 else
773 argliststart=(*(DWORD**)args)+insertnr-1;
775 if (fmtstr[strlen(fmtstr)-1]=='s') {
776 DWORD xarr[3];
778 xarr[0]=(DWORD)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)(*(argliststart+0)));
779 /* possible invalid pointers */
780 xarr[1]=*(argliststart+1);
781 xarr[2]=*(argliststart+2);
782 sprintfbuf=HeapAlloc(GetProcessHeap(),0,lstrlen32W((LPWSTR)argliststart[0])*2+1);
784 /* CMF - This makes a BIG assumption about va_list */
785 vsprintf(sprintfbuf, fmtstr, (va_list) xarr);
786 } else {
787 sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);
789 /* CMF - This makes a BIG assumption about va_list */
790 vsprintf(sprintfbuf, fmtstr, (va_list) argliststart);
792 x=sprintfbuf;
793 while (*x) {
794 ADD_TO_T(*x++);
796 HeapFree(GetProcessHeap(),0,sprintfbuf);
797 HeapFree(GetProcessHeap(),0,fmtstr);
798 break;
799 case 'n':
800 /* FIXME: perhaps add \r too? */
801 ADD_TO_T('\n');
802 f++;
803 break;
804 case '0':
805 nolinefeed=1;
806 f++;
807 break;
808 default:ADD_TO_T(*f++)
809 break;
812 } else {
813 ADD_TO_T(*f++)
816 *t='\0';
818 if (!nolinefeed && t[-1]!='\n')
819 ADD_TO_T('\n');
820 talloced = strlen(target)+1;
821 if (nSize && talloced<nSize)
822 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
823 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
824 /* nSize is the MINIMUM size */
825 *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc32(GMEM_ZEROINIT,talloced*2+2);
826 lstrcpynAtoW(*(LPWSTR*)lpBuffer,target,talloced);
827 } else
828 lstrcpynAtoW(lpBuffer,target,nSize);
829 HeapFree(GetProcessHeap(),0,target);
830 if (from) HeapFree(GetProcessHeap(),0,from);
831 return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
832 lstrlen32W(*(LPWSTR*)lpBuffer):
833 lstrlen32W(lpBuffer);
835 #undef ADD_TO_T