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.
For me this fails on Windows, because test exe is not run with permissions necessary to create the keys. The test is still incomplete - it doesn't test what happens when this chain pointing back to first progid, so { MyApp.DocumentTest.CurVer = MyApp.DocumentTest.1; MyApp.DocumentTest1.CurVer = MyApp.DocumentTest }. On Windows this fails. This should fail properly in case of { Test -> Test.1 -> Test.2 -> Test.1 } too.