2 * FormatMessage implementation
4 * Copyright 1996 Marcus Meissner
16 #include "wine/unicode.h"
17 #include "wine/winestring.h"
20 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(resource
);
25 /* Messages...used by FormatMessage32* (KERNEL32.something)
27 * They can be specified either directly or using a message ID and
28 * loading them from the resource.
30 * The resourcedata has following format:
32 * 0: DWORD nrofentries
33 * nrofentries * subentry:
36 * 8: DWORD offset from start to the stringentries
38 * (lastentry-firstentry) * stringentry:
39 * 0: WORD len (0 marks end) [ includes the 4 byte header length ]
42 * (stringentry i of a subentry refers to the ID 'firstentry+i')
44 * Yes, ANSI strings in win32 resources. Go figure.
47 /**********************************************************************
48 * load_messageA (internal)
50 static INT
load_messageA( HMODULE instance
, UINT id
, WORD lang
,
51 LPSTR buffer
, INT buflen
)
55 PMESSAGE_RESOURCE_DATA mrd
;
56 PMESSAGE_RESOURCE_BLOCK mrb
;
57 PMESSAGE_RESOURCE_ENTRY mre
;
60 TRACE("instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD
)instance
, (DWORD
)id
, buffer
, (DWORD
)buflen
);
62 /*FIXME: I am not sure about the '1' ... But I've only seen those entries*/
63 hrsrc
= FindResourceExW(instance
,RT_MESSAGELISTW
,(LPWSTR
)1,lang
);
65 hmem
= LoadResource( instance
, hrsrc
);
68 mrd
= (PMESSAGE_RESOURCE_DATA
)LockResource(hmem
);
70 mrb
= &(mrd
->Blocks
[0]);
71 for (i
=mrd
->NumberOfBlocks
;i
--;) {
72 if ((id
>=mrb
->LowId
) && (id
<=mrb
->HighId
)) {
73 mre
= (PMESSAGE_RESOURCE_ENTRY
)(((char*)mrd
)+mrb
->OffsetToEntries
);
84 mre
= (PMESSAGE_RESOURCE_ENTRY
)(((char*)mre
)+mre
->Length
);
87 TRACE(" - strlen=%d\n",slen
);
88 i
= min(buflen
- 1, slen
);
92 if (mre
->Flags
& MESSAGE_RESOURCE_UNICODE
)
93 lstrcpynWtoA(buffer
, (LPWSTR
)mre
->Text
, i
);
95 lstrcpynA(buffer
, (LPSTR
)mre
->Text
, i
);
104 TRACE("'%s' copied !\n", buffer
);
109 /**********************************************************************
110 * load_messageW (internal)
112 static INT
load_messageW( HMODULE instance
, UINT id
, WORD lang
,
113 LPWSTR buffer
, INT buflen
)
116 LPSTR buffer2
= NULL
;
117 if (buffer
&& buflen
)
118 buffer2
= HeapAlloc( GetProcessHeap(), 0, buflen
);
119 retval
= load_messageA(instance
,id
,lang
,buffer2
,buflen
);
123 lstrcpynAtoW( buffer
, buffer2
, buflen
);
124 retval
= strlenW( buffer
);
126 HeapFree( GetProcessHeap(), 0, buffer2
);
133 /***********************************************************************
134 * FormatMessageA (KERNEL32.138)
135 * FIXME: missing wrap,
137 DWORD WINAPI
FormatMessageA(
146 LPDWORD args
=(LPDWORD
)_args
;
148 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
152 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
155 HMODULE hmodule
= (HMODULE
)lpSource
;
158 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
159 dwFlags
,lpSource
,dwMessageId
,dwLanguageId
,lpBuffer
,nSize
,args
);
160 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
161 && (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)) return 0;
162 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
163 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
164 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
166 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
)
167 FIXME("line wrapping (%lu) not supported.\n", width
);
169 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
) {
170 from
= HEAP_strdupA( GetProcessHeap(), 0, (LPSTR
)lpSource
);
173 if (dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
174 hmodule
= GetModuleHandleA("kernel32");
175 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
178 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
181 bufsize
=load_messageA(hmodule
,dwMessageId
,
182 MAKELANGID(LANG_NEUTRAL
,SUBLANG_NEUTRAL
),NULL
,100);
183 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
184 MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),NULL
,100);
185 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
186 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
187 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
188 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
189 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
190 MAKELANGID(LANG_ENGLISH
,SUBLANG_ENGLISH_US
),NULL
,100);
192 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
196 from
= HeapAlloc( GetProcessHeap(), 0, bufsize
+ 1 );
197 load_messageA(hmodule
,dwMessageId
,dwLanguageId
,from
,bufsize
+1);
199 target
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 100);
203 #define ADD_TO_T(c) do { \
205 if (t-target == talloced) {\
206 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
207 t = target+talloced;\
217 char *fmtstr
,*x
,*lastf
;
228 case '1':case '2':case '3':case '4':case '5':
229 case '6':case '7':case '8':case '9':
232 case '0':case '1':case '2':case '3':
233 case '4':case '5':case '6':case '7':
236 insertnr
=insertnr
*10+*f
-'0';
245 if (NULL
!=(x
=strchr(f
,'!'))) {
247 fmtstr
=HeapAlloc(GetProcessHeap(),0,strlen(f
)+2);
248 sprintf(fmtstr
,"%%%s",f
);
251 fmtstr
=HeapAlloc(GetProcessHeap(),0,strlen(f
)+2);
252 sprintf(fmtstr
,"%%%s",f
);
253 f
+=strlen(f
); /*at \0*/
259 fmtstr
=HEAP_strdupA(GetProcessHeap(),0,"%s");
262 LPSTR b
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
= 100);
264 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
265 argliststart
=args
+insertnr
-1;
267 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
269 /* CMF - This makes a BIG assumption about va_list */
270 while (vsnprintf(b
, sz
, fmtstr
, (va_list) argliststart
) < 0) {
271 b
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, b
, sz
+= 100);
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
);
320 talloced
= strlen(target
)+1;
321 if (nSize
&& talloced
<nSize
) {
322 target
= (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
324 TRACE("-- %s\n",debugstr_a(target
));
325 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
326 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,max(nSize
, talloced
));
327 memcpy(*(LPSTR
*)lpBuffer
,target
,talloced
);
329 lstrcpynA(lpBuffer
,target
,nSize
);
331 HeapFree(GetProcessHeap(),0,target
);
332 if (from
) HeapFree(GetProcessHeap(),0,from
);
333 TRACE("-- returning %d\n", (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ? strlen(*(LPSTR
*)lpBuffer
):strlen(lpBuffer
));
334 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
335 strlen(*(LPSTR
*)lpBuffer
):
339 #endif /* __i386__ */
344 /***********************************************************************
345 * FormatMessageW (KERNEL32.138)
347 DWORD WINAPI
FormatMessageW(
356 LPDWORD args
=(LPDWORD
)_args
;
358 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
362 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
365 HMODULE hmodule
= (HMODULE
)lpSource
;
368 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
369 dwFlags
,lpSource
,dwMessageId
,dwLanguageId
,lpBuffer
,nSize
,args
);
370 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
371 && (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)) return 0;
372 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
373 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
374 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
376 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
)
377 FIXME("line wrapping not supported.\n");
379 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
) {
380 from
= HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR
)lpSource
);
383 if (dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
384 hmodule
= GetModuleHandleA("kernel32");
385 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
388 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
391 bufsize
=load_messageA(hmodule
,dwMessageId
,
392 MAKELANGID(LANG_NEUTRAL
,SUBLANG_NEUTRAL
),NULL
,100);
393 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
394 MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),NULL
,100);
395 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
396 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
397 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
398 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
399 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
400 MAKELANGID(LANG_ENGLISH
,SUBLANG_ENGLISH_US
),NULL
,100);
402 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
406 from
= HeapAlloc( GetProcessHeap(), 0, bufsize
+ 1 );
407 load_messageA(hmodule
,dwMessageId
,dwLanguageId
,from
,bufsize
+1);
409 target
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 100 );
413 #define ADD_TO_T(c) do {\
415 if (t-target == talloced) {\
416 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
417 t = target+talloced;\
427 char *fmtstr
,*sprintfbuf
,*x
;
437 case '1':case '2':case '3':case '4':case '5':
438 case '6':case '7':case '8':case '9':
441 case '0':case '1':case '2':case '3':
442 case '4':case '5':case '6':case '7':
445 insertnr
=insertnr
*10+*f
-'0';
454 if (NULL
!=(x
=strchr(f
,'!')))
457 fmtstr
=HeapAlloc( GetProcessHeap(), 0, strlen(f
)+2);
458 sprintf(fmtstr
,"%%%s",f
);
461 fmtstr
=HeapAlloc(GetProcessHeap(),0,strlen(f
));
462 sprintf(fmtstr
,"%%%s",f
);
463 f
+=strlen(f
); /*at \0*/
469 fmtstr
=HEAP_strdupA( GetProcessHeap(),0,"%s");
470 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
471 argliststart
=args
+insertnr
-1;
473 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
475 if (fmtstr
[strlen(fmtstr
)-1]=='s' && argliststart
[0]) {
478 xarr
[0]=(DWORD
)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR
)(*(argliststart
+0)));
479 /* possible invalid pointers */
480 xarr
[1]=*(argliststart
+1);
481 xarr
[2]=*(argliststart
+2);
482 sprintfbuf
=HeapAlloc(GetProcessHeap(),0,strlenW((LPWSTR
)argliststart
[0])*2+1);
484 /* CMF - This makes a BIG assumption about va_list */
485 vsprintf(sprintfbuf
, fmtstr
, (va_list) xarr
);
487 sprintfbuf
=HeapAlloc(GetProcessHeap(),0,100);
489 /* CMF - This makes a BIG assumption about va_list */
490 vsprintf(sprintfbuf
, fmtstr
, (va_list) argliststart
);
496 HeapFree(GetProcessHeap(),0,sprintfbuf
);
497 HeapFree(GetProcessHeap(),0,fmtstr
);
533 talloced
= strlen(target
)+1;
534 if (nSize
&& talloced
<nSize
)
535 target
= (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
536 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
537 /* nSize is the MINIMUM size */
538 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,talloced
*2+2);
539 lstrcpynAtoW(*(LPWSTR
*)lpBuffer
,target
,talloced
);
541 lstrcpynAtoW(lpBuffer
,target
,nSize
);
542 HeapFree(GetProcessHeap(),0,target
);
543 if (from
) HeapFree(GetProcessHeap(),0,from
);
544 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
545 strlenW(*(LPWSTR
*)lpBuffer
):
549 #endif /* __i386__ */