[resend] shell32: fix two bugs in IQueryAssocations
Theodore Dubois
tblodt at icloud.com
Wed Mar 2 19:57:28 CST 2016
Basically, returns the correct value for
ASSOCSTR_FRIENDLYDOCNAME and ASSOCSTR_DEFAULTICON
when passed a ProgID instead of a file extension.
Also adds some tests to make sure it works.
Signed-off-by: Theodore Dubois <tblodt at icloud.com>
---
dlls/shell32/assoc.c | 142 ++++++++++++++++++++++++---------------------
dlls/shell32/tests/assoc.c | 96 ++++++++++++++++++++++++++++++
include/wine/test.h | 1 +
3 files changed, 174 insertions(+), 65 deletions(-)
diff --git a/dlls/shell32/assoc.c b/dlls/shell32/assoc.c
index 90d00a8..ca52a0b 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
*
@@ -186,20 +188,26 @@ static HRESULT WINAPI IQueryAssociations_fnInit(
LONG ret;
TRACE("(%p)->(%d,%s,%p,%p)\n", iface,
- cfFlags,
- debugstr_w(pszAssoc),
- hkeyProgid,
- hWnd);
+ cfFlags,
+ debugstr_w(pszAssoc),
+ hkeyProgid,
+ hWnd);
if (hWnd != NULL)
FIXME("hwnd != NULL not supported\n");
if (cfFlags != 0)
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,34 @@ 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:
diff --git a/dlls/shell32/tests/assoc.c b/dlls/shell32/tests/assoc.c
index 8aa2535..8b86516 100644
--- a/dlls/shell32/tests/assoc.c
+++ b/dlls/shell32/tests/assoc.c
@@ -19,6 +19,7 @@
#define COBJMACROS
+#include <stdio.h>
#include <stdarg.h>
#include "shlwapi.h"
@@ -100,13 +101,108 @@ static struct assoc_getstring_test getstring_tests[] =
{ NULL }
};
+static BOOL getstring_test(LPCWSTR assocName, HKEY progIdKey, ASSOCSTR str, LPCWSTR extra,
+ HRESULT expected_hr, LPCWSTR expected_string) {
+ IQueryAssociations *assoc;
+ HRESULT hr;
+ WCHAR *buffer;
+ DWORD len;
+
+ /* I would like to #define gs_ok to call ok and return false if !condition, but varargs macros are C99. */
+ hr = CoCreateInstance(&CLSID_QueryAssociations, NULL, CLSCTX_INPROC_SERVER, &IID_IQueryAssociations, (void*)&assoc);
+ ok(hr == S_OK, "failed to create IQueryAssociations, 0x%x\n", hr);
+ if (hr != S_OK)
+ return FALSE;
+ hr = IQueryAssociations_Init(assoc, 0, assocName, progIdKey, NULL);
+ ok(hr == S_OK, "IQueryAssociations::Init failed, 0x%x\n", hr);
+ if (hr != S_OK)
+ return FALSE;
+
+ hr = IQueryAssociations_GetString(assoc, 0, str, extra, NULL, &len);
+ if (hr != S_FALSE) {
+ ok(hr == expected_hr, "GetString returned 0x%x, expected 0x%x\n", hr, expected_hr);
+ if (hr != expected_hr)
+ return FALSE;
+ }
+ if (FAILED(hr))
+ return TRUE;
+ buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ ok(buffer != NULL, "out of memory\n");
+ if (buffer == NULL)
+ return FALSE;
+ hr = IQueryAssociations_GetString(assoc, 0, str, extra, buffer, &len);
+ ok(hr == expected_hr, "GetString returned 0x%x, expected 0x%x\n", hr, expected_hr);
+ if (hr != expected_hr)
+ return FALSE;
+
+ if (expected_string) {
+ ok(lstrcmpW(buffer, expected_string) == 0, "GetString returned %s, expected %s\n",
+ wine_dbgstr_w(buffer), wine_dbgstr_w(expected_string));
+ if (lstrcmpW(buffer, expected_string) != 0)
+ return FALSE;
+ }
+ return TRUE;
+}
+
static void test_IQueryAssociations_GetString(void)
{
+ static WCHAR test_extensionW[] = {'.','t','e','s','t',0};
+ static WCHAR test_progidW[] = {'t','e','s','t','f','i','l','e',0};
+ static WCHAR DefaultIconW[] = {'D','e','f','a','u','l','t','I','c','o','n',0};
+ /* folder.ico, why not */
+ static WCHAR test_iconW[] = {'s','h','e','l','l','3','2','.','d','l','l',',','1',0};
+ HKEY test_extension_key;
+ HKEY test_progid_key;
+ HKEY test_defaulticon_key;
+ LRESULT r;
+
struct assoc_getstring_test *ptr = getstring_tests;
IQueryAssociations *assoc;
HRESULT hr;
DWORD len;
int i = 0;
+ BOOL getstring_test_result;
+
+ trace("getstring\n");
+ /* This macro is necessary because of what the ok macro expands to. Failures would report the wrong line number. */
+#define TEST_GET_STRING(a,p,s,e,eh,es) \
+ getstring_test_result = getstring_test(a,p,s,e,eh,es);\
+ ok(getstring_test_result, "\n");
+
+ /* request for default icon on extension with no progid should return default document icon
+ (exact string may change between versions of windows) */
+ r = RegCreateKeyExW(HKEY_CLASSES_ROOT, test_extensionW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &test_extension_key, NULL);
+ ok(r == ERROR_SUCCESS, "RegCreateKeyExW(HKCR, \".test\") failed: 0x%lx\n", r);
+ TEST_GET_STRING(test_extensionW, NULL, ASSOCSTR_DEFAULTICON, NULL, S_OK, NULL);
+
+ r = RegSetValueExW(test_extension_key, NULL, 0, REG_SZ, (PBYTE)test_progidW, sizeof(test_progidW));
+ ok(r == ERROR_SUCCESS, "RegSetValueExW(HKCR\\.test, NULL, \"testfile\") failed: 0x%lx\n", r);
+ TEST_GET_STRING(test_extensionW, NULL, ASSOCSTR_DEFAULTICON, NULL, S_OK, NULL);
+
+ /* adding progid key with no information shuld fail to return information */
+ r = RegCreateKeyExW(HKEY_CLASSES_ROOT, test_progidW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &test_progid_key, NULL);
+ ok(r == ERROR_SUCCESS, "RegCreateKeyExW(HKCR, \"testfile\") failed: 0x%lx\n", r);
+ TEST_GET_STRING(test_extensionW, NULL, ASSOCSTR_DEFAULTICON, NULL, HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION), NULL);
+ TEST_GET_STRING(test_progidW, NULL, ASSOCSTR_DEFAULTICON, NULL, HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION), NULL);
+ TEST_GET_STRING(NULL, test_progid_key, ASSOCSTR_DEFAULTICON, NULL, HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION), NULL);
+
+ /* adding information to the progid should return that information */
+ r = RegCreateKeyExW(test_progid_key, DefaultIconW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &test_defaulticon_key, NULL);
+ ok(r == ERROR_SUCCESS, "RegCreateKeyExW(HKCR\\testfile\\DefaultIcon) failed: 0x%lx\n", r);
+ r = RegSetValueExW(test_defaulticon_key, NULL, 0, REG_SZ, (PBYTE)test_iconW, sizeof(test_iconW));
+ ok(r == ERROR_SUCCESS, "RegSetValueExW(HKCR\\testfile\\DefaultIcon, NULL, \"folder.ico\") failed: 0x%lx\n", r);
+ TEST_GET_STRING(test_extensionW, NULL, ASSOCSTR_DEFAULTICON, NULL, S_OK, test_iconW);
+ TEST_GET_STRING(test_progidW, NULL, ASSOCSTR_DEFAULTICON, NULL, S_OK, test_iconW);
+ TEST_GET_STRING(NULL, test_progid_key, ASSOCSTR_DEFAULTICON, NULL, S_OK, test_iconW);
+
+ RegDeleteKeyW(HKEY_CLASSES_ROOT, test_extensionW);
+ RegDeleteKeyW(HKEY_CLASSES_ROOT, test_progidW);
+
+ hr = CoCreateInstance(&CLSID_QueryAssociations, NULL, CLSCTX_INPROC_SERVER, &IID_IQueryAssociations, (void*)&assoc);
+ ok(hr == S_OK, "failed to create object, 0x%x\n", hr);
+
+ hr = IQueryAssociations_Init(assoc, 0, httpW, NULL, NULL);
+ ok(hr == S_OK, "Init failed, 0x%x\n", hr);
hr = CoCreateInstance(&CLSID_QueryAssociations, NULL, CLSCTX_INPROC_SERVER, &IID_IQueryAssociations, (void*)&assoc);
ok(hr == S_OK, "failed to create object, 0x%x\n", hr);
diff --git a/include/wine/test.h b/include/wine/test.h
index cb9018d..2a5eb32 100644
--- a/include/wine/test.h
+++ b/include/wine/test.h
@@ -670,6 +670,7 @@ int main( int argc, char **argv )
{
char p[128];
+ printf("main running\n");
setvbuf (stdout, NULL, _IONBF, 0);
winetest_argc = argc;
--
2.5.4 (Apple Git-61)
More information about the wine-patches
mailing list