[PATCH 0/2] MR10565: shcore: Implement Set/GetCurrentProcessExplicitAppUserModelID.
Wine Bug: https://bugs.winehq.org/show_bug.cgi?id=59625 Set/GetCurrentProcessExplicitAppUserModelID were stubs. Set returned S_OK but discarded the value, Get always returned NULL with E_NOTIMPL. This broke .NET WPF applications that set an AppUserModelID during startup and later retrieve it, causing "String argument cannot be null or empty" crashes. Implement both using a process-wide variable protected by a critical section. Callers receive CoTaskMemAlloc'd copies per the API contract. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10565
From: Robert Gerigk <Robert-Gerigk@online.de> Wine's shcore.dll had Set/GetCurrentProcessExplicitAppUserModelID as stubs. SetCurrentProcessExplicitAppUserModelID returned S_OK but discarded the value, and GetCurrentProcessExplicitAppUserModelID always returned NULL with E_NOTIMPL. This broke applications that set an AppUserModelID and later retrieve it, causing "String argument cannot be null or empty" crashes in .NET WPF applications. Implement both functions using a process-wide static variable protected by a critical section. SetCurrentProcessExplicitAppUserModelID stores a CoTaskMemAlloc'd copy of the ID, and GetCurrentProcessExplicitAppUserModelID returns a CoTaskMemAlloc'd copy to the caller. Signed-off-by: Jan Robert Gerigk <Robert-Gerigk@online.de> --- dlls/shcore/main.c | 50 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/dlls/shcore/main.c b/dlls/shcore/main.c index f04853cb9f5..5c29a69d4c9 100644 --- a/dlls/shcore/main.c +++ b/dlls/shcore/main.c @@ -249,17 +249,59 @@ HRESULT WINAPI IUnknown_SetSite(IUnknown *obj, IUnknown *site) return hr; } +static WCHAR *explicit_app_user_model_id; +static CRITICAL_SECTION appid_cs; +static CRITICAL_SECTION_DEBUG appid_cs_debug = +{ + 0, 0, &appid_cs, + { &appid_cs_debug.ProcessLocksList, &appid_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": appid_cs") } +}; +static CRITICAL_SECTION appid_cs = { &appid_cs_debug, -1, 0, 0, 0, 0 }; + HRESULT WINAPI SetCurrentProcessExplicitAppUserModelID(const WCHAR *appid) { - FIXME("%s: stub\n", debugstr_w(appid)); + WCHAR *new_id = NULL; + + TRACE("%s\n", debugstr_w(appid)); + + if (appid) + { + DWORD len = (lstrlenW(appid) + 1) * sizeof(WCHAR); + new_id = CoTaskMemAlloc(len); + if (!new_id) return E_OUTOFMEMORY; + memcpy(new_id, appid, len); + } + + EnterCriticalSection(&appid_cs); + CoTaskMemFree(explicit_app_user_model_id); + explicit_app_user_model_id = new_id; + LeaveCriticalSection(&appid_cs); + return S_OK; } HRESULT WINAPI GetCurrentProcessExplicitAppUserModelID(const WCHAR **appid) { - FIXME("%p: stub\n", appid); - *appid = NULL; - return E_NOTIMPL; + TRACE("%p\n", appid); + + if (!appid) return E_INVALIDARG; + + EnterCriticalSection(&appid_cs); + if (explicit_app_user_model_id) + { + DWORD len = (lstrlenW(explicit_app_user_model_id) + 1) * sizeof(WCHAR); + *appid = CoTaskMemAlloc(len); + if (*appid) + memcpy((WCHAR *)*appid, explicit_app_user_model_id, len); + } + else + { + *appid = NULL; + } + LeaveCriticalSection(&appid_cs); + + return *appid ? S_OK : E_FAIL; } /************************************************************************* -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10565
From: Robert Gerigk <Robert-Gerigk@online.de> Test parameter validation, set/get round-trip, and ID update behavior. Signed-off-by: Jan Robert Gerigk <Robert-Gerigk@online.de> --- dlls/shcore/tests/Makefile.in | 2 +- dlls/shcore/tests/shcore.c | 56 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/dlls/shcore/tests/Makefile.in b/dlls/shcore/tests/Makefile.in index 2b7eaa65686..d40498fda15 100644 --- a/dlls/shcore/tests/Makefile.in +++ b/dlls/shcore/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = shcore.dll -IMPORTS = advapi32 +IMPORTS = advapi32 ole32 SOURCES = \ shcore.c diff --git a/dlls/shcore/tests/shcore.c b/dlls/shcore/tests/shcore.c index 539c2e5c1bc..6dc828a50d1 100644 --- a/dlls/shcore/tests/shcore.c +++ b/dlls/shcore/tests/shcore.c @@ -23,10 +23,13 @@ #include <windows.h> #include "initguid.h" #include "objidl.h" +#include "objbase.h" #include "shlwapi.h" #include "wine/test.h" +static HRESULT (WINAPI *pSetCurrentProcessExplicitAppUserModelID)(const WCHAR *); +static HRESULT (WINAPI *pGetCurrentProcessExplicitAppUserModelID)(const WCHAR **); static HRESULT (WINAPI *pGetProcessReference)(IUnknown **); static void (WINAPI *pSetProcessReference)(IUnknown *); static HRESULT (WINAPI *pSHGetInstanceExplorer)(IUnknown **); @@ -62,6 +65,8 @@ static const char * initial_buffer ="0123456789"; static void init(HMODULE hshcore) { #define X(f) p##f = (void*)GetProcAddress(hshcore, #f) + X(SetCurrentProcessExplicitAppUserModelID); + X(GetCurrentProcessExplicitAppUserModelID); X(GetProcessReference); X(SetProcessReference); X(SHUnicodeToAnsi); @@ -777,6 +782,56 @@ static void test_stream_size(void) DeleteFileA(filename); } +static void test_AppUserModelID(void) +{ + const WCHAR *appid = NULL; + HRESULT hr; + + if (!pSetCurrentProcessExplicitAppUserModelID || !pGetCurrentProcessExplicitAppUserModelID) + { + win_skip("AppUserModelID functions not available.\n"); + return; + } + + /* Get before Set should return E_FAIL or similar */ + appid = (void *)0xdeadbeef; + hr = pGetCurrentProcessExplicitAppUserModelID(&appid); + ok(hr == E_FAIL || hr == E_NOTIMPL, "Got hr %#lx.\n", hr); + ok(appid == NULL, "Expected NULL, got %p.\n", appid); + + /* NULL argument to Get */ + hr = pGetCurrentProcessExplicitAppUserModelID(NULL); + ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr); + + /* Set a valid ID */ + hr = pSetCurrentProcessExplicitAppUserModelID(L"Wine.Test.AppId"); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + /* Get should return the ID we set */ + appid = NULL; + hr = pGetCurrentProcessExplicitAppUserModelID(&appid); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(appid != NULL, "Expected non-NULL appid.\n"); + if (appid) + { + ok(!lstrcmpW(appid, L"Wine.Test.AppId"), "Got %s.\n", wine_dbgstr_w(appid)); + CoTaskMemFree((void *)appid); + } + + /* Set a different ID */ + hr = pSetCurrentProcessExplicitAppUserModelID(L"Wine.Test.AppId2"); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + appid = NULL; + hr = pGetCurrentProcessExplicitAppUserModelID(&appid); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + if (appid) + { + ok(!lstrcmpW(appid, L"Wine.Test.AppId2"), "Got %s.\n", wine_dbgstr_w(appid)); + CoTaskMemFree((void *)appid); + } +} + START_TEST(shcore) { HMODULE hshcore = LoadLibraryA("shcore.dll"); @@ -789,6 +844,7 @@ START_TEST(shcore) init(hshcore); + test_AppUserModelID(); test_process_reference(); test_SHUnicodeToAnsi(); test_SHAnsiToUnicode(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10565
participants (2)
-
Jan Robert Gerigk (@RgSg86) -
Robert Gerigk