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.
-- v13: combase:clsid_from_string_reg() add read of CurVer key value. ole32:Do not zero out when not a CLSID ole32/tests:Remove now succeeding todo_wine
From: Maotong Zhang zmtong1988@gmail.com
--- dlls/ole32/tests/compobj.c | 11 ----------- 1 file changed, 11 deletions(-)
diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index 3f358a8ef8e..b5a4e88b132 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -526,15 +526,11 @@ static void test_CLSIDFromProgID(void) ok(!ret, "Failed to create a test key.\n");
hr = CLSIDFromProgID(L"MyApp.DocumentTest", &clsid); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(IsEqualCLSID(&clsid, &CLSID_non_existent), "Unexpected clsid %s.\n", wine_dbgstr_guid(&clsid));
hr = CLSIDFromProgID(L"MyApp.DocumentTest.1", &clsid); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(IsEqualCLSID(&clsid, &CLSID_non_existent), "Unexpected clsid %s.\n", wine_dbgstr_guid(&clsid));
hr = CLSIDFromProgID(L"MyApp.DocumentTest.2", &clsid); @@ -552,15 +548,11 @@ static void test_CLSIDFromProgID(void) ok(IsEqualCLSID(&clsid, &CLSID_NULL), "Unexpected clsid %s.\n", wine_dbgstr_guid(&clsid));
hr = CLSIDFromString(L"MyApp.DocumentTest", &clsid); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(IsEqualCLSID(&clsid, &CLSID_non_existent), "Unexpected clsid %s.\n", wine_dbgstr_guid(&clsid));
hr = CLSIDFromString(L"MyApp.DocumentTest.1", &clsid); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(IsEqualCLSID(&clsid, &CLSID_non_existent), "Unexpected clsid %s.\n", wine_dbgstr_guid(&clsid));
hr = CLSIDFromString(L"MyApp.DocumentTest.2", &clsid); @@ -569,15 +561,12 @@ static void test_CLSIDFromProgID(void)
clsid = CLSID_StdFont; hr = CLSIDFromString(L"MyApp.DocumentTest.3", &clsid); - todo_wine ok(hr == REGDB_E_INVALIDVALUE, "Unexpected hr %#lx.\n", hr); - todo_wine ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "Unexpected clsid %s.\n", wine_dbgstr_guid(&clsid));
clsid = CLSID_StdFont; hr = CLSIDFromString(L"MyApp.DocumentTest.5", &clsid); ok(hr == CO_E_CLASSSTRING, "Unexpected hr %#lx.\n", hr); - todo_wine ok(IsEqualCLSID(&clsid, &CLSID_StdFont), "Unexpected clsid %s.\n", wine_dbgstr_guid(&clsid));
RegDeleteTreeW(HKEY_CLASSES_ROOT, L"MyApp.DocumentTest");
From: Maotong Zhang zmtong1988@gmail.com
--- dlls/combase/combase.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index b3a1c9bd8fc..dee1df02697 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -1333,8 +1333,11 @@ static BOOL guid_from_string(LPCWSTR s, GUID *id)
if (!s || s[0] != '{') { - memset(id, 0, sizeof(*id)); - if (!s) return TRUE; + if (!s) + { + memset(id, 0, sizeof(*id)); + return TRUE; + } return FALSE; }
From: Maotong Zhang zmtong1988@gmail.com
--- dlls/combase/combase.c | 136 ++++++++++++++++++++++++++++++++++------- 1 file changed, 114 insertions(+), 22 deletions(-)
diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index dee1df02697..f1aa74cc356 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -1386,35 +1386,92 @@ static BOOL guid_from_string(LPCWSTR s, GUID *id) return FALSE; }
-static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid) +struct visited_node { - WCHAR buf2[CHARS_IN_GUID]; - LONG buf2len = sizeof(buf2); - HKEY xhkey; - WCHAR *buf; + LPCOLESTR progid; + struct visited_node *next; +};
- memset(clsid, 0, sizeof(*clsid)); - buf = malloc((lstrlenW(progid) + 8) * sizeof(WCHAR)); - if (!buf) return E_OUTOFMEMORY; +static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid, BOOL forceassign) +{ + HRESULT ret = CO_E_CLASSSTRING; + HKEY xhkey = NULL; + WCHAR szclsid[256] = {0}; + LONG cbclsid = sizeof(szclsid); + static struct visited_node *visitedhead = NULL; + struct visited_node *cur = NULL, *p = NULL; + BOOL hitloop = FALSE;
- lstrcpyW(buf, progid); - lstrcatW(buf, L"\CLSID"); - if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey)) + if (progid == NULL) { - free(buf); - WARN("couldn't open key for ProgID %s\n", debugstr_w(progid)); + *clsid = CLSID_NULL; + return E_INVALIDARG; + } + + if (*progid == 0) return CO_E_CLASSSTRING; + + for (p = visitedhead; p; p = p->next) + { + if (lstrcmpiW(progid, p->progid) == 0) + { + hitloop = TRUE; + break; + } } - free(buf);
- if (RegQueryValueW(xhkey, NULL, buf2, &buf2len)) + if (hitloop) + return forceassign ? CO_E_CLASSSTRING : REGDB_E_INVALIDVALUE; + + cur = (struct visited_node *)LocalAlloc(LMEM_FIXED, sizeof(struct visited_node)); + if (!cur) + return E_OUTOFMEMORY; + + cur->progid = progid; + cur->next = visitedhead; + visitedhead = cur; + + if (SUCCEEDED(open_classes_key(HKEY_CLASSES_ROOT, progid, MAXIMUM_ALLOWED, &xhkey))) { - RegCloseKey(xhkey); - WARN("couldn't query clsid value 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) + { + if (cbcurver > 0) + { + WCHAR *szcurver = (WCHAR *)LocalAlloc(LMEM_FIXED, cbcurver); + if (szcurver && RegQueryValueW(xhkey, L"CurVer", szcurver, &cbcurver) == ERROR_SUCCESS) + { + if (cbcurver >= sizeof(WCHAR)) + szcurver[(cbcurver / sizeof(WCHAR)) - 1] = 0; + + if (szcurver[0] != 0 && lstrcmpiW(szcurver, progid) != 0) + { + RegCloseKey(xhkey); + ret = clsid_from_string_reg(szcurver, clsid, forceassign); + LocalFree(szcurver); + goto cleanup; + } + } + if (szcurver) LocalFree(szcurver); + } + } + } + else + ret = guid_from_string(szclsid, clsid) ? S_OK : REGDB_E_INVALIDVALUE; } - RegCloseKey(xhkey); - return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING; + +cleanup: + if (xhkey) + RegCloseKey(xhkey); + + if (visitedhead == cur) + visitedhead = cur->next; + + LocalFree(cur); + + return ret; }
/****************************************************************************** @@ -1423,6 +1480,7 @@ static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid) HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, CLSID *clsid) { ACTCTX_SECTION_KEYED_DATA data; + HRESULT hr;
if (!progid || !clsid) return E_INVALIDARG; @@ -1437,7 +1495,11 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, CLSID *clsid) return S_OK; }
- return clsid_from_string_reg(progid, clsid); + hr = clsid_from_string_reg(progid, clsid, TRUE); + if (FAILED(hr)) + *clsid = GUID_NULL; + + return hr; }
/****************************************************************************** @@ -1461,13 +1523,43 @@ HRESULT WINAPI CLSIDFromString(LPCOLESTR str, LPCLSID clsid) if (!clsid) return E_INVALIDARG;
+ if (str == NULL) + { + *clsid = GUID_NULL; + return S_OK; + } + + if (*str == 0) + return CO_E_CLASSSTRING; + if (guid_from_string(str, clsid)) return S_OK;
/* It appears a ProgID is also valid */ - hr = clsid_from_string_reg(str, &tmp_id); + hr = clsid_from_string_reg(str, &tmp_id, FALSE); if (SUCCEEDED(hr)) + { *clsid = tmp_id; + return hr; + } + + /* Validate the content of str: only allow letters, digits, and '.' + If any other character is found, reset clsid to GUID_NULL and return CO_E_CLASSSTRING */ + if(str[0] != '{') + { + for (size_t i = 0; str[i]; i++) + { + WCHAR c = str[i]; + if (!((c >= L'0' && c <= L'9') || + (c >= L'a' && c <= L'z') || + (c >= L'A' && c <= L'Z') || + (c == L'.'))) + { + *clsid = GUID_NULL; + return CO_E_CLASSSTRING; + } + } + }
return hr; }