[1/2] ole32: Use wrappers around NT functions to access the registry in CoGetPSClsid.

Hans Leidekker hans at codeweavers.com
Mon Nov 26 08:20:13 CST 2012


Code adapted from advapi32/registry.c.
---
 dlls/ole32/compobj.c         |  119 +++++++++++++++++++++++++++++++++++++++++-
 dlls/ole32/compobj_private.h |    3 ++
 dlls/ole32/tests/compobj.c   |    2 +-
 3 files changed, 122 insertions(+), 2 deletions(-)

diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c
index 9c92c32..70508b6 100644
--- a/dlls/ole32/compobj.c
+++ b/dlls/ole32/compobj.c
@@ -47,6 +47,8 @@
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
@@ -135,6 +137,121 @@ static CRITICAL_SECTION_DEBUG class_cs_debug =
 };
 static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };
 
+/* wrapper for NtCreateKey that creates the key recursively if necessary */
+static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
+{
+    NTSTATUS status = NtCreateKey( (HANDLE *)retkey, access, attr, 0, NULL, 0, NULL );
+
+    if (status == STATUS_OBJECT_NAME_NOT_FOUND)
+    {
+        HANDLE subkey, root = attr->RootDirectory;
+        WCHAR *buffer = attr->ObjectName->Buffer;
+        DWORD attrs, pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR);
+        UNICODE_STRING str;
+
+        while (i < len && buffer[i] != '\\') i++;
+        if (i == len) return status;
+
+        attrs = attr->Attributes;
+        attr->ObjectName = &str;
+
+        while (i < len)
+        {
+            str.Buffer = buffer + pos;
+            str.Length = (i - pos) * sizeof(WCHAR);
+            status = NtCreateKey( &subkey, access, attr, 0, NULL, 0, NULL );
+            if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
+            if (status) return status;
+            attr->RootDirectory = subkey;
+            while (i < len && buffer[i] == '\\') i++;
+            pos = i;
+            while (i < len && buffer[i] != '\\') i++;
+        }
+        str.Buffer = buffer + pos;
+        str.Length = (i - pos) * sizeof(WCHAR);
+        attr->Attributes = attrs;
+        status = NtCreateKey( (PHANDLE)retkey, access, attr, 0, NULL, 0, NULL );
+        if (attr->RootDirectory != root) NtClose( attr->RootDirectory );
+    }
+    return status;
+}
+
+static const WCHAR classes_rootW[] =
+    {'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\','C','l','a','s','s','e','s',0};
+
+static HKEY classes_root_hkey;
+
+/* create the special HKEY_CLASSES_ROOT key */
+static HKEY create_classes_root_hkey(void)
+{
+    HKEY hkey, ret = 0;
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING name;
+
+    attr.Length = sizeof(attr);
+    attr.RootDirectory = 0;
+    attr.ObjectName = &name;
+    attr.Attributes = 0;
+    attr.SecurityDescriptor = NULL;
+    attr.SecurityQualityOfService = NULL;
+    RtlInitUnicodeString( &name, classes_rootW );
+    if (create_key( &hkey, MAXIMUM_ALLOWED, &attr )) return 0;
+    TRACE( "%s -> %p\n", debugstr_w(attr.ObjectName->Buffer), hkey );
+
+    if (!(ret = InterlockedCompareExchangePointer( (void **)&classes_root_hkey, hkey, 0 )))
+        ret = hkey;
+    else
+        NtClose( hkey );  /* somebody beat us to it */
+    return ret;
+}
+
+/* map the hkey from special root to normal key if necessary */
+static inline HKEY get_classes_root_hkey( HKEY hkey )
+{
+    HKEY ret = hkey;
+
+    if (hkey == HKEY_CLASSES_ROOT && !(ret = classes_root_hkey))
+        ret = create_classes_root_hkey();
+
+    return ret;
+}
+
+LSTATUS create_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
+{
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING nameW;
+
+    if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
+    attr.Length = sizeof(attr);
+    attr.RootDirectory = hkey;
+    attr.ObjectName = &nameW;
+    attr.Attributes = 0;
+    attr.SecurityDescriptor = NULL;
+    attr.SecurityQualityOfService = NULL;
+    RtlInitUnicodeString( &nameW, name );
+
+    return RtlNtStatusToDosError( create_key( retkey, access, &attr ) );
+}
+
+LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *retkey )
+{
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING nameW;
+
+    if (!(hkey = get_classes_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
+
+    attr.Length = sizeof(attr);
+    attr.RootDirectory = hkey;
+    attr.ObjectName = &nameW;
+    attr.Attributes = 0;
+    attr.SecurityDescriptor = NULL;
+    attr.SecurityQualityOfService = NULL;
+    RtlInitUnicodeString( &nameW, name );
+
+    return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) );
+}
+
 /*****************************************************************************
  * This section contains OpenDllList definitions
  *
@@ -2055,7 +2172,7 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
     strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
 
     /* Open the key.. */
-    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
+    if (open_classes_key(HKEY_CLASSES_ROOT, path, KEY_READ, &hkey))
     {
         WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
         return REGDB_E_IIDNOTREG;
diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h
index 0039655..b76e3a7 100644
--- a/dlls/ole32/compobj_private.h
+++ b/dlls/ole32/compobj_private.h
@@ -309,4 +309,7 @@ extern UINT object_descriptor_clipboard_format DECLSPEC_HIDDEN;
 extern UINT link_source_descriptor_clipboard_format DECLSPEC_HIDDEN;
 extern UINT ole_private_data_clipboard_format DECLSPEC_HIDDEN;
 
+extern LSTATUS create_classes_key(HKEY, const WCHAR *, REGSAM, HKEY *) DECLSPEC_HIDDEN;
+extern LSTATUS open_classes_key(HKEY, const WCHAR *, REGSAM, HKEY *) DECLSPEC_HIDDEN;
+
 #endif /* __WINE_OLE_COMPOBJ_H */
diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c
index 048b082..714feee 100644
--- a/dlls/ole32/tests/compobj.c
+++ b/dlls/ole32/tests/compobj.c
@@ -755,7 +755,7 @@ static void test_CoGetPSClsid(void)
     ok(!res, "RegOverridePredefKey returned %d\n", res);
 
     hr = CoGetPSClsid(&IID_IClassFactory, &clsid);
-    todo_wine ok_ole_success(hr, "CoGetPSClsid");
+    ok_ole_success(hr, "CoGetPSClsid");
 
     res = pRegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);
     ok(!res, "RegOverridePredefKey returned %d\n", res);
-- 
1.7.10.4







More information about the wine-patches mailing list