2 * FormatMessage implementation
4 * Copyright 1996 Marcus Meissner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 #include "wine/unicode.h"
36 #include "kernel_private.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(resource
);
43 /* Messages...used by FormatMessage32* (KERNEL32.something)
45 * They can be specified either directly or using a message ID and
46 * loading them from the resource.
48 * The resourcedata has following format:
50 * 0: DWORD nrofentries
51 * nrofentries * subentry:
54 * 8: DWORD offset from start to the stringentries
56 * (lastentry-firstentry) * stringentry:
57 * 0: WORD len (0 marks end) [ includes the 4 byte header length ]
60 * (stringentry i of a subentry refers to the ID 'firstentry+i')
62 * Yes, ANSI strings in win32 resources. Go figure.
65 /**********************************************************************
66 * load_messageA (internal)
68 static INT
load_messageA( HMODULE instance
, UINT id
, WORD lang
,
69 LPSTR buffer
, INT buflen
)
71 const MESSAGE_RESOURCE_ENTRY
*mre
;
74 TRACE("instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD
)instance
, (DWORD
)id
, buffer
, (DWORD
)buflen
);
76 if (RtlFindMessage( instance
, RT_MESSAGETABLE
, lang
, id
, &mre
) != STATUS_SUCCESS
) return 0;
79 TRACE(" - strlen=%d\n",slen
);
80 i
= min(buflen
- 1, slen
);
84 if (mre
->Flags
& MESSAGE_RESOURCE_UNICODE
)
85 WideCharToMultiByte( CP_ACP
, 0, (LPWSTR
)mre
->Text
, -1, buffer
, i
, NULL
, NULL
);
87 lstrcpynA(buffer
, (LPSTR
)mre
->Text
, i
);
96 TRACE("'%s' copied !\n", buffer
);
101 /**********************************************************************
102 * load_messageW (internal)
104 static INT
load_messageW( HMODULE instance
, UINT id
, WORD lang
,
105 LPWSTR buffer
, INT buflen
)
108 LPSTR buffer2
= NULL
;
109 if (buffer
&& buflen
)
110 buffer2
= HeapAlloc( GetProcessHeap(), 0, buflen
);
111 retval
= load_messageA(instance
,id
,lang
,buffer2
,buflen
);
115 lstrcpynAtoW( buffer
, buffer2
, buflen
);
116 retval
= strlenW( buffer
);
118 HeapFree( GetProcessHeap(), 0, buffer2
);
125 /***********************************************************************
126 * FormatMessageA (KERNEL32.@)
127 * FIXME: missing wrap,
129 DWORD WINAPI
FormatMessageA(
138 LPDWORD args
=(LPDWORD
)_args
;
139 #if defined(__i386__) || defined(__sparc__)
140 /* This implementation is completely dependent on the format of the va_list on x86 CPUs */
144 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
147 HMODULE hmodule
= (HMODULE
)lpSource
;
150 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
151 dwFlags
,lpSource
,dwMessageId
,dwLanguageId
,lpBuffer
,nSize
,args
);
152 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
153 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
154 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
156 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
)
157 FIXME("line wrapping (%lu) not supported.\n", width
);
159 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
161 from
= HeapAlloc( GetProcessHeap(), 0, strlen((LPSTR
)lpSource
)+1 );
162 strcpy( from
, (LPSTR
)lpSource
);
167 if (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)
170 hmodule
= GetModuleHandleW(NULL
);
171 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
173 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
) && (!bufsize
))
175 hmodule
= kernel32_handle
;
176 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
180 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
184 from
= HeapAlloc( GetProcessHeap(), 0, bufsize
+ 1 );
185 load_messageA(hmodule
,dwMessageId
,dwLanguageId
,from
,bufsize
+1);
187 target
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 100);
191 #define ADD_TO_T(c) do { \
193 if (t-target == talloced) {\
194 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
195 t = target+talloced;\
202 if (dwFlags
& FORMAT_MESSAGE_IGNORE_INSERTS
) {
210 char *fmtstr
,*x
,*lastf
;
221 case '1':case '2':case '3':case '4':case '5':
222 case '6':case '7':case '8':case '9':
225 case '0':case '1':case '2':case '3':
226 case '4':case '5':case '6':case '7':
229 insertnr
=insertnr
*10+*f
-'0';
238 if (NULL
!=(x
=strchr(f
,'!'))) {
240 fmtstr
=HeapAlloc(GetProcessHeap(),0,strlen(f
)+2);
241 sprintf(fmtstr
,"%%%s",f
);
244 fmtstr
=HeapAlloc(GetProcessHeap(),0,strlen(f
)+2);
245 sprintf(fmtstr
,"%%%s",f
);
246 f
+=strlen(f
); /*at \0*/
250 fmtstr
= HeapAlloc(GetProcessHeap(),0,3);
251 strcpy( fmtstr
, "%s" );
257 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
258 argliststart
=args
+insertnr
-1;
260 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
262 /* FIXME: precision and width components are not handled correctly */
263 if ( (strcmp(fmtstr
, "%ls") == 0) || (strcmp(fmtstr
,"%S") == 0) ) {
264 sz
= WideCharToMultiByte( CP_ACP
, 0, *(WCHAR
**)argliststart
, -1, NULL
, 0, NULL
, NULL
);
265 b
= HeapAlloc(GetProcessHeap(), 0, sz
);
266 WideCharToMultiByte( CP_ACP
, 0, *(WCHAR
**)argliststart
, -1, b
, sz
, NULL
, NULL
);
268 b
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
= 1000);
269 /* CMF - This makes a BIG assumption about va_list */
270 TRACE("A BIG assumption\n");
271 vsnprintf(b
, sz
, fmtstr
, (va_list) argliststart
);
273 for (x
=b
; *x
; x
++) ADD_TO_T(*x
);
275 HeapFree(GetProcessHeap(),0,b
);
277 /* NULL args - copy formatstr
280 while ((lastf
<f
)&&(*lastf
)) {
284 HeapFree(GetProcessHeap(),0,fmtstr
);
331 talloced
= strlen(target
)+1;
332 if (nSize
&& talloced
<nSize
) {
333 target
= (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
335 TRACE("-- %s\n",debugstr_a(target
));
336 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
337 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,max(nSize
, talloced
));
338 memcpy(*(LPSTR
*)lpBuffer
,target
,talloced
);
340 lstrcpynA(lpBuffer
,target
,nSize
);
342 HeapFree(GetProcessHeap(),0,target
);
343 if (from
) HeapFree(GetProcessHeap(),0,from
);
344 TRACE("-- returning %d\n", (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ? strlen(*(LPSTR
*)lpBuffer
):strlen(lpBuffer
));
345 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
346 strlen(*(LPSTR
*)lpBuffer
):
350 #endif /* __i386__ */
355 /***********************************************************************
356 * FormatMessageW (KERNEL32.@)
358 DWORD WINAPI
FormatMessageW(
367 LPDWORD args
=(LPDWORD
)_args
;
368 #if defined(__i386__) || defined(__sparc__)
369 /* This implementation is completely dependent on the format of the va_list on x86 CPUs */
373 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
376 HMODULE hmodule
= (HMODULE
)lpSource
;
379 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
380 dwFlags
,lpSource
,dwMessageId
,dwLanguageId
,lpBuffer
,nSize
,args
);
381 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
382 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
383 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
385 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
)
386 FIXME("line wrapping not supported.\n");
388 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
) {
389 from
= HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR
)lpSource
);
394 if (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)
397 hmodule
= GetModuleHandleW(NULL
);
398 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
400 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
) && (!bufsize
))
402 hmodule
= kernel32_handle
;
403 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
407 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
411 from
= HeapAlloc( GetProcessHeap(), 0, bufsize
+ 1 );
412 load_messageA(hmodule
,dwMessageId
,dwLanguageId
,from
,bufsize
+1);
414 target
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 100 );
418 #define ADD_TO_T(c) do {\
420 if (t-target == talloced) {\
421 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
422 t = target+talloced;\
429 if (dwFlags
& FORMAT_MESSAGE_IGNORE_INSERTS
) {
437 char *fmtstr
,*sprintfbuf
,*x
;
448 case '1':case '2':case '3':case '4':case '5':
449 case '6':case '7':case '8':case '9':
452 case '0':case '1':case '2':case '3':
453 case '4':case '5':case '6':case '7':
456 insertnr
=insertnr
*10+*f
-'0';
465 if (NULL
!=(x
=strchr(f
,'!'))) {
467 fmtstr
=HeapAlloc( GetProcessHeap(), 0, strlen(f
)+2);
468 sprintf(fmtstr
,"%%%s",f
);
471 fmtstr
=HeapAlloc(GetProcessHeap(),0,strlen(f
)+2);
472 sprintf(fmtstr
,"%%%s",f
);
473 f
+=strlen(f
); /*at \0*/
477 fmtstr
= HeapAlloc( GetProcessHeap(),0,3);
478 strcpy( fmtstr
, "%s" );
480 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
481 argliststart
=args
+insertnr
-1;
483 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
485 if (fmtstr
[strlen(fmtstr
)-1]=='s' && argliststart
[0]) {
488 xarr
[0]=(DWORD
)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR
)(*(argliststart
+0)));
489 /* possible invalid pointers */
490 xarr
[1]=*(argliststart
+1);
491 xarr
[2]=*(argliststart
+2);
492 sprintfbuf
=HeapAlloc(GetProcessHeap(),0,strlenW((LPWSTR
)argliststart
[0])*2+1);
494 /* CMF - This makes a BIG assumption about va_list */
495 vsprintf(sprintfbuf
, fmtstr
, (va_list) xarr
);
496 HeapFree(GetProcessHeap(), 0, (LPVOID
) xarr
[0]);
498 sprintfbuf
=HeapAlloc(GetProcessHeap(),0,100);
500 /* CMF - This makes a BIG assumption about va_list */
501 vsprintf(sprintfbuf
, fmtstr
, (va_list) argliststart
);
507 HeapFree(GetProcessHeap(),0,sprintfbuf
);
508 HeapFree(GetProcessHeap(),0,fmtstr
);
555 talloced
= strlen(target
)+1;
556 if (nSize
&& talloced
<nSize
)
557 target
= (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
558 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
559 /* nSize is the MINIMUM size */
560 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, target
, -1, NULL
, 0 );
561 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,len
*sizeof(WCHAR
));
562 MultiByteToWideChar( CP_ACP
, 0, target
, -1, *(LPWSTR
*)lpBuffer
, len
);
566 if (nSize
> 0 && !MultiByteToWideChar( CP_ACP
, 0, target
, -1, lpBuffer
, nSize
))
567 lpBuffer
[nSize
-1] = 0;
569 HeapFree(GetProcessHeap(),0,target
);
570 if (from
) HeapFree(GetProcessHeap(),0,from
);
571 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
572 strlenW(*(LPWSTR
*)lpBuffer
):
576 #endif /* __i386__ */