2 * FormatMessage implementation
4 * Copyright 1996 Marcus Meissner
16 #include "wine/unicode.h"
19 #include "debugtools.h"
21 DEFAULT_DEBUG_CHANNEL(resource
);
24 /* Messages...used by FormatMessage32* (KERNEL32.something)
26 * They can be specified either directly or using a message ID and
27 * loading them from the resource.
29 * The resourcedata has following format:
31 * 0: DWORD nrofentries
32 * nrofentries * subentry:
35 * 8: DWORD offset from start to the stringentries
37 * (lastentry-firstentry) * stringentry:
38 * 0: WORD len (0 marks end) [ includes the 4 byte header length ]
41 * (stringentry i of a subentry refers to the ID 'firstentry+i')
43 * Yes, ANSI strings in win32 resources. Go figure.
46 /**********************************************************************
47 * load_messageA (internal)
49 static INT
load_messageA( HMODULE instance
, UINT id
, WORD lang
,
50 LPSTR buffer
, INT buflen
)
54 PMESSAGE_RESOURCE_DATA mrd
;
55 PMESSAGE_RESOURCE_BLOCK mrb
;
56 PMESSAGE_RESOURCE_ENTRY mre
;
59 TRACE("instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD
)instance
, (DWORD
)id
, buffer
, (DWORD
)buflen
);
61 /*FIXME: I am not sure about the '1' ... But I've only seen those entries*/
62 hrsrc
= FindResourceExW(instance
,RT_MESSAGELISTW
,(LPWSTR
)1,lang
);
64 hmem
= LoadResource( instance
, hrsrc
);
67 mrd
= (PMESSAGE_RESOURCE_DATA
)LockResource(hmem
);
69 mrb
= &(mrd
->Blocks
[0]);
70 for (i
=mrd
->NumberOfBlocks
;i
--;) {
71 if ((id
>=mrb
->LowId
) && (id
<=mrb
->HighId
)) {
72 mre
= (PMESSAGE_RESOURCE_ENTRY
)(((char*)mrd
)+mrb
->OffsetToEntries
);
83 mre
= (PMESSAGE_RESOURCE_ENTRY
)(((char*)mre
)+mre
->Length
);
86 TRACE(" - strlen=%d\n",slen
);
87 i
= min(buflen
- 1, slen
);
91 if (mre
->Flags
& MESSAGE_RESOURCE_UNICODE
)
92 lstrcpynWtoA(buffer
, (LPWSTR
)mre
->Text
, i
);
94 lstrcpynA(buffer
, (LPSTR
)mre
->Text
, i
);
103 TRACE("'%s' copied !\n", buffer
);
108 /**********************************************************************
109 * load_messageW (internal)
111 static INT
load_messageW( HMODULE instance
, UINT id
, WORD lang
,
112 LPWSTR buffer
, INT buflen
)
115 LPSTR buffer2
= NULL
;
116 if (buffer
&& buflen
)
117 buffer2
= HeapAlloc( GetProcessHeap(), 0, buflen
);
118 retval
= load_messageA(instance
,id
,lang
,buffer2
,buflen
);
122 lstrcpynAtoW( buffer
, buffer2
, buflen
);
123 retval
= strlenW( buffer
);
125 HeapFree( GetProcessHeap(), 0, buffer2
);
132 /***********************************************************************
133 * FormatMessageA (KERNEL32.138)
134 * FIXME: missing wrap,
136 DWORD WINAPI
FormatMessageA(
143 LPDWORD args
/* va_list *args */
146 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
150 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
153 HMODULE hmodule
= (HMODULE
)lpSource
;
156 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
157 dwFlags
,lpSource
,dwMessageId
,dwLanguageId
,lpBuffer
,nSize
,args
);
158 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
159 && (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)) return 0;
160 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
161 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
162 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
164 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
)
165 FIXME("line wrapping (%lu) not supported.\n", width
);
167 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
) {
168 from
= HEAP_strdupA( GetProcessHeap(), 0, (LPSTR
)lpSource
);
171 dwMessageId
&= 0xFFFF;
172 if (dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
173 hmodule
= GetModuleHandleA("kernel32");
174 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
177 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
180 bufsize
=load_messageA(hmodule
,dwMessageId
,
181 MAKELANGID(LANG_NEUTRAL
,SUBLANG_NEUTRAL
),NULL
,100);
182 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
183 MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),NULL
,100);
184 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
185 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
186 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
187 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
188 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
189 MAKELANGID(LANG_ENGLISH
,SUBLANG_ENGLISH_US
),NULL
,100);
191 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
195 from
= HeapAlloc( GetProcessHeap(), 0, bufsize
+ 1 );
196 load_messageA(hmodule
,dwMessageId
,dwLanguageId
,from
,bufsize
+1);
198 target
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 100);
202 #define ADD_TO_T(c) do { \
204 if (t-target == talloced) {\
205 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
206 t = target+talloced;\
216 char *fmtstr
,*x
,*lastf
;
227 case '1':case '2':case '3':case '4':case '5':
228 case '6':case '7':case '8':case '9':
231 case '0':case '1':case '2':case '3':
232 case '4':case '5':case '6':case '7':
235 insertnr
=insertnr
*10+*f
-'0';
244 if (NULL
!=(x
=strchr(f
,'!'))) {
246 fmtstr
=HeapAlloc(GetProcessHeap(),0,strlen(f
)+2);
247 sprintf(fmtstr
,"%%%s",f
);
250 fmtstr
=HeapAlloc(GetProcessHeap(),0,strlen(f
)+2);
251 sprintf(fmtstr
,"%%%s",f
);
252 f
+=strlen(f
); /*at \0*/
258 fmtstr
=HEAP_strdupA(GetProcessHeap(),0,"%s");
261 LPSTR b
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
= 100);
263 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
264 argliststart
=args
+insertnr
-1;
266 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
268 /* CMF - This makes a BIG assumption about va_list */
269 while (vsnprintf(b
, sz
, fmtstr
, (va_list) argliststart
) < 0) {
270 b
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, b
, sz
+= 100);
272 for (x
=b
; *x
; x
++) ADD_TO_T(*x
);
274 HeapFree(GetProcessHeap(),0,b
);
276 /* NULL args - copy formatstr
279 while ((lastf
<f
)&&(*lastf
)) {
283 HeapFree(GetProcessHeap(),0,fmtstr
);
319 talloced
= strlen(target
)+1;
320 if (nSize
&& talloced
<nSize
) {
321 target
= (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
323 TRACE("-- %s\n",debugstr_a(target
));
324 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
325 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,max(nSize
, talloced
));
326 memcpy(*(LPSTR
*)lpBuffer
,target
,talloced
);
328 lstrcpynA(lpBuffer
,target
,nSize
);
330 HeapFree(GetProcessHeap(),0,target
);
331 if (from
) HeapFree(GetProcessHeap(),0,from
);
332 TRACE("-- returning %d\n", (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ? strlen(*(LPSTR
*)lpBuffer
):strlen(lpBuffer
));
333 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
334 strlen(*(LPSTR
*)lpBuffer
):
338 #endif /* __i386__ */
343 /***********************************************************************
344 * FormatMessageW (KERNEL32.138)
346 DWORD WINAPI
FormatMessageW(
353 LPDWORD args
/* va_list *args */
356 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
360 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
363 HMODULE hmodule
= (HMODULE
)lpSource
;
366 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
367 dwFlags
,lpSource
,dwMessageId
,dwLanguageId
,lpBuffer
,nSize
,args
);
368 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
369 && (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)) return 0;
370 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
371 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
372 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
374 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
)
375 FIXME("line wrapping not supported.\n");
377 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
) {
378 from
= HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR
)lpSource
);
381 dwMessageId
&= 0xFFFF;
382 if (dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
383 hmodule
= GetModuleHandleA("kernel32");
384 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
387 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
390 bufsize
=load_messageA(hmodule
,dwMessageId
,
391 MAKELANGID(LANG_NEUTRAL
,SUBLANG_NEUTRAL
),NULL
,100);
392 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
393 MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),NULL
,100);
394 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
395 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
396 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
397 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
398 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
399 MAKELANGID(LANG_ENGLISH
,SUBLANG_ENGLISH_US
),NULL
,100);
401 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
405 from
= HeapAlloc( GetProcessHeap(), 0, bufsize
+ 1 );
406 load_messageA(hmodule
,dwMessageId
,dwLanguageId
,from
,bufsize
+1);
408 target
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 100 );
412 #define ADD_TO_T(c) do {\
414 if (t-target == talloced) {\
415 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
416 t = target+talloced;\
426 char *fmtstr
,*sprintfbuf
,*x
;
436 case '1':case '2':case '3':case '4':case '5':
437 case '6':case '7':case '8':case '9':
440 case '0':case '1':case '2':case '3':
441 case '4':case '5':case '6':case '7':
444 insertnr
=insertnr
*10+*f
-'0';
453 if (NULL
!=(x
=strchr(f
,'!')))
456 fmtstr
=HeapAlloc( GetProcessHeap(), 0, strlen(f
)+2);
457 sprintf(fmtstr
,"%%%s",f
);
460 fmtstr
=HeapAlloc(GetProcessHeap(),0,strlen(f
));
461 sprintf(fmtstr
,"%%%s",f
);
462 f
+=strlen(f
); /*at \0*/
468 fmtstr
=HEAP_strdupA( GetProcessHeap(),0,"%s");
469 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
470 argliststart
=args
+insertnr
-1;
472 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
474 if (fmtstr
[strlen(fmtstr
)-1]=='s' && argliststart
[0]) {
477 xarr
[0]=(DWORD
)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR
)(*(argliststart
+0)));
478 /* possible invalid pointers */
479 xarr
[1]=*(argliststart
+1);
480 xarr
[2]=*(argliststart
+2);
481 sprintfbuf
=HeapAlloc(GetProcessHeap(),0,strlenW((LPWSTR
)argliststart
[0])*2+1);
483 /* CMF - This makes a BIG assumption about va_list */
484 vsprintf(sprintfbuf
, fmtstr
, (va_list) xarr
);
486 sprintfbuf
=HeapAlloc(GetProcessHeap(),0,100);
488 /* CMF - This makes a BIG assumption about va_list */
489 vsprintf(sprintfbuf
, fmtstr
, (va_list) argliststart
);
495 HeapFree(GetProcessHeap(),0,sprintfbuf
);
496 HeapFree(GetProcessHeap(),0,fmtstr
);
532 talloced
= strlen(target
)+1;
533 if (nSize
&& talloced
<nSize
)
534 target
= (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
535 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
536 /* nSize is the MINIMUM size */
537 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,talloced
*2+2);
538 lstrcpynAtoW(*(LPWSTR
*)lpBuffer
,target
,talloced
);
540 lstrcpynAtoW(lpBuffer
,target
,nSize
);
541 HeapFree(GetProcessHeap(),0,target
);
542 if (from
) HeapFree(GetProcessHeap(),0,from
);
543 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
544 strlenW(*(LPWSTR
*)lpBuffer
):
548 #endif /* __i386__ */