Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/shcore/main.c | 90 ++++++++++++++++++ dlls/shcore/shcore.spec | 8 +- dlls/shcore/tests/shcore.c | 182 +++++++++++++++++++++++++++++++++++++ 3 files changed, 276 insertions(+), 4 deletions(-)
diff --git a/dlls/shcore/main.c b/dlls/shcore/main.c index bf477aefcc..88c36ecf2d 100644 --- a/dlls/shcore/main.c +++ b/dlls/shcore/main.c @@ -1455,3 +1455,93 @@ HRESULT WINAPI SHStrDupA(const char *src, WCHAR **dest)
return S_OK; } + +/************************************************************************* + * SHAnsiToAnsi [SHCORE.@] + */ +DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len) +{ + DWORD ret; + + TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len); + + if (!src || !dest || dest_len <= 0) + return 0; + + lstrcpynA(dest, src, dest_len); + ret = strlen(dest); + + return src[ret] ? 0 : ret + 1; +} + +/************************************************************************* + * SHUnicodeToAnsi [SHCORE.@] + */ +DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len) +{ + int ret = 1; + + TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len); + + if (!dest || !dest_len) + return 0; + + if (src) + { + ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL); + if (!ret) + { + dest[dest_len - 1] = 0; + ret = dest_len; + } + } + else + dest[0] = 0; + + return ret; +} + +/************************************************************************* + * SHUnicodeToUnicode [SHCORE.@] + */ +DWORD WINAPI SHUnicodeToUnicode(const WCHAR *src, WCHAR *dest, int dest_len) +{ + DWORD ret; + + TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len); + + if (!src || !dest || dest_len <= 0) + return 0; + + lstrcpynW(dest, src, dest_len); + ret = strlenW(dest); + + return src[ret] ? 0 : ret + 1; +} + +/************************************************************************* + * SHAnsiToUnicode [SHCORE.@] + */ +DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len) +{ + int ret = 1; + + TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len); + + if (!dest || !dest_len) + return 0; + + if (src) + { + ret = MultiByteToWideChar(CP_ACP, 0, src, -1, dest, dest_len); + if (!ret) + { + dest[dest_len - 1] = 0; + ret = dest_len; + } + } + else + dest[0] = 0; + + return ret; +} diff --git a/dlls/shcore/shcore.spec b/dlls/shcore/shcore.spec index 1473bf7b0a..918ba5595c 100644 --- a/dlls/shcore/shcore.spec +++ b/dlls/shcore/shcore.spec @@ -29,8 +29,8 @@ @ stub RegisterScaleChangeEvent @ stub RegisterScaleChangeNotifications @ stub RevokeScaleChangeNotifications -@ stdcall SHAnsiToAnsi(str ptr long) shlwapi.SHAnsiToAnsi -@ stdcall SHAnsiToUnicode(str ptr long) shlwapi.SHAnsiToUnicode +@ stdcall SHAnsiToAnsi(str ptr long) +@ stdcall SHAnsiToUnicode(str ptr long) @ stdcall SHCopyKeyA(long str long long) shlwapi.SHCopyKeyA @ stdcall SHCopyKeyW(long wstr long long) shlwapi.SHCopyKeyW @ stdcall SHCreateMemStream(ptr long) @@ -75,8 +75,8 @@ @ stdcall SHSetValueW(long wstr wstr long ptr long) shlwapi.SHSetValueW @ stdcall SHStrDupA(str ptr) @ stdcall SHStrDupW(wstr ptr) -@ stdcall SHUnicodeToAnsi(wstr ptr ptr) shlwapi.SHUnicodeToAnsi -@ stdcall SHUnicodeToUnicode(wstr ptr long) shlwapi.SHUnicodeToUnicode +@ stdcall SHUnicodeToAnsi(wstr ptr ptr) +@ stdcall SHUnicodeToUnicode(wstr ptr long) @ stdcall SetCurrentProcessExplicitAppUserModelID(wstr) @ stdcall SetProcessDpiAwareness(long) @ stdcall SetProcessReference(ptr) diff --git a/dlls/shcore/tests/shcore.c b/dlls/shcore/tests/shcore.c index 904d8264cd..f788afdd22 100644 --- a/dlls/shcore/tests/shcore.c +++ b/dlls/shcore/tests/shcore.c @@ -29,12 +29,20 @@ static HRESULT (WINAPI *pGetProcessReference)(IUnknown **); static void (WINAPI *pSetProcessReference)(IUnknown *); static HRESULT (WINAPI *pSHGetInstanceExplorer)(IUnknown **); +static int (WINAPI *pSHUnicodeToAnsi)(const WCHAR *, char *, int); +static int (WINAPI *pSHAnsiToUnicode)(const char *, WCHAR *, int); +static int (WINAPI *pSHAnsiToAnsi)(const char *, char *, int); +static int (WINAPI *pSHUnicodeToUnicode)(const WCHAR *, WCHAR *, int);
static void init(HMODULE hshcore) { #define X(f) p##f = (void*)GetProcAddress(hshcore, #f) X(GetProcessReference); X(SetProcessReference); + X(SHUnicodeToAnsi); + X(SHAnsiToUnicode); + X(SHAnsiToAnsi); + X(SHUnicodeToUnicode); #undef X }
@@ -122,6 +130,176 @@ static void test_process_reference(void) ok(test_unk2.refcount == 3, "Unexpected refcount %u.\n", test_unk2.refcount); }
+static void test_SHUnicodeToAnsi(void) +{ + static const WCHAR testW[] = {'t','e','s','t',0}; + static const WCHAR emptyW[] = { 0 }; + char buff[16]; + int ret; + + ret = pSHUnicodeToAnsi(NULL, NULL, 0); + ok(ret == 0, "Unexpected return value %d.\n", ret); + + strcpy(buff, "abc"); + ret = pSHUnicodeToAnsi(NULL, buff, 2); + ok(ret == 1, "Unexpected return value %d.\n", ret); + ok(buff[0] == 0 && buff[1] == 'b', "Unexpected buffer contents.\n"); + + buff[0] = 1; + ret = pSHUnicodeToAnsi(NULL, buff, 0); + ok(ret == 0, "Unexpected return value %d.\n", ret); + ok(buff[0] == 1, "Unexpected buffer contents.\n"); + + buff[0] = 1; + strcpy(buff, "test"); + ret = pSHUnicodeToAnsi(emptyW, buff, 1); + ok(ret == 1, "Unexpected return value %d.\n", ret); + ok(*buff == 0, "Unexpected buffer contents.\n"); + + buff[0] = 1; + ret = pSHUnicodeToAnsi(testW, buff, 0); + ok(ret == 0, "Unexpected return value %d.\n", ret); + ok(buff[0] == 1, "Unexpected buffer contents.\n"); + + buff[0] = 1; + ret = pSHUnicodeToAnsi(testW, buff, 1); + ok(ret == 1, "Unexpected return value %d.\n", ret); + ok(*buff == 0, "Unexpected buffer contents.\n"); + + ret = pSHUnicodeToAnsi(testW, buff, 16); + ok(ret == 5, "Unexpected return value %d.\n", ret); + ok(!strcmp(buff, "test"), "Unexpected buffer contents.\n"); + + ret = pSHUnicodeToAnsi(testW, buff, 2); + ok(ret == 2, "Unexpected return value %d.\n", ret); + ok(!strcmp(buff, "t"), "Unexpected buffer contents.\n"); +} + +static void test_SHAnsiToUnicode(void) +{ + static const WCHAR testW[] = {'t','e','s','t',0}; + WCHAR buffW[16]; + int ret; + + ret = pSHAnsiToUnicode(NULL, NULL, 0); + ok(ret == 0, "Unexpected return value %d.\n", ret); + + buffW[0] = 1; + buffW[1] = 2; + ret = pSHAnsiToUnicode(NULL, buffW, 2); + ok(ret == 1, "Unexpected return value %d.\n", ret); + ok(buffW[0] == 0 && buffW[1] == 2, "Unexpected buffer contents.\n"); + + buffW[0] = 1; + ret = pSHAnsiToUnicode(NULL, buffW, 0); + ok(ret == 0, "Unexpected return value %d.\n", ret); + ok(buffW[0] == 1, "Unexpected buffer contents.\n"); + + buffW[0] = 1; + ret = pSHAnsiToUnicode("", buffW, 1); + ok(ret == 1, "Unexpected return value %d.\n", ret); + ok(*buffW == 0, "Unexpected buffer contents.\n"); + + buffW[0] = 1; + ret = pSHAnsiToUnicode("test", buffW, 0); + ok(ret == 0, "Unexpected return value %d.\n", ret); + ok(buffW[0] == 1, "Unexpected buffer contents.\n"); + + buffW[0] = 1; + ret = pSHAnsiToUnicode("test", buffW, 1); + ok(ret == 1, "Unexpected return value %d.\n", ret); + ok(*buffW == 0, "Unexpected buffer contents.\n"); + + ret = pSHAnsiToUnicode("test", buffW, 16); + ok(ret == 5, "Unexpected return value %d.\n", ret); + ok(!lstrcmpW(buffW, testW), "Unexpected buffer contents.\n"); + + ret = pSHAnsiToUnicode("test", buffW, 2); + ok(ret == 2, "Unexpected return value %d.\n", ret); + ok(buffW[0] == 't' && buffW[1] == 0, "Unexpected buffer contents.\n"); +} + +static void test_SHAnsiToAnsi(void) +{ + char buff[16]; + int ret; + + ret = pSHAnsiToAnsi(NULL, NULL, 0); + ok(ret == 0, "Unexpected return value %d.\n", ret); + + strcpy(buff, "abcdefghijklm"); + ret = pSHAnsiToAnsi("test", buff, 3); + ok(ret == 0, "Unexpected return value %d.\n", ret); + ok(!strcmp(buff, "te"), "Unexpected buffer contents.\n"); + ok(buff[3] == 'd', "Unexpected buffer contents.\n"); + + strcpy(buff, "abcdefghijklm"); + ret = pSHAnsiToAnsi("", buff, 3); + ok(ret == 1, "Unexpected return value %d.\n", ret); + ok(!*buff, "Unexpected buffer contents.\n"); + ok(buff[3] == 'd', "Unexpected buffer contents.\n"); + + strcpy(buff, "abcdefghijklm"); + ret = pSHAnsiToAnsi("test", buff, 4); + ok(ret == 0, "Unexpected return value %d.\n", ret); + ok(!strcmp(buff, "tes"), "Unexpected buffer contents.\n"); + ok(buff[4] == 'e', "Unexpected buffer contents.\n"); + + strcpy(buff, "abcdefghijklm"); + ret = pSHAnsiToAnsi("test", buff, 5); + ok(ret == 5, "Unexpected return value %d.\n", ret); + ok(!strcmp(buff, "test"), "Unexpected buffer contents.\n"); + ok(buff[5] == 'f', "Unexpected buffer contents.\n"); + + strcpy(buff, "abcdefghijklm"); + ret = pSHAnsiToAnsi("test", buff, 6); + ok(ret == 5, "Unexpected return value %d.\n", ret); + ok(!strcmp(buff, "test"), "Unexpected buffer contents.\n"); + ok(buff[5] == 'f', "Unexpected buffer contents.\n"); +} + +static void test_SHUnicodeToUnicode(void) +{ + static const WCHAR testW[] = {'t','e','s','t',0}; + static const WCHAR strW[] = {'a','b','c','d','e','f','g','h','i','k','l','m',0}; + static const WCHAR emptyW[] = { 0 }; + WCHAR buff[16]; + int ret; + + ret = pSHUnicodeToUnicode(NULL, NULL, 0); + ok(ret == 0, "Unexpected return value %d.\n", ret); + + lstrcpyW(buff, strW); + ret = pSHUnicodeToUnicode(testW, buff, 3); + ok(ret == 0, "Unexpected return value %d.\n", ret); + ok(!memcmp(buff, testW, 2 * sizeof(WCHAR)) && !buff[2], "Unexpected buffer contents.\n"); + ok(buff[3] == 'd', "Unexpected buffer contents.\n"); + + lstrcpyW(buff, strW); + ret = pSHUnicodeToUnicode(emptyW, buff, 3); + ok(ret == 1, "Unexpected return value %d.\n", ret); + ok(!*buff, "Unexpected buffer contents.\n"); + ok(buff[3] == 'd', "Unexpected buffer contents.\n"); + + lstrcpyW(buff, strW); + ret = pSHUnicodeToUnicode(testW, buff, 4); + ok(ret == 0, "Unexpected return value %d.\n", ret); + ok(!memcmp(buff, testW, 3 * sizeof(WCHAR)) && !buff[3], "Unexpected buffer contents.\n"); + ok(buff[4] == 'e', "Unexpected buffer contents.\n"); + + lstrcpyW(buff, strW); + ret = pSHUnicodeToUnicode(testW, buff, 5); + ok(ret == 5, "Unexpected return value %d.\n", ret); + ok(!lstrcmpW(buff, testW), "Unexpected buffer contents.\n"); + ok(buff[5] == 'f', "Unexpected buffer contents.\n"); + + lstrcpyW(buff, strW); + ret = pSHUnicodeToUnicode(testW, buff, 6); + ok(ret == 5, "Unexpected return value %d.\n", ret); + ok(!lstrcmpW(buff, testW), "Unexpected buffer contents.\n"); + ok(buff[5] == 'f', "Unexpected buffer contents.\n"); +} + START_TEST(shcore) { HMODULE hshcore = LoadLibraryA("shcore.dll"); @@ -135,4 +313,8 @@ START_TEST(shcore) init(hshcore);
test_process_reference(); + test_SHUnicodeToAnsi(); + test_SHAnsiToUnicode(); + test_SHAnsiToAnsi(); + test_SHUnicodeToUnicode(); }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/shcore/Makefile.in | 2 +- dlls/shcore/main.c | 240 +++++++++++++++++++++++++++++++++++++--- dlls/shcore/shcore.spec | 8 +- 3 files changed, 228 insertions(+), 22 deletions(-)
diff --git a/dlls/shcore/Makefile.in b/dlls/shcore/Makefile.in index 050be57804..ccef84e87d 100644 --- a/dlls/shcore/Makefile.in +++ b/dlls/shcore/Makefile.in @@ -1,5 +1,5 @@ MODULE = shcore.dll -IMPORTS = user32 gdi32 ole32 +IMPORTS = user32 gdi32 ole32 advapi32
C_SRCS = \ main.c diff --git a/dlls/shcore/main.c b/dlls/shcore/main.c index 88c36ecf2d..1228c9d0e1 100644 --- a/dlls/shcore/main.c +++ b/dlls/shcore/main.c @@ -517,6 +517,9 @@ struct shstream BYTE *buffer; DWORD length; DWORD position; + + HKEY hkey; + WCHAR *valuename; } mem; struct { @@ -776,6 +779,29 @@ static const IStreamVtbl memstreamvtbl = shstream_Clone, };
+static struct shstream *shstream_create(const IStreamVtbl *vtbl, const BYTE *data, UINT data_len) +{ + struct shstream *stream; + + if (!data) + data_len = 0; + + stream = heap_alloc(sizeof(*stream)); + stream->IStream_iface.lpVtbl = vtbl; + stream->refcount = 1; + stream->u.mem.buffer = heap_alloc(data_len); + if (!stream->u.mem.buffer) + { + heap_free(stream); + return NULL; + } + memcpy(stream->u.mem.buffer, data, data_len); + stream->u.mem.length = data_len; + stream->u.mem.position = 0; + + return stream; +} + /************************************************************************* * SHCreateMemStream [SHCORE.@] * @@ -798,23 +824,8 @@ IStream * WINAPI SHCreateMemStream(const BYTE *data, UINT data_len)
TRACE("(%p, %u)\n", data, data_len);
- if (!data) - data_len = 0; - - stream = heap_alloc(sizeof(*stream)); - stream->IStream_iface.lpVtbl = &memstreamvtbl; - stream->refcount = 1; - stream->u.mem.buffer = heap_alloc(data_len); - if (!stream->u.mem.buffer) - { - heap_free(stream); - return NULL; - } - memcpy(stream->u.mem.buffer, data, data_len); - stream->u.mem.length = data_len; - stream->u.mem.position = 0; - - return &stream->IStream_iface; + stream = shstream_create(&memstreamvtbl, data, data_len); + return stream ? &stream->IStream_iface : NULL; }
static ULONG WINAPI filestream_Release(IStream *iface) @@ -1134,6 +1145,201 @@ HRESULT WINAPI SHCreateStreamOnFileA(const char *path, DWORD mode, IStream **str return hr; }
+static ULONG WINAPI regstream_Release(IStream *iface) +{ + struct shstream *stream = impl_from_IStream(iface); + ULONG refcount = InterlockedDecrement(&stream->refcount); + + TRACE("(%p)->(%u)\n", stream, refcount); + + if (!refcount) + { + if (stream->u.mem.hkey) + { + if (stream->u.mem.length) + RegSetValueExW(stream->u.mem.hkey, stream->u.mem.valuename, 0, REG_BINARY, + (const BYTE *)stream->u.mem.buffer, stream->u.mem.length); + else + RegDeleteValueW(stream->u.mem.hkey, stream->u.mem.valuename); + RegCloseKey(stream->u.mem.hkey); + } + CoTaskMemFree(stream->u.mem.valuename); + heap_free(stream->u.mem.buffer); + heap_free(stream); + } + + return refcount; +} + +static const IStreamVtbl regstreamvtbl = +{ + shstream_QueryInterface, + shstream_AddRef, + regstream_Release, + memstream_Read, + memstream_Write, + memstream_Seek, + memstream_SetSize, + shstream_CopyTo, + shstream_Commit, + shstream_Revert, + shstream_LockRegion, + shstream_UnlockRegion, + memstream_Stat, + shstream_Clone, +}; + +/************************************************************************* + * SHOpenRegStream2W [SHCORE.@] + */ +IStream * WINAPI SHOpenRegStream2W(HKEY hKey, const WCHAR *subkey, const WCHAR *value, DWORD mode) +{ + struct shstream *stream; + HKEY hStrKey = NULL; + BYTE *buff = NULL; + DWORD length = 0; + LONG ret; + + TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_w(subkey), debugstr_w(value), mode); + + if (mode == STGM_READ) + ret = RegOpenKeyExW(hKey, subkey, 0, KEY_READ, &hStrKey); + else /* in write mode we make sure the subkey exits */ + ret = RegCreateKeyExW(hKey, subkey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hStrKey, NULL); + + if (ret == ERROR_SUCCESS) + { + if (mode == STGM_READ || mode == STGM_READWRITE) + { + /* read initial data */ + ret = RegQueryValueExW(hStrKey, value, 0, 0, 0, &length); + if (ret == ERROR_SUCCESS && length) + { + buff = heap_alloc(length); + RegQueryValueExW(hStrKey, value, 0, 0, buff, &length); + } + } + + if (!length) + buff = heap_alloc(length); + + stream = shstream_create(®streamvtbl, buff, length); + heap_free(buff); + if (stream) + { + stream->u.mem.hkey = hStrKey; + SHStrDupW(value, &stream->u.mem.valuename); + return &stream->IStream_iface; + } + } + + heap_free(buff); + if (hStrKey) + RegCloseKey(hStrKey); + + return NULL; +} + +/************************************************************************* + * SHOpenRegStream2A [SHCORE.@] + */ +IStream * WINAPI SHOpenRegStream2A(HKEY hKey, const char *subkey, const char *value, DWORD mode) +{ + WCHAR *subkeyW = NULL, *valueW = NULL; + IStream *stream; + + TRACE("(%p, %s, %s, %#x)\n", hKey, debugstr_a(subkey), debugstr_a(value), mode); + + if (subkey && FAILED(SHStrDupA(subkey, &subkeyW))) + return NULL; + if (value && FAILED(SHStrDupA(value, &valueW))) + { + CoTaskMemFree(subkeyW); + return NULL; + } + + stream = SHOpenRegStream2W(hKey, subkeyW, valueW, mode); + CoTaskMemFree(subkeyW); + CoTaskMemFree(valueW); + return stream; +} + +/************************************************************************* + * SHOpenRegStreamA [SHCORE.@] + */ +IStream * WINAPI SHOpenRegStreamA(HKEY hkey, const char *subkey, const char *value, DWORD mode) +{ + WCHAR *subkeyW = NULL, *valueW = NULL; + IStream *stream; + + TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_a(subkey), debugstr_a(value), mode); + + if (subkey && FAILED(SHStrDupA(subkey, &subkeyW))) + return NULL; + if (value && FAILED(SHStrDupA(value, &valueW))) + { + CoTaskMemFree(subkeyW); + return NULL; + } + + stream = SHOpenRegStreamW(hkey, subkeyW, valueW, mode); + CoTaskMemFree(subkeyW); + CoTaskMemFree(valueW); + return stream; +} + +static ULONG WINAPI dummystream_AddRef(IStream *iface) +{ + TRACE("()\n"); + return 2; +} + +static ULONG WINAPI dummystream_Release(IStream *iface) +{ + TRACE("()\n"); + return 1; +} + +static HRESULT WINAPI dummystream_Read(IStream *iface, void *buff, ULONG buff_size, ULONG *read_len) +{ + if (read_len) + *read_len = 0; + + return E_NOTIMPL; +} + +static const IStreamVtbl dummystreamvtbl = +{ + shstream_QueryInterface, + dummystream_AddRef, + dummystream_Release, + dummystream_Read, + memstream_Write, + memstream_Seek, + memstream_SetSize, + shstream_CopyTo, + shstream_Commit, + shstream_Revert, + shstream_LockRegion, + shstream_UnlockRegion, + memstream_Stat, + shstream_Clone, +}; + +static struct shstream dummyregstream = { { &dummystreamvtbl } }; + +/************************************************************************* + * SHOpenRegStreamW [SHCORE.@] + */ +IStream * WINAPI SHOpenRegStreamW(HKEY hkey, const WCHAR *subkey, const WCHAR *value, DWORD mode) +{ + IStream *stream; + + TRACE("(%p, %s, %s, %#x)\n", hkey, debugstr_w(subkey), debugstr_w(value), mode); + stream = SHOpenRegStream2W(hkey, subkey, value, mode); + return stream ? stream : &dummyregstream.IStream_iface; +} + struct threadref { IUnknown IUnknown_iface; diff --git a/dlls/shcore/shcore.spec b/dlls/shcore/shcore.spec index 918ba5595c..bd2bf12df1 100644 --- a/dlls/shcore/shcore.spec +++ b/dlls/shcore/shcore.spec @@ -53,10 +53,10 @@ @ stdcall SHGetThreadRef(ptr) @ stdcall SHGetValueA( long str str ptr ptr ptr ) shlwapi.SHGetValueA @ stdcall SHGetValueW( long wstr wstr ptr ptr ptr ) shlwapi.SHGetValueW -@ stdcall SHOpenRegStream2A(long str str long) shlwapi.SHOpenRegStream2A -@ stdcall SHOpenRegStream2W(long wstr wstr long) shlwapi.SHOpenRegStream2W -@ stdcall SHOpenRegStreamA(long str str long) shlwapi.SHOpenRegStreamA -@ stdcall SHOpenRegStreamW(long wstr wstr long) shlwapi.SHOpenRegStreamW +@ stdcall SHOpenRegStream2A(long str str long) +@ stdcall SHOpenRegStream2W(long wstr wstr long) +@ stdcall SHOpenRegStreamA(long str str long) +@ stdcall SHOpenRegStreamW(long wstr wstr long) @ stdcall SHQueryInfoKeyA(long ptr ptr ptr ptr) shlwapi.SHQueryInfoKeyA @ stdcall SHQueryInfoKeyW(long ptr ptr ptr ptr) shlwapi.SHQueryInfoKeyW @ stdcall SHQueryValueExA(long str ptr ptr ptr ptr) shlwapi.SHQueryValueExA
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/shcore/main.c | 12 ++++++++++++ dlls/shcore/shcore.spec | 2 +- dlls/shcore/tests/Makefile.in | 1 + dlls/shcore/tests/shcore.c | 20 ++++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/dlls/shcore/main.c b/dlls/shcore/main.c index 1228c9d0e1..96ba7d791b 100644 --- a/dlls/shcore/main.c +++ b/dlls/shcore/main.c @@ -1751,3 +1751,15 @@ DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len)
return ret; } + +/************************************************************************* + * SHRegDuplicateHKey [SHCORE.@] + */ +HKEY WINAPI SHRegDuplicateHKey(HKEY hKey) +{ + HKEY newKey = 0; + + RegOpenKeyExW(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey); + TRACE("new key is %p\n", newKey); + return newKey; +} diff --git a/dlls/shcore/shcore.spec b/dlls/shcore/shcore.spec index bd2bf12df1..c7a8744a2c 100644 --- a/dlls/shcore/shcore.spec +++ b/dlls/shcore/shcore.spec @@ -61,7 +61,7 @@ @ stdcall SHQueryInfoKeyW(long ptr ptr ptr ptr) shlwapi.SHQueryInfoKeyW @ stdcall SHQueryValueExA(long str ptr ptr ptr ptr) shlwapi.SHQueryValueExA @ stdcall SHQueryValueExW(long wstr ptr ptr ptr ptr) shlwapi.SHQueryValueExW -@ stdcall SHRegDuplicateHKey(long) shlwapi.SHRegDuplicateHKey +@ stdcall SHRegDuplicateHKey(long) @ stdcall SHRegGetIntW(ptr wstr long) shlwapi.SHRegGetIntW @ stdcall SHRegGetPathA(long str str ptr long) shlwapi.SHRegGetPathA @ stdcall SHRegGetPathW(long wstr wstr ptr long) shlwapi.SHRegGetPathW diff --git a/dlls/shcore/tests/Makefile.in b/dlls/shcore/tests/Makefile.in index 0ea769a348..4f537fa387 100644 --- a/dlls/shcore/tests/Makefile.in +++ b/dlls/shcore/tests/Makefile.in @@ -1,4 +1,5 @@ TESTDLL = shcore.dll +IMPORTS = advapi32
C_SRCS = \ shcore.c diff --git a/dlls/shcore/tests/shcore.c b/dlls/shcore/tests/shcore.c index f788afdd22..0945e12174 100644 --- a/dlls/shcore/tests/shcore.c +++ b/dlls/shcore/tests/shcore.c @@ -33,6 +33,7 @@ static int (WINAPI *pSHUnicodeToAnsi)(const WCHAR *, char *, int); static int (WINAPI *pSHAnsiToUnicode)(const char *, WCHAR *, int); static int (WINAPI *pSHAnsiToAnsi)(const char *, char *, int); static int (WINAPI *pSHUnicodeToUnicode)(const WCHAR *, WCHAR *, int); +static HKEY (WINAPI *pSHRegDuplicateHKey)(HKEY);
static void init(HMODULE hshcore) { @@ -43,6 +44,7 @@ static void init(HMODULE hshcore) X(SHAnsiToUnicode); X(SHAnsiToAnsi); X(SHUnicodeToUnicode); + X(SHRegDuplicateHKey); #undef X }
@@ -300,6 +302,23 @@ static void test_SHUnicodeToUnicode(void) ok(buff[5] == 'f', "Unexpected buffer contents.\n"); }
+static void test_SHRegDuplicateHKey(void) +{ + HKEY hkey, hkey2; + DWORD ret; + + ret = RegCreateKeyA(HKEY_CURRENT_USER, "Software\Wine\Test", &hkey); + ok(!ret, "Failed to create test key, ret %d.\n", ret); + + hkey2 = pSHRegDuplicateHKey(hkey); + ok(hkey2 != NULL && hkey2 != hkey, "Unexpected duplicate key.\n"); + + RegCloseKey(hkey2); + RegCloseKey(hkey); + + RegDeleteKeyA(HKEY_CURRENT_USER, "Software\Wine\Test"); +} + START_TEST(shcore) { HMODULE hshcore = LoadLibraryA("shcore.dll"); @@ -317,4 +336,5 @@ START_TEST(shcore) test_SHAnsiToUnicode(); test_SHAnsiToAnsi(); test_SHUnicodeToUnicode(); + test_SHRegDuplicateHKey(); }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/shcore/main.c | 110 +++++++++++++++++++++++++++++++++++++ dlls/shcore/shcore.spec | 12 ++-- dlls/shcore/tests/shcore.c | 25 +++++++++ 3 files changed, 141 insertions(+), 6 deletions(-)
diff --git a/dlls/shcore/main.c b/dlls/shcore/main.c index 96ba7d791b..94e1ab1bbb 100644 --- a/dlls/shcore/main.c +++ b/dlls/shcore/main.c @@ -1763,3 +1763,113 @@ HKEY WINAPI SHRegDuplicateHKey(HKEY hKey) TRACE("new key is %p\n", newKey); return newKey; } + +/************************************************************************* + * SHDeleteEmptyKeyW [SHCORE.@] + */ +DWORD WINAPI SHDeleteEmptyKeyW(HKEY hkey, const WCHAR *subkey) +{ + DWORD ret, count = 0; + HKEY hsubkey = 0; + + TRACE("(%p, %s)\n", hkey, debugstr_w(subkey)); + + ret = RegOpenKeyExW(hkey, subkey, 0, KEY_READ, &hsubkey); + if (!ret) + { + ret = RegQueryInfoKeyW(hsubkey, NULL, NULL, NULL, &count, + NULL, NULL, NULL, NULL, NULL, NULL, NULL); + RegCloseKey(hsubkey); + if (!ret) + { + if (count) + ret = ERROR_KEY_HAS_CHILDREN; + else + ret = RegDeleteKeyW(hkey, subkey); + } + } + + return ret; +} + +/************************************************************************* + * SHDeleteEmptyKeyA [SHCORE.@] + */ +DWORD WINAPI SHDeleteEmptyKeyA(HKEY hkey, const char *subkey) +{ + WCHAR *subkeyW = NULL; + DWORD ret; + + TRACE("(%p, %s)\n", hkey, debugstr_a(subkey)); + + if (subkey && FAILED(SHStrDupA(subkey, &subkeyW))) + return ERROR_OUTOFMEMORY; + + ret = SHDeleteEmptyKeyW(hkey, subkeyW); + CoTaskMemFree(subkeyW); + return ret; +} + +/************************************************************************* + * SHDeleteKeyW [SHCORE.@] + */ +DWORD WINAPI SHDeleteKeyW(HKEY hkey, const WCHAR *subkey) +{ + TRACE("(%p, %s)\n", hkey, debugstr_w(subkey)); + + return RegDeleteTreeW(hkey, subkey); +} + +/************************************************************************* + * SHDeleteKeyA [SHCORE.@] + */ +DWORD WINAPI SHDeleteKeyA(HKEY hkey, const char *subkey) +{ + TRACE("(%p, %s)\n", hkey, debugstr_a(subkey)); + + return RegDeleteTreeA(hkey, subkey); +} + +/************************************************************************* + * SHDeleteValueW [SHCORE.@] + */ +DWORD WINAPI SHDeleteValueW(HKEY hkey, const WCHAR *subkey, const WCHAR *value) +{ + HKEY hsubkey; + DWORD ret; + + TRACE("(%p, %s, %s)\n", hkey, debugstr_w(subkey), debugstr_w(value)); + + ret = RegOpenKeyExW(hkey, subkey, 0, KEY_SET_VALUE, &hsubkey); + if (!ret) + { + ret = RegDeleteValueW(hsubkey, value); + RegCloseKey(hsubkey); + } + + return ret; +} + +/************************************************************************* + * SHDeleteValueA [SHCORE.@] + */ +DWORD WINAPI SHDeleteValueA(HKEY hkey, const char *subkey, const char *value) +{ + WCHAR *subkeyW = NULL, *valueW = NULL; + DWORD ret; + + TRACE("(%p, %s, %s)\n", hkey, debugstr_a(subkey), debugstr_a(value)); + + if (subkey && FAILED(SHStrDupA(subkey, &subkeyW))) + return ERROR_OUTOFMEMORY; + if (value && FAILED(SHStrDupA(value, &valueW))) + { + CoTaskMemFree(subkeyW); + return ERROR_OUTOFMEMORY; + } + + ret = SHDeleteValueW(hkey, subkeyW, valueW); + CoTaskMemFree(subkeyW); + CoTaskMemFree(valueW); + return ret; +} diff --git a/dlls/shcore/shcore.spec b/dlls/shcore/shcore.spec index c7a8744a2c..d6e48368ae 100644 --- a/dlls/shcore/shcore.spec +++ b/dlls/shcore/shcore.spec @@ -40,12 +40,12 @@ @ stdcall SHCreateThread(ptr ptr long ptr) @ stdcall SHCreateThreadRef(ptr ptr) @ stub SHCreateThreadWithHandle -@ stdcall SHDeleteEmptyKeyA(long ptr) shlwapi.SHDeleteEmptyKeyA -@ stdcall SHDeleteEmptyKeyW(long ptr) shlwapi.SHDeleteEmptyKeyW -@ stdcall SHDeleteKeyA(long str) shlwapi.SHDeleteKeyA -@ stdcall SHDeleteKeyW(long wstr) shlwapi.SHDeleteKeyW -@ stdcall SHDeleteValueA(long str str) shlwapi.SHDeleteValueA -@ stdcall SHDeleteValueW(long wstr wstr) shlwapi.SHDeleteValueW +@ stdcall SHDeleteEmptyKeyA(long ptr) +@ stdcall SHDeleteEmptyKeyW(long ptr) +@ stdcall SHDeleteKeyA(long str) +@ stdcall SHDeleteKeyW(long wstr) +@ stdcall SHDeleteValueA(long str str) +@ stdcall SHDeleteValueW(long wstr wstr) @ stdcall SHEnumKeyExA(long long str ptr) shlwapi.SHEnumKeyExA @ stdcall SHEnumKeyExW(long long wstr ptr) shlwapi.SHEnumKeyExW @ stdcall SHEnumValueA(long long str ptr ptr ptr ptr) shlwapi.SHEnumValueA diff --git a/dlls/shcore/tests/shcore.c b/dlls/shcore/tests/shcore.c index 0945e12174..e1af2a2edc 100644 --- a/dlls/shcore/tests/shcore.c +++ b/dlls/shcore/tests/shcore.c @@ -34,6 +34,7 @@ static int (WINAPI *pSHAnsiToUnicode)(const char *, WCHAR *, int); static int (WINAPI *pSHAnsiToAnsi)(const char *, char *, int); static int (WINAPI *pSHUnicodeToUnicode)(const WCHAR *, WCHAR *, int); static HKEY (WINAPI *pSHRegDuplicateHKey)(HKEY); +static DWORD (WINAPI *pSHDeleteKeyA)(HKEY, const char *);
static void init(HMODULE hshcore) { @@ -45,6 +46,7 @@ static void init(HMODULE hshcore) X(SHAnsiToAnsi); X(SHUnicodeToUnicode); X(SHRegDuplicateHKey); + X(SHDeleteKeyA); #undef X }
@@ -319,6 +321,28 @@ static void test_SHRegDuplicateHKey(void) RegDeleteKeyA(HKEY_CURRENT_USER, "Software\Wine\Test"); }
+static void test_SHDeleteKey(void) +{ + HKEY hkey, hkey2; + DWORD ret; + + ret = RegCreateKeyA(HKEY_CURRENT_USER, "Software\Wine\Test", &hkey); + ok(!ret, "Failed to create test key, %d.\n", ret); + + ret = RegCreateKeyA(hkey, "delete_key", &hkey2); + ok(!ret, "Failed to create test key, %d.\n", ret); + RegCloseKey(hkey2); + + ret = RegDeleteKeyA(HKEY_CURRENT_USER, "Software\Wine\Test"); + ok(ret == ERROR_ACCESS_DENIED, "Unexpected return value %d.\n", ret); + + ret = pSHDeleteKeyA(HKEY_CURRENT_USER, "Software\Wine\Test"); + ok(!ret, "Failed to delete a key, %d.\n", ret); + + ret = RegCloseKey(hkey); + ok(!ret, "Failed to delete a key, %d.\n", ret); +} + START_TEST(shcore) { HMODULE hshcore = LoadLibraryA("shcore.dll"); @@ -337,4 +361,5 @@ START_TEST(shcore) test_SHAnsiToAnsi(); test_SHUnicodeToUnicode(); test_SHRegDuplicateHKey(); + test_SHDeleteKey(); }
This still looks unnecessarily complicative IMO.
Nikolay Sivov nsivov@codeweavers.com wrote:
+DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len) +{
- DWORD ret;
- TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
- if (!src || !dest || dest_len <= 0)
return 0;
- lstrcpynA(dest, src, dest_len);
- ret = strlen(dest);
- return src[ret] ? 0 : ret + 1;
+}
lstrcpynA(dest, src, dest_len); ret = strlen(dest); if (ret) ret++; return ret;
+DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len) +{
- int ret = 1;
- TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
- if (!dest || !dest_len)
return 0;
- if (src)
- {
ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
if (!ret)
{
dest[dest_len - 1] = 0;
ret = dest_len;
}
- }
- else
dest[0] = 0;
- return ret;
+}
if (!src) { *dst = 0; return 1; }
if (!WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL)) dest[dest_len - 1] = 0; return dest_len;
On 11/29/18 12:22 PM, Dmitry Timoshkov wrote:
This still looks unnecessarily complicative IMO.
Nikolay Sivov nsivov@codeweavers.com wrote:
+DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len) +{
- DWORD ret;
- TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
- if (!src || !dest || dest_len <= 0)
return 0;
- lstrcpynA(dest, src, dest_len);
- ret = strlen(dest);
- return src[ret] ? 0 : ret + 1;
+}
lstrcpynA(dest, src, dest_len); ret = strlen(dest); if (ret) ret++; return ret;
It won't pass the tests.
+DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len) +{
- int ret = 1;
- TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
- if (!dest || !dest_len)
return 0;
- if (src)
- {
ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
if (!ret)
{
dest[dest_len - 1] = 0;
ret = dest_len;
}
- }
- else
dest[0] = 0;
- return ret;
+}
if (!src) { *dst = 0; return 1; }
if (!WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL)) dest[dest_len - 1] = 0; return dest_len;
This does the same thing.
Nikolay Sivov nsivov@codeweavers.com wrote:
+DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len) +{
- DWORD ret;
- TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
- if (!src || !dest || dest_len <= 0)
return 0;
- lstrcpynA(dest, src, dest_len);
- ret = strlen(dest);
- return src[ret] ? 0 : ret + 1;
+}
lstrcpynA(dest, src, dest_len); ret = strlen(dest); if (ret) ret++; return ret;
It won't pass the tests.
... because of a typo.
+DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len) +{
- int ret = 1;
- TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
- if (!dest || !dest_len)
return 0;
- if (src)
- {
ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
if (!ret)
{
dest[dest_len - 1] = 0;
ret = dest_len;
}
- }
- else
dest[0] = 0;
- return ret;
+}
if (!src) { *dst = 0; return 1; }
if (!WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL)) dest[dest_len - 1] = 0; return dest_len;
This does the same thing.
That's the whole point: do the same thing using simpler code.
On Thu, Nov 29, 2018 at 12:02 PM Dmitry Timoshkov dmitry@baikal.ru wrote:
Nikolay Sivov nsivov@codeweavers.com wrote:
+DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len) +{
- DWORD ret;
- TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
- if (!src || !dest || dest_len <= 0)
return 0;
- lstrcpynA(dest, src, dest_len);
- ret = strlen(dest);
- return src[ret] ? 0 : ret + 1;
+}
lstrcpynA(dest, src, dest_len); ret = strlen(dest); if (ret) ret++; return ret;
It won't pass the tests.
... because of a typo.
Nikolay had a point here, though: this scans the string twice, but at this point it probably doesn't matter.
On a related note: I'm wondering if we should have a custom Wine strcpy helper (at least for wide version) for cases like these.
All it would do is return the string's end instead of the beginning (which is completely useless), or return the amount copied, whatever. Something useful.
Then we can easily do (ret - base) to get the length. strcpyW would be implemented on top of it then.
Just an idea.
Dmitry Timoshkov dmitry@baikal.ru writes:
Nikolay Sivov nsivov@codeweavers.com wrote:
if (!src) { *dst = 0; return 1; }
if (!WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL)) dest[dest_len - 1] = 0; return dest_len;
This does the same thing.
That's the whole point: do the same thing using simpler code.
It doesn't do the same thing, the return value is wrong.
Alexandre Julliard julliard@winehq.org wrote:
if (!src) { *dst = 0; return 1; }
if (!WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL)) dest[dest_len - 1] = 0; return dest_len;
This does the same thing.
That's the whole point: do the same thing using simpler code.
It doesn't do the same thing, the return value is wrong.
You are right of course, thanks.