3 * reactos/lib/kernel32/misc/errormsg.c
7 * FormatMessage implementation
9 * Copyright 1996 Marcus Meissner
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "../include/debug.h"
35 /* DO NOT USE IT!! it will go away soon */
36 inline static LPSTR
HEAP_strdupWtoA( HANDLE heap
, DWORD flags
, LPCWSTR str
)
41 if (!str
) return NULL
;
42 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
43 ret
= RtlAllocateHeap(RtlGetProcessHeap(), flags
, len
);
44 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
48 /* Messages...used by FormatMessage32* (KERNEL32.something)
50 * They can be specified either directly or using a message ID and
51 * loading them from the resource.
53 * The resourcedata has following format:
55 * 0: DWORD nrofentries
56 * nrofentries * subentry:
59 * 8: DWORD offset from start to the stringentries
61 * (lastentry-firstentry) * stringentry:
62 * 0: WORD len (0 marks end) [ includes the 4 byte header length ]
65 * (stringentry i of a subentry refers to the ID 'firstentry+i')
67 * Yes, ANSI strings in win32 resources. Go figure.
70 /**********************************************************************
71 * load_messageA (internal)
73 static INT
load_messageA( HMODULE instance
, UINT id
, WORD lang
,
74 LPSTR buffer
, INT buflen
)
78 PMESSAGE_RESOURCE_DATA mrd
;
79 PMESSAGE_RESOURCE_BLOCK mrb
;
80 PMESSAGE_RESOURCE_ENTRY mre
;
83 //TRACE("instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD)instance, (DWORD)id, buffer, (DWORD)buflen);
85 /*FIXME: I am not sure about the '1' ... But I've only seen those entries*/
86 hrsrc
= FindResourceExW(instance
,(LPWSTR
)RT_MESSAGETABLE
,(LPWSTR
)1,lang
);
88 hmem
= LoadResource( instance
, hrsrc
);
91 mrd
= (PMESSAGE_RESOURCE_DATA
)LockResource(hmem
);
93 mrb
= &(mrd
->Blocks
[0]);
94 for (i
=mrd
->NumberOfBlocks
;i
--;) {
95 if ((id
>=mrb
->LowId
) && (id
<=mrb
->HighId
)) {
96 mre
= (PMESSAGE_RESOURCE_ENTRY
)(((char*)mrd
)+mrb
->OffsetToEntries
);
107 mre
= (PMESSAGE_RESOURCE_ENTRY
)(((char*)mre
)+mre
->Length
);
110 //TRACE(" - strlen=%d\n",slen);
111 i
= min(buflen
- 1, slen
);
115 if (mre
->Flags
& MESSAGE_RESOURCE_UNICODE
)
116 WideCharToMultiByte( CP_ACP
, 0, (LPWSTR
)mre
->Text
, -1, buffer
, i
, NULL
, NULL
);
118 lstrcpynA(buffer
, (LPSTR
)mre
->Text
, i
);
127 //TRACE("'%s' copied !\n", buffer);
128 //TRACE("'%s'\n", buffer);
134 /**********************************************************************
135 * load_messageW (internal)
137 static INT
load_messageW( HMODULE instance
, UINT id
, WORD lang
,
138 LPWSTR buffer
, INT buflen
)
141 LPSTR buffer2
= NULL
;
142 if (buffer
&& buflen
)
143 buffer2
= HeapAlloc( GetProcessHeap(), 0, buflen
);
144 retval
= load_messageA(instance
,id
,lang
,buffer2
,buflen
);
148 lstrcpynAtoW( buffer
, buffer2
, buflen
);
149 retval
= lstrlenW( buffer
);
151 HeapFree( GetProcessHeap(), 0, buffer2
);
158 /***********************************************************************
159 * FormatMessageA (KERNEL32.@)
160 * FIXME: missing wrap,
164 DWORD WINAPI
FormatMessageA(
173 LPDWORD args
=(LPDWORD
)_args
;
174 #if defined(__i386__) || defined(__sparc__)
175 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
179 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
182 HMODULE hmodule
= (HMODULE
)lpSource
;
185 //TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n", dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
186 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
187 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
188 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
190 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
)
191 //FIXME("line wrapping (%lu) not supported.\n", width);
193 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
195 from
= RtlAllocateHeap(RtlGetProcessHeap(), 0, lstrlenA((LPSTR
)lpSource
)+1 );
196 strcpy( from
, (LPSTR
)lpSource
);
201 if (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)
203 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
204 if ((!bufsize
) && (!dwLanguageId
)) {
205 bufsize
=load_messageA(hmodule
,dwMessageId
,
206 MAKELANGID(LANG_NEUTRAL
,SUBLANG_NEUTRAL
),NULL
,100);
207 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
208 MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),NULL
,100);
209 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
210 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
211 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
212 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
213 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
214 MAKELANGID(LANG_ENGLISH
,SUBLANG_ENGLISH_US
),NULL
,100);
217 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
) && (!bufsize
))
219 hmodule
= GetModuleHandleA("kernel32");
220 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
221 if ((!bufsize
) && (!dwLanguageId
)) {
222 bufsize
=load_messageA(hmodule
,dwMessageId
,
223 MAKELANGID(LANG_NEUTRAL
,SUBLANG_NEUTRAL
),NULL
,100);
224 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
225 MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),NULL
,100);
226 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
227 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
228 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
229 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
230 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
231 MAKELANGID(LANG_ENGLISH
,SUBLANG_ENGLISH_US
),NULL
,100);
236 TRACE("FormatMessageA: dwFlags=%#x hmodule=%#x dwMessageId=%#x - could not load message\n", dwFlags
, hmodule
, dwMessageId
);
237 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
241 from
= RtlAllocateHeap(RtlGetProcessHeap(), 0, bufsize
+ 1 );
242 load_messageA(hmodule
,dwMessageId
,dwLanguageId
,from
,bufsize
+1);
244 target
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, 100);
248 #define ADD_TO_T(c) do { \
250 if (t-target == talloced) {\
251 target = (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
252 t = target+talloced;\
259 if (dwFlags
& FORMAT_MESSAGE_IGNORE_INSERTS
) {
267 char *fmtstr
,*x
,*lastf
;
278 case '1':case '2':case '3':case '4':case '5':
279 case '6':case '7':case '8':case '9':
282 case '0':case '1':case '2':case '3':
283 case '4':case '5':case '6':case '7':
286 insertnr
=insertnr
*10+*f
-'0';
295 if (NULL
!=(x
=strchr(f
,'!'))) {
297 fmtstr
=RtlAllocateHeap(RtlGetProcessHeap(),0,lstrlenA(f
)+2);
298 sprintf(fmtstr
,"%%%s",f
);
301 fmtstr
=RtlAllocateHeap(RtlGetProcessHeap(),0,lstrlenA(f
)+2);
302 sprintf(fmtstr
,"%%%s",f
);
303 f
+=lstrlenA(f
); /*at \0*/
307 fmtstr
= RtlAllocateHeap(RtlGetProcessHeap(),0,3);
308 strcpy( fmtstr
, "%s" );
314 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
315 argliststart
=args
+insertnr
-1;
317 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
319 /* FIXME: precision and width components are not handled correctly */
320 if ( (strcmp(fmtstr
, "%ls") == 0) || (strcmp(fmtstr
,"%S") == 0) ) {
321 sz
= WideCharToMultiByte( CP_ACP
, 0, *(WCHAR
**)argliststart
, -1, NULL
, 0, NULL
, NULL
);
322 b
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sz
);
323 WideCharToMultiByte( CP_ACP
, 0, *(WCHAR
**)argliststart
, -1, b
, sz
, NULL
, NULL
);
325 b
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, sz
= 1000);
326 /* CMF - This makes a BIG assumption about va_list */
327 //TRACE("A BIG assumption\n");
328 _vsnprintf(b
, sz
, fmtstr
, (va_list) argliststart
);
330 for (x
=b
; *x
; x
++) ADD_TO_T(*x
);
332 RtlFreeHeap(RtlGetProcessHeap(),0,b
);
334 /* NULL args - copy formatstr
337 while ((lastf
<f
)&&(*lastf
)) {
341 RtlFreeHeap(GetProcessHeap(),0,fmtstr
);
388 talloced
= lstrlenA(target
)+1;
389 if (nSize
&& talloced
<nSize
) {
390 target
= (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
392 //TRACE("-- %s\n",debugstr_a(target));
393 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
394 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,max(nSize
, talloced
));
395 memcpy(*(LPSTR
*)lpBuffer
,target
,talloced
);
397 lstrcpynA(lpBuffer
,target
,nSize
);
399 RtlFreeHeap(RtlGetProcessHeap(),0,target
);
400 if (from
) RtlFreeHeap(RtlGetProcessHeap(),0,from
);
401 //TRACE("-- returning %d\n", (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? lstrlenA(*(LPSTR*)lpBuffer):lstrlenA(lpBuffer));
402 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
403 lstrlenA(*(LPSTR
*)lpBuffer
):
406 FIXME("FormatMessageA: unimplemented\n");
408 #endif /* __i386__ */
413 /***********************************************************************
414 * FormatMessageW (KERNEL32.@)
418 DWORD WINAPI
FormatMessageW(
427 LPDWORD args
=(LPDWORD
)_args
;
428 #if defined(__i386__) || defined(__sparc__)
429 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
433 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
436 HMODULE hmodule
= (HMODULE
)lpSource
;
439 //TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n", dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
440 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
441 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
442 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
444 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
) {
445 //FIXME("line wrapping not supported.\n");
448 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
) {
449 from
= (LPSTR
)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR
)lpSource
);
454 if (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)
456 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
457 if ((!bufsize
) && (!dwLanguageId
)) {
458 bufsize
=load_messageA(hmodule
,dwMessageId
,
459 MAKELANGID(LANG_NEUTRAL
,SUBLANG_NEUTRAL
),NULL
,100);
460 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
461 MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),NULL
,100);
462 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
463 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
464 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
465 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
466 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
467 MAKELANGID(LANG_ENGLISH
,SUBLANG_ENGLISH_US
),NULL
,100);
470 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
) && (!bufsize
))
472 hmodule
= GetModuleHandleA("kernel32");
473 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
474 if ((!bufsize
) && (!dwLanguageId
)) {
475 bufsize
=load_messageA(hmodule
,dwMessageId
,
476 MAKELANGID(LANG_NEUTRAL
,SUBLANG_NEUTRAL
),NULL
,100);
477 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
478 MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),NULL
,100);
479 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
480 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
481 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
482 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
483 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
484 MAKELANGID(LANG_ENGLISH
,SUBLANG_ENGLISH_US
),NULL
,100);
489 TRACE("FormatMessageW: dwFlags=%#x hmodule=%#x dwMessageId=%#x - could not load message\n", dwFlags
, hmodule
, dwMessageId
);
490 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
494 from
= RtlAllocateHeap(RtlGetProcessHeap(), 0, bufsize
+ 1 );
495 load_messageA(hmodule
,dwMessageId
,dwLanguageId
,from
,bufsize
+1);
497 target
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, 100 );
501 #define ADD_TO_T(c) do {\
503 if (t-target == talloced) {\
504 target = (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
505 t = target+talloced;\
512 if (dwFlags
& FORMAT_MESSAGE_IGNORE_INSERTS
) {
520 char *fmtstr
,*sprintfbuf
,*x
;
531 case '1':case '2':case '3':case '4':case '5':
532 case '6':case '7':case '8':case '9':
535 case '0':case '1':case '2':case '3':
536 case '4':case '5':case '6':case '7':
539 insertnr
=insertnr
*10+*f
-'0';
548 if (NULL
!=(x
=strchr(f
,'!'))) {
550 fmtstr
=RtlAllocateHeap(RtlGetProcessHeap(), 0, lstrlenA(f
)+2);
551 sprintf(fmtstr
,"%%%s",f
);
554 fmtstr
=RtlAllocateHeap(RtlGetProcessHeap(),0,lstrlenA(f
));
555 sprintf(fmtstr
,"%%%s",f
);
556 f
+=lstrlenA(f
); /*at \0*/
560 fmtstr
= RtlAllocateHeap(RtlGetProcessHeap(),0,3);
561 strcpy( fmtstr
, "%s" );
563 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
564 argliststart
=args
+insertnr
-1;
566 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
568 if (fmtstr
[lstrlenA(fmtstr
)-1]=='s' && argliststart
[0]) {
571 xarr
[0]=(DWORD
)HEAP_strdupWtoA(RtlGetProcessHeap(),0,(LPWSTR
)(*(argliststart
+0)));
572 /* possible invalid pointers */
573 xarr
[1]=*(argliststart
+1);
574 xarr
[2]=*(argliststart
+2);
575 sprintfbuf
=RtlAllocateHeap(RtlGetProcessHeap(),0,lstrlenW((LPWSTR
)argliststart
[0])*2+1);
577 /* CMF - This makes a BIG assumption about va_list */
578 vsprintf(sprintfbuf
, fmtstr
, (va_list) xarr
);
579 RtlFreeHeap(RtlGetProcessHeap(), 0, (LPVOID
) xarr
[0]);
581 sprintfbuf
=RtlAllocateHeap(RtlGetProcessHeap(),0,100);
583 /* CMF - This makes a BIG assumption about va_list */
584 vsprintf(sprintfbuf
, fmtstr
, (va_list) argliststart
);
590 RtlFreeHeap(RtlGetProcessHeap(),0,sprintfbuf
);
591 RtlFreeHeap(RtlGetProcessHeap(),0,fmtstr
);
638 talloced
= lstrlenA(target
)+1;
639 if (nSize
&& talloced
<nSize
)
640 target
= (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
641 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
642 /* nSize is the MINIMUM size */
643 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, target
, -1, NULL
, 0 );
644 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,len
*sizeof(WCHAR
));
645 MultiByteToWideChar( CP_ACP
, 0, target
, -1, *(LPWSTR
*)lpBuffer
, len
);
649 if (nSize
> 0 && !MultiByteToWideChar( CP_ACP
, 0, target
, -1, lpBuffer
, nSize
))
650 lpBuffer
[nSize
-1] = 0;
652 RtlFreeHeap(RtlGetProcessHeap(),0,target
);
653 if (from
) RtlFreeHeap(RtlGetProcessHeap(),0,from
);
654 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
655 lstrlenW(*(LPWSTR
*)lpBuffer
):
658 FIXME("FormatMessageW: unimplemented\n");
660 #endif /* __i386__ */