diff --git a/dlls/shell32/assoc.c b/dlls/shell32/assoc.c index 90d00a84213..a3d21b9ae02 100644 --- a/dlls/shell32/assoc.c +++ b/dlls/shell32/assoc.c @@ -88,6 +88,8 @@ static inline struct enumassochandlers *impl_from_IEnumAssocHandlers(IEnumAssocH return CONTAINING_RECORD(iface, struct enumassochandlers, IEnumAssocHandlers_iface); } +static HRESULT ASSOC_GetValue(HKEY hkey, const WCHAR *name, void **data, DWORD *data_size); + /************************************************************************** * IQueryAssociations_QueryInterface * @@ -196,10 +198,16 @@ static HRESULT WINAPI IQueryAssociations_fnInit( FIXME("unsupported flags: %x\n", cfFlags); RegCloseKey(This->hkeySource); - RegCloseKey(This->hkeyProgID); + if (This->hkeySource != This->hkeyProgID) + RegCloseKey(This->hkeyProgID); This->hkeySource = This->hkeyProgID = NULL; + + /* If the process of initializing hkeyProgID fails, just return S_OK. That's what Windows does. */ if (pszAssoc != NULL) { + WCHAR *progId; + HRESULT hr; + ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, pszAssoc, 0, @@ -207,22 +215,51 @@ static HRESULT WINAPI IQueryAssociations_fnInit( &This->hkeySource); if (ret) return S_OK; - /* if this is not a prog id */ - if ((*pszAssoc == '.') || (*pszAssoc == '{')) + /* if this is a progid */ + if (*pszAssoc != '.' && *pszAssoc != '{') { - RegOpenKeyExW(This->hkeySource, - szProgID, - 0, - KEY_READ, - &This->hkeyProgID); - } - else This->hkeyProgID = This->hkeySource; + return S_OK; + } + + /* if it's not a progid, it's a file extension or clsid */ + if (*pszAssoc == '.') + { + /* for a file extension, the progid is the default value */ + hr = ASSOC_GetValue(This->hkeySource, NULL, (void**)&progId, NULL); + if (FAILED(hr)) + return S_OK; + } + else /* if (*pszAssoc == '{') */ + { + HKEY progIdKey; + /* for a clsid, the progid is the default value of the ProgID subkey */ + ret = RegOpenKeyExW(This->hkeySource, + szProgID, + 0, + KEY_READ, + &progIdKey); + if (ret != ERROR_SUCCESS) + return S_OK; + hr = ASSOC_GetValue(progIdKey, NULL, (void**)&progId, NULL); + if (FAILED(hr)) + return S_OK; + RegCloseKey(progIdKey); + } + + /* open the actual progid key, the one with the shell subkey */ + ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, + progId, + 0, + KEY_READ, + &This->hkeyProgID); + HeapFree(GetProcessHeap(), 0, progId); + return S_OK; } else if (hkeyProgid != NULL) { - This->hkeyProgID = hkeyProgid; + This->hkeySource = This->hkeyProgID = hkeyProgid; return S_OK; } else @@ -507,33 +544,15 @@ static HRESULT WINAPI IQueryAssociations_fnGetString( case ASSOCSTR_FRIENDLYDOCNAME: { - WCHAR *pszFileType; - DWORD ret; - DWORD size; + WCHAR *docName; - hr = ASSOC_GetValue(This->hkeySource, NULL, (void**)&pszFileType, NULL); - if (FAILED(hr)) - return hr; - size = 0; - ret = RegGetValueW(HKEY_CLASSES_ROOT, pszFileType, NULL, RRF_RT_REG_SZ, NULL, NULL, &size); - if (ret == ERROR_SUCCESS) - { - WCHAR *docName = HeapAlloc(GetProcessHeap(), 0, size); - if (docName) - { - ret = RegGetValueW(HKEY_CLASSES_ROOT, pszFileType, NULL, RRF_RT_REG_SZ, NULL, docName, &size); - if (ret == ERROR_SUCCESS) - hr = ASSOC_ReturnString(flags, pszOut, pcchOut, docName, strlenW(docName) + 1); - else - hr = HRESULT_FROM_WIN32(ret); - HeapFree(GetProcessHeap(), 0, docName); - } - else - hr = E_OUTOFMEMORY; + hr = ASSOC_GetValue(This->hkeyProgID, NULL, (void**)&docName, NULL); + if (FAILED(hr)) { + /* hKeyProgID is NULL or there is no default value, so fail */ + return HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION); } - else - hr = HRESULT_FROM_WIN32(ret); - HeapFree(GetProcessHeap(), 0, pszFileType); + hr = ASSOC_ReturnString(flags, pszOut, pcchOut, docName, strlenW(docName) + 1); + HeapFree(GetProcessHeap(), 0, docName); return hr; } @@ -623,41 +642,33 @@ get_friendly_name_fail: case ASSOCSTR_DEFAULTICON: { static const WCHAR DefaultIconW[] = {'D','e','f','a','u','l','t','I','c','o','n',0}; - WCHAR *pszFileType; + static const WCHAR documentIcon[] = {'s','h','e','l','l','3','2','.','d','l','l',',','0',0}; DWORD ret; DWORD size; - HKEY hkeyFile; - hr = ASSOC_GetValue(This->hkeySource, NULL, (void**)&pszFileType, NULL); - if (FAILED(hr)) - return hr; - ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, pszFileType, 0, KEY_READ, &hkeyFile); + size = 0; + ret = RegGetValueW(This->hkeyProgID, DefaultIconW, NULL, RRF_RT_REG_SZ, NULL, NULL, &size); if (ret == ERROR_SUCCESS) { - size = 0; - ret = RegGetValueW(hkeyFile, DefaultIconW, NULL, RRF_RT_REG_SZ, NULL, NULL, &size); - if (ret == ERROR_SUCCESS) + WCHAR *icon = HeapAlloc(GetProcessHeap(), 0, size); + if (icon) { - WCHAR *icon = HeapAlloc(GetProcessHeap(), 0, size); - if (icon) - { - ret = RegGetValueW(hkeyFile, DefaultIconW, NULL, RRF_RT_REG_SZ, NULL, icon, &size); - if (ret == ERROR_SUCCESS) - hr = ASSOC_ReturnString(flags, pszOut, pcchOut, icon, strlenW(icon) + 1); - else - hr = HRESULT_FROM_WIN32(ret); - HeapFree(GetProcessHeap(), 0, icon); - } + ret = RegGetValueW(This->hkeyProgID, DefaultIconW, NULL, RRF_RT_REG_SZ, NULL, icon, &size); + if (ret == ERROR_SUCCESS) + hr = ASSOC_ReturnString(flags, pszOut, pcchOut, icon, strlenW(icon) + 1); else - hr = E_OUTOFMEMORY; + hr = HRESULT_FROM_WIN32(ret); + HeapFree(GetProcessHeap(), 0, icon); } else - hr = HRESULT_FROM_WIN32(ret); - RegCloseKey(hkeyFile); + hr = E_OUTOFMEMORY; + } else { + /* there is no DefaultIcon subkey or hkeyProgID is NULL, so return the default document icon */ + if (This->hkeyProgID == NULL) + hr = ASSOC_ReturnString(flags, pszOut, pcchOut, documentIcon, strlenW(documentIcon) + 1); + else + return HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION); } - else - hr = HRESULT_FROM_WIN32(ret); - HeapFree(GetProcessHeap(), 0, pszFileType); return hr; } case ASSOCSTR_SHELLEXTENSION: