Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
7b012817
Commit
7b012817
authored
May 13, 2020
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
kernelbase: Reimplement FormatMessageA/W using RtlFormatMessage().
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
3214ca84
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
206 additions
and
675 deletions
+206
-675
Makefile.in
dlls/kernel32/Makefile.in
+0
-1
format_msg.c
dlls/kernel32/format_msg.c
+0
-648
kernel32.spec
dlls/kernel32/kernel32.spec
+2
-2
format_msg.c
dlls/kernel32/tests/format_msg.c
+11
-22
kernelbase.spec
dlls/kernelbase/kernelbase.spec
+2
-2
locale.c
dlls/kernelbase/locale.c
+191
-0
No files found.
dlls/kernel32/Makefile.in
View file @
7b012817
...
...
@@ -16,7 +16,6 @@ C_SRCS = \
editline.c
\
environ.c
\
file.c
\
format_msg.c
\
heap.c
\
kernel_main.c
\
lcformat.c
\
...
...
dlls/kernel32/format_msg.c
deleted
100644 → 0
View file @
3214ca84
/*
* FormatMessage implementation
*
* Copyright 1996 Marcus Meissner
* Copyright 2009 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "winternl.h"
#include "winuser.h"
#include "winnls.h"
#include "wine/unicode.h"
#include "kernel_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
resource
);
struct
format_args
{
ULONG_PTR
*
args
;
__ms_va_list
*
list
;
int
last
;
};
/* Messages used by FormatMessage
*
* They can be specified either directly or using a message ID and
* loading them from the resource.
*
* The resourcedata has following format:
* start:
* 0: DWORD nrofentries
* nrofentries * subentry:
* 0: DWORD firstentry
* 4: DWORD lastentry
* 8: DWORD offset from start to the stringentries
*
* (lastentry-firstentry) * stringentry:
* 0: WORD len (0 marks end) [ includes the 4 byte header length ]
* 2: WORD flags
* 4: CHAR[len-4]
* (stringentry i of a subentry refers to the ID 'firstentry+i')
*
* Yes, ANSI strings in win32 resources. Go figure.
*/
/**********************************************************************
* load_message (internal)
*/
static
LPWSTR
load_message
(
HMODULE
module
,
UINT
id
,
WORD
lang
)
{
const
MESSAGE_RESOURCE_ENTRY
*
mre
;
WCHAR
*
buffer
;
TRACE
(
"module = %p, id = %08x
\n
"
,
module
,
id
);
if
(
!
module
)
module
=
GetModuleHandleW
(
NULL
);
if
(
!
set_ntstatus
(
RtlFindMessage
(
module
,
RT_MESSAGETABLE
,
lang
,
id
,
&
mre
)))
return
NULL
;
if
(
mre
->
Flags
&
MESSAGE_RESOURCE_UNICODE
)
{
int
len
=
(
strlenW
(
(
const
WCHAR
*
)
mre
->
Text
)
+
1
)
*
sizeof
(
WCHAR
);
if
(
!
(
buffer
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
)))
return
NULL
;
memcpy
(
buffer
,
mre
->
Text
,
len
);
}
else
{
int
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
(
const
char
*
)
mre
->
Text
,
-
1
,
NULL
,
0
);
if
(
!
(
buffer
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
)
)))
return
NULL
;
MultiByteToWideChar
(
CP_ACP
,
0
,
(
const
char
*
)
mre
->
Text
,
-
1
,
buffer
,
len
);
}
TRACE
(
"returning %s
\n
"
,
wine_dbgstr_w
(
buffer
));
return
buffer
;
}
static
LPWSTR
search_message
(
DWORD
flags
,
HMODULE
module
,
UINT
id
,
WORD
lang
)
{
LPWSTR
from
=
NULL
;
if
(
flags
&
FORMAT_MESSAGE_FROM_HMODULE
)
from
=
load_message
(
module
,
id
,
lang
);
if
(
!
from
&&
(
flags
&
FORMAT_MESSAGE_FROM_SYSTEM
))
{
/* Fold win32 hresult to its embedded error code. */
if
(
HRESULT_SEVERITY
(
id
)
==
SEVERITY_ERROR
&&
HRESULT_FACILITY
(
id
)
==
FACILITY_WIN32
)
{
id
=
HRESULT_CODE
(
id
);
}
from
=
load_message
(
kernel32_handle
,
id
,
lang
);
}
return
from
;
}
/**********************************************************************
* get_arg (internal)
*/
static
ULONG_PTR
get_arg
(
int
nr
,
DWORD
flags
,
struct
format_args
*
args
)
{
if
(
nr
==
-
1
)
nr
=
args
->
last
+
1
;
if
(
args
->
list
)
{
if
(
!
args
->
args
)
args
->
args
=
HeapAlloc
(
GetProcessHeap
(),
0
,
99
*
sizeof
(
ULONG_PTR
)
);
while
(
nr
>
args
->
last
)
args
->
args
[
args
->
last
++
]
=
va_arg
(
*
args
->
list
,
ULONG_PTR
);
}
if
(
nr
>
args
->
last
)
args
->
last
=
nr
;
return
args
->
args
[
nr
-
1
];
}
/**********************************************************************
* format_insert (internal)
*/
static
LPCWSTR
format_insert
(
BOOL
unicode_caller
,
int
insert
,
LPCWSTR
format
,
DWORD
flags
,
struct
format_args
*
args
,
LPWSTR
*
result
)
{
static
const
WCHAR
fmt_u
[]
=
{
'%'
,
'u'
,
0
};
WCHAR
*
wstring
=
NULL
,
*
p
,
fmt
[
256
];
ULONG_PTR
arg
;
int
size
;
if
(
*
format
!=
'!'
)
/* simple string */
{
arg
=
get_arg
(
insert
,
flags
,
args
);
if
(
unicode_caller
||
!
arg
)
{
static
const
WCHAR
nullW
[]
=
{
'('
,
'n'
,
'u'
,
'l'
,
'l'
,
')'
,
0
};
const
WCHAR
*
str
=
(
const
WCHAR
*
)
arg
;
if
(
!
str
)
str
=
nullW
;
*
result
=
HeapAlloc
(
GetProcessHeap
(),
0
,
(
strlenW
(
str
)
+
1
)
*
sizeof
(
WCHAR
)
);
strcpyW
(
*
result
,
str
);
}
else
{
const
char
*
str
=
(
const
char
*
)
arg
;
DWORD
length
=
MultiByteToWideChar
(
CP_ACP
,
0
,
str
,
-
1
,
NULL
,
0
);
*
result
=
HeapAlloc
(
GetProcessHeap
(),
0
,
length
*
sizeof
(
WCHAR
)
);
MultiByteToWideChar
(
CP_ACP
,
0
,
str
,
-
1
,
*
result
,
length
);
}
return
format
;
}
format
++
;
p
=
fmt
;
*
p
++
=
'%'
;
while
(
*
format
==
'0'
||
*
format
==
'+'
||
*
format
==
'-'
||
*
format
==
' '
||
*
format
==
'*'
||
*
format
==
'#'
)
{
if
(
*
format
==
'*'
)
{
p
+=
sprintfW
(
p
,
fmt_u
,
get_arg
(
insert
,
flags
,
args
));
insert
=
-
1
;
format
++
;
}
else
*
p
++
=
*
format
++
;
}
while
(
*
format
>=
'0'
&&
*
format
<=
'9'
)
*
p
++
=
*
format
++
;
if
(
*
format
==
'.'
)
{
*
p
++
=
*
format
++
;
if
(
*
format
==
'*'
)
{
p
+=
sprintfW
(
p
,
fmt_u
,
get_arg
(
insert
,
flags
,
args
));
insert
=
-
1
;
format
++
;
}
else
while
(
*
format
>=
'0'
&&
*
format
<=
'9'
)
*
p
++
=
*
format
++
;
}
/* replicate MS bug: drop an argument when using va_list with width/precision */
if
(
insert
==
-
1
&&
args
->
list
)
args
->
last
--
;
arg
=
get_arg
(
insert
,
flags
,
args
);
/* check for ascii string format */
if
((
format
[
0
]
==
'h'
&&
format
[
1
]
==
's'
)
||
(
format
[
0
]
==
'h'
&&
format
[
1
]
==
'S'
)
||
(
unicode_caller
&&
format
[
0
]
==
'S'
)
||
(
!
unicode_caller
&&
format
[
0
]
==
's'
))
{
DWORD
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
(
char
*
)
arg
,
-
1
,
NULL
,
0
);
wstring
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
)
);
MultiByteToWideChar
(
CP_ACP
,
0
,
(
char
*
)
arg
,
-
1
,
wstring
,
len
);
arg
=
(
ULONG_PTR
)
wstring
;
*
p
++
=
's'
;
}
/* check for ascii character format */
else
if
((
format
[
0
]
==
'h'
&&
format
[
1
]
==
'c'
)
||
(
format
[
0
]
==
'h'
&&
format
[
1
]
==
'C'
)
||
(
unicode_caller
&&
format
[
0
]
==
'C'
)
||
(
!
unicode_caller
&&
format
[
0
]
==
'c'
))
{
char
ch
=
arg
;
wstring
=
HeapAlloc
(
GetProcessHeap
(),
0
,
2
*
sizeof
(
WCHAR
)
);
MultiByteToWideChar
(
CP_ACP
,
0
,
&
ch
,
1
,
wstring
,
1
);
wstring
[
1
]
=
0
;
arg
=
(
ULONG_PTR
)
wstring
;
*
p
++
=
's'
;
}
/* check for wide string format */
else
if
((
format
[
0
]
==
'l'
&&
format
[
1
]
==
's'
)
||
(
format
[
0
]
==
'l'
&&
format
[
1
]
==
'S'
)
||
(
format
[
0
]
==
'w'
&&
format
[
1
]
==
's'
)
||
(
!
unicode_caller
&&
format
[
0
]
==
'S'
))
{
*
p
++
=
's'
;
}
/* check for wide character format */
else
if
((
format
[
0
]
==
'l'
&&
format
[
1
]
==
'c'
)
||
(
format
[
0
]
==
'l'
&&
format
[
1
]
==
'C'
)
||
(
format
[
0
]
==
'w'
&&
format
[
1
]
==
'c'
)
||
(
!
unicode_caller
&&
format
[
0
]
==
'C'
))
{
*
p
++
=
'c'
;
}
/* FIXME: handle I64 etc. */
else
while
(
*
format
&&
*
format
!=
'!'
)
*
p
++
=
*
format
++
;
*
p
=
0
;
size
=
256
;
for
(;;)
{
WCHAR
*
ret
=
HeapAlloc
(
GetProcessHeap
(),
0
,
size
*
sizeof
(
WCHAR
)
);
int
needed
=
snprintfW
(
ret
,
size
,
fmt
,
arg
);
if
(
needed
==
-
1
||
needed
>=
size
)
{
HeapFree
(
GetProcessHeap
(),
0
,
ret
);
size
=
max
(
needed
+
1
,
size
*
2
);
}
else
{
*
result
=
ret
;
break
;
}
}
while
(
*
format
&&
*
format
!=
'!'
)
format
++
;
if
(
*
format
==
'!'
)
format
++
;
HeapFree
(
GetProcessHeap
(),
0
,
wstring
);
return
format
;
}
struct
_format_message_data
{
LPWSTR
formatted
;
DWORD
size
;
LPWSTR
t
;
LPWSTR
space
;
BOOL
inspace
;
DWORD
width
,
w
;
};
static
void
format_add_char
(
struct
_format_message_data
*
fmd
,
WCHAR
c
)
{
*
fmd
->
t
++
=
c
;
if
(
fmd
->
width
&&
fmd
->
width
!=
FORMAT_MESSAGE_MAX_WIDTH_MASK
)
{
switch
(
c
)
{
case
'\r'
:
case
'\n'
:
fmd
->
space
=
NULL
;
fmd
->
inspace
=
FALSE
;
fmd
->
w
=
0
;
break
;
case
' '
:
if
(
!
fmd
->
inspace
)
fmd
->
space
=
fmd
->
t
-
1
;
fmd
->
inspace
=
TRUE
;
fmd
->
w
++
;
break
;
default:
fmd
->
inspace
=
FALSE
;
fmd
->
w
++
;
}
if
(
fmd
->
w
==
fmd
->
width
)
{
LPWSTR
notspace
;
if
(
fmd
->
space
)
{
notspace
=
fmd
->
space
;
while
(
notspace
!=
fmd
->
t
&&
*
notspace
==
' '
)
notspace
++
;
}
else
notspace
=
fmd
->
space
=
fmd
->
t
;
fmd
->
w
=
fmd
->
t
-
notspace
;
memmove
(
fmd
->
space
+
2
,
notspace
,
fmd
->
w
*
sizeof
(
*
fmd
->
t
));
*
fmd
->
space
++
=
'\r'
;
*
fmd
->
space
++
=
'\n'
;
fmd
->
t
=
fmd
->
space
+
fmd
->
w
;
fmd
->
space
=
NULL
;
fmd
->
inspace
=
FALSE
;
}
}
if
((
DWORD
)(
fmd
->
t
-
fmd
->
formatted
)
==
fmd
->
size
)
{
DWORD_PTR
ispace
=
fmd
->
space
-
fmd
->
formatted
;
/* Allocate two extra characters so we can insert a '\r\n' in
* the middle of a word.
*/
fmd
->
formatted
=
HeapReAlloc
(
GetProcessHeap
(),
0
,
fmd
->
formatted
,
(
fmd
->
size
*
2
+
2
)
*
sizeof
(
WCHAR
));
fmd
->
t
=
fmd
->
formatted
+
fmd
->
size
;
if
(
fmd
->
space
)
fmd
->
space
=
fmd
->
formatted
+
ispace
;
fmd
->
size
*=
2
;
}
}
/**********************************************************************
* format_message (internal)
*/
static
LPWSTR
format_message
(
BOOL
unicode_caller
,
DWORD
dwFlags
,
LPCWSTR
fmtstr
,
struct
format_args
*
format_args
)
{
struct
_format_message_data
fmd
;
LPCWSTR
f
;
BOOL
eos
=
FALSE
;
fmd
.
size
=
100
;
fmd
.
formatted
=
fmd
.
t
=
HeapAlloc
(
GetProcessHeap
(),
0
,
(
fmd
.
size
+
2
)
*
sizeof
(
WCHAR
)
);
fmd
.
width
=
dwFlags
&
FORMAT_MESSAGE_MAX_WIDTH_MASK
;
fmd
.
w
=
0
;
fmd
.
inspace
=
FALSE
;
fmd
.
space
=
NULL
;
f
=
fmtstr
;
while
(
*
f
&&
!
eos
)
{
if
(
*
f
==
'%'
)
{
int
insertnr
;
WCHAR
*
str
,
*
x
;
f
++
;
switch
(
*
f
)
{
case
'1'
:
case
'2'
:
case
'3'
:
case
'4'
:
case
'5'
:
case
'6'
:
case
'7'
:
case
'8'
:
case
'9'
:
if
(
dwFlags
&
FORMAT_MESSAGE_IGNORE_INSERTS
)
goto
ignore_inserts
;
else
if
(((
dwFlags
&
FORMAT_MESSAGE_ARGUMENT_ARRAY
)
&&
!
format_args
->
args
)
||
(
!
(
dwFlags
&
FORMAT_MESSAGE_ARGUMENT_ARRAY
)
&&
!
format_args
->
list
))
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
HeapFree
(
GetProcessHeap
(),
0
,
fmd
.
formatted
);
return
NULL
;
}
insertnr
=
*
f
-
'0'
;
switch
(
f
[
1
])
{
case
'0'
:
case
'1'
:
case
'2'
:
case
'3'
:
case
'4'
:
case
'5'
:
case
'6'
:
case
'7'
:
case
'8'
:
case
'9'
:
f
++
;
insertnr
=
insertnr
*
10
+
*
f
-
'0'
;
f
++
;
break
;
default:
f
++
;
break
;
}
f
=
format_insert
(
unicode_caller
,
insertnr
,
f
,
dwFlags
,
format_args
,
&
str
);
for
(
x
=
str
;
*
x
;
x
++
)
format_add_char
(
&
fmd
,
*
x
);
HeapFree
(
GetProcessHeap
(),
0
,
str
);
break
;
case
'n'
:
format_add_char
(
&
fmd
,
'\r'
);
format_add_char
(
&
fmd
,
'\n'
);
f
++
;
break
;
case
'r'
:
format_add_char
(
&
fmd
,
'\r'
);
f
++
;
break
;
case
't'
:
format_add_char
(
&
fmd
,
'\t'
);
f
++
;
break
;
case
'0'
:
eos
=
TRUE
;
f
++
;
break
;
case
'\0'
:
SetLastError
(
ERROR_INVALID_PARAMETER
);
HeapFree
(
GetProcessHeap
(),
0
,
fmd
.
formatted
);
return
NULL
;
ignore_inserts:
default:
if
(
dwFlags
&
FORMAT_MESSAGE_IGNORE_INSERTS
)
format_add_char
(
&
fmd
,
'%'
);
format_add_char
(
&
fmd
,
*
f
++
);
break
;
}
}
else
{
WCHAR
ch
=
*
f
;
f
++
;
if
(
ch
==
'\r'
)
{
if
(
*
f
==
'\n'
)
f
++
;
if
(
fmd
.
width
)
format_add_char
(
&
fmd
,
' '
);
else
{
format_add_char
(
&
fmd
,
'\r'
);
format_add_char
(
&
fmd
,
'\n'
);
}
}
else
{
if
(
ch
==
'\n'
)
{
if
(
fmd
.
width
)
format_add_char
(
&
fmd
,
' '
);
else
{
format_add_char
(
&
fmd
,
'\r'
);
format_add_char
(
&
fmd
,
'\n'
);
}
}
else
format_add_char
(
&
fmd
,
ch
);
}
}
}
*
fmd
.
t
=
'\0'
;
return
fmd
.
formatted
;
}
/***********************************************************************
* FormatMessageA (KERNEL32.@)
*/
DWORD
WINAPI
FormatMessageA
(
DWORD
dwFlags
,
LPCVOID
lpSource
,
DWORD
dwMessageId
,
DWORD
dwLanguageId
,
LPSTR
lpBuffer
,
DWORD
nSize
,
__ms_va_list
*
args
)
{
struct
format_args
format_args
;
DWORD
ret
=
0
;
LPWSTR
target
;
DWORD
destlength
;
LPWSTR
from
;
TRACE
(
"(0x%x,%p,%d,0x%x,%p,%d,%p)
\n
"
,
dwFlags
,
lpSource
,
dwMessageId
,
dwLanguageId
,
lpBuffer
,
nSize
,
args
);
if
(
dwFlags
&
FORMAT_MESSAGE_ALLOCATE_BUFFER
)
{
if
(
!
lpBuffer
)
{
SetLastError
(
ERROR_NOT_ENOUGH_MEMORY
);
return
0
;
}
else
*
(
LPSTR
*
)
lpBuffer
=
NULL
;
}
if
(
dwFlags
&
FORMAT_MESSAGE_ARGUMENT_ARRAY
)
{
format_args
.
args
=
(
ULONG_PTR
*
)
args
;
format_args
.
list
=
NULL
;
format_args
.
last
=
0
;
}
else
{
format_args
.
args
=
NULL
;
format_args
.
list
=
args
;
format_args
.
last
=
0
;
}
from
=
NULL
;
if
(
dwFlags
&
FORMAT_MESSAGE_FROM_STRING
)
{
DWORD
length
=
MultiByteToWideChar
(
CP_ACP
,
0
,
lpSource
,
-
1
,
NULL
,
0
);
from
=
HeapAlloc
(
GetProcessHeap
(),
0
,
length
*
sizeof
(
WCHAR
)
);
MultiByteToWideChar
(
CP_ACP
,
0
,
lpSource
,
-
1
,
from
,
length
);
}
else
if
(
dwFlags
&
(
FORMAT_MESSAGE_FROM_HMODULE
|
FORMAT_MESSAGE_FROM_SYSTEM
))
{
from
=
search_message
(
dwFlags
,
(
HMODULE
)
lpSource
,
dwMessageId
,
dwLanguageId
);
if
(
!
from
)
return
0
;
}
else
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
return
0
;
}
target
=
format_message
(
FALSE
,
dwFlags
,
from
,
&
format_args
);
if
(
!
target
)
goto
failure
;
TRACE
(
"-- %s
\n
"
,
debugstr_w
(
target
));
/* Only try writing to an output buffer if there are processed characters
* in the temporary output buffer. */
if
(
*
target
)
{
destlength
=
WideCharToMultiByte
(
CP_ACP
,
0
,
target
,
-
1
,
NULL
,
0
,
NULL
,
NULL
);
if
(
dwFlags
&
FORMAT_MESSAGE_ALLOCATE_BUFFER
)
{
LPSTR
buf
=
LocalAlloc
(
LMEM_ZEROINIT
,
max
(
nSize
,
destlength
));
WideCharToMultiByte
(
CP_ACP
,
0
,
target
,
-
1
,
buf
,
destlength
,
NULL
,
NULL
);
*
((
LPSTR
*
)
lpBuffer
)
=
buf
;
}
else
{
if
(
nSize
<
destlength
)
{
SetLastError
(
ERROR_INSUFFICIENT_BUFFER
);
goto
failure
;
}
WideCharToMultiByte
(
CP_ACP
,
0
,
target
,
-
1
,
lpBuffer
,
destlength
,
NULL
,
NULL
);
}
ret
=
destlength
-
1
;
/* null terminator */
}
failure:
HeapFree
(
GetProcessHeap
(),
0
,
target
);
HeapFree
(
GetProcessHeap
(),
0
,
from
);
if
(
!
(
dwFlags
&
FORMAT_MESSAGE_ARGUMENT_ARRAY
))
HeapFree
(
GetProcessHeap
(),
0
,
format_args
.
args
);
TRACE
(
"-- returning %u
\n
"
,
ret
);
return
ret
;
}
/***********************************************************************
* FormatMessageW (KERNEL32.@)
*/
DWORD
WINAPI
FormatMessageW
(
DWORD
dwFlags
,
LPCVOID
lpSource
,
DWORD
dwMessageId
,
DWORD
dwLanguageId
,
LPWSTR
lpBuffer
,
DWORD
nSize
,
__ms_va_list
*
args
)
{
struct
format_args
format_args
;
DWORD
ret
=
0
;
LPWSTR
target
;
DWORD
talloced
;
LPWSTR
from
;
TRACE
(
"(0x%x,%p,%d,0x%x,%p,%d,%p)
\n
"
,
dwFlags
,
lpSource
,
dwMessageId
,
dwLanguageId
,
lpBuffer
,
nSize
,
args
);
if
(
!
lpBuffer
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
return
0
;
}
if
(
dwFlags
&
FORMAT_MESSAGE_ALLOCATE_BUFFER
)
*
(
LPWSTR
*
)
lpBuffer
=
NULL
;
if
(
dwFlags
&
FORMAT_MESSAGE_ARGUMENT_ARRAY
)
{
format_args
.
args
=
(
ULONG_PTR
*
)
args
;
format_args
.
list
=
NULL
;
format_args
.
last
=
0
;
}
else
{
format_args
.
args
=
NULL
;
format_args
.
list
=
args
;
format_args
.
last
=
0
;
}
from
=
NULL
;
if
(
dwFlags
&
FORMAT_MESSAGE_FROM_STRING
)
{
from
=
HeapAlloc
(
GetProcessHeap
(),
0
,
(
strlenW
(
lpSource
)
+
1
)
*
sizeof
(
WCHAR
)
);
strcpyW
(
from
,
lpSource
);
}
else
if
(
dwFlags
&
(
FORMAT_MESSAGE_FROM_HMODULE
|
FORMAT_MESSAGE_FROM_SYSTEM
))
{
from
=
search_message
(
dwFlags
,
(
HMODULE
)
lpSource
,
dwMessageId
,
dwLanguageId
);
if
(
!
from
)
return
0
;
}
else
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
return
0
;
}
target
=
format_message
(
TRUE
,
dwFlags
,
from
,
&
format_args
);
if
(
!
target
)
goto
failure
;
talloced
=
strlenW
(
target
)
+
1
;
TRACE
(
"-- %s
\n
"
,
debugstr_w
(
target
));
/* Only allocate a buffer if there are processed characters in the
* temporary output buffer. If a caller supplies the buffer, then
* a null terminator will be written to it. */
if
(
dwFlags
&
FORMAT_MESSAGE_ALLOCATE_BUFFER
)
{
if
(
*
target
)
{
/* nSize is the MINIMUM size */
*
((
LPVOID
*
)
lpBuffer
)
=
LocalAlloc
(
LMEM_ZEROINIT
,
max
(
nSize
,
talloced
)
*
sizeof
(
WCHAR
));
strcpyW
(
*
(
LPWSTR
*
)
lpBuffer
,
target
);
}
}
else
{
if
(
nSize
<
talloced
)
{
SetLastError
(
ERROR_INSUFFICIENT_BUFFER
);
goto
failure
;
}
strcpyW
(
lpBuffer
,
target
);
}
ret
=
talloced
-
1
;
/* null terminator */
failure:
HeapFree
(
GetProcessHeap
(),
0
,
target
);
HeapFree
(
GetProcessHeap
(),
0
,
from
);
if
(
!
(
dwFlags
&
FORMAT_MESSAGE_ARGUMENT_ARRAY
))
HeapFree
(
GetProcessHeap
(),
0
,
format_args
.
args
);
TRACE
(
"-- returning %u
\n
"
,
ret
);
return
ret
;
}
dlls/kernel32/kernel32.spec
View file @
7b012817
...
...
@@ -522,8 +522,8 @@
@ stdcall -import FlushViewOfFile(ptr long)
@ stdcall FoldStringA(long str long ptr long)
@ stdcall -import FoldStringW(long wstr long ptr long)
@ stdcall FormatMessageA(long ptr long long ptr long ptr)
@ stdcall FormatMessageW(long ptr long long ptr long ptr)
@ stdcall
-import
FormatMessageA(long ptr long long ptr long ptr)
@ stdcall
-import
FormatMessageW(long ptr long long ptr long ptr)
@ stdcall FreeConsole()
@ stdcall -import FreeEnvironmentStringsA(ptr)
@ stdcall -import FreeEnvironmentStringsW(ptr)
...
...
dlls/kernel32/tests/format_msg.c
View file @
7b012817
...
...
@@ -77,7 +77,7 @@ static void test_message_from_string_wide(void)
error
=
GetLastError
();
ok
(
!
lstrcmpW
(
L""
,
out
),
"failed out=%s
\n
"
,
wine_dbgstr_w
(
out
));
ok
(
r
==
0
,
"succeeded: r=%d
\n
"
,
r
);
ok
(
(
error
==
0xdeadbeef
)
||
(
error
==
ERROR_NO_WORK_DONE
),
"last error %u
\n
"
,
error
);
ok
(
error
==
ERROR_NO_WORK_DONE
||
broken
(
error
==
0xdeadbeef
),
"last error %u
\n
"
,
error
);
/* format placeholder with no specifier */
SetLastError
(
0xdeadbeef
);
...
...
@@ -94,8 +94,7 @@ static void test_message_from_string_wide(void)
lstrcpyW
(
out
,
L"xxxxxx"
);
r
=
FormatMessageW
(
FORMAT_MESSAGE_FROM_STRING
,
L"test%"
,
0
,
0
,
out
,
ARRAY_SIZE
(
out
),
NULL
);
error
=
GetLastError
();
ok
(
!
lstrcmpW
(
out
,
L"xxxxxx"
)
||
broken
(
!
lstrcmpW
(
out
,
L"testxx"
)),
/* W2K3+ */
ok
(
!
lstrcmpW
(
out
,
L"testxx"
)
||
broken
(
!
lstrcmpW
(
out
,
L"xxxxxx"
)),
/* winxp */
"Expected the buffer to be unchanged
\n
"
);
ok
(
r
==
0
,
"succeeded: r=%d
\n
"
,
r
);
ok
(
error
==
ERROR_INVALID_PARAMETER
,
"last error %u
\n
"
,
error
);
...
...
@@ -359,7 +358,7 @@ static void test_message_from_string(void)
r
=
FormatMessageA
(
FORMAT_MESSAGE_FROM_STRING
,
""
,
0
,
0
,
out
,
ARRAY_SIZE
(
out
),
NULL
);
ok
(
!
memcmp
(
out
,
init_buf
,
sizeof
(
init_buf
)),
"Expected the buffer to be untouched
\n
"
);
ok
(
r
==
0
,
"succeeded: r=%d
\n
"
,
r
);
ok
(
(
GetLastError
()
==
0xdeadbeef
)
||
(
GetLastError
()
==
ERROR_NO_WORK_DONE
),
ok
(
GetLastError
()
==
ERROR_NO_WORK_DONE
||
broken
(
GetLastError
()
==
0xdeadbeef
),
"last error %u
\n
"
,
GetLastError
());
/* format placeholder with no specifier */
...
...
@@ -661,8 +660,8 @@ static void test_message_ignore_inserts(void)
ARRAY_SIZE
(
out
),
NULL
);
ok
(
ret
==
0
,
"Expected FormatMessageA to return 0, got %d
\n
"
,
ret
);
ok
(
!
memcmp
(
out
,
init_buf
,
sizeof
(
init_buf
)),
"Expected the output buffer to be untouched
\n
"
);
ok
(
(
GetLastError
()
==
0xdeadbeef
)
||
(
GetLastError
()
==
ERROR_NO_WORK_DONE
),
"Expected GetLastError() to return
0xdeadbeef or
ERROR_NO_WORK_DONE, got %u
\n
"
,
GetLastError
());
ok
(
GetLastError
()
==
ERROR_NO_WORK_DONE
||
broken
(
GetLastError
()
==
0xdeadbeef
),
"Expected GetLastError() to return ERROR_NO_WORK_DONE, got %u
\n
"
,
GetLastError
());
/* Insert sequences are ignored. */
ret
=
FormatMessageA
(
FORMAT_MESSAGE_FROM_STRING
|
FORMAT_MESSAGE_IGNORE_INSERTS
,
"test%1%2!*.*s!%99"
,
0
,
0
,
out
,
...
...
@@ -751,8 +750,8 @@ static void test_message_ignore_inserts_wide(void)
ARRAY_SIZE
(
out
),
NULL
);
ok
(
ret
==
0
,
"Expected FormatMessageW to return 0, got %d
\n
"
,
ret
);
ok
(
!
lstrcmpW
(
L""
,
out
),
"Expected the output buffer to be the empty string, got %s
\n
"
,
wine_dbgstr_w
(
out
));
ok
(
(
GetLastError
()
==
0xdeadbeef
)
||
(
GetLastError
()
==
ERROR_NO_WORK_DONE
),
"Expected GetLastError() to return
0xdeadbeef or
ERROR_NO_WORK_DONE, got %u
\n
"
,
GetLastError
());
ok
(
GetLastError
()
==
ERROR_NO_WORK_DONE
||
broken
(
GetLastError
()
==
0xdeadbeef
),
"Expected GetLastError() to return ERROR_NO_WORK_DONE, got %u
\n
"
,
GetLastError
());
/* Insert sequences are ignored. */
ret
=
FormatMessageW
(
FORMAT_MESSAGE_FROM_STRING
|
FORMAT_MESSAGE_IGNORE_INSERTS
,
L"test%1%2!*.*s!%99"
,
0
,
0
,
out
,
...
...
@@ -1066,7 +1065,6 @@ static void test_message_insufficient_buffer_wide(void)
ok
(
GetLastError
()
==
ERROR_INSUFFICIENT_BUFFER
,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u
\n
"
,
GetLastError
());
todo_wine
ok
(
!
memcmp
(
out
,
L"
\0
xxxxx"
,
6
*
sizeof
(
WCHAR
))
||
broken
(
!
lstrcmpW
(
out
,
L"xxxxxx"
)),
/* winxp */
"Expected the buffer to be truncated
\n
"
);
...
...
@@ -1078,7 +1076,6 @@ static void test_message_insufficient_buffer_wide(void)
ok
(
GetLastError
()
==
ERROR_INSUFFICIENT_BUFFER
,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u
\n
"
,
GetLastError
());
todo_wine
ok
(
!
memcmp
(
out
,
L"tes
\0
xx"
,
6
*
sizeof
(
WCHAR
))
||
broken
(
!
lstrcmpW
(
out
,
L"xxxxxx"
)),
/* winxp */
"Expected the buffer to be truncated
\n
"
);
...
...
@@ -1185,8 +1182,8 @@ static void test_message_allocate_buffer(void)
""
,
0
,
0
,
(
char
*
)
&
buf
,
0
,
NULL
);
ok
(
ret
==
0
,
"Expected FormatMessageA to return 0, got %u
\n
"
,
ret
);
ok
(
buf
==
NULL
,
"Expected output buffer pointer to be NULL
\n
"
);
ok
(
(
GetLastError
()
==
0xdeadbeef
)
||
(
GetLastError
()
==
ERROR_NO_WORK_DONE
),
"Expected GetLastError() to return
0xdeadbeef or
ERROR_NO_WORK_DONE, got %u
\n
"
,
GetLastError
());
ok
(
GetLastError
()
==
ERROR_NO_WORK_DONE
||
broken
(
GetLastError
()
==
0xdeadbeef
),
"Expected GetLastError() to return ERROR_NO_WORK_DONE, got %u
\n
"
,
GetLastError
());
buf
=
(
char
*
)
0xdeadbeef
;
ret
=
FormatMessageA
(
FORMAT_MESSAGE_FROM_STRING
|
FORMAT_MESSAGE_ALLOCATE_BUFFER
,
...
...
@@ -1279,8 +1276,8 @@ static void test_message_allocate_buffer_wide(void)
L""
,
0
,
0
,
(
WCHAR
*
)
&
buf
,
0
,
NULL
);
ok
(
ret
==
0
,
"Expected FormatMessageW to return 0, got %u
\n
"
,
ret
);
ok
(
buf
==
NULL
,
"Expected output buffer pointer to be NULL
\n
"
);
ok
(
(
GetLastError
()
==
0xdeadbeef
)
||
(
GetLastError
()
==
ERROR_NO_WORK_DONE
),
"Expected GetLastError() to return
0xdeadbeef or
ERROR_NO_WORK_DONE, got %u
\n
"
,
GetLastError
());
ok
(
GetLastError
()
==
ERROR_NO_WORK_DONE
||
broken
(
GetLastError
()
==
0xdeadbeef
),
"Expected GetLastError() to return ERROR_NO_WORK_DONE, got %u
\n
"
,
GetLastError
());
buf
=
(
WCHAR
*
)
0xdeadbeef
;
ret
=
FormatMessageW
(
FORMAT_MESSAGE_FROM_STRING
|
FORMAT_MESSAGE_ALLOCATE_BUFFER
,
...
...
@@ -1637,18 +1634,14 @@ static void test_message_from_64bit_number(void)
r
=
doitW
(
FORMAT_MESSAGE_FROM_STRING
,
L"%1!I64u!"
,
0
,
0
,
outW
,
ARRAY_SIZE
(
outW
),
unsigned_tests
[
i
].
number
);
MultiByteToWideChar
(
CP_ACP
,
0
,
unsigned_tests
[
i
].
expected
,
-
1
,
expW
,
ARRAY_SIZE
(
expW
));
todo_wine
{
ok
(
!
lstrcmpW
(
outW
,
expW
),
"[%d] failed, expected %s, got %s
\n
"
,
i
,
unsigned_tests
[
i
].
expected
,
wine_dbgstr_w
(
outW
));
ok
(
r
==
unsigned_tests
[
i
].
len
,
"[%d] failed: r=%d
\n
"
,
i
,
r
);
}
r
=
doit
(
FORMAT_MESSAGE_FROM_STRING
,
"%1!I64u!"
,
0
,
0
,
outA
,
sizeof
(
outA
),
unsigned_tests
[
i
].
number
);
todo_wine
{
ok
(
!
strcmp
(
outA
,
unsigned_tests
[
i
].
expected
),
"[%d] failed, expected %s, got %s
\n
"
,
i
,
unsigned_tests
[
i
].
expected
,
outA
);
ok
(
r
==
unsigned_tests
[
i
].
len
,
"[%d] failed: r=%d
\n
"
,
i
,
r
);
}
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
signed_tests
);
i
++
)
...
...
@@ -1656,18 +1649,14 @@ todo_wine {
r
=
doitW
(
FORMAT_MESSAGE_FROM_STRING
,
L"%1!I64d!"
,
0
,
0
,
outW
,
ARRAY_SIZE
(
outW
),
signed_tests
[
i
].
number
);
MultiByteToWideChar
(
CP_ACP
,
0
,
signed_tests
[
i
].
expected
,
-
1
,
expW
,
ARRAY_SIZE
(
expW
));
todo_wine
{
ok
(
!
lstrcmpW
(
outW
,
expW
),
"[%d] failed, expected %s, got %s
\n
"
,
i
,
signed_tests
[
i
].
expected
,
wine_dbgstr_w
(
outW
));
ok
(
r
==
signed_tests
[
i
].
len
,
"[%d] failed: r=%d
\n
"
,
i
,
r
);
}
r
=
doit
(
FORMAT_MESSAGE_FROM_STRING
,
"%1!I64d!"
,
0
,
0
,
outA
,
sizeof
(
outA
),
signed_tests
[
i
].
number
);
todo_wine
{
ok
(
!
strcmp
(
outA
,
signed_tests
[
i
].
expected
),
"[%d] failed, expected %s, got %s
\n
"
,
i
,
signed_tests
[
i
].
expected
,
outA
);
ok
(
r
==
signed_tests
[
i
].
len
,
"[%d] failed: r=%d
\n
"
,
i
,
r
);
}
}
}
...
...
dlls/kernelbase/kernelbase.spec
View file @
7b012817
...
...
@@ -387,8 +387,8 @@
@ stdcall FoldStringW(long wstr long ptr long)
# @ stub ForceSyncFgPolicyInternal
# @ stub FormatApplicationUserModelId
@ stdcall FormatMessageA(long ptr long long ptr long ptr)
kernel32.FormatMessageA
@ stdcall FormatMessageW(long ptr long long ptr long ptr)
kernel32.FormatMessageW
@ stdcall FormatMessageA(long ptr long long ptr long ptr)
@ stdcall FormatMessageW(long ptr long long ptr long ptr)
@ stdcall FreeConsole()
@ stdcall FreeEnvironmentStringsA(ptr) FreeEnvironmentStringsW
@ stdcall FreeEnvironmentStringsW(ptr)
...
...
dlls/kernelbase/locale.c
View file @
7b012817
...
...
@@ -3639,6 +3639,197 @@ INT WINAPI DECLSPEC_HOTPATCH FoldStringW( DWORD flags, LPCWSTR src, INT srclen,
}
static
const
WCHAR
*
get_message
(
DWORD
flags
,
const
void
*
src
,
UINT
id
,
UINT
lang
,
BOOL
ansi
,
WCHAR
**
buffer
)
{
DWORD
len
;
if
(
!
(
flags
&
FORMAT_MESSAGE_FROM_STRING
))
{
const
MESSAGE_RESOURCE_ENTRY
*
entry
;
NTSTATUS
status
=
STATUS_INVALID_PARAMETER
;
if
(
flags
&
FORMAT_MESSAGE_FROM_HMODULE
)
{
HMODULE
module
=
(
HMODULE
)
src
;
if
(
!
module
)
module
=
GetModuleHandleW
(
0
);
status
=
RtlFindMessage
(
module
,
RT_MESSAGETABLE
,
lang
,
id
,
&
entry
);
}
if
(
status
&&
(
flags
&
FORMAT_MESSAGE_FROM_SYSTEM
))
{
/* Fold win32 hresult to its embedded error code. */
if
(
HRESULT_SEVERITY
(
id
)
==
SEVERITY_ERROR
&&
HRESULT_FACILITY
(
id
)
==
FACILITY_WIN32
)
id
=
HRESULT_CODE
(
id
);
status
=
RtlFindMessage
(
kernel32_handle
,
RT_MESSAGETABLE
,
lang
,
id
,
&
entry
);
}
if
(
!
set_ntstatus
(
status
))
return
NULL
;
src
=
entry
->
Text
;
ansi
=
!
(
entry
->
Flags
&
MESSAGE_RESOURCE_UNICODE
);
}
if
(
!
ansi
)
return
src
;
len
=
MultiByteToWideChar
(
CP_ACP
,
0
,
src
,
-
1
,
NULL
,
0
);
if
(
!
(
*
buffer
=
HeapAlloc
(
GetProcessHeap
(),
0
,
len
*
sizeof
(
WCHAR
)
)))
return
NULL
;
MultiByteToWideChar
(
CP_ACP
,
0
,
src
,
-
1
,
*
buffer
,
len
);
return
*
buffer
;
}
/***********************************************************************
* FormatMessageA (kernelbase.@)
*/
DWORD
WINAPI
DECLSPEC_HOTPATCH
FormatMessageA
(
DWORD
flags
,
const
void
*
source
,
DWORD
msgid
,
DWORD
langid
,
char
*
buffer
,
DWORD
size
,
__ms_va_list
*
args
)
{
DWORD
ret
=
0
;
ULONG
len
,
retsize
=
0
;
ULONG
width
=
(
flags
&
FORMAT_MESSAGE_MAX_WIDTH_MASK
);
const
WCHAR
*
src
;
WCHAR
*
result
,
*
message
=
NULL
;
NTSTATUS
status
;
TRACE
(
"(0x%x,%p,%d,0x%x,%p,%d,%p)
\n
"
,
flags
,
source
,
msgid
,
langid
,
buffer
,
size
,
args
);
if
(
flags
&
FORMAT_MESSAGE_ALLOCATE_BUFFER
)
{
if
(
!
buffer
)
{
SetLastError
(
ERROR_NOT_ENOUGH_MEMORY
);
return
0
;
}
*
(
char
**
)
buffer
=
NULL
;
}
if
(
size
>=
32768
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
return
0
;
}
if
(
width
==
0xff
)
width
=
~
0u
;
if
(
!
(
src
=
get_message
(
flags
,
source
,
msgid
,
langid
,
TRUE
,
&
message
)))
return
0
;
if
(
!
(
result
=
HeapAlloc
(
GetProcessHeap
(),
0
,
65536
)))
status
=
STATUS_NO_MEMORY
;
else
status
=
RtlFormatMessage
(
src
,
width
,
!!
(
flags
&
FORMAT_MESSAGE_IGNORE_INSERTS
),
TRUE
,
!!
(
flags
&
FORMAT_MESSAGE_ARGUMENT_ARRAY
),
args
,
result
,
65536
,
&
retsize
);
HeapFree
(
GetProcessHeap
(),
0
,
message
);
if
(
status
==
STATUS_BUFFER_OVERFLOW
)
{
SetLastError
(
ERROR_INSUFFICIENT_BUFFER
);
goto
done
;
}
if
(
!
set_ntstatus
(
status
))
goto
done
;
len
=
WideCharToMultiByte
(
CP_ACP
,
0
,
result
,
retsize
/
sizeof
(
WCHAR
),
NULL
,
0
,
NULL
,
NULL
);
if
(
len
<=
1
)
{
SetLastError
(
ERROR_NO_WORK_DONE
);
goto
done
;
}
if
(
flags
&
FORMAT_MESSAGE_ALLOCATE_BUFFER
)
{
char
*
buf
=
LocalAlloc
(
LMEM_ZEROINIT
,
max
(
size
,
len
));
if
(
!
buf
)
{
SetLastError
(
ERROR_NOT_ENOUGH_MEMORY
);
goto
done
;
}
*
(
char
**
)
buffer
=
buf
;
WideCharToMultiByte
(
CP_ACP
,
0
,
result
,
retsize
/
sizeof
(
WCHAR
),
buf
,
max
(
size
,
len
),
NULL
,
NULL
);
}
else
if
(
len
>
size
)
{
SetLastError
(
ERROR_INSUFFICIENT_BUFFER
);
goto
done
;
}
else
WideCharToMultiByte
(
CP_ACP
,
0
,
result
,
retsize
/
sizeof
(
WCHAR
),
buffer
,
size
,
NULL
,
NULL
);
ret
=
len
-
1
;
done:
HeapFree
(
GetProcessHeap
(),
0
,
result
);
return
ret
;
}
/***********************************************************************
* FormatMessageW (kernelbase.@)
*/
DWORD
WINAPI
DECLSPEC_HOTPATCH
FormatMessageW
(
DWORD
flags
,
const
void
*
source
,
DWORD
msgid
,
DWORD
langid
,
WCHAR
*
buffer
,
DWORD
size
,
__ms_va_list
*
args
)
{
ULONG
retsize
=
0
;
ULONG
width
=
(
flags
&
FORMAT_MESSAGE_MAX_WIDTH_MASK
);
const
WCHAR
*
src
;
WCHAR
*
message
=
NULL
;
NTSTATUS
status
;
TRACE
(
"(0x%x,%p,%d,0x%x,%p,%d,%p)
\n
"
,
flags
,
source
,
msgid
,
langid
,
buffer
,
size
,
args
);
if
(
!
buffer
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
return
0
;
}
if
(
width
==
0xff
)
width
=
~
0u
;
if
(
flags
&
FORMAT_MESSAGE_ALLOCATE_BUFFER
)
*
(
LPWSTR
*
)
buffer
=
NULL
;
if
(
!
(
src
=
get_message
(
flags
,
source
,
msgid
,
langid
,
FALSE
,
&
message
)))
return
0
;
if
(
flags
&
FORMAT_MESSAGE_ALLOCATE_BUFFER
)
{
WCHAR
*
result
;
ULONG
alloc
=
max
(
size
*
sizeof
(
WCHAR
),
65536
);
for
(;;)
{
if
(
!
(
result
=
HeapAlloc
(
GetProcessHeap
(),
0
,
alloc
)))
{
status
=
STATUS_NO_MEMORY
;
break
;
}
status
=
RtlFormatMessage
(
src
,
width
,
!!
(
flags
&
FORMAT_MESSAGE_IGNORE_INSERTS
),
FALSE
,
!!
(
flags
&
FORMAT_MESSAGE_ARGUMENT_ARRAY
),
args
,
result
,
alloc
,
&
retsize
);
if
(
!
status
)
{
if
(
retsize
<=
sizeof
(
WCHAR
))
HeapFree
(
GetProcessHeap
(),
0
,
result
);
else
*
(
WCHAR
**
)
buffer
=
HeapReAlloc
(
GetProcessHeap
(),
HEAP_REALLOC_IN_PLACE_ONLY
,
result
,
max
(
retsize
,
size
*
sizeof
(
WCHAR
)
));
break
;
}
HeapFree
(
GetProcessHeap
(),
0
,
result
);
if
(
status
!=
STATUS_BUFFER_OVERFLOW
)
break
;
alloc
*=
2
;
}
}
else
status
=
RtlFormatMessage
(
src
,
width
,
!!
(
flags
&
FORMAT_MESSAGE_IGNORE_INSERTS
),
FALSE
,
!!
(
flags
&
FORMAT_MESSAGE_ARGUMENT_ARRAY
),
args
,
buffer
,
size
*
sizeof
(
WCHAR
),
&
retsize
);
HeapFree
(
GetProcessHeap
(),
0
,
message
);
if
(
status
==
STATUS_BUFFER_OVERFLOW
)
{
if
(
size
)
buffer
[
size
-
1
]
=
0
;
SetLastError
(
ERROR_INSUFFICIENT_BUFFER
);
return
0
;
}
if
(
!
set_ntstatus
(
status
))
return
0
;
if
(
retsize
<=
sizeof
(
WCHAR
))
SetLastError
(
ERROR_NO_WORK_DONE
);
return
retsize
/
sizeof
(
WCHAR
)
-
1
;
}
/******************************************************************************
* GetACP (kernelbase.@)
*/
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment