Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/shcore/main.c | 102 +++++++++++++++++++++++++++++++++++++ dlls/shcore/shcore.spec | 8 +-- dlls/shcore/tests/shcore.c | 95 ++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+), 4 deletions(-)
diff --git a/dlls/shcore/main.c b/dlls/shcore/main.c index bf477aefcc..2f32a741f4 100644 --- a/dlls/shcore/main.c +++ b/dlls/shcore/main.c @@ -1455,3 +1455,105 @@ 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 = 0; + + TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len); + + if (!src || !dest || dest_len <= 0) + return 0; + + while (dest_len > 1 && *src) + { + dest_len--; + *dest++ = *src++; + ret++; + } + + if (dest_len) + { + *dest = 0; + ret++; + } + + return ret; +} + +/************************************************************************* + * SHUnicodeToAnsi [SHCORE.@] + */ +DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len) +{ + int required = 1; + + TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len); + + if (!dest || !dest_len) + return 0; + + if (src) + { + required = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL); + } + dest_len = min(required, dest_len); + + dest[dest_len - 1] = 0; + return dest_len; +} + +/************************************************************************* + * SHUnicodeToUnicode [SHCORE.@] + */ +DWORD WINAPI SHUnicodeToUnicode(const WCHAR *src, WCHAR *dest, int dest_len) +{ + DWORD ret = 0; + + TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len); + + if (!src || !dest || dest_len <= 0) + return 0; + + while (dest_len > 1 && *src) + { + dest_len--; + *dest++ = *src++; + ret++; + } + + if (dest_len) + { + *dest = 0; + ret++; + } + + return ret; +} + +/************************************************************************* + * SHAnsiToUnicode [SHCORE.@] + */ +DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len) +{ + int required = 1; + + TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len); + + if (!dest || !dest_len) + return 0; + + if (src) + { + required = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); + MultiByteToWideChar(CP_ACP, 0, src, -1, dest, dest_len); + } + dest_len = min(required, dest_len); + + dest[dest_len - 1] = 0; + return dest_len; +} 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..15fcda5449 100644 --- a/dlls/shcore/tests/shcore.c +++ b/dlls/shcore/tests/shcore.c @@ -29,12 +29,16 @@ 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 void init(HMODULE hshcore) { #define X(f) p##f = (void*)GetProcAddress(hshcore, #f) X(GetProcessReference); X(SetProcessReference); + X(SHUnicodeToAnsi); + X(SHAnsiToUnicode); #undef X }
@@ -122,6 +126,95 @@ 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"); +} + START_TEST(shcore) { HMODULE hshcore = LoadLibraryA("shcore.dll"); @@ -135,4 +228,6 @@ START_TEST(shcore) init(hshcore);
test_process_reference(); + test_SHUnicodeToAnsi(); + test_SHAnsiToUnicode(); }
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 2f32a741f4..2c592c858c 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 2c592c858c..906eb78c72 100644 --- a/dlls/shcore/main.c +++ b/dlls/shcore/main.c @@ -1763,3 +1763,15 @@ DWORD WINAPI SHAnsiToUnicode(const char *src, WCHAR *dest, int dest_len) dest[dest_len - 1] = 0; return dest_len; } + +/************************************************************************* + * 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 15fcda5449..7412297804 100644 --- a/dlls/shcore/tests/shcore.c +++ b/dlls/shcore/tests/shcore.c @@ -31,6 +31,7 @@ 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 HKEY (WINAPI *pSHRegDuplicateHKey)(HKEY);
static void init(HMODULE hshcore) { @@ -39,6 +40,7 @@ static void init(HMODULE hshcore) X(SetProcessReference); X(SHUnicodeToAnsi); X(SHAnsiToUnicode); + X(SHRegDuplicateHKey); #undef X }
@@ -215,6 +217,23 @@ static void test_SHAnsiToUnicode(void) ok(buffW[0] == 't' && buffW[1] == 0, "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"); @@ -230,4 +249,5 @@ START_TEST(shcore) test_process_reference(); test_SHUnicodeToAnsi(); test_SHAnsiToUnicode(); + 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 906eb78c72..b332b3c72b 100644 --- a/dlls/shcore/main.c +++ b/dlls/shcore/main.c @@ -1775,3 +1775,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..8b02cfbf21 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 str) +@ stdcall SHDeleteEmptyKeyW(long wstr) +@ 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 7412297804..bf9ad8e505 100644 --- a/dlls/shcore/tests/shcore.c +++ b/dlls/shcore/tests/shcore.c @@ -32,6 +32,7 @@ static HRESULT (WINAPI *pSHGetInstanceExplorer)(IUnknown **); static int (WINAPI *pSHUnicodeToAnsi)(const WCHAR *, char *, int); static int (WINAPI *pSHAnsiToUnicode)(const char *, WCHAR *, int); static HKEY (WINAPI *pSHRegDuplicateHKey)(HKEY); +static DWORD (WINAPI *pSHDeleteKeyA)(HKEY, const char *);
static void init(HMODULE hshcore) { @@ -41,6 +42,7 @@ static void init(HMODULE hshcore) X(SHUnicodeToAnsi); X(SHAnsiToUnicode); X(SHRegDuplicateHKey); + X(SHDeleteKeyA); #undef X }
@@ -234,6 +236,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"); @@ -250,4 +274,5 @@ START_TEST(shcore) test_SHUnicodeToAnsi(); test_SHAnsiToUnicode(); test_SHRegDuplicateHKey(); + test_SHDeleteKey(); }
Nikolay Sivov nsivov@codeweavers.com wrote:
+DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len) +{
- DWORD ret = 0;
- TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
- if (!src || !dest || dest_len <= 0)
return 0;
- while (dest_len > 1 && *src)
- {
dest_len--;
*dest++ = *src++;
ret++;
- }
- if (dest_len)
- {
*dest = 0;
ret++;
- }
- return ret;
+}
Still the same duplication without a reasonable explanation.
+DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len) +{
- int required = 1;
- TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
- if (!dest || !dest_len)
return 0;
- if (src)
- {
required = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
It should be possible to avoid doing the conversion twice.
Same comments apply for remaining implementations.
On 11/29/18 9:10 AM, Dmitry Timoshkov wrote:
Nikolay Sivov nsivov@codeweavers.com wrote:
+DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len) +{
- DWORD ret = 0;
- TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
- if (!src || !dest || dest_len <= 0)
return 0;
- while (dest_len > 1 && *src)
- {
dest_len--;
*dest++ = *src++;
ret++;
- }
- if (dest_len)
- {
*dest = 0;
ret++;
- }
- return ret;
+}
Still the same duplication without a reasonable explanation.
It's used to get correct return value.
+DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len) +{
- int required = 1;
- TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
- if (!dest || !dest_len)
return 0;
- if (src)
- {
required = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
It should be possible to avoid doing the conversion twice.
Second call returns 0 for shorter buffer. If you have actual suggestion I'm sure nobody would mind if you posted it.
Same comments apply for remaining implementations.
Nikolay Sivov nsivov@codeweavers.com wrote:
+DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len) +{
- DWORD ret = 0;
- TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
- if (!src || !dest || dest_len <= 0)
return 0;
- while (dest_len > 1 && *src)
- {
dest_len--;
*dest++ = *src++;
ret++;
- }
- if (dest_len)
- {
*dest = 0;
ret++;
- }
- return ret;
+}
Still the same duplication without a reasonable explanation.
It's used to get correct return value.
lstrcpynA(dst, src, dstlen); return strlen(dst) + 1;
+DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len) +{
- int required = 1;
- TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
- if (!dest || !dest_len)
return 0;
- if (src)
- {
required = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
It should be possible to avoid doing the conversion twice.
Second call returns 0 for shorter buffer.
ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL); if (!ret) dest[dest_len - 1] = 0; return dest_len;
If you have actual suggestion I'm sure nobody would mind if you posted it.
Sure.
On 11/29/18 9:34 AM, Dmitry Timoshkov wrote:
Nikolay Sivov nsivov@codeweavers.com wrote:
+DWORD WINAPI SHAnsiToAnsi(const char *src, char *dest, int dest_len) +{
- DWORD ret = 0;
- TRACE("(%s, %p, %d)\n", debugstr_a(src), dest, dest_len);
- if (!src || !dest || dest_len <= 0)
return 0;
- while (dest_len > 1 && *src)
- {
dest_len--;
*dest++ = *src++;
ret++;
- }
- if (dest_len)
- {
*dest = 0;
ret++;
- }
- return ret;
+}
Still the same duplication without a reasonable explanation.
It's used to get correct return value.
lstrcpynA(dst, src, dstlen); return strlen(dst) + 1;
This won't work because it should return 0 in case of truncation. Even if it did work, this duplicates a loop.
I'll add more tests.
+DWORD WINAPI SHUnicodeToAnsi(const WCHAR *src, char *dest, int dest_len) +{
- int required = 1;
- TRACE("(%s, %p, %d)\n", debugstr_w(src), dest, dest_len);
- if (!dest || !dest_len)
return 0;
- if (src)
- {
required = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL);
It should be possible to avoid doing the conversion twice.
Second call returns 0 for shorter buffer.
ret = WideCharToMultiByte(CP_ACP, 0, src, -1, dest, dest_len, NULL, NULL); if (!ret) dest[dest_len - 1] = 0; return dest_len;
Ok.
If you have actual suggestion I'm sure nobody would mind if you posted it.
Sure.