diff --git a/dlls/shlwapi/ordinal.c b/dlls/shlwapi/ordinal.c index 375ddaf7ad2..412dac19dc4 100644 --- a/dlls/shlwapi/ordinal.c +++ b/dlls/shlwapi/ordinal.c @@ -4854,3 +4854,127 @@ BOOL WINAPI SHPropertyBag_ReadLONG(IPropertyBag *ppb, LPCWSTR pszPropName, LPLON } return hr; } + +/* return flags for SHGetObjectCompatFlags, names derived from registry value names */ +#define OBJCOMPAT_OTNEEDSSFCACHE 0x00000001 +#define OBJCOMPAT_NO_WEBVIEW 0x00000002 +#define OBJCOMPAT_UNBINDABLE 0x00000004 +#define OBJCOMPAT_PINDLL 0x00000008 +#define OBJCOMPAT_NEEDSFILESYSANCESTOR 0x00000010 +#define OBJCOMPAT_NOTAFILESYSTEM 0x00000020 +#define OBJCOMPAT_CTXMENU_NOVERBS 0x00000040 +#define OBJCOMPAT_CTXMENU_LIMITEDQI 0x00000080 +#define OBJCOMPAT_COCREATESHELLFOLDERONLY 0x00000100 +#define OBJCOMPAT_NEEDSSTORAGEANCESTOR 0x00000200 +#define OBJCOMPAT_NOLEGACYWEBVIEW 0x00000400 +#define OBJCOMPAT_CTXMENU_XPQCMFLAGS 0x00001000 +#define OBJCOMPAT_NOIPROPERTYSTORE 0x00002000 + +/* a search table for compatibility flags */ +struct objcompat_entry { + const WCHAR name[30]; + DWORD value; +}; + +/* expected to be sorted by name */ +static const struct objcompat_entry objcompat_table[] = { + { {'C','O','C','R','E','A','T','E','S','H','E','L','L','F','O','L','D','E','R','O','N','L','Y',0}, + OBJCOMPAT_COCREATESHELLFOLDERONLY }, + { {'C','T','X','M','E','N','U','_','L','I','M','I','T','E','D','Q','I',0}, + OBJCOMPAT_CTXMENU_LIMITEDQI }, + { {'C','T','X','M','E','N','U','_','N','O','V','E','R','B','S',0}, + OBJCOMPAT_CTXMENU_LIMITEDQI }, + { {'C','T','X','M','E','N','U','_','X','P','Q','C','M','F','L','A','G','S',0}, + OBJCOMPAT_CTXMENU_XPQCMFLAGS }, + { {'N','E','E','D','S','F','I','L','E','S','Y','S','A','N','C','E','S','T','O','R',0}, + OBJCOMPAT_NEEDSFILESYSANCESTOR }, + { {'N','E','E','D','S','S','T','O','R','A','G','E','A','N','C','E','S','T','O','R',0}, + OBJCOMPAT_NEEDSSTORAGEANCESTOR }, + { {'N','O','I','P','R','O','P','E','R','T','Y','S','T','O','R','E',0}, + OBJCOMPAT_NOIPROPERTYSTORE }, + { {'N','O','L','E','G','A','C','Y','W','E','B','V','I','E','W',0}, + OBJCOMPAT_NOLEGACYWEBVIEW }, + { {'N','O','T','A','F','I','L','E','S','Y','S','T','E','M',0}, + OBJCOMPAT_NOTAFILESYSTEM }, + { {'N','O','_','W','E','B','V','I','E','W',0}, + OBJCOMPAT_NO_WEBVIEW }, + { {'O','T','N','E','E','D','S','S','F','C','A','C','H','E',0}, + OBJCOMPAT_OTNEEDSSFCACHE }, + { {'P','I','N','D','L','L',0}, + OBJCOMPAT_PINDLL }, + { {'U','N','B','I','N','D','A','B','L','E',0}, + OBJCOMPAT_UNBINDABLE } +}; + +/************************************************************************** + * SHGetObjectCompatFlags (SHLWAPI.476) + * + * Function returns an integer representation of compatibility flags stored + * in registry for CLSID under ShellCompatibility subkey. + * + * PARAMS + * pUnk: pointer to object IUnknown interface, idetifies CLSID + * clsid: pointer to CLSID to retrieve data for + * + * RETURNS + * 0 on failure, flags set on success + */ +DWORD WINAPI SHGetObjectCompatFlags(IUnknown *pUnk, const CLSID *clsid) +{ + static const WCHAR compatpathW[] = + {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'S','h','e','l','l','C','o','m','p','a','t','i','b','i','l','i','t','y','\\', + 'O','b','j','e','c','t','s','\\','%','s',0}; + WCHAR strW[sizeof(compatpathW)/sizeof(WCHAR) + 38 /* { CLSID } */]; + DWORD ret, length = sizeof(strW)/sizeof(WCHAR); + OLECHAR *clsid_str; + HKEY key; + INT i; + + TRACE("%p %s\n", pUnk, debugstr_guid(clsid)); + + if (!pUnk && !clsid) return 0; + + if (pUnk && !clsid) + { + FIXME("iface not handled\n"); + return 0; + } + + StringFromCLSID(clsid, &clsid_str); + sprintfW(strW, compatpathW, clsid_str); + CoTaskMemFree(clsid_str); + + ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, strW, &key); + if (ret != ERROR_SUCCESS) return 0; + + /* now collect flag values */ + ret = 0; + for (i = 0; RegEnumValueW(key, i, strW, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; i++) + { + INT left, right, res, x; + + /* search in table */ + left = 0; + right = sizeof(objcompat_table) / sizeof(struct objcompat_entry) - 1; + + while (right >= left) { + x = (left + right) / 2; + res = strcmpW(strW, objcompat_table[x].name); + if (res == 0) + { + ret |= objcompat_table[x].value; + break; + } + else if (res < 0) + right = x - 1; + else + left = x + 1; + } + + length = sizeof(strW)/sizeof(WCHAR); + } + + return ret; +} diff --git a/dlls/shlwapi/shlwapi.spec b/dlls/shlwapi/shlwapi.spec index 3091783f580..60476468d5b 100644 --- a/dlls/shlwapi/shlwapi.spec +++ b/dlls/shlwapi/shlwapi.spec @@ -473,7 +473,7 @@ 473 stub -noname SHGetIniStringUTF7W 474 stub -noname SHSetIniStringUTF7W 475 stdcall -noname GetShellSecurityDescriptor(ptr long) -476 stub -noname SHGetObjectCompatFlags +476 stdcall -noname SHGetObjectCompatFlags(ptr ptr) 477 stub -noname SHCreatePropertyBagOnMemory 478 stdcall -noname IUnknown_TranslateAcceleratorIO(ptr ptr) 479 stdcall -noname IUnknown_UIActivateIO(ptr long ptr) diff --git a/dlls/shlwapi/tests/ordinal.c b/dlls/shlwapi/tests/ordinal.c index 083934b3b19..223aac405b2 100644 --- a/dlls/shlwapi/tests/ordinal.c +++ b/dlls/shlwapi/tests/ordinal.c @@ -47,6 +47,8 @@ static HRESULT(WINAPI *pSHPropertyBag_ReadLONG)(IPropertyBag *,LPCWSTR,LPLONG); static LONG (WINAPI *pSHSetWindowBits)(HWND, INT, UINT, UINT); static INT (WINAPI *pSHFormatDateTimeA)(const FILETIME UNALIGNED*, DWORD*, LPSTR, UINT); static INT (WINAPI *pSHFormatDateTimeW)(const FILETIME UNALIGNED*, DWORD*, LPWSTR, UINT); +static DWORD (WINAPI *pSHGetObjectCompatFlags)(IUnknown*, const CLSID*); +static BOOL (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *); static HMODULE hmlang; static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT); @@ -1787,6 +1789,88 @@ if (0) ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n"); } +static void test_SHGetObjectCompatFlags(void) +{ + struct compat_value { + CHAR nameA[30]; + DWORD value; + }; + + struct compat_value values[] = { + { "OTNEEDSSFCACHE", 0x1 }, + { "NO_WEBVIEW", 0x2 }, + { "UNBINDABLE", 0x4 }, + { "PINDLL", 0x8 }, + { "NEEDSFILESYSANCESTOR", 0x10 }, + { "NOTAFILESYSTEM", 0x20 }, + { "CTXMENU_NOVERBS", 0x40 }, + { "CTXMENU_LIMITEDQI", 0x80 }, + { "COCREATESHELLFOLDERONLY", 0x100 }, + { "NEEDSSTORAGEANCESTOR", 0x200 }, + { "NOLEGACYWEBVIEW", 0x400 }, + { "CTXMENU_XPQCMFLAGS", 0x1000 }, + { "NOIPROPERTYSTORE", 0x2000 } + }; + + static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects"; + CHAR keyA[39]; /* {CLSID} */ + HKEY root; + DWORD ret; + int i; + + if (!pSHGetObjectCompatFlags) + { + win_skip("SHGetObjectCompatFlags isn't available\n"); + return; + } + + /* null args */ + ret = pSHGetObjectCompatFlags(NULL, NULL); + ok(ret == 0, "got %d\n", ret); + + ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, compat_path, &root); + if (ret != ERROR_SUCCESS) + { + skip("No compatibility class data found\n"); + return; + } + + for (i = 0; RegEnumKeyA(root, i, keyA, sizeof(keyA)) == ERROR_SUCCESS; i++) + { + HKEY clsid_key; + + if (RegOpenKeyA(root, keyA, &clsid_key) == ERROR_SUCCESS) + { + CHAR valueA[30]; + DWORD expected = 0, got, length = sizeof(valueA); + CLSID clsid; + int v; + + for (v = 0; RegEnumValueA(clsid_key, v, valueA, &length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; v++) + { + int j; + + for (j = 0; j < sizeof(values)/sizeof(struct compat_value); j++) + if (lstrcmpA(values[j].nameA, valueA) == 0) + { + expected |= values[j].value; + break; + } + + length = sizeof(valueA); + } + + pGUIDFromStringA(keyA, &clsid); + got = pSHGetObjectCompatFlags(NULL, &clsid); + ok(got == expected, "got 0x%08x, expected 0x%08x. Key %s\n", got, expected, keyA); + + RegCloseKey(clsid_key); + } + } + + RegCloseKey(root); +} + static void init_pointers(void) { #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord))) @@ -1798,11 +1882,13 @@ static void init_pointers(void) MAKEFUNC(SHSetWindowBits, 165); MAKEFUNC(ConnectToConnectionPoint, 168); MAKEFUNC(SHSearchMapInt, 198); + MAKEFUNC(GUIDFromStringA, 269); MAKEFUNC(SHPackDispParams, 282); MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283); MAKEFUNC(IConnectionPoint_SimpleInvoke, 284); MAKEFUNC(SHFormatDateTimeA, 353); MAKEFUNC(SHFormatDateTimeW, 354); + MAKEFUNC(SHGetObjectCompatFlags, 476); MAKEFUNC(SHPropertyBag_ReadLONG, 496); #undef MAKEFUNC } @@ -1827,4 +1913,5 @@ START_TEST(ordinal) test_SHSetWindowBits(); test_SHFormatDateTimeA(); test_SHFormatDateTimeW(); + test_SHGetObjectCompatFlags(); }