[PATCH v2] ole32: Properly implement OleRegGetUserType()
Nikolay Sivov
nsivov at codeweavers.com
Wed Dec 30 12:57:23 CST 2015
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
v2: includes tests, uses regular Reg* API to make key overrides work
dlls/ole32/ole2.c | 118 ++++++++++++++++++++++++++++++---------------
dlls/ole32/tests/compobj.c | 111 +++++++++++++++++++++++++++++++++++++++++-
2 files changed, 188 insertions(+), 41 deletions(-)
diff --git a/dlls/ole32/ole2.c b/dlls/ole32/ole2.c
index e7e6510..0aecb96 100644
--- a/dlls/ole32/ole2.c
+++ b/dlls/ole32/ole2.c
@@ -53,6 +53,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(ole);
WINE_DECLARE_DEBUG_CHANNEL(accel);
+#define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
+
/******************************************************************************
* These are static/global variables and internal data structures that the
* OLE module uses to maintain its state.
@@ -659,71 +661,107 @@ HRESULT WINAPI RevokeDragDrop(HWND hwnd)
return hr;
}
+/* Open HKCR\\CLSID\\{string form of clsid}\\{keyname} key, while respecting predefined keys overrides. */
+static HRESULT openkey_for_clsid(REFCLSID clsid, const WCHAR *keyname, REGSAM access, HKEY *subkey)
+{
+ static const WCHAR clsidfmtW[] = {'C','L','S','I','D','\\',0};
+ WCHAR path[CHARS_IN_GUID + ARRAYSIZE(clsidfmtW) - 1];
+ LONG res;
+ HKEY key;
+
+ strcpyW(path, clsidfmtW);
+ StringFromGUID2(clsid, path + strlenW(clsidfmtW), CHARS_IN_GUID);
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
+ if (res == ERROR_FILE_NOT_FOUND)
+ return REGDB_E_CLASSNOTREG;
+ else if (res != ERROR_SUCCESS)
+ return REGDB_E_READREGDB;
+
+ if (!keyname)
+ {
+ *subkey = key;
+ return S_OK;
+ }
+
+ res = RegOpenKeyExW(key, keyname, 0, access, subkey);
+ RegCloseKey(key);
+ if (res == ERROR_FILE_NOT_FOUND)
+ return REGDB_E_KEYMISSING;
+ else if (res != ERROR_SUCCESS)
+ return REGDB_E_READREGDB;
+
+ return S_OK;
+}
+
/***********************************************************************
* OleRegGetUserType (OLE32.@)
- *
- * This implementation of OleRegGetUserType ignores the dwFormOfType
- * parameter and always returns the full name of the object. This is
- * not too bad since this is the case for many objects because of the
- * way they are registered.
- */
-HRESULT WINAPI OleRegGetUserType(
- REFCLSID clsid,
- DWORD dwFormOfType,
- LPOLESTR* pszUserType)
-{
- DWORD dwKeyType;
- DWORD cbData;
- HKEY clsidKey;
+ */
+HRESULT WINAPI OleRegGetUserType(REFCLSID clsid, DWORD form, LPOLESTR *usertype)
+{
+ static const WCHAR auxusertypeW[] = {'A','u','x','U','s','e','r','T','y','p','e','\\','%','d',0};
+ DWORD valuetype, valuelen;
+ WCHAR auxkeynameW[16];
+ HKEY usertypekey;
HRESULT hres;
LONG ret;
- TRACE("(%s, %d, %p)\n", debugstr_guid(clsid), dwFormOfType, pszUserType);
+ TRACE("(%s, %u, %p)\n", debugstr_guid(clsid), form, usertype);
- if (!pszUserType)
+ if (!usertype)
return E_INVALIDARG;
- *pszUserType = NULL;
+ *usertype = NULL;
- hres = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &clsidKey);
+ /* Return immediately if it's not registered. */
+ hres = openkey_for_clsid(clsid, NULL, KEY_READ, &usertypekey);
if (FAILED(hres))
return hres;
- /*
- * Retrieve the size of the name string.
- */
- cbData = 0;
+ valuelen = 0;
- if (RegQueryValueExW(clsidKey, emptyW, NULL, &dwKeyType, NULL, &cbData))
+ /* Try additional types if requested. If they don't exist fall back to USERCLASSTYPE_FULL. */
+ if (form != USERCLASSTYPE_FULL)
{
- RegCloseKey(clsidKey);
- return REGDB_E_READREGDB;
+ HKEY auxkey;
+
+ sprintfW(auxkeynameW, auxusertypeW, form);
+ if (openkey_for_clsid(clsid, auxkeynameW, KEY_READ, &auxkey) == S_OK)
+ {
+ if (!RegQueryValueExW(auxkey, emptyW, NULL, &valuetype, NULL, &valuelen) && valuelen)
+ {
+ RegCloseKey(usertypekey);
+ usertypekey = auxkey;
+ }
+ else
+ RegCloseKey(auxkey);
+ }
}
- /*
- * Allocate a buffer for the registry value.
- */
- *pszUserType = CoTaskMemAlloc(cbData);
+ valuelen = 0;
+ if (RegQueryValueExW(usertypekey, emptyW, NULL, &valuetype, NULL, &valuelen))
+ {
+ RegCloseKey(usertypekey);
+ return REGDB_E_READREGDB;
+ }
- if (*pszUserType==NULL)
+ *usertype = CoTaskMemAlloc(valuelen);
+ if (!*usertype)
{
- RegCloseKey(clsidKey);
+ RegCloseKey(usertypekey);
return E_OUTOFMEMORY;
}
- ret = RegQueryValueExW(clsidKey,
+ ret = RegQueryValueExW(usertypekey,
emptyW,
NULL,
- &dwKeyType,
- (LPBYTE) *pszUserType,
- &cbData);
-
- RegCloseKey(clsidKey);
-
+ &valuetype,
+ (LPBYTE)*usertype,
+ &valuelen);
+ RegCloseKey(usertypekey);
if (ret != ERROR_SUCCESS)
{
- CoTaskMemFree(*pszUserType);
- *pszUserType = NULL;
+ CoTaskMemFree(*usertype);
+ *usertype = NULL;
return REGDB_E_READREGDB;
}
diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c
index 792d7dc..ee001e6 100644
--- a/dlls/ole32/tests/compobj.c
+++ b/dlls/ole32/tests/compobj.c
@@ -2229,11 +2229,29 @@ static void test_OleRegGetUserType(void)
{
static const WCHAR stdfont_usertypeW[] = {'S','t','a','n','d','a','r','d',' ','F','o','n','t',0};
static const WCHAR stdfont2_usertypeW[] = {'C','L','S','I','D','_','S','t','d','F','o','n','t',0};
+ static const WCHAR clsidkeyW[] = {'C','L','S','I','D',0};
+ static const WCHAR defvalueW[] = {'D','e','f','a','u','l','t',' ','N','a','m','e',0};
+ static const WCHAR auxvalue0W[] = {'A','u','x',' ','N','a','m','e',' ','0',0};
+ static const WCHAR auxvalue2W[] = {'A','u','x',' ','N','a','m','e',' ','2',0};
+ static const WCHAR auxvalue3W[] = {'A','u','x',' ','N','a','m','e',' ','3',0};
+ static const WCHAR auxvalue4W[] = {'A','u','x',' ','N','a','m','e',' ','4',0};
+
+ static const char auxvalues[][16] = {
+ "Aux Name 0",
+ "Aux Name 1",
+ "Aux Name 2",
+ "Aux Name 3",
+ "Aux Name 4"
+ };
+
+ WCHAR clsidW[39];
ULONG_PTR cookie;
HANDLE handle;
HRESULT hr;
WCHAR *str;
- DWORD form;
+ DWORD form, ret, disposition;
+ HKEY overridehkey, clsidhkey, hkey, auxhkey, classkey;
+ int i;
for (form = 0; form <= USERCLASSTYPE_APPNAME+1; form++) {
hr = OleRegGetUserType(&CLSID_Testclass, form, NULL);
@@ -2273,6 +2291,97 @@ static void test_OleRegGetUserType(void)
pDeactivateActCtx(0, cookie);
pReleaseActCtx(handle);
}
+
+ /* test using registered CLSID */
+ ret = RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Classes", 0, NULL, 0,
+ KEY_ALL_ACCESS, NULL, &overridehkey, NULL);
+ ok(!ret, "failed to create a key %d, error %d\n", ret, GetLastError());
+
+ ret = pRegOverridePredefKey(HKEY_CLASSES_ROOT, overridehkey);
+ ok(!ret, "RegOverridePredefKey returned %d, error %d\n", ret, GetLastError());
+
+ StringFromGUID2(&CLSID_non_existent, clsidW, sizeof(clsidW)/sizeof(clsidW[0]));
+
+ ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsidkeyW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &clsidhkey, &disposition);
+ ok(!ret, "failed to create a key %d, error %d\n", ret, GetLastError());
+
+ ret = RegCreateKeyExW(clsidhkey, clsidW, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &classkey, NULL);
+ ok(!ret, "failed to create a key %d, error %d\n", ret, GetLastError());
+
+ ret = RegSetValueExW(classkey, NULL, 0, REG_SZ, (const BYTE*)defvalueW, sizeof(defvalueW));
+ ok(!ret, "got %d, error %d\n", ret, GetLastError());
+
+ ret = RegCreateKeyExA(classkey, "AuxUserType", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &auxhkey, NULL);
+ ok(!ret, "got %d, error %d\n", ret, GetLastError());
+
+ /* populate AuxUserType */
+ for (i = 0; i <= 4; i++) {
+ char name[16];
+
+ sprintf(name, "AuxUserType\\%d", i);
+ ret = RegCreateKeyExA(classkey, name, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL);
+ ok(!ret, "got %d, error %d\n", ret, GetLastError());
+
+ ret = RegSetValueExA(hkey, NULL, 0, REG_SZ, (const BYTE*)auxvalues[i], strlen(auxvalues[i]));
+ ok(!ret, "got %d, error %d\n", ret, GetLastError());
+ RegCloseKey(hkey);
+ }
+
+ str = NULL;
+ hr = OleRegGetUserType(&CLSID_non_existent, 0, &str);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+ ok(!lstrcmpW(str, auxvalue0W), "got %s\n", wine_dbgstr_w(str));
+ CoTaskMemFree(str);
+
+ str = NULL;
+ hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_FULL, &str);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+ ok(!lstrcmpW(str, defvalueW), "got %s\n", wine_dbgstr_w(str));
+ CoTaskMemFree(str);
+
+ str = NULL;
+ hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_SHORT, &str);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+ ok(!lstrcmpW(str, auxvalue2W), "got %s\n", wine_dbgstr_w(str));
+ CoTaskMemFree(str);
+
+ str = NULL;
+ hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_APPNAME, &str);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+ ok(!lstrcmpW(str, auxvalue3W), "got %s\n", wine_dbgstr_w(str));
+ CoTaskMemFree(str);
+
+ str = NULL;
+ hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_APPNAME+1, &str);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+ ok(!lstrcmpW(str, auxvalue4W), "got %s\n", wine_dbgstr_w(str));
+ CoTaskMemFree(str);
+
+ str = NULL;
+ hr = OleRegGetUserType(&CLSID_non_existent, USERCLASSTYPE_APPNAME+2, &str);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+ ok(!lstrcmpW(str, defvalueW), "got %s\n", wine_dbgstr_w(str));
+ CoTaskMemFree(str);
+
+ /* registry cleanup */
+ for (i = 0; i <= 4; i++)
+ {
+ char name[2];
+ sprintf(name, "%d", i);
+ RegDeleteKeyA(auxhkey, name);
+ }
+ RegCloseKey(auxhkey);
+ RegDeleteKeyA(classkey, "AuxUserType");
+ RegCloseKey(classkey);
+ RegDeleteKeyW(clsidhkey, clsidW);
+ RegCloseKey(clsidhkey);
+ if (disposition == REG_CREATED_NEW_KEY)
+ RegDeleteKeyA(HKEY_CLASSES_ROOT, "CLSID");
+
+ ret = pRegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);
+ ok(!ret, "RegOverridePredefKey returned %d, error %d\n", ret, GetLastError());
+
+ RegCloseKey(overridehkey);
}
static void test_CoCreateGuid(void)
{
--
2.6.4
More information about the wine-patches
mailing list