[PATCH] Partially implement SHGetObjectCompatFlags with tests

Nikolay Sivov nsivov at codeweavers.com
Thu Mar 11 17:16:00 CST 2010


---
 dlls/shlwapi/ordinal.c       |  125 ++++++++++++++++++++++++++++++++++++++++++
 dlls/shlwapi/shlwapi.spec    |    2 +-
 dlls/shlwapi/tests/ordinal.c |   87 +++++++++++++++++++++++++++++
 3 files changed, 213 insertions(+), 1 deletions(-)

diff --git a/dlls/shlwapi/ordinal.c b/dlls/shlwapi/ordinal.c
index 375ddaf..7da56a9 100644
--- a/dlls/shlwapi/ordinal.c
+++ b/dlls/shlwapi/ordinal.c
@@ -4854,3 +4854,128 @@ 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 3091783..6047646 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 83aec78..3e74662 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);
@@ -1786,6 +1788,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)))
@@ -1797,11 +1881,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
 }
@@ -1826,4 +1912,5 @@ START_TEST(ordinal)
     test_SHSetWindowBits();
     test_SHFormatDateTimeA();
     test_SHFormatDateTimeW();
+    test_SHGetObjectCompatFlags();
 }
-- 
1.5.6.5


--=-AeEw+nMa+BB4eIO+kAKT--




More information about the wine-patches mailing list