format_msg.c 20.8 KB
Newer Older
Dave Pickles's avatar
Dave Pickles committed
1 2 3 4
/*
 * FormatMessage implementation
 *
 * Copyright 1996 Marcus Meissner
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Dave Pickles's avatar
Dave Pickles committed
19 20 21 22
 */

#include "config.h"

23
#include <stdarg.h>
Dave Pickles's avatar
Dave Pickles committed
24 25 26
#include <stdio.h>
#include <string.h>

27
#include "ntstatus.h"
28
#define WIN32_NO_STATUS
Dave Pickles's avatar
Dave Pickles committed
29 30 31
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
32
#include "winternl.h"
33
#include "winuser.h"
Dave Pickles's avatar
Dave Pickles committed
34
#include "winnls.h"
35
#include "wine/unicode.h"
36
#include "kernel_private.h"
37
#include "wine/debug.h"
Dave Pickles's avatar
Dave Pickles committed
38

39
WINE_DEFAULT_DEBUG_CHANNEL(resource);
Dave Pickles's avatar
Dave Pickles committed
40 41


42
/* Messages used by FormatMessage
43
 *
Dave Pickles's avatar
Dave Pickles committed
44 45
 * They can be specified either directly or using a message ID and
 * loading them from the resource.
46
 *
Dave Pickles's avatar
Dave Pickles committed
47 48 49 50 51 52 53 54 55
 * The resourcedata has following format:
 * start:
 * 0: DWORD nrofentries
 * nrofentries * subentry:
 *	0: DWORD firstentry
 *	4: DWORD lastentry
 *      8: DWORD offset from start to the stringentries
 *
 * (lastentry-firstentry) * stringentry:
56
 * 0: WORD len (0 marks end)	[ includes the 4 byte header length ]
Dave Pickles's avatar
Dave Pickles committed
57 58 59 60 61 62 63
 * 2: WORD flags
 * 4: CHAR[len-4]
 * 	(stringentry i of a subentry refers to the ID 'firstentry+i')
 *
 * Yes, ANSI strings in win32 resources. Go figure.
 */

64 65
static const WCHAR PCNTFMTWSTR[] = { '%','%','%','s',0 };
static const WCHAR FMTWSTR[] = { '%','s',0 };
66

Dave Pickles's avatar
Dave Pickles committed
67
/**********************************************************************
68
 *	load_messageW		(internal)
Dave Pickles's avatar
Dave Pickles committed
69
 */
70
static LPWSTR load_messageW( HMODULE module, UINT id, WORD lang )
Dave Pickles's avatar
Dave Pickles committed
71
{
72
    const MESSAGE_RESOURCE_ENTRY *mre;
73
    WCHAR *buffer;
Dave Pickles's avatar
Dave Pickles committed
74

75
    TRACE("module = %p, id = %08x\n", module, id );
Dave Pickles's avatar
Dave Pickles committed
76

77 78
    if (!module) module = GetModuleHandleW( NULL );
    if (RtlFindMessage( module, RT_MESSAGETABLE, lang, id, &mre ) != STATUS_SUCCESS) return NULL;
79

80
    if (mre->Flags & MESSAGE_RESOURCE_UNICODE)
81 82 83 84 85
    {
        int len = (strlenW( (const WCHAR *)mre->Text ) + 1) * sizeof(WCHAR);
        if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL;
        memcpy( buffer, mre->Text, len );
    }
86
    else
87
    {
Mike McCormack's avatar
Mike McCormack committed
88
        int len = MultiByteToWideChar( CP_ACP, 0, (const char *)mre->Text, -1, NULL, 0 );
89
        if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL;
Mike McCormack's avatar
Mike McCormack committed
90
        MultiByteToWideChar( CP_ACP, 0, (const char*)mre->Text, -1, buffer, len );
Dave Pickles's avatar
Dave Pickles committed
91
    }
92 93
    TRACE("returning %s\n", wine_dbgstr_w(buffer));
    return buffer;
Dave Pickles's avatar
Dave Pickles committed
94 95
}

96

Dave Pickles's avatar
Dave Pickles committed
97
/**********************************************************************
98
 *	load_messageA		(internal)
Dave Pickles's avatar
Dave Pickles committed
99
 */
100
static LPSTR load_messageA( HMODULE module, UINT id, WORD lang )
Dave Pickles's avatar
Dave Pickles committed
101
{
102 103
    const MESSAGE_RESOURCE_ENTRY *mre;
    char *buffer;
104

105
    TRACE("module = %p, id = %08x\n", module, id );
106

107 108
    if (!module) module = GetModuleHandleW( NULL );
    if (RtlFindMessage( module, RT_MESSAGETABLE, lang, id, &mre ) != STATUS_SUCCESS) return NULL;
109

110
    if (mre->Flags & MESSAGE_RESOURCE_UNICODE)
Dave Pickles's avatar
Dave Pickles committed
111
    {
112 113 114 115 116 117
        int len = WideCharToMultiByte( CP_ACP, 0, (const WCHAR *)mre->Text, -1, NULL, 0, NULL, NULL );
        if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL;
        WideCharToMultiByte( CP_ACP, 0, (const WCHAR *)mre->Text, -1, buffer, len, NULL, NULL );
    }
    else
    {
Mike McCormack's avatar
Mike McCormack committed
118
        int len = strlen((const char*)mre->Text) + 1;
119 120 121 122 123
        if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL;
        memcpy( buffer, mre->Text, len );
    }
    TRACE("returning %s\n", wine_dbgstr_a(buffer));
    return buffer;
Dave Pickles's avatar
Dave Pickles committed
124 125 126 127
}


/***********************************************************************
128
 *           FormatMessageA   (KERNEL32.@)
Dave Pickles's avatar
Dave Pickles committed
129 130 131 132 133 134 135 136 137
 * FIXME: missing wrap,
 */
DWORD WINAPI FormatMessageA(
	DWORD	dwFlags,
	LPCVOID	lpSource,
	DWORD	dwMessageId,
	DWORD	dwLanguageId,
	LPSTR	lpBuffer,
	DWORD	nSize,
138
	__ms_va_list* _args )
139 140
{
    LPDWORD args=(LPDWORD)_args;
141
    DWORD ret = 0;
142
#if defined(__i386__) || defined(__sparc__)
143
/* This implementation is completely dependent on the format of the va_list on x86 CPUs */
144 145 146 147 148 149 150
    LPSTR	target,t;
    DWORD	talloced;
    LPSTR	from,f;
    DWORD	width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
    BOOL    eos = FALSE;
    CHAR	ch;

151
    TRACE("(0x%x,%p,%d,0x%x,%p,%d,%p)\n",
152 153 154 155 156
          dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
    if ((dwFlags & FORMAT_MESSAGE_FROM_STRING)
        &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
           || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0;

157 158 159 160 161 162
    if (!lpBuffer)
    {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return 0;
    }

163
    if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK)
164
        FIXME("line wrapping (%u) not supported.\n", width);
165
    from = NULL;
166 167
    if (dwFlags & FORMAT_MESSAGE_FROM_STRING)
    {
168 169
        from = HeapAlloc( GetProcessHeap(), 0, strlen(lpSource) + 1 );
        strcpy( from, lpSource );
170 171
    }
    else {
172
        from = NULL;
173
        if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE)
174 175 176
            from = load_messageA( (HMODULE)lpSource, dwMessageId, dwLanguageId );
        if (!from && (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM))
            from = load_messageA( kernel32_handle, dwMessageId, dwLanguageId );
177

178 179
        if (!from)
        {
180 181 182
            SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND);
            return 0;
        }
183 184 185 186
    }
    target	= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100);
    t	= target;
    talloced= 100;
Dave Pickles's avatar
Dave Pickles committed
187

188
#define ADD_TO_T(c) do { \
189
        *t++=c;\
190
        if ((DWORD)(t-target) == talloced) {\
191
            target = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
192 193 194
            t = target+talloced;\
            talloced*=2;\
      }\
195
} while (0)
Dave Pickles's avatar
Dave Pickles committed
196

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
    if (from) {
        f=from;
        if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) {
            while (*f && !eos)
                ADD_TO_T(*f++);
        }
        else {
            while (*f && !eos) {
                if (*f=='%') {
                    int insertnr;
                    char *fmtstr,*x,*lastf;
                    DWORD *argliststart;

                    fmtstr = NULL;
                    lastf = f;
                    f++;
                    if (!*f) {
                        ADD_TO_T('%');
                        continue;
                    }
                    switch (*f) {
                    case '1':case '2':case '3':case '4':case '5':
                    case '6':case '7':case '8':case '9':
                        insertnr=*f-'0';
                        switch (f[1]) {
                        case '0':case '1':case '2':case '3':
                        case '4':case '5':case '6':case '7':
                        case '8':case '9':
                            f++;
                            insertnr=insertnr*10+*f-'0';
                            f++;
                            break;
                        default:
                            f++;
                            break;
                        }
                        if (*f=='!') {
                            f++;
                            if (NULL!=(x=strchr(f,'!'))) {
                                *x='\0';
                                fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
                                sprintf(fmtstr,"%%%s",f);
                                f=x+1;
                            } else {
                                fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2);
                                sprintf(fmtstr,"%%%s",f);
                                f+=strlen(f); /*at \0*/
                            }
                        } else {
246 247 248
                            if(!args) break;
                            fmtstr = HeapAlloc(GetProcessHeap(),0,3);
                            strcpy( fmtstr, "%s" );
249 250 251 252 253 254 255 256 257 258 259
                        }
                        if (args) {
                            int sz;
                            LPSTR b;

                            if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
                                argliststart=args+insertnr-1;
                            else
                                argliststart=(*(DWORD**)args)+insertnr-1;

                                /* FIXME: precision and width components are not handled correctly */
260 261 262
                            if (strcmp(fmtstr, "%ls") == 0 || strcmp(fmtstr,"%S") == 0 || strcmp(fmtstr,"%ws") == 0)
                            {
                                sz = WideCharToMultiByte(CP_ACP, 0, *(WCHAR**)argliststart, -1, NULL, 0, NULL, NULL);
263
                                b = HeapAlloc(GetProcessHeap(), 0, sz);
264 265 266 267 268
                                WideCharToMultiByte(CP_ACP, 0, *(WCHAR**)argliststart, -1, b, sz, NULL, NULL);
                            }
                            else if (strcmp(fmtstr, "%wc") == 0)
                            {
                                sz = WideCharToMultiByte(CP_ACP, 0, (WCHAR *)argliststart, 1, NULL, 0, NULL, NULL);
269
                                b = HeapAlloc(GetProcessHeap(), 0, sz + 1);
270
                                WideCharToMultiByte(CP_ACP, 0, (WCHAR *)argliststart, 1, b, sz, NULL, NULL);
271
                                b[sz] = 0;
272 273 274
                            }
                            else
                            {
275
                                b = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz = 1000);
276 277
                                /* CMF - This makes a BIG assumption about va_list */
                                TRACE("A BIG assumption\n");
278
                                vsnprintf(b, sz, fmtstr, (va_list) argliststart);
279 280 281 282 283
                            }
                            for (x=b; *x; x++) ADD_TO_T(*x);

                            HeapFree(GetProcessHeap(),0,b);
                        } else {
284
                                /* NULL args - copy formatstr
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
                                 * (probably wrong)
                                 */
                            while ((lastf<f)&&(*lastf)) {
                                ADD_TO_T(*lastf++);
                            }
                        }
                        HeapFree(GetProcessHeap(),0,fmtstr);
                        break;
                    case 'n':
                        ADD_TO_T('\r');
                        ADD_TO_T('\n');
                        f++;
                        break;
                    case '0':
                        eos = TRUE;
                        f++;
                        break;
                    default:
                        ADD_TO_T(*f++);
                        break;
                    }
                } else {
                    ch = *f;
                    f++;
                    if (ch == '\r') {
                        if (*f == '\n')
                            f++;
312 313 314
                        if(width)
                            ADD_TO_T(' ');
                        else
315 316 317 318
                        {
                            ADD_TO_T('\r');
                            ADD_TO_T('\n');
                        }
319 320 321 322 323 324 325 326 327 328 329
                    } else {
                        if (ch == '\n')
                        {
                            if(width)
                                ADD_TO_T(' ');
                            else
                            {
                                ADD_TO_T('\r');
                                ADD_TO_T('\n');
                            }
                        }
330 331 332 333 334 335 336 337 338 339
                        else
                            ADD_TO_T(ch);
                    }
                }
            }
        }
        *t='\0';
    }
    talloced = strlen(target)+1;
    if (nSize && talloced<nSize) {
340
        target = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize);
341 342 343
    }
    TRACE("-- %s\n",debugstr_a(target));
    if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
344
        *((LPVOID*)lpBuffer) = LocalAlloc(LMEM_ZEROINIT,max(nSize, talloced));
345 346 347 348 349
        memcpy(*(LPSTR*)lpBuffer,target,talloced);
    } else {
        lstrcpynA(lpBuffer,target,nSize);
    }
    HeapFree(GetProcessHeap(),0,target);
350
    HeapFree(GetProcessHeap(),0,from);
351
    ret = (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? strlen(*(LPSTR*)lpBuffer) : strlen(lpBuffer);
Dave Pickles's avatar
Dave Pickles committed
352
#endif /* __i386__ */
353
    TRACE("-- returning %d\n", ret);
354
    return ret;
Dave Pickles's avatar
Dave Pickles committed
355 356 357 358 359
}
#undef ADD_TO_T


/***********************************************************************
360
 *           FormatMessageW   (KERNEL32.@)
Dave Pickles's avatar
Dave Pickles committed
361 362 363 364 365 366 367 368
 */
DWORD WINAPI FormatMessageW(
	DWORD	dwFlags,
	LPCVOID	lpSource,
	DWORD	dwMessageId,
	DWORD	dwLanguageId,
	LPWSTR	lpBuffer,
	DWORD	nSize,
369
	__ms_va_list* _args )
370 371
{
    LPDWORD args=(LPDWORD)_args;
372
#if defined(__i386__) || defined(__sparc__)
373
/* This implementation is completely dependent on the format of the va_list on x86 CPUs */
374
    LPWSTR target,t;
375
    DWORD talloced;
376
    LPWSTR from,f;
377 378
    DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK;
    BOOL eos = FALSE;
379
    WCHAR ch;
380
    static const WCHAR fmt_wc[] = {'%','w','c',0};
381

382
    TRACE("(0x%x,%p,%d,0x%x,%p,%d,%p)\n",
383 384 385 386 387
          dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
    if ((dwFlags & FORMAT_MESSAGE_FROM_STRING)
        &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
           || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0;

388 389 390 391 392 393
    if (!lpBuffer)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return 0;
    }

394 395 396 397
    if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK)
        FIXME("line wrapping not supported.\n");
    from = NULL;
    if (dwFlags & FORMAT_MESSAGE_FROM_STRING) {
398
        from = HeapAlloc( GetProcessHeap(), 0, (strlenW(lpSource) + 1) *
399
            sizeof(WCHAR) );
400
        strcpyW( from, lpSource );
401 402
    }
    else {
403
        from = NULL;
404
        if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE)
405 406 407
            from = load_messageW( (HMODULE)lpSource, dwMessageId, dwLanguageId );
        if (!from && (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM))
            from = load_messageW( kernel32_handle, dwMessageId, dwLanguageId );
408

409 410
        if (!from)
        {
411 412 413
            SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND);
            return 0;
        }
414
    }
415
    target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 * sizeof(WCHAR) );
416 417
    t = target;
    talloced= 100;
Dave Pickles's avatar
Dave Pickles committed
418

419
#define ADD_TO_T(c)  do {\
420
    *t++=c;\
421
    if ((DWORD)(t-target) == talloced) {\
422
        target = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2*sizeof(WCHAR));\
423 424 425
        t = target+talloced;\
        talloced*=2;\
    } \
426
} while (0)
Dave Pickles's avatar
Dave Pickles committed
427

428 429 430 431 432
    if (from) {
        f=from;
        if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) {
            while (*f && !eos)
                ADD_TO_T(*f++);
433
        }
434 435 436 437
        else {
            while (*f && !eos) {
                if (*f=='%') {
                    int insertnr;
438
                    WCHAR *fmtstr,*sprintfbuf,*x;
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
                    DWORD *argliststart;

                    fmtstr = NULL;
                    f++;
                    if (!*f) {
                        ADD_TO_T('%');
                        continue;
                    }

                    switch (*f) {
                    case '1':case '2':case '3':case '4':case '5':
                    case '6':case '7':case '8':case '9':
                        insertnr=*f-'0';
                        switch (f[1]) {
                        case '0':case '1':case '2':case '3':
                        case '4':case '5':case '6':case '7':
                        case '8':case '9':
                            f++;
                            insertnr=insertnr*10+*f-'0';
                            f++;
                            break;
                        default:
                            f++;
                            break;
                        }
                        if (*f=='!') {
                            f++;
466
                            if (NULL!=(x=strchrW(f,'!'))) {
467
                                *x='\0';
468 469
                                fmtstr=HeapAlloc( GetProcessHeap(), 0,(strlenW(f)+2)*sizeof(WCHAR));
                                sprintfW(fmtstr,PCNTFMTWSTR,f);
470 471
                                f=x+1;
                            } else {
472 473 474
                                fmtstr=HeapAlloc(GetProcessHeap(),0,(strlenW(f)+2)*sizeof(WCHAR));
                                sprintfW(fmtstr,PCNTFMTWSTR,f);
                                f+=strlenW(f); /*at \0*/
475 476
                            }
                        } else {
477
                            if(!args) break;
478 479
                            fmtstr = HeapAlloc( GetProcessHeap(),0,3*sizeof(WCHAR));
                            strcpyW( fmtstr, FMTWSTR );
480 481 482 483 484 485
                        }
                        if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
                            argliststart=args+insertnr-1;
                        else
                            argliststart=(*(DWORD**)args)+insertnr-1;

486
                        if (fmtstr[strlenW(fmtstr)-1]=='s' && argliststart[0]) {
487
                            DWORD xarr[3];
488
                            WCHAR *fmt_end = fmtstr + strlenW(fmtstr) - 1;
489

490 491
                            /* remap %ws to %ls */
                            if (fmt_end > fmtstr && (fmt_end[-1] == 'w')) fmt_end[-1] = 'l';
492
                            xarr[0]=*(argliststart+0);
493 494 495
                            /* possible invalid pointers */
                            xarr[1]=*(argliststart+1);
                            xarr[2]=*(argliststart+2);
496
                            sprintfbuf=HeapAlloc(GetProcessHeap(),0,(strlenW((LPWSTR)argliststart[0])*2+1)*sizeof(WCHAR));
497 498

                            /* CMF - This makes a BIG assumption about va_list */
499
                            vsprintfW(sprintfbuf, fmtstr, (va_list) xarr);
500 501 502 503 504
                        }
                        else if (strcmpW(fmtstr, fmt_wc) == 0) {
                            sprintfbuf = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * 2);
                            sprintfbuf[0] = *(WCHAR *)argliststart;
                            sprintfbuf[1] = 0;
505 506 507 508
                        } else {
                            sprintfbuf=HeapAlloc(GetProcessHeap(),0,100);

                            /* CMF - This makes a BIG assumption about va_list */
509
                            vsprintfW(sprintfbuf, fmtstr, (va_list) argliststart);
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
                        }
                        x=sprintfbuf;
                        while (*x) {
                            ADD_TO_T(*x++);
                        }
                        HeapFree(GetProcessHeap(),0,sprintfbuf);
                        HeapFree(GetProcessHeap(),0,fmtstr);
                        break;
                    case 'n':
                        ADD_TO_T('\r');
                        ADD_TO_T('\n');
                        f++;
                        break;
                    case '0':
                        eos = TRUE;
                        f++;
                        break;
                    default:
                        ADD_TO_T(*f++);
                        break;
                    }
                } else {
                    ch = *f;
                    f++;
                    if (ch == '\r') {
                        if (*f == '\n')
                            f++;
537 538 539
                        if(width)
                            ADD_TO_T(' ');
                        else
540 541 542 543
                        {
                            ADD_TO_T('\r');
                            ADD_TO_T('\n');
                        }
544 545 546 547 548 549 550 551 552 553 554
                    } else {
                        if (ch == '\n')
                        {
                            if(width)
                                ADD_TO_T(' ');
                            else
                            {
                                ADD_TO_T('\r');
                                ADD_TO_T('\n');
                            }
                        }
555 556 557 558 559
                        else
                            ADD_TO_T(ch);
                    }
                }
            }
560
        }
561 562
        *t='\0';
    }
563
    talloced = strlenW(target)+1;
564
    if (nSize && talloced<nSize)
565
        target = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize*sizeof(WCHAR));
566 567
    if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
        /* nSize is the MINIMUM size */
568
        DWORD len = strlenW(target) + 1;
569
        *((LPVOID*)lpBuffer) = LocalAlloc(LMEM_ZEROINIT,len*sizeof(WCHAR));
570
        strcpyW(*(LPWSTR*)lpBuffer, target);
571
    }
572 573
    else lstrcpynW(lpBuffer, target, nSize);

574
    HeapFree(GetProcessHeap(),0,target);
575
    HeapFree(GetProcessHeap(),0,from);
576 577
    TRACE("ret=%s\n", wine_dbgstr_w((dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
        *(LPWSTR*)lpBuffer : lpBuffer));
578 579 580
    return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
        strlenW(*(LPWSTR*)lpBuffer):
            strlenW(lpBuffer);
Dave Pickles's avatar
Dave Pickles committed
581
#else
582
    return 0;
Dave Pickles's avatar
Dave Pickles committed
583 584 585
#endif /* __i386__ */
}
#undef ADD_TO_T