From: Fabian Maurer <dark.shadow4(a)web.de> We can't return the unicode string size, this returns sizes to small for multi-byte characters. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54295 --- dlls/kernel32/tests/environ.c | 30 ++++++++++++++++++++++++++++++ dlls/kernelbase/process.c | 27 +++++++++++++++++---------- dlls/shlwapi/tests/shreg.c | 7 ++----- 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/dlls/kernel32/tests/environ.c b/dlls/kernel32/tests/environ.c index 2a15fb92dfd..abf09a9e1cc 100644 --- a/dlls/kernel32/tests/environ.c +++ b/dlls/kernel32/tests/environ.c @@ -441,8 +441,10 @@ static void test_ExpandEnvironmentStringsA(void) "ExpandEnvironmentStrings returned %ld\n", ret_size); /* Try to get the required buffer size 'the natural way' */ + SetLastError(0xdeadbeef); strcpy(buf, "%EnvVar%"); ret_size = ExpandEnvironmentStringsA(buf, NULL, 0); + ok(GetLastError() == 0xdeadbeef, "got last error %ld\n", GetLastError()); ok(ret_size == strlen(value)+1 || /* win98 */ ret_size == (strlen(value)+1)*2 || /* NT4 */ ret_size == strlen(value)+2 || /* win2k, XP, win2k3 */ @@ -459,7 +461,9 @@ static void test_ExpandEnvironmentStringsA(void) ret_size, lstrlenA(value)+1); /* Try with a buffer that's too small */ + SetLastError(0xdeadbeef); ret_size = ExpandEnvironmentStringsA(buf, buf1, 12); + ok(GetLastError() == 0xdeadbeef, "got last error %ld\n", GetLastError()); /* v5.1.2600.2945 (XP SP2) returns len + 2 here! */ ok(ret_size == strlen(value)+1 || ret_size == strlen(value)+2 || ret_size == (strlen(value)+1)*2 /* NT4 */, @@ -509,6 +513,32 @@ static void test_ExpandEnvironmentStringsA(void) SetEnvironmentVariableA("IndirectVar", NULL); SetEnvironmentVariableA("EnvVar", NULL); + + if (GetACP() == 932) /* shift-jis */ + { + const char* japanese_test = "\x88\xEA\x93\xF1\x8E\x4F\x8E\x6C\x8C\xDC\x98\x5A\x8E\xB5\x94\xAA\x8B\xE3"; /* Japanese Kanji for "one" to "nine", in shift-jis */ + int japanese_len = strlen(japanese_test); + + SetLastError(0xdeadbeef); + ret_size = ExpandEnvironmentStringsA(japanese_test, NULL, 0); + ok(GetLastError() == 0xdeadbeef, "got last error %ld\n", GetLastError()); + ok(ret_size >= japanese_len, "Needed at least %d, got %lu\n", japanese_len, ret_size); + + SetLastError(0xdeadbeef); + ret_size = ExpandEnvironmentStringsA(japanese_test, buf, ret_size); + ok(GetLastError() == 0xdeadbeef, "got last error %ld\n", GetLastError()); + ok(ret_size >= japanese_len, "Needed at least %d, got %lu\n", japanese_len, ret_size); + ok(!strcmp(buf, japanese_test), "Got %s\n", debugstr_a(buf)); + + SetLastError(0xdeadbeef); + ret_size = ExpandEnvironmentStringsA(japanese_test, buf, japanese_len / 2); /* Buffer too small */ + ok(GetLastError() == 0xdeadbeef, "got last error %ld\n", GetLastError()); + ok(ret_size >= japanese_len, "Needed at least %d, got %lu\n", japanese_len, ret_size); + } + else + { + skip("Skipping japanese language tests\n"); + } } static void test_GetComputerName(void) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 8aa732602ec..8e604ec62fb 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -1400,23 +1400,30 @@ DWORD WINAPI DECLSPEC_HOTPATCH ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, { UNICODE_STRING us_src; PWSTR dstW = NULL; - DWORD ret; + DWORD count_neededW; + DWORD count_neededA = 0; RtlCreateUnicodeStringFromAsciiz( &us_src, src ); - if (count) - { - if (!(dstW = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR)))) return 0; - ret = ExpandEnvironmentStringsW( us_src.Buffer, dstW, count); - if (ret) WideCharToMultiByte( CP_ACP, 0, dstW, ret, dst, count, NULL, NULL ); - } - else ret = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0 ); + /* We always need to call ExpandEnvironmentStringsW, since we need the result to calculate the needed buffer size */ + count_neededW = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0 ); + if (!(dstW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count_neededW * sizeof(WCHAR)))) goto cleanup; + count_neededW = ExpandEnvironmentStringsW( us_src.Buffer, dstW, count_neededW); + + /* Calculate needed buffer */ + count_neededA = WideCharToMultiByte( CP_ACP, 0, dstW, count_neededW, NULL, 0, NULL, NULL ); + if (!count_neededA) goto cleanup; + + /* If provided buffer is enough, do actual conversion */ + if (count >= count_neededA) + count_neededA = WideCharToMultiByte( CP_ACP, 0, dstW, count_neededW, dst, count, NULL, NULL ); + +cleanup: RtlFreeUnicodeString( &us_src ); HeapFree( GetProcessHeap(), 0, dstW ); - return ret; + return count_neededA; } - /*********************************************************************** * ExpandEnvironmentStringsW (kernelbase.@) */ diff --git a/dlls/shlwapi/tests/shreg.c b/dlls/shlwapi/tests/shreg.c index bc411779c8f..75d4dfae7eb 100644 --- a/dlls/shlwapi/tests/shreg.c +++ b/dlls/shlwapi/tests/shreg.c @@ -290,11 +290,8 @@ static void test_SHQueryValueEx(void) broken(ERROR_SUCCESS == dwRet), /* < IE5.5*/ "Expected ERROR_MORE_DATA, got (%lu)\n", dwRet); - todo_wine - { - ok( (0 == strcmp("", buf)) || (0 == strcmp(sTestpath2, buf)), - "Expected empty or unexpanded string (win98), got (%s)\n", buf); - } + ok( (0 == strcmp("", buf)) || (0 == strcmp(sTestpath2, buf)), + "Expected empty or unexpanded string (win98), got (%s)\n", buf); ok( dwSize >= nUsedBuffer2 || broken(dwSize == (strlen("") + 1)), /* < IE 5.5 */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4045