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 WideCharToMultiByte( CP_ACP
, 0, (LPWSTR
)mre
->Text
, -1, buffer
, i
, NULL
, NULL
);
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(
145 LPDWORD args
=(LPDWORD
)_args
;
147 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
151 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
154 HMODULE hmodule
= (HMODULE
)lpSource
;
157 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
158 dwFlags
,lpSource
,dwMessageId
,dwLanguageId
,lpBuffer
,nSize
,args
);
159 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
160 && (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)) return 0;
161 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
162 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
163 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
165 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
)
166 FIXME("line wrapping (%lu) not supported.\n", width
);
168 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
) {
169 from
= HEAP_strdupA( GetProcessHeap(), 0, (LPSTR
)lpSource
);
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");
263 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
264 argliststart
=args
+insertnr
-1;
266 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
268 /* FIXME: precision and width components are not handled correctly */
269 if (strcmp(fmtstr
, "%ls") == 0) {
270 sz
= WideCharToMultiByte( CP_ACP
, 0, *(WCHAR
**)argliststart
, -1, NULL
, 0, NULL
, NULL
);
271 b
= HeapAlloc(GetProcessHeap(), 0, sz
);
272 WideCharToMultiByte( CP_ACP
, 0, *(WCHAR
**)argliststart
, -1, b
, sz
, NULL
, NULL
);
274 b
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
= 100);
275 /* CMF - This makes a BIG assumption about va_list */
276 while (vsnprintf(b
, sz
, fmtstr
, (va_list) argliststart
) < 0) {
277 b
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, b
, sz
+= 100);
280 for (x
=b
; *x
; x
++) ADD_TO_T(*x
);
282 HeapFree(GetProcessHeap(),0,b
);
284 /* NULL args - copy formatstr
287 while ((lastf
<f
)&&(*lastf
)) {
291 HeapFree(GetProcessHeap(),0,fmtstr
);
327 talloced
= strlen(target
)+1;
328 if (nSize
&& talloced
<nSize
) {
329 target
= (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
331 TRACE("-- %s\n",debugstr_a(target
));
332 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
333 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,max(nSize
, talloced
));
334 memcpy(*(LPSTR
*)lpBuffer
,target
,talloced
);
336 lstrcpynA(lpBuffer
,target
,nSize
);
338 HeapFree(GetProcessHeap(),0,target
);
339 if (from
) HeapFree(GetProcessHeap(),0,from
);
340 TRACE("-- returning %d\n", (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ? strlen(*(LPSTR
*)lpBuffer
):strlen(lpBuffer
));
341 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
342 strlen(*(LPSTR
*)lpBuffer
):
346 #endif /* __i386__ */
351 /***********************************************************************
352 * FormatMessageW (KERNEL32.138)
354 DWORD WINAPI
FormatMessageW(
363 LPDWORD args
=(LPDWORD
)_args
;
365 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
369 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
372 HMODULE hmodule
= (HMODULE
)lpSource
;
375 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
376 dwFlags
,lpSource
,dwMessageId
,dwLanguageId
,lpBuffer
,nSize
,args
);
377 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
378 && (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)) return 0;
379 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
380 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
381 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
383 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
)
384 FIXME("line wrapping not supported.\n");
386 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
) {
387 from
= HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR
)lpSource
);
390 if (dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
391 hmodule
= GetModuleHandleA("kernel32");
392 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
395 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
398 bufsize
=load_messageA(hmodule
,dwMessageId
,
399 MAKELANGID(LANG_NEUTRAL
,SUBLANG_NEUTRAL
),NULL
,100);
400 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
401 MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),NULL
,100);
402 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
403 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
404 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
405 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
406 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
407 MAKELANGID(LANG_ENGLISH
,SUBLANG_ENGLISH_US
),NULL
,100);
409 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
413 from
= HeapAlloc( GetProcessHeap(), 0, bufsize
+ 1 );
414 load_messageA(hmodule
,dwMessageId
,dwLanguageId
,from
,bufsize
+1);
416 target
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 100 );
420 #define ADD_TO_T(c) do {\
422 if (t-target == talloced) {\
423 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
424 t = target+talloced;\
434 char *fmtstr
,*sprintfbuf
,*x
;
444 case '1':case '2':case '3':case '4':case '5':
445 case '6':case '7':case '8':case '9':
448 case '0':case '1':case '2':case '3':
449 case '4':case '5':case '6':case '7':
452 insertnr
=insertnr
*10+*f
-'0';
461 if (NULL
!=(x
=strchr(f
,'!')))
464 fmtstr
=HeapAlloc( GetProcessHeap(), 0, strlen(f
)+2);
465 sprintf(fmtstr
,"%%%s",f
);
468 fmtstr
=HeapAlloc(GetProcessHeap(),0,strlen(f
));
469 sprintf(fmtstr
,"%%%s",f
);
470 f
+=strlen(f
); /*at \0*/
476 fmtstr
=HEAP_strdupA( GetProcessHeap(),0,"%s");
477 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
478 argliststart
=args
+insertnr
-1;
480 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
482 if (fmtstr
[strlen(fmtstr
)-1]=='s' && argliststart
[0]) {
485 xarr
[0]=(DWORD
)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR
)(*(argliststart
+0)));
486 /* possible invalid pointers */
487 xarr
[1]=*(argliststart
+1);
488 xarr
[2]=*(argliststart
+2);
489 sprintfbuf
=HeapAlloc(GetProcessHeap(),0,strlenW((LPWSTR
)argliststart
[0])*2+1);
491 /* CMF - This makes a BIG assumption about va_list */
492 vsprintf(sprintfbuf
, fmtstr
, (va_list) xarr
);
494 sprintfbuf
=HeapAlloc(GetProcessHeap(),0,100);
496 /* CMF - This makes a BIG assumption about va_list */
497 vsprintf(sprintfbuf
, fmtstr
, (va_list) argliststart
);
503 HeapFree(GetProcessHeap(),0,sprintfbuf
);
504 HeapFree(GetProcessHeap(),0,fmtstr
);
540 talloced
= strlen(target
)+1;
541 if (nSize
&& talloced
<nSize
)
542 target
= (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
543 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
544 /* nSize is the MINIMUM size */
545 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, target
, -1, NULL
, 0 );
546 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,len
*sizeof(WCHAR
));
547 MultiByteToWideChar( CP_ACP
, 0, target
, -1, *(LPWSTR
*)lpBuffer
, len
);
551 if (nSize
> 0 && !MultiByteToWideChar( CP_ACP
, 0, target
, -1, lpBuffer
, nSize
))
552 lpBuffer
[nSize
-1] = 0;
554 HeapFree(GetProcessHeap(),0,target
);
555 if (from
) HeapFree(GetProcessHeap(),0,from
);
556 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
557 strlenW(*(LPWSTR
*)lpBuffer
):
561 #endif /* __i386__ */