1 /* $Id: errormsg.c,v 1.5 2003/05/19 19:42:30 guido Exp $
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
26 #include <ddk/ntddk.h>
29 #include <kernel32/kernel32.h>
30 #include <kernel32/error.h>
37 //#include <ntdll/ntdll.h>
39 //#define DPRINTF DPRINT
41 //#define SetLastError(x)
46 #define strlenW lstrlen
47 #define strlen lstrlen
49 //#define MAKEINTRESOURCE(i) (LPTSTR) ((DWORD) ((WORD) (i)))
50 //#define MAKEINTRESOURCEA(i) (LPTSTR) ((DWORD) ((WORD) (i)))
51 //#define MAKEINTRESOURCEW(i) (LPTSTR) ((DWORD) ((WORD) (i)))
53 //#define MAKEINTRESOURCEA(i) (LPSTR)((ULONG_PTR)((WORD)(i)))
54 //#define MAKEINTRESOURCEW(i) (LPWSTR)((ULONG_PTR)((WORD)(i)))
55 //#define MAKEINTRESOURCE WINELIB_NAME_AW(MAKEINTRESOURCE)
59 int HEAP_strdupWtoA(HANDLE hHeap
, int flags
, LPWSTR lpSource
)
72 //#include "winbase.h"
73 //#include "winerror.h"
74 //#include "winuser.h"
76 //#include "wine/unicode.h"
78 //#include "wine/debug.h"
80 //WINE_DEFAULT_DEBUG_CHANNEL(resource);
82 typedef struct tagMESSAGE_RESOURCE_ENTRY
{
86 } MESSAGE_RESOURCE_ENTRY
,*PMESSAGE_RESOURCE_ENTRY
;
87 #define MESSAGE_RESOURCE_UNICODE 0x0001
89 typedef struct tagMESSAGE_RESOURCE_BLOCK
{
92 DWORD OffsetToEntries
;
93 } MESSAGE_RESOURCE_BLOCK
,*PMESSAGE_RESOURCE_BLOCK
;
95 typedef struct tagMESSAGE_RESOURCE_DATA
{
97 MESSAGE_RESOURCE_BLOCK Blocks
[ 1 ];
98 } MESSAGE_RESOURCE_DATA
,*PMESSAGE_RESOURCE_DATA
;
101 //#define RT_RCDATAA MAKEINTRESOURCEA(10)
102 //#define RT_RCDATAW MAKEINTRESOURCEW(10)
103 ////#define RT_RCDATA WINELIB_NAME_AW(RT_RCDATA)
104 //#define RT_MESSAGETABLEA MAKEINTRESOURCEA(11)
105 #define RT_MESSAGETABLEW MAKEINTRESOURCEW(11)
106 ////#define RT_MESSAGETABLE WINELIB_NAME_AW(RT_MESSAGETABLE)
108 /* Messages...used by FormatMessage32* (KERNEL32.something)
110 * They can be specified either directly or using a message ID and
111 * loading them from the resource.
113 * The resourcedata has following format:
115 * 0: DWORD nrofentries
116 * nrofentries * subentry:
117 * 0: DWORD firstentry
119 * 8: DWORD offset from start to the stringentries
121 * (lastentry-firstentry) * stringentry:
122 * 0: WORD len (0 marks end) [ includes the 4 byte header length ]
125 * (stringentry i of a subentry refers to the ID 'firstentry+i')
127 * Yes, ANSI strings in win32 resources. Go figure.
130 /**********************************************************************
131 * load_messageA (internal)
133 static INT
load_messageA( HMODULE instance
, UINT id
, WORD lang
,
134 LPSTR buffer
, INT buflen
)
138 PMESSAGE_RESOURCE_DATA mrd
;
139 PMESSAGE_RESOURCE_BLOCK mrb
;
140 PMESSAGE_RESOURCE_ENTRY mre
;
143 //TRACE("instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD)instance, (DWORD)id, buffer, (DWORD)buflen);
145 /*FIXME: I am not sure about the '1' ... But I've only seen those entries*/
146 hrsrc
= FindResourceExW(instance
,RT_MESSAGETABLEW
,(LPWSTR
)1,lang
);
147 if (!hrsrc
) return 0;
148 hmem
= LoadResource( instance
, hrsrc
);
151 mrd
= (PMESSAGE_RESOURCE_DATA
)LockResource(hmem
);
153 mrb
= &(mrd
->Blocks
[0]);
154 for (i
=mrd
->NumberOfBlocks
;i
--;) {
155 if ((id
>=mrb
->LowId
) && (id
<=mrb
->HighId
)) {
156 mre
= (PMESSAGE_RESOURCE_ENTRY
)(((char*)mrd
)+mrb
->OffsetToEntries
);
167 mre
= (PMESSAGE_RESOURCE_ENTRY
)(((char*)mre
)+mre
->Length
);
170 //TRACE(" - strlen=%d\n",slen);
171 i
= min(buflen
- 1, slen
);
175 if (mre
->Flags
& MESSAGE_RESOURCE_UNICODE
)
176 WideCharToMultiByte( CP_ACP
, 0, (LPWSTR
)mre
->Text
, -1, buffer
, i
, NULL
, NULL
);
178 lstrcpynA(buffer
, (LPSTR
)mre
->Text
, i
);
187 //TRACE("'%s' copied !\n", buffer);
188 TRACE("'%s'\n", buffer
);
194 /**********************************************************************
195 * load_messageW (internal)
197 static INT
load_messageW( HMODULE instance
, UINT id
, WORD lang
,
198 LPWSTR buffer
, INT buflen
)
201 LPSTR buffer2
= NULL
;
202 if (buffer
&& buflen
)
203 buffer2
= HeapAlloc( GetProcessHeap(), 0, buflen
);
204 retval
= load_messageA(instance
,id
,lang
,buffer2
,buflen
);
208 lstrcpynAtoW( buffer
, buffer2
, buflen
);
209 retval
= strlenW( buffer
);
211 HeapFree( GetProcessHeap(), 0, buffer2
);
218 /***********************************************************************
219 * FormatMessageA (KERNEL32.@)
220 * FIXME: missing wrap,
222 DWORD WINAPI
FormatMessageA(
231 LPDWORD args
=(LPDWORD
)_args
;
232 #if defined(__i386__) || defined(__sparc__)
233 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
237 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
240 HMODULE hmodule
= (HMODULE
)lpSource
;
243 //TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n", dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
244 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
245 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
246 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
248 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
)
249 FIXME("line wrapping (%lu) not supported.\n", width
);
251 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
253 from
= RtlAllocateHeap(RtlGetProcessHeap(), 0, strlen((LPSTR
)lpSource
)+1 );
254 strcpy( from
, (LPSTR
)lpSource
);
259 if (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)
261 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
262 if ((!bufsize
) && (!dwLanguageId
)) {
263 bufsize
=load_messageA(hmodule
,dwMessageId
,
264 MAKELANGID(LANG_NEUTRAL
,SUBLANG_NEUTRAL
),NULL
,100);
265 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
266 MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),NULL
,100);
267 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
268 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
269 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
270 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
271 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
272 MAKELANGID(LANG_ENGLISH
,SUBLANG_ENGLISH_US
),NULL
,100);
275 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
) && (!bufsize
))
277 hmodule
= GetModuleHandleA("kernel32");
278 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
279 if ((!bufsize
) && (!dwLanguageId
)) {
280 bufsize
=load_messageA(hmodule
,dwMessageId
,
281 MAKELANGID(LANG_NEUTRAL
,SUBLANG_NEUTRAL
),NULL
,100);
282 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
283 MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),NULL
,100);
284 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
285 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
286 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
287 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
288 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
289 MAKELANGID(LANG_ENGLISH
,SUBLANG_ENGLISH_US
),NULL
,100);
294 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
298 from
= RtlAllocateHeap(RtlGetProcessHeap(), 0, bufsize
+ 1 );
299 load_messageA(hmodule
,dwMessageId
,dwLanguageId
,from
,bufsize
+1);
301 target
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, 100);
305 #define ADD_TO_T(c) do { \
307 if (t-target == talloced) {\
308 target = (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
309 t = target+talloced;\
316 if (dwFlags
& FORMAT_MESSAGE_IGNORE_INSERTS
) {
324 char *fmtstr
,*x
,*lastf
;
335 case '1':case '2':case '3':case '4':case '5':
336 case '6':case '7':case '8':case '9':
339 case '0':case '1':case '2':case '3':
340 case '4':case '5':case '6':case '7':
343 insertnr
=insertnr
*10+*f
-'0';
352 if (NULL
!=(x
=strchr(f
,'!'))) {
354 fmtstr
=RtlAllocateHeap(RtlGetProcessHeap(),0,strlen(f
)+2);
355 sprintf(fmtstr
,"%%%s",f
);
358 fmtstr
=RtlAllocateHeap(RtlGetProcessHeap(),0,strlen(f
)+2);
359 sprintf(fmtstr
,"%%%s",f
);
360 f
+=strlen(f
); /*at \0*/
364 fmtstr
= RtlAllocateHeap(RtlGetProcessHeap(),0,3);
365 strcpy( fmtstr
, "%s" );
371 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
372 argliststart
=args
+insertnr
-1;
374 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
376 /* FIXME: precision and width components are not handled correctly */
377 if ( (strcmp(fmtstr
, "%ls") == 0) || (strcmp(fmtstr
,"%S") == 0) ) {
378 sz
= WideCharToMultiByte( CP_ACP
, 0, *(WCHAR
**)argliststart
, -1, NULL
, 0, NULL
, NULL
);
379 b
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sz
);
380 WideCharToMultiByte( CP_ACP
, 0, *(WCHAR
**)argliststart
, -1, b
, sz
, NULL
, NULL
);
382 b
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, sz
= 1000);
383 /* CMF - This makes a BIG assumption about va_list */
384 TRACE("A BIG assumption\n");
385 //vsnprintf(b, sz, fmtstr, (va_list) argliststart);
387 for (x
=b
; *x
; x
++) ADD_TO_T(*x
);
389 RtlFreeHeap(RtlGetProcessHeap(),0,b
);
391 /* NULL args - copy formatstr
394 while ((lastf
<f
)&&(*lastf
)) {
398 RtlFreeHeap(GetProcessHeap(),0,fmtstr
);
445 talloced
= strlen(target
)+1;
446 if (nSize
&& talloced
<nSize
) {
447 target
= (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
449 //TRACE("-- %s\n",debugstr_a(target));
450 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
451 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,max(nSize
, talloced
));
452 memcpy(*(LPSTR
*)lpBuffer
,target
,talloced
);
454 lstrcpynA(lpBuffer
,target
,nSize
);
456 RtlFreeHeap(RtlGetProcessHeap(),0,target
);
457 if (from
) RtlFreeHeap(RtlGetProcessHeap(),0,from
);
458 //TRACE("-- returning %d\n", (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? strlen(*(LPSTR*)lpBuffer):strlen(lpBuffer));
459 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
460 strlen(*(LPSTR
*)lpBuffer
):
464 #endif /* __i386__ */
469 /***********************************************************************
470 * FormatMessageW (KERNEL32.@)
472 DWORD WINAPI
FormatMessageW(
481 LPDWORD args
=(LPDWORD
)_args
;
482 #if defined(__i386__) || defined(__sparc__)
483 /* This implementation is completely dependant on the format of the va_list on x86 CPUs */
487 DWORD width
= dwFlags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
;
490 HMODULE hmodule
= (HMODULE
)lpSource
;
493 //TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n", dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
494 if ((dwFlags
& FORMAT_MESSAGE_FROM_STRING
)
495 &&((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
)
496 || (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
))) return 0;
498 if (width
&& width
!= FORMAT_MESSAGE_MAX_WIDTH_MASK
) {
499 FIXME("line wrapping not supported.\n");
502 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
) {
503 from
= HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR
)lpSource
);
508 if (dwFlags
& FORMAT_MESSAGE_FROM_HMODULE
)
510 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
511 if ((!bufsize
) && (!dwLanguageId
)) {
512 bufsize
=load_messageA(hmodule
,dwMessageId
,
513 MAKELANGID(LANG_NEUTRAL
,SUBLANG_NEUTRAL
),NULL
,100);
514 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
515 MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),NULL
,100);
516 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
517 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
518 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
519 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
520 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
521 MAKELANGID(LANG_ENGLISH
,SUBLANG_ENGLISH_US
),NULL
,100);
524 if ((dwFlags
& FORMAT_MESSAGE_FROM_SYSTEM
) && (!bufsize
))
526 hmodule
= GetModuleHandleA("kernel32");
527 bufsize
=load_messageA(hmodule
,dwMessageId
,dwLanguageId
,NULL
,100);
528 if ((!bufsize
) && (!dwLanguageId
)) {
529 bufsize
=load_messageA(hmodule
,dwMessageId
,
530 MAKELANGID(LANG_NEUTRAL
,SUBLANG_NEUTRAL
),NULL
,100);
531 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
532 MAKELANGID(LANG_NEUTRAL
,SUBLANG_DEFAULT
),NULL
,100);
533 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
534 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
535 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
536 MAKELANGID(LANG_NEUTRAL
,SUBLANG_SYS_DEFAULT
),NULL
,100);
537 if (!bufsize
) bufsize
=load_messageA(hmodule
,dwMessageId
,
538 MAKELANGID(LANG_ENGLISH
,SUBLANG_ENGLISH_US
),NULL
,100);
543 SetLastError (ERROR_RESOURCE_LANG_NOT_FOUND
);
547 from
= RtlAllocateHeap(RtlGetProcessHeap(), 0, bufsize
+ 1 );
548 load_messageA(hmodule
,dwMessageId
,dwLanguageId
,from
,bufsize
+1);
550 target
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, 100 );
554 #define ADD_TO_T(c) do {\
556 if (t-target == talloced) {\
557 target = (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\
558 t = target+talloced;\
565 if (dwFlags
& FORMAT_MESSAGE_IGNORE_INSERTS
) {
573 char *fmtstr
,*sprintfbuf
,*x
;
584 case '1':case '2':case '3':case '4':case '5':
585 case '6':case '7':case '8':case '9':
588 case '0':case '1':case '2':case '3':
589 case '4':case '5':case '6':case '7':
592 insertnr
=insertnr
*10+*f
-'0';
601 if (NULL
!=(x
=strchr(f
,'!'))) {
603 fmtstr
=RtlAllocateHeap(RtlGetProcessHeap(), 0, strlen(f
)+2);
604 sprintf(fmtstr
,"%%%s",f
);
607 fmtstr
=RtlAllocateHeap(RtlGetProcessHeap(),0,strlen(f
));
608 sprintf(fmtstr
,"%%%s",f
);
609 f
+=strlen(f
); /*at \0*/
613 fmtstr
= RtlAllocateHeap(RtlGetProcessHeap(),0,3);
614 strcpy( fmtstr
, "%s" );
616 if (dwFlags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
)
617 argliststart
=args
+insertnr
-1;
619 argliststart
=(*(DWORD
**)args
)+insertnr
-1;
621 if (fmtstr
[strlen(fmtstr
)-1]=='s' && argliststart
[0]) {
624 xarr
[0]=(DWORD
)HEAP_strdupWtoA(RtlGetProcessHeap(),0,(LPWSTR
)(*(argliststart
+0)));
625 /* possible invalid pointers */
626 xarr
[1]=*(argliststart
+1);
627 xarr
[2]=*(argliststart
+2);
628 sprintfbuf
=RtlAllocateHeap(RtlGetProcessHeap(),0,strlenW((LPWSTR
)argliststart
[0])*2+1);
630 /* CMF - This makes a BIG assumption about va_list */
631 vsprintf(sprintfbuf
, fmtstr
, (va_list) xarr
);
632 RtlFreeHeap(RtlGetProcessHeap(), 0, (LPVOID
) xarr
[0]);
634 sprintfbuf
=RtlAllocateHeap(RtlGetProcessHeap(),0,100);
636 /* CMF - This makes a BIG assumption about va_list */
637 vsprintf(sprintfbuf
, fmtstr
, (va_list) argliststart
);
643 RtlFreeHeap(RtlGetProcessHeap(),0,sprintfbuf
);
644 RtlFreeHeap(RtlGetProcessHeap(),0,fmtstr
);
691 talloced
= strlen(target
)+1;
692 if (nSize
&& talloced
<nSize
)
693 target
= (char*)RtlReAllocateHeap(RtlGetProcessHeap(),HEAP_ZERO_MEMORY
,target
,nSize
);
694 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
695 /* nSize is the MINIMUM size */
696 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, target
, -1, NULL
, 0 );
697 *((LPVOID
*)lpBuffer
) = (LPVOID
)LocalAlloc(GMEM_ZEROINIT
,len
*sizeof(WCHAR
));
698 MultiByteToWideChar( CP_ACP
, 0, target
, -1, *(LPWSTR
*)lpBuffer
, len
);
702 if (nSize
> 0 && !MultiByteToWideChar( CP_ACP
, 0, target
, -1, lpBuffer
, nSize
))
703 lpBuffer
[nSize
-1] = 0;
705 RtlFreeHeap(RtlGetProcessHeap(),0,target
);
706 if (from
) RtlFreeHeap(RtlGetProcessHeap(),0,from
);
707 return (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) ?
708 strlenW(*(LPWSTR
*)lpBuffer
):
712 #endif /* __i386__ */
735 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
754 #define MAX_MSG_STR_LEN 200
756 if (lpBuffer
!= NULL
) {
758 if (dwFlags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) {
759 pBuf
= LocalAlloc(LPTR
, max(nSize
, MAX_MSG_STR_LEN
));
763 *(LPSTR
*)lpBuffer
= pBuf
;
765 pBuf
= *(LPSTR
*)lpBuffer
;
768 if (dwFlags
& FORMAT_MESSAGE_FROM_STRING
) {
772 //FORMAT_MESSAGE_IGNORE_INSERTS
773 //FORMAT_MESSAGE_FROM_STRING
774 //FORMAT_MESSAGE_FROM_HMODULE
775 //FORMAT_MESSAGE_FROM_SYSTEM
776 //FORMAT_MESSAGE_ARGUMENT_ARRAY
781 FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
784 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
790 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);