[Python-checkins] r79620 - in python/trunk: Doc/library/_winreg.rst Lib/test/test_winreg.py PC/_winreg.c

brian.curtin python-checkins at python.org
Fri Apr 2 23:18:14 CEST 2010


Author: brian.curtin
Date: Fri Apr  2 23:18:14 2010
New Revision: 79620

Log:
Implement #7347. Add CreateKeyEx, DeleteKeyEx, and update _winreg tests.

*ReflectionKey functions used to not be documented or tested, but they are
now sufficiently documented and tested on platforms where they apply. 
Additionally, fixed a bug in QueryReflectionKey which was returning an
incorrect value.

All tests pass from XP through Windows 7, on 32 and 64-bit platforms.


Modified:
   python/trunk/Doc/library/_winreg.rst
   python/trunk/Lib/test/test_winreg.py
   python/trunk/PC/_winreg.c

Modified: python/trunk/Doc/library/_winreg.rst
==============================================================================
--- python/trunk/Doc/library/_winreg.rst	(original)
+++ python/trunk/Doc/library/_winreg.rst	Fri Apr  2 23:18:14 2010
@@ -68,15 +68,40 @@
    :exc:`WindowsError` exception is  raised.
 
 
+.. function:: CreateKeyEx(key, sub_key[, res=0[, sam=KEY_ALL_ACCESS]])
+
+   Creates or opens the specified key, returning a :dfn:`handle object`
+
+   *key* is an already open key, or one of the predefined :const:`HKEY_\*`
+   constants.
+
+   *sub_key* is a string that names the key this method opens or creates.
+
+   *res* is a reserved integer, and must be zero. The default is zero.
+
+   *sam* is an integer that specifies an access mask that describes the desired
+   security access for the key. Default is :const:`KEY_ALL_ACCESS`
+
+   If *key* is one of the predefined keys, *sub_key* may  be ``None``. In that
+   case, the handle returned is the same key handle  passed in to the function.
+
+   If the key already exists, this function opens the existing key.
+
+   The return value is the handle of the opened key. If the function fails, a
+   :exc:`WindowsError` exception is raised.
+
+.. versionadded:: 2.7
+
+
 .. function:: DeleteKey(key, sub_key)
 
    Deletes the specified key.
 
-   *key* is an already open key, or any one of the predefined  :const:`HKEY_\*`
+   *key* is an already open key, or any one of the predefined :const:`HKEY_\*`
    constants.
 
-   *sub_key* is a string that must be a subkey of the key  identified by the *key*
-   parameter.  This value must not be  ``None``, and the key may not have subkeys.
+   *sub_key* is a string that must be a subkey of the key identified by the *key*
+   parameter.  This value must not be ``None``, and the key may not have subkeys.
 
    *This method can not delete keys with subkeys.*
 
@@ -84,6 +109,37 @@
    If the method fails, a :exc:`WindowsError`  exception is raised.
 
 
+.. function:: DeleteKeyEx(key, sub_key[, sam=KEY_WOW64_64KEY[, res=0]])
+
+   Deletes the specified key.
+
+   .. note::
+      The :func:`DeleteKeyEx` function is implemented with the RegDeleteKeyEx
+      Windows API function, which is specific to 64-bit versions of Windows.
+      See http://msdn.microsoft.com/en-us/library/ms724847%28VS.85%29.aspx
+
+   *key* is an already open key, or any one of the predefined :const:`HKEY_\*`
+   constants.
+
+   *sub_key* is a string that must be a subkey of the key identified by the
+   *key* parameter. This value must not be ``None``, and the key may not have
+   subkeys.
+
+   *res* is a reserved integer, and must be zero. The default is zero.
+
+   *sam* is an integer that specifies an access mask that describes the
+   desired security access for the key. Default is :const:`KEY_WOW64_64KEY`
+
+   *This method can not delete keys with subkeys.*
+
+   If the method succeeds, the entire key, including all of its values, is
+   removed. If the method fails, a :exc:`WindowsError` exception is raised.
+
+   On unsupported Windows versions, :exc:`NotImplementedError` is raised.
+
+.. versionadded:: 2.7
+
+
 .. function:: DeleteValue(key, value)
 
    Removes a named value from a registry key.
@@ -383,6 +439,48 @@
    registry.  This helps the registry perform efficiently.
 
 
+.. function:: DisableReflectionKey(key)
+
+   Disables registry reflection for 32-bit processes running on a 64-bit
+   Operating System.
+
+   *key* is an already open key, or one of the predefined :const:`HKEY_\*`
+   constants.
+
+   Will generally raise :exc:`NotImplemented` if executed on a 32-bit
+   Operating System.
+
+   If the key is not on the reflection list, the function succeeds but has no
+   effect. Disabling reflection for a key does not affect reflection of any
+   subkeys.
+
+
+.. function:: EnableReflectionKey(key)
+
+   Restores registry reflection for the specified disabled key.
+
+   *key* is an already open key, or one of the predefined :const:`HKEY_\*`
+   constants.
+
+   Will generally raise :exc:`NotImplemented` if executed on a 32-bit
+   Operating System.
+
+   Restoring reflection for a key does not affect reflection of any subkeys.
+
+
+.. function:: QueryReflectionKey(key)
+
+   Determines the reflection state for the specified key.
+
+   *key* is an already open key, or one of the predefined :const:`HKEY_\*`
+   constants.
+
+   Returns ``True`` if reflection is disabled.
+
+   Will generally raise :exc:`NotImplemented` if executed on a 32-bit
+   Operating System.
+
+
 .. _handle-object:
 
 Registry Handle Objects

Modified: python/trunk/Lib/test/test_winreg.py
==============================================================================
--- python/trunk/Lib/test/test_winreg.py	(original)
+++ python/trunk/Lib/test/test_winreg.py	Fri Apr  2 23:18:14 2010
@@ -4,13 +4,32 @@
 import os, sys
 import unittest
 from test import test_support
+from platform import machine
 
 # Do this first so test will be skipped if module doesn't exist
 test_support.import_module('_winreg')
 # Now import everything
 from _winreg import *
 
+try:
+    REMOTE_NAME = sys.argv[sys.argv.index("--remote")+1]
+except (IndexError, ValueError):
+    REMOTE_NAME = None
+
+# tuple of (major, minor)
+WIN_VER = sys.getwindowsversion()[:2]
+# Some tests should only run on 64-bit architectures where WOW64 will be.
+WIN64_MACHINE = True if machine() == "AMD64" else False
+
+# Starting with Windows 7 and Windows Server 2008 R2, WOW64 no longer uses
+# registry reflection and formerly reflected keys are shared instead.
+# Windows 7 and Windows Server 2008 R2 are version 6.1. Due to this, some
+# tests are only valid up until 6.1
+HAS_REFLECTION = True if WIN_VER < (6, 1) else False
+
 test_key_name = "SOFTWARE\\Python Registry Test Key - Delete Me"
+# On OS'es that support reflection we should test with a reflected key
+test_reflect_key_name = "SOFTWARE\\Classes\\Python Test Key - Delete Me"
 
 test_data = [
     ("Int Value",     45,                                      REG_DWORD),
@@ -32,8 +51,7 @@
                            "values"], REG_MULTI_SZ),
     ]
 
-class WinregTests(unittest.TestCase):
-    remote_name = None
+class BaseWinregTests(unittest.TestCase):
 
     def setUp(self):
         # Make sure that the test key is absent when the test
@@ -56,7 +74,7 @@
         CloseKey(hkey)
         DeleteKey(root, subkey)
 
-    def WriteTestData(self, root_key):
+    def _write_test_data(self, root_key, CreateKey=CreateKey):
         # Set the default value for this key.
         SetValue(root_key, test_key_name, REG_SZ, "Default value")
         key = CreateKey(root_key, test_key_name)
@@ -96,7 +114,7 @@
         except EnvironmentError:
             pass
 
-    def ReadTestData(self, root_key):
+    def _read_test_data(self, root_key, OpenKey=OpenKey):
         # Check we can get default value for this key.
         val = QueryValue(root_key, test_key_name)
         self.assertEquals(val, "Default value",
@@ -136,7 +154,7 @@
 
         key.Close()
 
-    def DeleteTestData(self, root_key):
+    def _delete_test_data(self, root_key):
         key = OpenKey(root_key, test_key_name, 0, KEY_ALL_ACCESS)
         sub_key = OpenKey(key, "sub_key", 0, KEY_ALL_ACCESS)
         # It is not necessary to delete the values before deleting
@@ -166,38 +184,175 @@
         except WindowsError: # Use this error name this time
             pass
 
-    def TestAll(self, root_key):
-        self.WriteTestData(root_key)
-        self.ReadTestData(root_key)
-        self.DeleteTestData(root_key)
+    def _test_all(self, root_key):
+        self._write_test_data(root_key)
+        self._read_test_data(root_key)
+        self._delete_test_data(root_key)
+
+class LocalWinregTests(BaseWinregTests):
+
+    def test_registry_works(self):
+        self._test_all(HKEY_CURRENT_USER)
+
+    def test_registry_works_extended_functions(self):
+        # Substitute the regular CreateKey and OpenKey calls with their
+        # extended counterparts.
+        # Note: DeleteKeyEx is not used here because it is platform dependent
+        cke = lambda key, sub_key: CreateKeyEx(key, sub_key, 0, KEY_ALL_ACCESS)
+        self._write_test_data(HKEY_CURRENT_USER, cke)
 
-    def testLocalMachineRegistryWorks(self):
-        self.TestAll(HKEY_CURRENT_USER)
+        oke = lambda key, sub_key: OpenKeyEx(key, sub_key, 0, KEY_READ)
+        self._read_test_data(HKEY_CURRENT_USER, oke)
 
-    def testConnectRegistryToLocalMachineWorks(self):
+        self._delete_test_data(HKEY_CURRENT_USER)
+
+    def test_connect_registry_to_local_machine_works(self):
         # perform minimal ConnectRegistry test which just invokes it
         h = ConnectRegistry(None, HKEY_LOCAL_MACHINE)
+        self.assertNotEqual(h.handle, 0)
         h.Close()
+        self.assertEqual(h.handle, 0)
 
-    def testRemoteMachineRegistryWorks(self):
-        if not self.remote_name:
-            return # remote machine name not specified
-        remote_key = ConnectRegistry(self.remote_name, HKEY_CURRENT_USER)
-        self.TestAll(remote_key)
+    def test_inexistant_remote_registry(self):
+        connect = lambda: ConnectRegistry("abcdefghijkl", HKEY_CURRENT_USER)
+        self.assertRaises(WindowsError, connect)
 
-    def testExpandEnvironmentStrings(self):
+    def test_expand_environment_strings(self):
         r = ExpandEnvironmentStrings(u"%windir%\\test")
         self.assertEqual(type(r), unicode)
         self.assertEqual(r, os.environ["windir"] + "\\test")
 
+    def test_context_manager(self):
+        # ensure that the handle is closed if an exception occurs
+        try:
+            with ConnectRegistry(None, HKEY_LOCAL_MACHINE) as h:
+                self.assertNotEqual(h.handle, 0)
+                raise WindowsError
+        except WindowsError:
+            self.assertEqual(h.handle, 0)
+
+    # Reflection requires XP x64/Vista at a minimum. XP doesn't have this stuff
+    # or DeleteKeyEx so make sure their use raises NotImplementedError
+    @unittest.skipUnless(WIN_VER < (5, 2), "Requires Windows XP")
+    def test_reflection_unsupported(self):
+        try:
+            with CreateKey(HKEY_CURRENT_USER, test_key_name) as ck:
+                self.assertNotEqual(ck.handle, 0)
+
+            key = OpenKey(HKEY_CURRENT_USER, test_key_name)
+            self.assertNotEqual(key.handle, 0)
+
+            self.assertRaises(NotImplementedError, DisableReflectionKey(key))
+            self.assertRaises(NotImplementedError, EnableReflectionKey(key))
+            self.assertRaises(NotImplementedError, QueryReflectionKey(key))
+            self.assertRaises(NotImplementedError,
+                              DeleteKeyEx(HKEY_CURRENT_USER, test_key_name))
+        finally:
+            DeleteKey(HKEY_CURRENT_USER, test_key_name)
+
+
+ at unittest.skipUnless(REMOTE_NAME, "Skipping remote registry tests")
+class RemoteWinregTests(BaseWinregTests):
+
+    def test_remote_registry_works(self):
+        remote_key = ConnectRegistry(REMOTE_NAME, HKEY_CURRENT_USER)
+        self._test_all(remote_key)
+
+
+ at unittest.skipUnless(WIN64_MACHINE, "x64 specific registry tests")
+class Win64WinregTests(BaseWinregTests):
+
+    def test_reflection_functions(self):
+        # Test that we can call the query, enable, and disable functions
+        # on a key which isn't on the reflection list with no consequences.
+        with OpenKey(HKEY_LOCAL_MACHINE, "Software") as key:
+            # HKLM\Software is redirected but not reflected in all OSes
+            self.assertTrue(QueryReflectionKey(key))
+            self.assertEquals(None, EnableReflectionKey(key))
+            self.assertEquals(None, DisableReflectionKey(key))
+            self.assertTrue(QueryReflectionKey(key))
+
+    @unittest.skipUnless(HAS_REFLECTION, "OS doesn't support reflection")
+    def test_reflection(self):
+        # Test that we can create, open, and delete keys in the 32-bit
+        # area. Because we are doing this in a key which gets reflected,
+        # test the differences of 32 and 64-bit keys before and after the
+        # reflection occurs (ie. when the created key is closed).
+        try:
+            with CreateKeyEx(HKEY_CURRENT_USER, test_reflect_key_name, 0,
+                             KEY_ALL_ACCESS | KEY_WOW64_32KEY) as created_key:
+                self.assertNotEqual(created_key.handle, 0)
+
+                # The key should now be available in the 32-bit area
+                with OpenKey(HKEY_CURRENT_USER, test_reflect_key_name, 0,
+                             KEY_ALL_ACCESS | KEY_WOW64_32KEY) as key:
+                    self.assertNotEqual(key.handle, 0)
+
+                # Write a value to what currently is only in the 32-bit area
+                SetValueEx(created_key, "", 0, REG_SZ, "32KEY")
+
+                # The key is not reflected until created_key is closed.
+                # The 64-bit version of the key should not be available yet.
+                open_fail = lambda: OpenKey(HKEY_CURRENT_USER,
+                                            test_reflect_key_name, 0,
+                                            KEY_READ | KEY_WOW64_64KEY)
+                self.assertRaises(WindowsError, open_fail)
+
+            # Now explicitly open the 64-bit version of the key
+            with OpenKey(HKEY_CURRENT_USER, test_reflect_key_name, 0,
+                         KEY_ALL_ACCESS | KEY_WOW64_64KEY) as key:
+                self.assertNotEqual(key.handle, 0)
+                # Make sure the original value we set is there
+                self.assertEqual("32KEY", QueryValue(key, ""))
+                # Set a new value, which will get reflected to 32-bit
+                SetValueEx(key, "", 0, REG_SZ, "64KEY")
+
+            # Reflection uses a "last-writer wins policy, so the value we set
+            # on the 64-bit key should be the same on 32-bit
+            with OpenKey(HKEY_CURRENT_USER, test_reflect_key_name, 0,
+                         KEY_READ | KEY_WOW64_32KEY) as key:
+                self.assertEqual("64KEY", QueryValue(key, ""))
+        finally:
+            DeleteKeyEx(HKEY_CURRENT_USER, test_reflect_key_name,
+                        KEY_WOW64_32KEY, 0)
+
+    @unittest.skipUnless(HAS_REFLECTION, "OS doesn't support reflection")
+    def test_disable_reflection(self):
+        # Make use of a key which gets redirected and reflected
+        try:
+            with CreateKeyEx(HKEY_CURRENT_USER, test_reflect_key_name, 0,
+                             KEY_ALL_ACCESS | KEY_WOW64_32KEY) as created_key:
+                # QueryReflectionKey returns whether or not the key is disabled
+                disabled = QueryReflectionKey(created_key)
+                self.assertEqual(type(disabled), bool)
+                # HKCU\Software\Classes is reflected by default
+                self.assertFalse(disabled)
+
+                DisableReflectionKey(created_key)
+                self.assertTrue(QueryReflectionKey(created_key))
+
+            # The key is now closed and would normally be reflected to the
+            # 64-bit area, but let's make sure that didn't happen.
+            open_fail = lambda: OpenKeyEx(HKEY_CURRENT_USER,
+                                          test_reflect_key_name, 0,
+                                          KEY_READ | KEY_WOW64_64KEY)
+            self.assertRaises(WindowsError, open_fail)
+
+            # Make sure the 32-bit key is actually there
+            with OpenKeyEx(HKEY_CURRENT_USER, test_reflect_key_name, 0,
+                           KEY_READ | KEY_WOW64_32KEY) as key:
+                self.assertNotEqual(key.handle, 0)
+        finally:
+            DeleteKeyEx(HKEY_CURRENT_USER, test_reflect_key_name,
+                        KEY_WOW64_32KEY, 0)
+
+
 def test_main():
-    test_support.run_unittest(WinregTests)
+    test_support.run_unittest(LocalWinregTests, RemoteWinregTests,
+                              Win64WinregTests)
 
 if __name__ == "__main__":
-    try:
-        WinregTests.remote_name = sys.argv[sys.argv.index("--remote")+1]
-    except (IndexError, ValueError):
+    if not REMOTE_NAME:
         print "Remote registry calls can be tested using",
         print "'test_winreg.py --remote \\\\machine_name'"
-        WinregTests.remote_name = None
     test_main()

Modified: python/trunk/PC/_winreg.c
==============================================================================
--- python/trunk/PC/_winreg.c	(original)
+++ python/trunk/PC/_winreg.c	Fri Apr  2 23:18:14 2010
@@ -89,7 +89,7 @@
 "key is the predefined handle to connect to.\n"
 "\n"
 "The return value is the handle of the opened key.\n"
-"If the function fails, an EnvironmentError exception is raised.");
+"If the function fails, a WindowsError exception is raised.");
 
 PyDoc_STRVAR(CreateKey_doc,
 "key = CreateKey(key, sub_key) - Creates or opens the specified key.\n"
@@ -104,6 +104,21 @@
 "The return value is the handle of the opened key.\n"
 "If the function fails, an exception is raised.");
 
+PyDoc_STRVAR(CreateKeyEx_doc,
+"key = CreateKeyEx(key, sub_key, res, sam) - Creates or opens the specified key.\n"
+"\n"
+"key is an already open key, or one of the predefined HKEY_* constants\n"
+"sub_key is a string that names the key this method opens or creates.\n"
+"res is a reserved integer, and must be zero.  Default is zero.\n"
+"sam is an integer that specifies an access mask that describes the desired\n"
+" If key is one of the predefined keys, sub_key may be None. In that case,\n"
+" the handle returned is the same key handle passed in to the function.\n"
+"\n"
+"If the key already exists, this function opens the existing key\n"
+"\n"
+"The return value is the handle of the opened key.\n"
+"If the function fails, an exception is raised.");
+
 PyDoc_STRVAR(DeleteKey_doc,
 "DeleteKey(key, sub_key) - Deletes the specified key.\n"
 "\n"
@@ -114,7 +129,22 @@
 "This method can not delete keys with subkeys.\n"
 "\n"
 "If the method succeeds, the entire key, including all of its values,\n"
-"is removed.  If the method fails, an EnvironmentError exception is raised.");
+"is removed.  If the method fails, a WindowsError exception is raised.");
+
+PyDoc_STRVAR(DeleteKeyEx_doc,
+"DeleteKeyEx(key, sub_key, sam, res) - Deletes the specified key.\n"
+"\n"
+"key is an already open key, or any one of the predefined HKEY_* constants.\n"
+"sub_key is a string that must be a subkey of the key identified by the key parameter.\n"
+"res is a reserved integer, and must be zero.  Default is zero.\n"
+"sam is an integer that specifies an access mask that describes the desired\n"
+" This value must not be None, and the key may not have subkeys.\n"
+"\n"
+"This method can not delete keys with subkeys.\n"
+"\n"
+"If the method succeeds, the entire key, including all of its values,\n"
+"is removed.  If the method fails, a WindowsError exception is raised.\n"
+"On unsupported Windows versions, NotImplementedError is raised.");
 
 PyDoc_STRVAR(DeleteValue_doc,
 "DeleteValue(key, value) - Removes a named value from a registry key.\n"
@@ -129,7 +159,7 @@
 "index is an integer that identifies the index of the key to retrieve.\n"
 "\n"
 "The function retrieves the name of one subkey each time it is called.\n"
-"It is typically called repeatedly until an EnvironmentError exception is\n"
+"It is typically called repeatedly until a WindowsError exception is\n"
 "raised, indicating no more values are available.");
 
 PyDoc_STRVAR(EnumValue_doc,
@@ -138,7 +168,7 @@
 "index is an integer that identifies the index of the value to retrieve.\n"
 "\n"
 "The function retrieves the name of one subkey each time it is called.\n"
-"It is typically called repeatedly, until an EnvironmentError exception\n"
+"It is typically called repeatedly, until a WindowsError exception\n"
 "is raised, indicating no more values.\n"
 "\n"
 "The result is a tuple of 3 items:\n"
@@ -192,7 +222,7 @@
 " security access for the key.  Default is KEY_READ\n"
 "\n"
 "The result is a new handle to the specified key\n"
-"If the function fails, an EnvironmentError exception is raised.");
+"If the function fails, a WindowsError exception is raised.");
 
 PyDoc_STRVAR(OpenKeyEx_doc, "See OpenKey()");
 
@@ -1014,6 +1044,29 @@
 }
 
 static PyObject *
+PyCreateKeyEx(PyObject *self, PyObject *args)
+{
+	HKEY hKey;
+	PyObject *obKey;
+	char *subKey;
+	HKEY retKey;
+	int res = 0;
+	REGSAM sam = KEY_WRITE;
+	long rc;
+	if (!PyArg_ParseTuple(args, "Oz|ii:CreateKeyEx", &obKey, &subKey,
+						  &res, &sam))
+		return NULL;
+	if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE))
+		return NULL;
+
+	rc = RegCreateKeyEx(hKey, subKey, res, NULL, (DWORD)NULL, 
+						sam, NULL, &retKey, NULL);
+	if (rc != ERROR_SUCCESS)
+		return PyErr_SetFromWindowsErrWithFunction(rc, "CreateKeyEx");
+	return PyHKEY_FromHKEY(retKey);
+}
+
+static PyObject *
 PyDeleteKey(PyObject *self, PyObject *args)
 {
 	HKEY hKey;
@@ -1032,6 +1085,46 @@
 }
 
 static PyObject *
+PyDeleteKeyEx(PyObject *self, PyObject *args)
+{
+	HKEY hKey;
+	PyObject *obKey;
+	HMODULE hMod;
+	typedef LONG (WINAPI *RDKEFunc)(HKEY, const char*, REGSAM, int);
+	RDKEFunc pfn = NULL;
+	char *subKey;
+	long rc;
+	int res = 0;
+	REGSAM sam = KEY_WOW64_64KEY;
+
+	if (!PyArg_ParseTuple(args, "Os|ii:DeleteKeyEx",
+						  &obKey, &subKey, &sam, &res))
+		return NULL;
+	if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE))
+		return NULL;
+
+	/* Only available on 64bit platforms, so we must load it
+	   dynamically. */
+	hMod = GetModuleHandle("advapi32.dll");
+	if (hMod)
+		pfn = (RDKEFunc)GetProcAddress(hMod,
+									   "RegDeleteKeyExA");
+	if (!pfn) {
+		PyErr_SetString(PyExc_NotImplementedError,
+						"not implemented on this platform");
+		return NULL;
+	}
+	Py_BEGIN_ALLOW_THREADS
+	rc = (*pfn)(hKey, subKey, sam, res);
+	Py_END_ALLOW_THREADS
+
+	if (rc != ERROR_SUCCESS)
+		return PyErr_SetFromWindowsErrWithFunction(rc, "RegDeleteKeyEx");
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
 PyDeleteValue(PyObject *self, PyObject *args)
 {
 	HKEY hKey;
@@ -1479,8 +1572,8 @@
 	if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE))
 		return NULL;
 
-	// Only available on 64bit platforms, so we must load it
-	// dynamically.
+	/* Only available on 64bit platforms, so we must load it
+	   dynamically. */
 	hMod = GetModuleHandle("advapi32.dll");
 	if (hMod)
 		pfn = (RDRKFunc)GetProcAddress(hMod,
@@ -1515,8 +1608,8 @@
 	if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE))
 		return NULL;
 
-	// Only available on 64bit platforms, so we must load it
-	// dynamically.
+	/* Only available on 64bit platforms, so we must load it
+	   dynamically. */
 	hMod = GetModuleHandle("advapi32.dll");
 	if (hMod)
 		pfn = (RERKFunc)GetProcAddress(hMod,
@@ -1552,8 +1645,8 @@
 	if (!PyHKEY_AsHKEY(obKey, &hKey, FALSE))
 		return NULL;
 
-	// Only available on 64bit platforms, so we must load it
-	// dynamically.
+	/* Only available on 64bit platforms, so we must load it
+	   dynamically. */
 	hMod = GetModuleHandle("advapi32.dll");
 	if (hMod)
 		pfn = (RQRKFunc)GetProcAddress(hMod,
@@ -1569,14 +1662,16 @@
 	if (rc != ERROR_SUCCESS)
 		return PyErr_SetFromWindowsErrWithFunction(rc,
 		                                           "RegQueryReflectionKey");
-	return PyBool_FromLong(rc);
+	return PyBool_FromLong(result);
 }
 
 static struct PyMethodDef winreg_methods[] = {
 	{"CloseKey",         PyCloseKey,        METH_VARARGS, CloseKey_doc},
 	{"ConnectRegistry",  PyConnectRegistry, METH_VARARGS, ConnectRegistry_doc},
 	{"CreateKey",        PyCreateKey,       METH_VARARGS, CreateKey_doc},
+	{"CreateKeyEx",      PyCreateKeyEx,     METH_VARARGS, CreateKeyEx_doc},
 	{"DeleteKey",        PyDeleteKey,       METH_VARARGS, DeleteKey_doc},
+	{"DeleteKeyEx",      PyDeleteKeyEx,     METH_VARARGS, DeleteKeyEx_doc},
 	{"DeleteValue",      PyDeleteValue,     METH_VARARGS, DeleteValue_doc},
 	{"DisableReflectionKey", PyDisableReflectionKey, METH_VARARGS, DisableReflectionKey_doc},
 	{"EnableReflectionKey",  PyEnableReflectionKey,  METH_VARARGS, EnableReflectionKey_doc},


More information about the Python-checkins mailing list