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
21 /* $Id: errormsg.c,v 1.9 2003/11/05 20:32:07 sedwards Exp $
23 * COPYRIGHT: See COPYING in the top level directory
24 * PROJECT: ReactOS Kernel32
25 * PURPOSE: Format Message
26 * FILE: lib/user32/controls/static.c
27 * PROGRAMER: Steven Edwards lib/kernel32/misc/errormsg.c
28 * REVISION HISTORY: 2003/11/05 Created
29 * NOTES: Adapted from Wine
32 #include <ddk/ntddk.h>
33 #include <kernel32/kernel32.h>
34 #include <kernel32/error.h>
37 #include <wine/unicode.h>
39 /* Wine porting stuff */
43 typedef struct tagMESSAGE_RESOURCE_ENTRY
{
47 } MESSAGE_RESOURCE_ENTRY
,*PMESSAGE_RESOURCE_ENTRY
;
48 #define MESSAGE_RESOURCE_UNICODE 0x0001
50 typedef struct tagMESSAGE_RESOURCE_BLOCK
{
53 DWORD OffsetToEntries
;
54 } MESSAGE_RESOURCE_BLOCK
,*PMESSAGE_RESOURCE_BLOCK
;
56 typedef struct tagMESSAGE_RESOURCE_DATA
{
58 MESSAGE_RESOURCE_BLOCK Blocks
[ 1 ];
59 } MESSAGE_RESOURCE_DATA
,*PMESSAGE_RESOURCE_DATA
;
61 /* These are needed so that we can call the functions from inside kernel itself */
63 LPVOID WINAPI
HeapAlloc( HANDLE heap
, DWORD flags
, SIZE_T size
)
65 return RtlAllocateHeap( heap
, flags
, size
);
68 BOOL WINAPI
HeapFree( HANDLE heap
, DWORD flags
, LPVOID ptr
)
70 return RtlFreeHeap( heap
, flags
, ptr
);
73 LPVOID WINAPI
HeapReAlloc( HANDLE heap
, DWORD flags
, LPVOID ptr
, SIZE_T size
)
75 return RtlReAllocateHeap( heap
, flags
, ptr
, size
);
79 /* DO NOT USE IT!! it will go away soon */
81 inline static LPSTR
HEAP_strdupWtoA( HANDLE heap
, DWORD flags
, LPCWSTR str
)
86 if (!str
) return NULL
;
87 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
88 ret
= HeapAlloc( heap
, flags
, len
);
89 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
93 /* End of WINE porting Code */
95 /* Messages...used by FormatMessage32* (KERNEL32.something)
97 * They can be specified either directly or using a message ID and
98 * loading them from the resource.
100 * The resourcedata has following format:
102 * 0: DWORD nrofentries
103 * nrofentries * subentry:
104 * 0: DWORD firstentry
106 * 8: DWORD offset from start to the stringentries
108 * (lastentry-firstentry) * stringentry:
109 * 0: WORD len (0 marks end) [ includes the 4 byte header length ]
112 * (stringentry i of a subentry refers to the ID 'firstentry+i')
114 * Yes, ANSI strings in win32 resources. Go figure.
117 /**********************************************************************
118 * load_messageA (internal)
120 static INT
load_messageA( HMODULE instance
, UINT id
, WORD lang
,
121 LPSTR buffer
, INT buflen
)
123 const MESSAGE_RESOURCE_ENTRY
*mre
;
126 TRACE("instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD
)instance
, (DWORD
)id
, buffer
, (DWORD
)buflen
);
128 //if (RtlFindMessage( instance, RT_MESSAGETABLE, lang, id, &mre ) != STATUS_SUCCESS) return 0;
131 TRACE(" - strlen=%d\n",slen
);
132 i
= min(buflen
- 1, slen
);
136 if (mre
->Flags
& MESSAGE_RESOURCE_UNICODE
)
137 WideCharToMultiByte( CP_ACP
, 0, (LPWSTR
)mre
->Text
, -1, buffer
, i
, NULL
, NULL
);
139 lstrcpynA(buffer
, (LPSTR
)mre
->Text
, i
);
148 TRACE("'%s' copied !\n", buffer
);
153 /**********************************************************************
154 * load_messageW (internal)
156 static INT
load_messageW( HMODULE instance
, UINT id
, WORD lang
,
157 LPWSTR buffer
, INT buflen
)
160 LPSTR buffer2
= NULL
;
161 if (buffer
&& buflen
)
162 buffer2
= HeapAlloc( GetProcessHeap(), 0, buflen
);
163 retval
= load_messageA(instance
,id
,lang
,buffer2
,buflen
);
167 lstrcpynAtoW( buffer
, buffer2
, buflen
);
168 retval
= strlenW( buffer
);
170 HeapFree( GetProcessHeap(), 0, buffer2
);
177 /***********************************************************************
178 * FormatMessageA (KERNEL32.@)
179 * FIXME: missing wrap,
181 DWORD WINAPI
FormatMessageA(
190 LPDWORD args
=(LPDWORD
)_args
;
191 #if defined(__i386__) || defined(__sparc__)
192 /* This implementation is completely dependent on the format of the va_list on x86 CPUs */
196 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
199 HMODULE hmodule
= (HMODULE
)lpSource
;
202 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
203 dwFlags
,lpSource
,dwMessageId
,dwLanguageId
,lpBuffer
,nSize
,args
);
204 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
205 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
206 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
208 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
)
209 FIXME("line wrapping (%lu) not supported.\n", width
);
211 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
213 from
= HeapAlloc( GetProcessHeap(), 0, strlen((LPSTR
)lpSource
)+1 );
214 strcpy( from
, (LPSTR
)lpSource
);
219 if (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)
222 hmodule
= GetModuleHandleW(NULL
);
223 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
225 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
) && (!bufsize
))
227 hmodule
= GetModuleHandleA("kernel32");
228 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
232 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
236 from
= HeapAlloc( GetProcessHeap(), 0, bufsize
+ 1 );
237 load_messageA(hmodule
,dwMessageId
,dwLanguageId
,from
,bufsize
+1);
239 target
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 100);
243 #define ADD_TO_T(c) do { \
245 if (t-target == talloced) {\
246 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
247 t = target+talloced;\
254 if (dwFlags
& FORMAT_MESSAGE_IGNORE_INSERTS
) {
262 char *fmtstr
,*x
,*lastf
;
273 case '1':case '2':case '3':case '4':case '5':
274 case '6':case '7':case '8':case '9':
277 case '0':case '1':case '2':case '3':
278 case '4':case '5':case '6':case '7':
281 insertnr
=insertnr
*10+*f
-'0';
290 if (NULL
!=(x
=strchr(f
,'!'))) {
292 fmtstr
=HeapAlloc(GetProcessHeap(),0,strlen(f
)+2);
293 sprintf(fmtstr
,"%%%s",f
);
296 fmtstr
=HeapAlloc(GetProcessHeap(),0,strlen(f
)+2);
297 sprintf(fmtstr
,"%%%s",f
);
298 f
+=strlen(f
); /*at \0*/
302 fmtstr
= HeapAlloc(GetProcessHeap(),0,3);
303 strcpy( fmtstr
, "%s" );
309 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
310 argliststart
=args
+insertnr
-1;
312 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
314 /* FIXME: precision and width components are not handled correctly */
315 if ( (strcmp(fmtstr
, "%ls") == 0) || (strcmp(fmtstr
,"%S") == 0) ) {
316 sz
= WideCharToMultiByte( CP_ACP
, 0, *(WCHAR
**)argliststart
, -1, NULL
, 0, NULL
, NULL
);
317 b
= HeapAlloc(GetProcessHeap(), 0, sz
);
318 WideCharToMultiByte( CP_ACP
, 0, *(WCHAR
**)argliststart
, -1, b
, sz
, NULL
, NULL
);
320 b
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
= 1000);
321 /* CMF - This makes a BIG assumption about va_list */
322 TRACE("A BIG assumption\n");
323 _vsnprintf(b
, sz
, fmtstr
, (va_list) argliststart
);
325 for (x
=b
; *x
; x
++) ADD_TO_T(*x
);
327 HeapFree(GetProcessHeap(),0,b
);
329 /* NULL args - copy formatstr
332 while ((lastf
<f
)&&(*lastf
)) {
336 HeapFree(GetProcessHeap(),0,fmtstr
);
383 talloced
= strlen(target
)+1;
384 if (nSize
&& talloced
<nSize
) {
385 target
= (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
387 //TRACE("-- %s\n",debugstr_a(target));
388 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
389 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,max(nSize
, talloced
));
390 memcpy(*(LPSTR
*)lpBuffer
,target
,talloced
);
392 lstrcpynA(lpBuffer
,target
,nSize
);
394 HeapFree(GetProcessHeap(),0,target
);
395 if (from
) HeapFree(GetProcessHeap(),0,from
);
396 TRACE("-- returning %d\n", (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ? strlen(*(LPSTR
*)lpBuffer
):strlen(lpBuffer
));
397 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
398 strlen(*(LPSTR
*)lpBuffer
):
402 #endif /* __i386__ */
407 /***********************************************************************
408 * FormatMessageW (KERNEL32.@)
410 DWORD WINAPI
FormatMessageW(
419 LPDWORD args
=(LPDWORD
)_args
;
420 #if defined(__i386__) || defined(__sparc__)
421 /* This implementation is completely dependent on the format of the va_list on x86 CPUs */
425 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
428 HMODULE hmodule
= (HMODULE
)lpSource
;
431 TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n",
432 dwFlags
,lpSource
,dwMessageId
,dwLanguageId
,lpBuffer
,nSize
,args
);
433 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
434 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
435 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
437 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
)
438 FIXME("line wrapping not supported.\n");
440 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
) {
441 from
= HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR
)lpSource
);
446 if (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)
449 hmodule
= GetModuleHandleW(NULL
);
450 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
452 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
) && (!bufsize
))
454 hmodule
= GetModuleHandleA("kernel32");
455 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
459 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
463 from
= HeapAlloc( GetProcessHeap(), 0, bufsize
+ 1 );
464 load_messageA(hmodule
,dwMessageId
,dwLanguageId
,from
,bufsize
+1);
466 target
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, 100 );
470 #define ADD_TO_T(c) do {\
472 if (t-target == talloced) {\
473 target = (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
474 t = target+talloced;\
481 if (dwFlags
& FORMAT_MESSAGE_IGNORE_INSERTS
) {
489 char *fmtstr
,*sprintfbuf
,*x
;
500 case '1':case '2':case '3':case '4':case '5':
501 case '6':case '7':case '8':case '9':
504 case '0':case '1':case '2':case '3':
505 case '4':case '5':case '6':case '7':
508 insertnr
=insertnr
*10+*f
-'0';
517 if (NULL
!=(x
=strchr(f
,'!'))) {
519 fmtstr
=HeapAlloc( GetProcessHeap(), 0, strlen(f
)+2);
520 sprintf(fmtstr
,"%%%s",f
);
523 fmtstr
=HeapAlloc(GetProcessHeap(),0,strlen(f
)+2);
524 sprintf(fmtstr
,"%%%s",f
);
525 f
+=strlen(f
); /*at \0*/
529 fmtstr
= HeapAlloc( GetProcessHeap(),0,3);
530 strcpy( fmtstr
, "%s" );
532 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
533 argliststart
=args
+insertnr
-1;
535 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
537 if (fmtstr
[strlen(fmtstr
)-1]=='s' && argliststart
[0]) {
540 xarr
[0]=(DWORD
)HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR
)(*(argliststart
+0)));
541 /* possible invalid pointers */
542 xarr
[1]=*(argliststart
+1);
543 xarr
[2]=*(argliststart
+2);
544 sprintfbuf
=HeapAlloc(GetProcessHeap(),0,strlenW((LPWSTR
)argliststart
[0])*2+1);
546 /* CMF - This makes a BIG assumption about va_list */
547 vsprintf(sprintfbuf
, fmtstr
, (va_list) xarr
);
548 HeapFree(GetProcessHeap(), 0, (LPVOID
) xarr
[0]);
550 sprintfbuf
=HeapAlloc(GetProcessHeap(),0,100);
552 /* CMF - This makes a BIG assumption about va_list */
553 vsprintf(sprintfbuf
, fmtstr
, (va_list) argliststart
);
559 HeapFree(GetProcessHeap(),0,sprintfbuf
);
560 HeapFree(GetProcessHeap(),0,fmtstr
);
607 talloced
= strlen(target
)+1;
608 if (nSize
&& talloced
<nSize
)
609 target
= (char*)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
610 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
611 /* nSize is the MINIMUM size */
612 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, target
, -1, NULL
, 0 );
613 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,len
*sizeof(WCHAR
));
614 MultiByteToWideChar( CP_ACP
, 0, target
, -1, *(LPWSTR
*)lpBuffer
, len
);
618 if (nSize
> 0 && !MultiByteToWideChar( CP_ACP
, 0, target
, -1, lpBuffer
, nSize
))
619 lpBuffer
[nSize
-1] = 0;
621 HeapFree(GetProcessHeap(),0,target
);
622 if (from
) HeapFree(GetProcessHeap(),0,from
);
623 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
624 strlenW(*(LPWSTR
*)lpBuffer
):
628 #endif /* __i386__ */