If the read ProgID only has a CurVer key and no CLSID key, it will directly return CO_E_CCLASSSTRING, causing the program to fail to continue running.
Add the key value for finding CurVer.
-- v9: combase:clsid_from_string_reg() add read of CurVer key value. ole32/tests:add the find CurVer test in CLSIDFromProgID.
From: Maotong Zhang zmtong1988@gmail.com
--- dlls/ole32/tests/compobj.c | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+)
diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index 94b83024b91..7971b5022f6 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -433,6 +433,8 @@ static void test_CLSIDFromProgID(void) ULONG_PTR cookie = 0; HANDLE handle; CLSID clsid; + HKEY hKey; + WCHAR clsidstr[39]; HRESULT hr = CLSIDFromProgID(stdfont, &clsid); ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08lx\n", hr); ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n"); @@ -441,6 +443,52 @@ static void test_CLSIDFromProgID(void) ok_ole_success(hr, "CLSIDFromString"); ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "clsid wasn't equal to CLSID_StdFont\n");
+ StringFromGUID2(&CLSID_non_existent, clsidstr, ARRAYSIZE(clsidstr)); + if (RegCreateKeyExW(HKEY_CLASSES_ROOT, L"MyApp.DocumentTest\CurVer", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS) + { + RegSetValueExW(hKey, NULL, 0, REG_SZ, (const BYTE *)L"MyApp.DocumentTest.1", (wcslen(L"MyApp.DocumentTest.1") + 1) * sizeof(WCHAR)); + RegCloseKey(hKey); + } + if (RegCreateKeyExW(HKEY_CLASSES_ROOT, L"MyApp.DocumentTest.1\CurVer", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS) + { + RegSetValueExW(hKey, NULL, 0, REG_SZ, (const BYTE *)L"MyApp.DocumentTest.2", (wcslen(L"MyApp.DocumentTest.2") + 1) * sizeof(WCHAR)); + RegCloseKey(hKey); + } + if (RegCreateKeyExW(HKEY_CLASSES_ROOT, L"MyApp.DocumentTest.2\CurVer", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS) + { + RegSetValueExW(hKey, NULL, 0, REG_SZ, (const BYTE *)L"MyApp.DocumentTest.1", (wcslen(L"MyApp.DocumentTest.1") + 1)* sizeof(WCHAR)); + RegCloseKey(hKey); + } + if (RegCreateKeyExW(HKEY_CLASSES_ROOT, L"MyApp.DocumentTest.2\CLSID", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS) + { + RegSetValueExW(hKey, NULL, 0, REG_SZ, (const BYTE *)clsidstr, (wcslen(clsidstr) + 1) * sizeof(WCHAR)); + RegCloseKey(hKey); + } + if (RegCreateKeyExW(HKEY_CLASSES_ROOT, L"MyApp.DocumentTest.3\CurVer", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS) + { + RegCloseKey(hKey); + } + + hr = CLSIDFromProgID(L"MyApp.DocumentTest", &clsid); + ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08lx\n", hr); + ok(IsEqualCLSID(&clsid, &CLSID_non_existent), "got wrong clsid %s\n", wine_dbgstr_guid(&clsid)); + + hr = CLSIDFromProgID(L"MyApp.DocumentTest.1", &clsid); + ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08lx\n", hr); + ok(IsEqualCLSID(&clsid, &CLSID_non_existent), "got wrong clsid %s\n", wine_dbgstr_guid(&clsid)); + + hr = CLSIDFromProgID(L"MyApp.DocumentTest.2", &clsid); + ok(hr == S_OK, "CLSIDFromProgID failed with error 0x%08lx\n", hr); + ok(IsEqualCLSID(&clsid, &CLSID_non_existent), "got wrong clsid %s\n", wine_dbgstr_guid(&clsid)); + + hr = CLSIDFromProgID(L"MyApp.DocumentTest.3", &clsid); + ok(hr == CO_E_CLASSSTRING, "CLSIDFromProgID CurVer content is empty should have returned CO_E_CLASSSTRING instead of 0x%08lx\n", hr); + ok(IsEqualCLSID(&clsid, &CLSID_NULL), "CLSIDFromProgID should have set clsid to all-zeros on failure\n"); + RegDeleteTreeW(HKEY_CLASSES_ROOT, L"MyApp.DocumentTest"); + RegDeleteTreeW(HKEY_CLASSES_ROOT, L"MyApp.DocumentTest.1"); + RegDeleteTreeW(HKEY_CLASSES_ROOT, L"MyApp.DocumentTest.2"); + RegDeleteTreeW(HKEY_CLASSES_ROOT, L"MyApp.DocumentTest.3"); + /* test some failure cases */
hr = CLSIDFromProgID(wszNonExistent, NULL);
From: Maotong Zhang zmtong1988@gmail.com
--- dlls/combase/combase.c | 51 +++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 18 deletions(-)
diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index b3a1c9bd8fc..3ee0fd82544 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -1385,33 +1385,48 @@ static BOOL guid_from_string(LPCWSTR s, GUID *id)
static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid) { - WCHAR buf2[CHARS_IN_GUID]; - LONG buf2len = sizeof(buf2); + HRESULT hr, ret; HKEY xhkey; - WCHAR *buf; + WCHAR szclsid[256] = {0}; + LONG cbclsid = sizeof(szclsid);
- memset(clsid, 0, sizeof(*clsid)); - buf = malloc((lstrlenW(progid) + 8) * sizeof(WCHAR)); - if (!buf) return E_OUTOFMEMORY; + if (!progid) + return E_INVALIDARG;
- lstrcpyW(buf, progid); - lstrcatW(buf, L"\CLSID"); - if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey)) + hr = open_classes_key(HKEY_CLASSES_ROOT, progid, MAXIMUM_ALLOWED, &xhkey); + if (SUCCEEDED(hr)) { - free(buf); - WARN("couldn't open key for ProgID %s\n", debugstr_w(progid)); - return CO_E_CLASSSTRING; + if (RegQueryValueW(xhkey, L"CLSID", szclsid, &cbclsid) != ERROR_SUCCESS) + { + LONG cbcurver = 0; + if (RegQueryValueW(xhkey, L"CurVer", NULL, &cbcurver) == ERROR_SUCCESS && cbcurver > 0) + { + WCHAR *szcurver = (WCHAR *)LocalAlloc(LMEM_FIXED, cbcurver); + if (szcurver) + { + if (RegQueryValueW(xhkey, L"CurVer", szcurver, &cbcurver) == ERROR_SUCCESS) + { + if (lstrcmpiW(szcurver, progid) != 0) + { + RegCloseKey(xhkey); + ret = clsid_from_string_reg(szcurver, clsid); + LocalFree(szcurver); + if (SUCCEEDED(ret)) return ret; + } + } + LocalFree(szcurver); + } + } + } + RegCloseKey(xhkey); } - free(buf);
- if (RegQueryValueW(xhkey, NULL, buf2, &buf2len)) + if (!guid_from_string(szclsid, clsid)) { - RegCloseKey(xhkey); - WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid)); + memset(clsid, 0, sizeof(*clsid)); return CO_E_CLASSSTRING; } - RegCloseKey(xhkey); - return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING; + return S_OK; }
/******************************************************************************
v3:Further improve implementations and expand tests.
clsid_from_string_reg() is only used by CLSIDFromProgID and CLSIDFromString; CLSIDFromString has already been tested, so no additional tests are needed tests will be added only for CLSIDFromProgID.