From 891cf2ac54b69cf7d2f8c093338108a7b1e24edf Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 9 Sep 2013 11:21:03 +0400 Subject: [PATCH] shell32: Added support for ASSOCF_NOTRUNCATE flag in GetString(). --- dlls/shell32/assoc.c | 67 ++++++++++++++++++--------- dlls/shell32/tests/assoc.c | 93 +++++++++++++++++++++++++++++++++++--- 2 files changed, 131 insertions(+), 29 deletions(-) diff --git a/dlls/shell32/assoc.c b/dlls/shell32/assoc.c index 65f4644c966..77b0a2dcd9a 100644 --- a/dlls/shell32/assoc.c +++ b/dlls/shell32/assoc.c @@ -392,17 +392,41 @@ static HRESULT ASSOC_ReturnData(void *out, DWORD *outlen, const void *data, } } -static HRESULT ASSOC_ReturnString(LPWSTR out, DWORD *outlen, LPCWSTR data, - DWORD datalen) +static HRESULT ASSOC_ReturnString(ASSOCF flags, LPWSTR out, DWORD *outlen, LPCWSTR data, DWORD datalen) { - HRESULT hres; + HRESULT hr = S_OK; + DWORD len; - assert(outlen); + TRACE("flags=0x%08x, data=%s\n", flags, debugstr_w(data)); - *outlen *= sizeof(WCHAR); - hres = ASSOC_ReturnData(out, outlen, data, datalen*sizeof(WCHAR)); - *outlen /= sizeof(WCHAR); - return hres; + if (!out) + { + *outlen = datalen; + return S_FALSE; + } + + if (*outlen < datalen) + { + if (flags & ASSOCF_NOTRUNCATE) + { + len = 0; + if (*outlen > 0) out[0] = 0; + hr = E_POINTER; + } + else + { + len = min(*outlen, datalen); + hr = E_NOT_SUFFICIENT_BUFFER; + } + *outlen = datalen; + } + else + len = datalen; + + if (len) + memcpy(out, data, len*sizeof(WCHAR)); + + return hr; } /************************************************************************** @@ -424,23 +448,22 @@ static HRESULT ASSOC_ReturnString(LPWSTR out, DWORD *outlen, LPCWSTR data, */ static HRESULT WINAPI IQueryAssociations_fnGetString( IQueryAssociations *iface, - ASSOCF cfFlags, + ASSOCF flags, ASSOCSTR str, LPCWSTR pszExtra, LPWSTR pszOut, DWORD *pcchOut) { IQueryAssociationsImpl *This = impl_from_IQueryAssociations(iface); - const ASSOCF cfUnimplemented = ~(0); + const ASSOCF unimplemented_flags = ~ASSOCF_NOTRUNCATE; DWORD len = 0; HRESULT hr; WCHAR path[MAX_PATH]; - TRACE("(%p,0x%08x,%u,%s,%p,%p)\n", This, cfFlags, str, - debugstr_w(pszExtra), pszOut, pcchOut); + TRACE("(%p)->(0x%08x, %u, %s, %p, %p)\n", This, flags, str, debugstr_w(pszExtra), pszOut, pcchOut); - if (cfFlags & cfUnimplemented) - FIXME("%08x: unimplemented flags!\n", cfFlags & cfUnimplemented); + if (flags & unimplemented_flags) + FIXME("%08x: unimplemented flags\n", flags & unimplemented_flags); if (!pcchOut) return E_UNEXPECTED; @@ -453,7 +476,7 @@ static HRESULT WINAPI IQueryAssociations_fnGetString( hr = ASSOC_GetCommand(This, pszExtra, &command); if (SUCCEEDED(hr)) { - hr = ASSOC_ReturnString(pszOut, pcchOut, command, strlenW(command) + 1); + hr = ASSOC_ReturnString(flags, pszOut, pcchOut, command, strlenW(command) + 1); HeapFree(GetProcessHeap(), 0, command); } return hr; @@ -465,7 +488,7 @@ static HRESULT WINAPI IQueryAssociations_fnGetString( if (FAILED(hr)) return hr; len++; - return ASSOC_ReturnString(pszOut, pcchOut, path, len); + return ASSOC_ReturnString(flags, pszOut, pcchOut, path, len); } case ASSOCSTR_FRIENDLYDOCNAME: @@ -486,7 +509,7 @@ static HRESULT WINAPI IQueryAssociations_fnGetString( { ret = RegGetValueW(HKEY_CLASSES_ROOT, pszFileType, NULL, RRF_RT_REG_SZ, NULL, docName, &size); if (ret == ERROR_SUCCESS) - hr = ASSOC_ReturnString(pszOut, pcchOut, docName, strlenW(docName) + 1); + hr = ASSOC_ReturnString(flags, pszOut, pcchOut, docName, strlenW(docName) + 1); else hr = HRESULT_FROM_WIN32(ret); HeapFree(GetProcessHeap(), 0, docName); @@ -542,7 +565,7 @@ static HRESULT WINAPI IQueryAssociations_fnGetString( /* Does strlenW(bufW) == 0 mean we use the filename? */ len = strlenW(bufW) + 1; TRACE("found FileDescription: %s\n", debugstr_w(bufW)); - hr = ASSOC_ReturnString(pszOut, pcchOut, bufW, len); + hr = ASSOC_ReturnString(flags, pszOut, pcchOut, bufW, len); HeapFree(GetProcessHeap(), 0, verinfoW); return hr; } @@ -552,7 +575,7 @@ get_friendly_name_fail: PathRemoveExtensionW(path); PathStripPathW(path); TRACE("using filename: %s\n", debugstr_w(path)); - hr = ASSOC_ReturnString(pszOut, pcchOut, path, strlenW(path) + 1); + hr = ASSOC_ReturnString(flags, pszOut, pcchOut, path, strlenW(path) + 1); HeapFree(GetProcessHeap(), 0, verinfoW); return hr; } @@ -573,7 +596,7 @@ get_friendly_name_fail: { ret = RegGetValueW(This->hkeySource, NULL, Content_TypeW, RRF_RT_REG_SZ, NULL, contentType, &size); if (ret == ERROR_SUCCESS) - hr = ASSOC_ReturnString(pszOut, pcchOut, contentType, strlenW(contentType) + 1); + hr = ASSOC_ReturnString(flags, pszOut, pcchOut, contentType, strlenW(contentType) + 1); else hr = HRESULT_FROM_WIN32(ret); HeapFree(GetProcessHeap(), 0, contentType); @@ -606,7 +629,7 @@ get_friendly_name_fail: { ret = RegGetValueW(hkeyFile, DefaultIconW, NULL, RRF_RT_REG_SZ, NULL, icon, &size); if (ret == ERROR_SUCCESS) - hr = ASSOC_ReturnString(pszOut, pcchOut, icon, strlenW(icon) + 1); + hr = ASSOC_ReturnString(flags, pszOut, pcchOut, icon, strlenW(icon) + 1); else hr = HRESULT_FROM_WIN32(ret); HeapFree(GetProcessHeap(), 0, icon); @@ -645,7 +668,7 @@ get_friendly_name_fail: RegCloseKey(hkey); if (ret) return HRESULT_FROM_WIN32(ret); - return ASSOC_ReturnString(pszOut, pcchOut, guid, size / sizeof(WCHAR)); + return ASSOC_ReturnString(flags, pszOut, pcchOut, guid, size / sizeof(WCHAR)); } default: diff --git a/dlls/shell32/tests/assoc.c b/dlls/shell32/tests/assoc.c index 29524dc601a..abfe6d4b556 100644 --- a/dlls/shell32/tests/assoc.c +++ b/dlls/shell32/tests/assoc.c @@ -35,13 +35,8 @@ static void test_IQueryAssociations_QueryInterface(void) IUnknown *unk; HRESULT hr; - /* this works since XP */ hr = CoCreateInstance(&CLSID_QueryAssociations, NULL, CLSCTX_INPROC_SERVER, &IID_IQueryAssociations, (void*)&qa); - - if (FAILED(hr)) { - win_skip("CoCreateInstance for IQueryAssociations returned 0x%x\n", hr); - return; - } + ok(hr == S_OK, "got 0x%08x\n", hr); hr = IQueryAssociations_QueryInterface(qa, &IID_IQueryAssociations, (void**)&qa2); ok(hr == S_OK, "QueryInterface (IQueryAssociations) returned 0x%x\n", hr); @@ -97,12 +92,96 @@ static void test_IApplicationAssociationRegistration_QueryInterface(void) IApplicationAssociationRegistration_Release(appreg); } +struct assoc_getstring_test +{ + const WCHAR *key; + ASSOCF flags; + ASSOCSTR str; + DWORD len; + HRESULT hr; + HRESULT brokenhr; +}; + +static const WCHAR httpW[] = {'h','t','t','p',0}; + +static struct assoc_getstring_test getstring_tests[] = +{ + { httpW, 0, ASSOCSTR_EXECUTABLE, 2, 0x8007007a /* E_NOT_SUFFICIENT_BUFFER */, S_OK }, + { httpW, ASSOCF_NOTRUNCATE, ASSOCSTR_EXECUTABLE, 2, E_POINTER }, + { NULL } +}; + +static void test_IQueryAssociations_GetString(void) +{ + struct assoc_getstring_test *ptr = getstring_tests; + IQueryAssociations *assoc; + HRESULT hr; + DWORD len; + int i = 0; + + 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); + + len = 0; + hr = IQueryAssociations_GetString(assoc, 0, ASSOCSTR_EXECUTABLE, NULL, NULL, &len); + ok(hr == S_FALSE, "got 0x%08x\n", hr); + ok(len > 0, "got wrong needed length, %d\n", len); + + while (ptr->key) + { + WCHAR buffW[MAX_PATH]; + DWORD len; + + hr = IQueryAssociations_Init(assoc, 0, ptr->key, NULL, NULL); + ok(hr == S_OK, "%d: Init failed, 0x%x\n", i, hr); + + len = ptr->len; + buffW[0] = ptr->flags & ASSOCF_NOTRUNCATE ? 0x1 : 0; + hr = IQueryAssociations_GetString(assoc, ptr->flags, ptr->str, NULL, buffW, &len); + if (hr != ptr->hr) + ok(broken(hr == ptr->brokenhr), "%d: GetString failed, 0x%08x\n", i, hr); + else + { + ok(hr == ptr->hr, "%d: GetString failed, 0x%08x\n", i, hr); + ok(len > ptr->len, "%d: got needed length %d\n", i, len); + } + + /* even with ASSOCF_NOTRUNCATE it's null terminated */ + if ((ptr->flags & ASSOCF_NOTRUNCATE) && (ptr->len > 0)) + ok(buffW[0] == 0 || broken(buffW[0] == 0x1) /* pre win7 */, "%d: got %x\n", i, buffW[0]); + + if (!(ptr->flags & ASSOCF_NOTRUNCATE) && ptr->len && FAILED(ptr->hr)) + ok(buffW[0] != 0, "%d: got %x\n", i, buffW[0]); + + i++; + ptr++; + } + + IQueryAssociations_Release(assoc); +} START_TEST(assoc) { + IQueryAssociations *qa; + HRESULT hr; + CoInitialize(NULL); - test_IQueryAssociations_QueryInterface(); + /* this works since XP */ + hr = CoCreateInstance(&CLSID_QueryAssociations, NULL, CLSCTX_INPROC_SERVER, &IID_IQueryAssociations, (void*)&qa); + if (hr == S_OK) + { + test_IQueryAssociations_QueryInterface(); + test_IQueryAssociations_GetString(); + + IQueryAssociations_Release(qa); + } + else + win_skip("IQueryAssociations not supported, 0x%x\n", hr); + test_IApplicationAssociationRegistration_QueryInterface(); CoUninitialize();