Commit 7b012817 authored by Alexandre Julliard's avatar Alexandre Julliard

kernelbase: Reimplement FormatMessageA/W using RtlFormatMessage().

parent 3214ca84
...@@ -16,7 +16,6 @@ C_SRCS = \ ...@@ -16,7 +16,6 @@ C_SRCS = \
editline.c \ editline.c \
environ.c \ environ.c \
file.c \ file.c \
format_msg.c \
heap.c \ heap.c \
kernel_main.c \ kernel_main.c \
lcformat.c \ lcformat.c \
......
...@@ -522,8 +522,8 @@ ...@@ -522,8 +522,8 @@
@ stdcall -import FlushViewOfFile(ptr long) @ stdcall -import FlushViewOfFile(ptr long)
@ stdcall FoldStringA(long str long ptr long) @ stdcall FoldStringA(long str long ptr long)
@ stdcall -import FoldStringW(long wstr long ptr long) @ stdcall -import FoldStringW(long wstr long ptr long)
@ stdcall FormatMessageA(long ptr long long ptr long ptr) @ stdcall -import FormatMessageA(long ptr long long ptr long ptr)
@ stdcall FormatMessageW(long ptr long long ptr long ptr) @ stdcall -import FormatMessageW(long ptr long long ptr long ptr)
@ stdcall FreeConsole() @ stdcall FreeConsole()
@ stdcall -import FreeEnvironmentStringsA(ptr) @ stdcall -import FreeEnvironmentStringsA(ptr)
@ stdcall -import FreeEnvironmentStringsW(ptr) @ stdcall -import FreeEnvironmentStringsW(ptr)
......
...@@ -77,7 +77,7 @@ static void test_message_from_string_wide(void) ...@@ -77,7 +77,7 @@ static void test_message_from_string_wide(void)
error = GetLastError(); error = GetLastError();
ok(!lstrcmpW(L"", out), "failed out=%s\n", wine_dbgstr_w(out)); ok(!lstrcmpW(L"", out), "failed out=%s\n", wine_dbgstr_w(out));
ok(r==0, "succeeded: r=%d\n", r); 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 */ /* format placeholder with no specifier */
SetLastError(0xdeadbeef); SetLastError(0xdeadbeef);
...@@ -94,8 +94,7 @@ static void test_message_from_string_wide(void) ...@@ -94,8 +94,7 @@ static void test_message_from_string_wide(void)
lstrcpyW( out, L"xxxxxx" ); lstrcpyW( out, L"xxxxxx" );
r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, L"test%", 0, 0, out, ARRAY_SIZE(out), NULL); r = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, L"test%", 0, 0, out, ARRAY_SIZE(out), NULL);
error = GetLastError(); error = GetLastError();
ok(!lstrcmpW( out, L"xxxxxx" ) || ok(!lstrcmpW(out, L"testxx") || broken(!lstrcmpW( out, L"xxxxxx" )), /* winxp */
broken(!lstrcmpW(out, L"testxx")), /* W2K3+ */
"Expected the buffer to be unchanged\n"); "Expected the buffer to be unchanged\n");
ok(r==0, "succeeded: r=%d\n", r); ok(r==0, "succeeded: r=%d\n", r);
ok(error==ERROR_INVALID_PARAMETER, "last error %u\n", error); ok(error==ERROR_INVALID_PARAMETER, "last error %u\n", error);
...@@ -359,7 +358,7 @@ static void test_message_from_string(void) ...@@ -359,7 +358,7 @@ static void test_message_from_string(void)
r = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "", 0, 0, out, ARRAY_SIZE(out), NULL); 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(!memcmp(out, init_buf, sizeof(init_buf)), "Expected the buffer to be untouched\n");
ok(r==0, "succeeded: r=%d\n", r); 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()); "last error %u\n", GetLastError());
/* format placeholder with no specifier */ /* format placeholder with no specifier */
...@@ -661,8 +660,8 @@ static void test_message_ignore_inserts(void) ...@@ -661,8 +660,8 @@ static void test_message_ignore_inserts(void)
ARRAY_SIZE(out), NULL); ARRAY_SIZE(out), NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %d\n", ret); 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(!memcmp(out, init_buf, sizeof(init_buf)), "Expected the output buffer to be untouched\n");
ok((GetLastError() == 0xdeadbeef) || (GetLastError() == ERROR_NO_WORK_DONE), ok(GetLastError() == ERROR_NO_WORK_DONE || broken(GetLastError() == 0xdeadbeef),
"Expected GetLastError() to return 0xdeadbeef or ERROR_NO_WORK_DONE, got %u\n", GetLastError()); "Expected GetLastError() to return ERROR_NO_WORK_DONE, got %u\n", GetLastError());
/* Insert sequences are ignored. */ /* Insert sequences are ignored. */
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, "test%1%2!*.*s!%99", 0, 0, out, 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) ...@@ -751,8 +750,8 @@ static void test_message_ignore_inserts_wide(void)
ARRAY_SIZE(out), NULL); ARRAY_SIZE(out), NULL);
ok(ret == 0, "Expected FormatMessageW to return 0, got %d\n", ret); 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(!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), ok(GetLastError() == ERROR_NO_WORK_DONE || broken(GetLastError() == 0xdeadbeef),
"Expected GetLastError() to return 0xdeadbeef or ERROR_NO_WORK_DONE, got %u\n", GetLastError()); "Expected GetLastError() to return ERROR_NO_WORK_DONE, got %u\n", GetLastError());
/* Insert sequences are ignored. */ /* Insert sequences are ignored. */
ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_IGNORE_INSERTS, L"test%1%2!*.*s!%99", 0, 0, out, 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) ...@@ -1066,7 +1065,6 @@ static void test_message_insufficient_buffer_wide(void)
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n", "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError()); GetLastError());
todo_wine
ok(!memcmp(out, L"\0xxxxx", 6 * sizeof(WCHAR)) || ok(!memcmp(out, L"\0xxxxx", 6 * sizeof(WCHAR)) ||
broken(!lstrcmpW( out, L"xxxxxx" )), /* winxp */ broken(!lstrcmpW( out, L"xxxxxx" )), /* winxp */
"Expected the buffer to be truncated\n"); "Expected the buffer to be truncated\n");
...@@ -1078,7 +1076,6 @@ static void test_message_insufficient_buffer_wide(void) ...@@ -1078,7 +1076,6 @@ static void test_message_insufficient_buffer_wide(void)
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n", "Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError()); GetLastError());
todo_wine
ok(!memcmp(out, L"tes\0xx", 6 * sizeof(WCHAR)) || ok(!memcmp(out, L"tes\0xx", 6 * sizeof(WCHAR)) ||
broken(!lstrcmpW( out, L"xxxxxx" )), /* winxp */ broken(!lstrcmpW( out, L"xxxxxx" )), /* winxp */
"Expected the buffer to be truncated\n"); "Expected the buffer to be truncated\n");
...@@ -1185,8 +1182,8 @@ static void test_message_allocate_buffer(void) ...@@ -1185,8 +1182,8 @@ static void test_message_allocate_buffer(void)
"", 0, 0, (char *)&buf, 0, NULL); "", 0, 0, (char *)&buf, 0, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret); ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(buf == NULL, "Expected output buffer pointer to be NULL\n"); ok(buf == NULL, "Expected output buffer pointer to be NULL\n");
ok((GetLastError() == 0xdeadbeef) || (GetLastError() == ERROR_NO_WORK_DONE), ok(GetLastError() == ERROR_NO_WORK_DONE || broken(GetLastError() == 0xdeadbeef),
"Expected GetLastError() to return 0xdeadbeef or ERROR_NO_WORK_DONE, got %u\n", GetLastError()); "Expected GetLastError() to return ERROR_NO_WORK_DONE, got %u\n", GetLastError());
buf = (char *)0xdeadbeef; buf = (char *)0xdeadbeef;
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
...@@ -1279,8 +1276,8 @@ static void test_message_allocate_buffer_wide(void) ...@@ -1279,8 +1276,8 @@ static void test_message_allocate_buffer_wide(void)
L"", 0, 0, (WCHAR *)&buf, 0, NULL); L"", 0, 0, (WCHAR *)&buf, 0, NULL);
ok(ret == 0, "Expected FormatMessageW to return 0, got %u\n", ret); ok(ret == 0, "Expected FormatMessageW to return 0, got %u\n", ret);
ok(buf == NULL, "Expected output buffer pointer to be NULL\n"); ok(buf == NULL, "Expected output buffer pointer to be NULL\n");
ok((GetLastError() == 0xdeadbeef) || (GetLastError() == ERROR_NO_WORK_DONE), ok(GetLastError() == ERROR_NO_WORK_DONE || broken(GetLastError() == 0xdeadbeef),
"Expected GetLastError() to return 0xdeadbeef or ERROR_NO_WORK_DONE, got %u\n", GetLastError()); "Expected GetLastError() to return ERROR_NO_WORK_DONE, got %u\n", GetLastError());
buf = (WCHAR *)0xdeadbeef; buf = (WCHAR *)0xdeadbeef;
ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
...@@ -1637,18 +1634,14 @@ static void test_message_from_64bit_number(void) ...@@ -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), r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!I64u!", 0, 0, outW, ARRAY_SIZE(outW),
unsigned_tests[i].number); unsigned_tests[i].number);
MultiByteToWideChar(CP_ACP, 0, unsigned_tests[i].expected, -1, expW, ARRAY_SIZE(expW)); 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, ok(!lstrcmpW(outW, expW),"[%d] failed, expected %s, got %s\n", i,
unsigned_tests[i].expected, wine_dbgstr_w(outW)); unsigned_tests[i].expected, wine_dbgstr_w(outW));
ok(r == unsigned_tests[i].len,"[%d] failed: r=%d\n", i, r); ok(r == unsigned_tests[i].len,"[%d] failed: r=%d\n", i, r);
}
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I64u!", r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I64u!",
0, 0, outA, sizeof(outA), unsigned_tests[i].number); 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, ok(!strcmp(outA, unsigned_tests[i].expected),"[%d] failed, expected %s, got %s\n", i,
unsigned_tests[i].expected, outA); unsigned_tests[i].expected, outA);
ok(r == unsigned_tests[i].len,"[%d] failed: r=%d\n", i, r); ok(r == unsigned_tests[i].len,"[%d] failed: r=%d\n", i, r);
}
} }
for (i = 0; i < ARRAY_SIZE(signed_tests); i++) for (i = 0; i < ARRAY_SIZE(signed_tests); i++)
...@@ -1656,18 +1649,14 @@ todo_wine { ...@@ -1656,18 +1649,14 @@ todo_wine {
r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!I64d!", 0, 0, outW, ARRAY_SIZE(outW), r = doitW(FORMAT_MESSAGE_FROM_STRING, L"%1!I64d!", 0, 0, outW, ARRAY_SIZE(outW),
signed_tests[i].number); signed_tests[i].number);
MultiByteToWideChar(CP_ACP, 0, signed_tests[i].expected, -1, expW, ARRAY_SIZE(expW)); 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, ok(!lstrcmpW(outW, expW),"[%d] failed, expected %s, got %s\n", i,
signed_tests[i].expected, wine_dbgstr_w(outW)); signed_tests[i].expected, wine_dbgstr_w(outW));
ok(r == signed_tests[i].len,"[%d] failed: r=%d\n", i, r); ok(r == signed_tests[i].len,"[%d] failed: r=%d\n", i, r);
}
r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I64d!", r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I64d!",
0, 0, outA, sizeof(outA), signed_tests[i].number); 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, ok(!strcmp(outA, signed_tests[i].expected),"[%d] failed, expected %s, got %s\n", i,
signed_tests[i].expected, outA); signed_tests[i].expected, outA);
ok(r == signed_tests[i].len,"[%d] failed: r=%d\n", i, r); ok(r == signed_tests[i].len,"[%d] failed: r=%d\n", i, r);
}
} }
} }
......
...@@ -387,8 +387,8 @@ ...@@ -387,8 +387,8 @@
@ stdcall FoldStringW(long wstr long ptr long) @ stdcall FoldStringW(long wstr long ptr long)
# @ stub ForceSyncFgPolicyInternal # @ stub ForceSyncFgPolicyInternal
# @ stub FormatApplicationUserModelId # @ stub FormatApplicationUserModelId
@ stdcall FormatMessageA(long ptr long long ptr long ptr) kernel32.FormatMessageA @ stdcall FormatMessageA(long ptr long long ptr long ptr)
@ stdcall FormatMessageW(long ptr long long ptr long ptr) kernel32.FormatMessageW @ stdcall FormatMessageW(long ptr long long ptr long ptr)
@ stdcall FreeConsole() @ stdcall FreeConsole()
@ stdcall FreeEnvironmentStringsA(ptr) FreeEnvironmentStringsW @ stdcall FreeEnvironmentStringsA(ptr) FreeEnvironmentStringsW
@ stdcall FreeEnvironmentStringsW(ptr) @ stdcall FreeEnvironmentStringsW(ptr)
......
...@@ -3639,6 +3639,197 @@ INT WINAPI DECLSPEC_HOTPATCH FoldStringW( DWORD flags, LPCWSTR src, INT srclen, ...@@ -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.@) * GetACP (kernelbase.@)
*/ */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment