From: Ivan Lyugaev <valy(a)etersoft.ru> Some COM applications register version-independent ProgIDs that point to version-specific classes through the CurVer registry key. This implements the correct logic for handling such cases --- dlls/combase/combase.c | 93 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 6 deletions(-) diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index 34a9a42dc2a..e6e083dcb1e 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -31,6 +31,8 @@ #include "wine/debug.h" +#define CLSID_FROM_STRING_RECURSION 0x80077777 + WINE_DEFAULT_DEBUG_CHANNEL(ole); HINSTANCE hProxyDll; @@ -1441,7 +1443,7 @@ static BOOL guid_from_string(LPCWSTR s, GUID *id) return FALSE; } -static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid) +static HRESULT clsid_from_string_reg_recursive(LPCOLESTR progid, CLSID *clsid, WCHAR **visited_progids, int call_depth) { WCHAR buf2[CHARS_IN_GUID]; LONG buf2len = sizeof(buf2); @@ -1449,35 +1451,114 @@ static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid) WCHAR *buf; memset(clsid, 0, sizeof(*clsid)); + + for (int i = 0; i < call_depth; i++) + { + if (visited_progids[i] && !lstrcmpW(visited_progids[i], progid)) + { + return CLSID_FROM_STRING_RECURSION; + } + } + + if (call_depth >= 10) + { + return CLSID_FROM_STRING_RECURSION; + } + + visited_progids[call_depth] = _wcsdup(progid); + if (!visited_progids[call_depth]) + { + return E_OUTOFMEMORY; + } + call_depth++; + buf = malloc((lstrlenW(progid) + 8) * sizeof(WCHAR)); - if (!buf) return E_OUTOFMEMORY; + if (!buf) + { + free(visited_progids[call_depth-1]); + visited_progids[call_depth-1] = NULL; + return E_OUTOFMEMORY; + } lstrcpyW(buf, progid); lstrcatW(buf, L"\\CLSID"); if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey)) { + WCHAR *curver; + LONG curverlen = 0; + free(buf); - WARN("couldn't open key for ProgID %s\n", debugstr_w(progid)); + + buf = malloc((lstrlenW(progid) + 9) * sizeof(WCHAR)); + lstrcpyW(buf, progid); + lstrcatW(buf, L"\\CurVer"); + + if (open_classes_key(HKEY_CLASSES_ROOT, buf, MAXIMUM_ALLOWED, &xhkey)) + { + WARN("couldn't open key for ProgID %s\n", debugstr_w(progid)); + free(buf); + free(visited_progids[call_depth-1]); + visited_progids[call_depth-1] = NULL; + return CO_E_CLASSSTRING; + } + + free(buf); + + if (RegQueryValueW(xhkey, NULL, NULL, &curverlen) == ERROR_SUCCESS) + { + curver = malloc(curverlen); + if (curver) + { + if (!RegQueryValueW(xhkey, NULL, curver, &curverlen)) + { + RegCloseKey(xhkey); + free(curver); + return clsid_from_string_reg_recursive(curver, clsid, visited_progids, call_depth); + } + free(curver); + } + } + else + { + WARN("couldn't query CurVer value size for ProgID %s\n", debugstr_w(progid)); + } + + RegCloseKey(xhkey); + free(visited_progids[call_depth-1]); + visited_progids[call_depth-1] = NULL; return CO_E_CLASSSTRING; } + free(buf); if (RegQueryValueW(xhkey, NULL, buf2, &buf2len)) { RegCloseKey(xhkey); WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid)); + free(visited_progids[call_depth-1]); + visited_progids[call_depth-1] = NULL; return CO_E_CLASSSTRING; } + RegCloseKey(xhkey); + free(visited_progids[call_depth-1]); + visited_progids[call_depth-1] = NULL; return guid_from_string(buf2, clsid) ? S_OK : CO_E_CLASSSTRING; } +static HRESULT clsid_from_string_reg(LPCOLESTR progid, CLSID *clsid) +{ + WCHAR *visited_progids[11] = {0}; + return clsid_from_string_reg_recursive(progid, clsid, visited_progids, 0); +} + /****************************************************************************** * CLSIDFromProgID (combase.@) */ HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, CLSID *clsid) { ACTCTX_SECTION_KEYED_DATA data; + HRESULT hr; if (!progid || !clsid) return E_INVALIDARG; @@ -1492,7 +1573,8 @@ 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); + return hr == CLSID_FROM_STRING_RECURSION ? CO_E_CLASSSTRING : hr; } /****************************************************************************** @@ -1523,8 +1605,7 @@ HRESULT WINAPI CLSIDFromString(LPCOLESTR str, LPCLSID clsid) hr = clsid_from_string_reg(str, &tmp_id); if (SUCCEEDED(hr)) *clsid = tmp_id; - - return hr; + return hr == CLSID_FROM_STRING_RECURSION ? REGDB_E_INVALIDVALUE : hr; } /****************************************************************************** -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9639