diff --git a/dlls/msvcp140/msvcp140.spec b/dlls/msvcp140/msvcp140.spec index f13ec563ace..284f6747367 100644 --- a/dlls/msvcp140/msvcp140.spec +++ b/dlls/msvcp140/msvcp140.spec @@ -3732,7 +3732,7 @@ @ cdecl _Thrd_start(ptr ptr ptr) _Thrd_start @ cdecl _Thrd_yield() _Thrd_yield @ stub _To_byte -@ stub _To_wide +@ cdecl _To_wide(str ptr) @ cdecl _Tolower(long ptr) _Tolower @ cdecl _Toupper(long ptr) _Toupper @ cdecl _Towlower(long ptr) _Towlower diff --git a/dlls/msvcp140/tests/msvcp140.c b/dlls/msvcp140/tests/msvcp140.c index c9646135e14..f3dd4a0ea01 100644 --- a/dlls/msvcp140/tests/msvcp140.c +++ b/dlls/msvcp140/tests/msvcp140.c @@ -18,6 +18,10 @@ #include +#include "windef.h" +#include "winbase.h" +#include "winnls.h" + #include "wine/test.h" #include "winbase.h" @@ -148,6 +152,8 @@ static int (__cdecl *p__Schedule_chore)(_Threadpool_chore*); static int (__cdecl *p__Reschedule_chore)(const _Threadpool_chore*); static void (__cdecl *p__Release_chore)(_Threadpool_chore*); +static int (__cdecl *p_To_wide)(const char *src, WCHAR *dst); + static HMODULE msvcp; #define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y) #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) @@ -209,6 +215,8 @@ static BOOL init(void) SET(p__Release_chore, "?_Release_chore@details@Concurrency@@YAXPAU_Threadpool_chore@12@@Z"); } + SET(p_To_wide, "_To_wide"); + init_thiscall_thunk(); return TRUE; } @@ -461,6 +469,52 @@ static void test_chore(void) p__Release_chore(&chore); } +static void test_to_wide(void) +{ + /* öäü߀Ÿ.A.B in cp1252, the two . are an undefined value and delete. + * With a different system codepage it will produce different results, so do not hardcode the + * expected output but convert it with MultiByteToWideChar. */ + static const char special_input[] = {0xf6, 0xe4, 0xfc, 0xdf, 0x80, 0x9f, 0x81, 0x41, 0x7f, 0x42, 0}; + static const char *tests[] = {"Testtest", special_input}; + WCHAR dst[MAX_PATH + 4] = {'A', 'B', 'C', 0, 'X', 'X', 'X', 'X', 'X', 'X', 'X'}; + WCHAR compare[MAX_PATH + 4] = {'A', 'B', 'C', 0, 'X', 'X', 'X', 'X', 'X', 'X', 'X'}; + int ret, expected; + unsigned int i; + char longstr[MAX_PATH + 3]; + + ret = p_To_wide(NULL, NULL); + ok(!ret, "Got unexpected result %d\n", ret); + ret = p_To_wide(tests[0], NULL); + ok(!ret, "Got unexpected result %d\n", ret); + ret = p_To_wide(NULL, dst); + ok(!ret, "Got unexpected result %d\n", ret); + ok(!memcmp(dst, compare, sizeof(compare)), "Destination was modified: %s\n", wine_dbgstr_w(dst)); + + for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i) + { + ret = p_To_wide(tests[i], dst); + expected = MultiByteToWideChar(CP_ACP, 0, tests[i], -1, compare, sizeof(compare) / sizeof(*compare)); + ok(ret == expected, "Got unexpected result %d, expected %d, test case %u\n", ret, expected, i); + ok(!memcmp(dst, compare, sizeof(compare)), "Got unexpected output %s, test case %u\n", + wine_dbgstr_w(dst), i); + } + + /* Output length is limited to MAX_PATH.*/ + for (i = MAX_PATH - 2; i < MAX_PATH + 2; ++i) + { + memset(longstr, 'A', sizeof(longstr)); + longstr[i] = 0; + memset(dst, 0xff, sizeof(dst)); + memset(compare, 0xff, sizeof(compare)); + + ret = p_To_wide(longstr, dst); + expected = MultiByteToWideChar(CP_ACP, 0, longstr, -1, compare, MAX_PATH); + ok(ret == expected, "Got unexpected result %d, expected %d, length %u\n", ret, expected, i); + ok(!memcmp(dst, compare, sizeof(compare)), "Got unexpected output %s, length %u\n", + wine_dbgstr_w(dst), i); + } +} + START_TEST(msvcp140) { if(!init()) return; @@ -470,5 +524,6 @@ START_TEST(msvcp140) test__ContextCallback(); test__TaskEventLogger(); test_chore(); + test_to_wide(); FreeLibrary(msvcp); } diff --git a/dlls/msvcp90/locale.c b/dlls/msvcp90/locale.c index d2fce47a4b8..8847ac20f74 100644 --- a/dlls/msvcp90/locale.c +++ b/dlls/msvcp90/locale.c @@ -11224,6 +11224,16 @@ size_t __cdecl wcsrtombs(char *dst, const wchar_t **pstr, size_t n, mbstate_t *s } #endif +int __cdecl _To_wide(const char *src, wchar_t *dst) +{ + TRACE("(%s %p)\n", debugstr_a(src), dst); + + if (!src || !dst) + return 0; + + return MultiByteToWideChar(CP_ACP, 0, src, -1, dst, MAX_PATH); +} + DEFINE_RTTI_DATA0(_Facet_base, 0, ".?AV_Facet_base@std@@") DEFINE_RTTI_DATA0(locale_facet, 0, ".?AVfacet@locale@std@@") DEFINE_RTTI_DATA1(locale__Locimp, 0, &locale_facet_rtti_base_descriptor, ".?AV_Locimp@locale@std@@")