From e3fac9662aab9d71c777d75bbd838662bec9b79d Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 9 Feb 2025 19:23:55 +0900 Subject: [PATCH 01/25] Enhance winreg.OpenKeyEx and winreg.CreateKeyEx --- .../pycore_global_objects_fini_generated.h | 1 + Include/internal/pycore_global_strings.h | 1 + .../internal/pycore_runtime_init_generated.h | 1 + .../internal/pycore_unicodeobject_generated.h | 4 + PC/clinic/winreg.c.h | 105 ++++++++++++------ PC/winreg.c | 35 ++++-- 6 files changed, 107 insertions(+), 40 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 90214a314031d1..187c978375b539 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -873,6 +873,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(coro)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(count)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(covariant)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(create_only)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cwd)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(data)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(database)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 97a75d0c46c867..79819df7e7d9b0 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -362,6 +362,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(coro) STRUCT_FOR_ID(count) STRUCT_FOR_ID(covariant) + STRUCT_FOR_ID(create_only) STRUCT_FOR_ID(cwd) STRUCT_FOR_ID(data) STRUCT_FOR_ID(database) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 4f928cc050bf8e..2a103937a721b8 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -871,6 +871,7 @@ extern "C" { INIT_ID(coro), \ INIT_ID(count), \ INIT_ID(covariant), \ + INIT_ID(create_only), \ INIT_ID(cwd), \ INIT_ID(data), \ INIT_ID(database), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 5b78d038fc1192..e55abacac68adb 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1244,6 +1244,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(create_only); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(cwd); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index 00fa6a75ec113e..4c5f88f823bbdf 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -284,7 +284,7 @@ winreg_CreateKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyDoc_STRVAR(winreg_CreateKeyEx__doc__, "CreateKeyEx($module, /, key, sub_key, reserved=0,\n" -" access=winreg.KEY_WRITE)\n" +" access=winreg.KEY_WRITE, options=0, create_only=False)\n" "--\n" "\n" "Creates or opens the specified key.\n" @@ -312,7 +312,8 @@ PyDoc_STRVAR(winreg_CreateKeyEx__doc__, static HKEY winreg_CreateKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, - int reserved, REGSAM access); + int reserved, REGSAM access, int options, + int create_only); static PyObject * winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -320,14 +321,14 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 4 + #define NUM_KEYWORDS 6 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(key), &_Py_ID(sub_key), &_Py_ID(reserved), &_Py_ID(access), }, + .ob_item = { &_Py_ID(key), &_Py_ID(sub_key), &_Py_ID(reserved), &_Py_ID(access), &_Py_ID(options), &_Py_ID(create_only), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -336,23 +337,25 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", NULL}; + static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", "options", "create_only", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "CreateKeyEx", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[4]; + PyObject *argsbuf[6]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HKEY key; const wchar_t *sub_key = NULL; int reserved = 0; REGSAM access = KEY_WRITE; + int options = 0; + int create_only = 0; HKEY _return_value; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 2, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + /*minpos*/ 2, /*maxpos*/ 6, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } @@ -384,12 +387,30 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py goto skip_optional_pos; } } - access = PyLong_AsInt(args[3]); - if (access == -1 && PyErr_Occurred()) { + if (args[3]) { + access = PyLong_AsInt(args[3]); + if (access == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[4]) { + options = PyLong_AsInt(args[4]); + if (options == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + create_only = PyObject_IsTrue(args[5]); + if (create_only < 0) { goto exit; } skip_optional_pos: - _return_value = winreg_CreateKeyEx_impl(module, key, sub_key, reserved, access); + _return_value = winreg_CreateKeyEx_impl(module, key, sub_key, reserved, access, options, create_only); if (_return_value == NULL) { goto exit; } @@ -906,7 +927,8 @@ winreg_LoadKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) #if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) PyDoc_STRVAR(winreg_OpenKey__doc__, -"OpenKey($module, /, key, sub_key, reserved=0, access=winreg.KEY_READ)\n" +"OpenKey($module, /, key, sub_key, reserved=0, access=winreg.KEY_READ,\n" +" options=0)\n" "--\n" "\n" "Opens the specified key.\n" @@ -929,7 +951,7 @@ PyDoc_STRVAR(winreg_OpenKey__doc__, static HKEY winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, - int reserved, REGSAM access); + int reserved, REGSAM access, int options); static PyObject * winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -937,14 +959,14 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 4 + #define NUM_KEYWORDS 5 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(key), &_Py_ID(sub_key), &_Py_ID(reserved), &_Py_ID(access), }, + .ob_item = { &_Py_ID(key), &_Py_ID(sub_key), &_Py_ID(reserved), &_Py_ID(access), &_Py_ID(options), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -953,23 +975,24 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", NULL}; + static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", "options", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "OpenKey", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[4]; + PyObject *argsbuf[5]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HKEY key; const wchar_t *sub_key = NULL; int reserved = 0; REGSAM access = KEY_READ; + int options = 0; HKEY _return_value; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 2, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + /*minpos*/ 2, /*maxpos*/ 5, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } @@ -1001,12 +1024,21 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje goto skip_optional_pos; } } - access = PyLong_AsInt(args[3]); - if (access == -1 && PyErr_Occurred()) { + if (args[3]) { + access = PyLong_AsInt(args[3]); + if (access == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + options = PyLong_AsInt(args[4]); + if (options == -1 && PyErr_Occurred()) { goto exit; } skip_optional_pos: - _return_value = winreg_OpenKey_impl(module, key, sub_key, reserved, access); + _return_value = winreg_OpenKey_impl(module, key, sub_key, reserved, access, options); if (_return_value == NULL) { goto exit; } @@ -1024,7 +1056,8 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje #if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) PyDoc_STRVAR(winreg_OpenKeyEx__doc__, -"OpenKeyEx($module, /, key, sub_key, reserved=0, access=winreg.KEY_READ)\n" +"OpenKeyEx($module, /, key, sub_key, reserved=0, access=winreg.KEY_READ,\n" +" options=0)\n" "--\n" "\n" "Opens the specified key.\n" @@ -1047,7 +1080,7 @@ PyDoc_STRVAR(winreg_OpenKeyEx__doc__, static HKEY winreg_OpenKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, - int reserved, REGSAM access); + int reserved, REGSAM access, int options); static PyObject * winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -1055,14 +1088,14 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 4 + #define NUM_KEYWORDS 5 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(key), &_Py_ID(sub_key), &_Py_ID(reserved), &_Py_ID(access), }, + .ob_item = { &_Py_ID(key), &_Py_ID(sub_key), &_Py_ID(reserved), &_Py_ID(access), &_Py_ID(options), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1071,23 +1104,24 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", NULL}; + static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", "options", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "OpenKeyEx", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[4]; + PyObject *argsbuf[5]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HKEY key; const wchar_t *sub_key = NULL; int reserved = 0; REGSAM access = KEY_READ; + int options = 0; HKEY _return_value; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 2, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + /*minpos*/ 2, /*maxpos*/ 5, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } @@ -1119,12 +1153,21 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb goto skip_optional_pos; } } - access = PyLong_AsInt(args[3]); - if (access == -1 && PyErr_Occurred()) { + if (args[3]) { + access = PyLong_AsInt(args[3]); + if (access == -1 && PyErr_Occurred()) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + options = PyLong_AsInt(args[4]); + if (options == -1 && PyErr_Occurred()) { goto exit; } skip_optional_pos: - _return_value = winreg_OpenKeyEx_impl(module, key, sub_key, reserved, access); + _return_value = winreg_OpenKeyEx_impl(module, key, sub_key, reserved, access, options); if (_return_value == NULL) { goto exit; } @@ -1766,4 +1809,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) #ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF #define WINREG_QUERYREFLECTIONKEY_METHODDEF #endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */ -/*[clinic end generated code: output=fbe9b075cd2fa833 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d655e9f02ebb0e92 input=a9049054013a1b77]*/ diff --git a/PC/winreg.c b/PC/winreg.c index efdf8addc06186..e38fb0a7cd178a 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -950,6 +950,8 @@ winreg.CreateKeyEx -> HKEY access: REGSAM(c_default='KEY_WRITE') = winreg.KEY_WRITE An integer that specifies an access mask that describes the desired security access for the key. Default is KEY_WRITE. + options: int = 0 + create_only: bool = False Creates or opens the specified key. @@ -964,19 +966,21 @@ If the function fails, an OSError exception is raised. static HKEY winreg_CreateKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, - int reserved, REGSAM access) -/*[clinic end generated code: output=51b53e38d5e00d4b input=42c2b03f98406b66]*/ + int reserved, REGSAM access, int options, + int create_only) +/*[clinic end generated code: output=10c0a5f7beea07e3 input=89977916fab6d95e]*/ { HKEY retKey; long rc; + DWORD disposition; if (PySys_Audit("winreg.CreateKey", "nun", (Py_ssize_t)key, sub_key, (Py_ssize_t)access) < 0) { return NULL; } - rc = RegCreateKeyExW(key, sub_key, reserved, NULL, 0, - access, NULL, &retKey, NULL); + rc = RegCreateKeyExW(key, sub_key, reserved, NULL, options, + access, NULL, &retKey, &disposition); if (rc != ERROR_SUCCESS) { PyErr_SetFromWindowsErrWithFunction(rc, "CreateKeyEx"); return NULL; @@ -985,6 +989,15 @@ winreg_CreateKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, (Py_ssize_t)retKey) < 0) { return NULL; } + if (create_only == TRUE) { + if (disposition == REG_OPENED_EXISTING_KEY) { + PyErr_SetString(PyExc_FileExistsError, ""); + if (retKey != key) { + RegCloseKey(key); + } + return NULL; + } + } return retKey; } @@ -1398,6 +1411,7 @@ winreg.OpenKey -> HKEY access: REGSAM(c_default='KEY_READ') = winreg.KEY_READ An integer that specifies an access mask that describes the desired security access for the key. Default is KEY_READ. + options: int = 0 Opens the specified key. @@ -1407,8 +1421,8 @@ If the function fails, an OSError exception is raised. static HKEY winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, - int reserved, REGSAM access) -/*[clinic end generated code: output=5efbad23b3ffe2e7 input=098505ac36a9ae28]*/ + int reserved, REGSAM access, int options) +/*[clinic end generated code: output=1cb0239fad9672e0 input=c0bb3ed652f63389]*/ { HKEY retKey; long rc; @@ -1418,6 +1432,9 @@ winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, (Py_ssize_t)access) < 0) { return NULL; } + if (options != 0) { + reserved = options; + } Py_BEGIN_ALLOW_THREADS rc = RegOpenKeyExW(key, sub_key, reserved, access, &retKey); Py_END_ALLOW_THREADS @@ -1443,10 +1460,10 @@ If the function fails, an OSError exception is raised. static HKEY winreg_OpenKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, - int reserved, REGSAM access) -/*[clinic end generated code: output=435e675800fa78c2 input=c6c4972af8622959]*/ + int reserved, REGSAM access, int options) +/*[clinic end generated code: output=08a607e6a6385ed4 input=c6c4972af8622959]*/ { - return winreg_OpenKey_impl(module, key, sub_key, reserved, access); + return winreg_OpenKey_impl(module, key, sub_key, reserved, access, options); } /*[clinic input] From 59dfa3d265e0a509751c91a625e07b573145da20 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 9 Feb 2025 23:44:23 +0900 Subject: [PATCH 02/25] Add tests --- Lib/test/test_winreg.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py index 924a962781a75b..7debcdacf2d267 100644 --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -228,6 +228,23 @@ def test_registry_works_extended_functions(self): self._delete_test_data(HKEY_CURRENT_USER) + def test_registry_works_with_options(self): + ckeo = lambda key, sub_key: CreateKeyEx(key, sub_key, 0, KEY_ALL_ACCESS, + options=REG_OPTION_VOLATILE) + self._write_test_data(HKEY_CURRENT_USER, CreateKey=ckeo) + + okeo = lambda key, sub_key: OpenKeyEx(key, sub_key, 0, KEY_READ, + options=REG_OPTION_VOLATILE) + self._read_test_data(HKEY_CURRENT_USER, OpenKey=okeo) + + self._delete_test_data(HKEY_CURRENT_USER) + + def test_create_only(self): + CreateKeyEx(HKEY_CURRENT_USER, test_key_name) + with self.assertRaises(FileExistsError): + CreateKeyEx(HKEY_CURRENT_USER, test_key_name, create_only=True) + DeleteKey(HKEY_CURRENT_USER, test_key_name) + def test_named_arguments(self): self._test_named_args(HKEY_CURRENT_USER, test_key_name) # Use the regular DeleteKey to clean up From bba8ba60dca7b15834545fe3a72ab692d8d5fb32 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 9 Feb 2025 23:47:32 +0900 Subject: [PATCH 03/25] Update sys.audit --- PC/winreg.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/PC/winreg.c b/PC/winreg.c index e38fb0a7cd178a..3bb75a12935f4e 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -974,9 +974,9 @@ winreg_CreateKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, long rc; DWORD disposition; - if (PySys_Audit("winreg.CreateKey", "nun", + if (PySys_Audit("winreg.CreateKey", "nunii", (Py_ssize_t)key, sub_key, - (Py_ssize_t)access) < 0) { + (Py_ssize_t)access, options, create_only) < 0) { return NULL; } rc = RegCreateKeyExW(key, sub_key, reserved, NULL, options, @@ -985,19 +985,21 @@ winreg_CreateKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, PyErr_SetFromWindowsErrWithFunction(rc, "CreateKeyEx"); return NULL; } - if (PySys_Audit("winreg.OpenKey/result", "n", - (Py_ssize_t)retKey) < 0) { - return NULL; - } if (create_only == TRUE) { if (disposition == REG_OPENED_EXISTING_KEY) { PyErr_SetString(PyExc_FileExistsError, ""); if (retKey != key) { + // This is predefined key and doesn't need close. RegCloseKey(key); } + PySys_Audit("winreg.OpenKey/result", "n", NULL0; return NULL; } } + if (PySys_Audit("winreg.OpenKey/result", "n", + (Py_ssize_t)retKey) < 0) { + return NULL; + } return retKey; } @@ -1427,9 +1429,9 @@ winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, HKEY retKey; long rc; - if (PySys_Audit("winreg.OpenKey", "nun", + if (PySys_Audit("winreg.OpenKey", "nuni", (Py_ssize_t)key, sub_key, - (Py_ssize_t)access) < 0) { + (Py_ssize_t)access, options) < 0) { return NULL; } if (options != 0) { From 47ea0ba6535afa554567b1daa1152fd30c89f56f Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 10 Feb 2025 00:00:39 +0900 Subject: [PATCH 04/25] Add news entry --- .../next/Windows/2025-02-10-00-00-00.gh-issue-95461.rBmMaH.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Windows/2025-02-10-00-00-00.gh-issue-95461.rBmMaH.rst diff --git a/Misc/NEWS.d/next/Windows/2025-02-10-00-00-00.gh-issue-95461.rBmMaH.rst b/Misc/NEWS.d/next/Windows/2025-02-10-00-00-00.gh-issue-95461.rBmMaH.rst new file mode 100644 index 00000000000000..b1b6a67d0ce14e --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2025-02-10-00-00-00.gh-issue-95461.rBmMaH.rst @@ -0,0 +1,2 @@ +Add *options* and *create_only* parameters to :meth:``winreg.CreateKeyEx``. +Add *options* parameter to :meth:``winreg.OpenKeyEx``. From d6251e0804059cc72311885d0ce71eab31346293 Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 10 Feb 2025 00:08:15 +0900 Subject: [PATCH 05/25] Add documents --- PC/winreg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PC/winreg.c b/PC/winreg.c index 3bb75a12935f4e..8887665f4f60f8 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -951,7 +951,10 @@ winreg.CreateKeyEx -> HKEY An integer that specifies an access mask that describes the desired security access for the key. Default is KEY_WRITE. options: int = 0 + Can be one of the REG_OPTION_* constants. create_only: bool = False + When set to True, raise FileExistsError if the key is already exists. + Default is False. Creates or opens the specified key. @@ -1414,6 +1417,7 @@ winreg.OpenKey -> HKEY An integer that specifies an access mask that describes the desired security access for the key. Default is KEY_READ. options: int = 0 + Can be one of the REG_OPTION_* constants. Opens the specified key. From f4f4fff1c31caacf6146b185a1b2dcbcad115a1d Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 10 Feb 2025 00:11:48 +0900 Subject: [PATCH 06/25] Fix sphinx error --- .../Windows/2025-02-10-00-00-00.gh-issue-95461.rBmMaH.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Windows/2025-02-10-00-00-00.gh-issue-95461.rBmMaH.rst b/Misc/NEWS.d/next/Windows/2025-02-10-00-00-00.gh-issue-95461.rBmMaH.rst index b1b6a67d0ce14e..5861aab1f47b06 100644 --- a/Misc/NEWS.d/next/Windows/2025-02-10-00-00-00.gh-issue-95461.rBmMaH.rst +++ b/Misc/NEWS.d/next/Windows/2025-02-10-00-00-00.gh-issue-95461.rBmMaH.rst @@ -1,2 +1,2 @@ -Add *options* and *create_only* parameters to :meth:``winreg.CreateKeyEx``. -Add *options* parameter to :meth:``winreg.OpenKeyEx``. +Add *options* and *create_only* parameters to :meth:`winreg.CreateKeyEx`. +Add *options* parameter to :meth:`winreg.OpenKeyEx`. From 1fd89dbd281977a716acb432987c8e69882bdb78 Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 10 Feb 2025 00:18:54 +0900 Subject: [PATCH 07/25] Fix typo --- PC/winreg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PC/winreg.c b/PC/winreg.c index 8887665f4f60f8..10d87d049154dd 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -995,7 +995,7 @@ winreg_CreateKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, // This is predefined key and doesn't need close. RegCloseKey(key); } - PySys_Audit("winreg.OpenKey/result", "n", NULL0; + PySys_Audit("winreg.OpenKey/result", "n", NULL); return NULL; } } From 28bf171ebdb95c2290f7f047983f44e5d8b27e8d Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 10 Feb 2025 00:24:49 +0900 Subject: [PATCH 08/25] Regenerate files --- PC/clinic/winreg.c.h | 11 ++++++++++- PC/winreg.c | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index 4c5f88f823bbdf..7d2d44491c1e20 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -298,6 +298,11 @@ PyDoc_STRVAR(winreg_CreateKeyEx__doc__, " access\n" " An integer that specifies an access mask that describes the\n" " desired security access for the key. Default is KEY_WRITE.\n" +" options\n" +" Can be one of the REG_OPTION_* constants.\n" +" create_only\n" +" When set to True, raise FileExistsError if the key is already exists.\n" +" Default is False.\n" "\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" @@ -942,6 +947,8 @@ PyDoc_STRVAR(winreg_OpenKey__doc__, " access\n" " An integer that specifies an access mask that describes the desired\n" " security access for the key. Default is KEY_READ.\n" +" options\n" +" Can be one of the REG_OPTION_* constants.\n" "\n" "The result is a new handle to the specified key.\n" "If the function fails, an OSError exception is raised."); @@ -1071,6 +1078,8 @@ PyDoc_STRVAR(winreg_OpenKeyEx__doc__, " access\n" " An integer that specifies an access mask that describes the desired\n" " security access for the key. Default is KEY_READ.\n" +" options\n" +" Can be one of the REG_OPTION_* constants.\n" "\n" "The result is a new handle to the specified key.\n" "If the function fails, an OSError exception is raised."); @@ -1809,4 +1818,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) #ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF #define WINREG_QUERYREFLECTIONKEY_METHODDEF #endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */ -/*[clinic end generated code: output=d655e9f02ebb0e92 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e93a17f1faf11685 input=a9049054013a1b77]*/ diff --git a/PC/winreg.c b/PC/winreg.c index 10d87d049154dd..202888ed3f3012 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -971,7 +971,7 @@ static HKEY winreg_CreateKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, int reserved, REGSAM access, int options, int create_only) -/*[clinic end generated code: output=10c0a5f7beea07e3 input=89977916fab6d95e]*/ +/*[clinic end generated code: output=10c0a5f7beea07e3 input=23d740b8cd7fb0df]*/ { HKEY retKey; long rc; @@ -1428,7 +1428,7 @@ If the function fails, an OSError exception is raised. static HKEY winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, int reserved, REGSAM access, int options) -/*[clinic end generated code: output=1cb0239fad9672e0 input=c0bb3ed652f63389]*/ +/*[clinic end generated code: output=1cb0239fad9672e0 input=22143fbb7e9bd606]*/ { HKEY retKey; long rc; From 94ed98bc82f9cea3bd401d0cb505ddb20cd66751 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 11 Feb 2025 17:10:44 +0900 Subject: [PATCH 09/25] Revert the changes on sys.audit --- PC/winreg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PC/winreg.c b/PC/winreg.c index 202888ed3f3012..cb844a82751003 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -977,9 +977,9 @@ winreg_CreateKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, long rc; DWORD disposition; - if (PySys_Audit("winreg.CreateKey", "nunii", + if (PySys_Audit("winreg.CreateKey", "nun", (Py_ssize_t)key, sub_key, - (Py_ssize_t)access, options, create_only) < 0) { + (Py_ssize_t)access) < 0) { return NULL; } rc = RegCreateKeyExW(key, sub_key, reserved, NULL, options, @@ -1433,9 +1433,9 @@ winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, HKEY retKey; long rc; - if (PySys_Audit("winreg.OpenKey", "nuni", + if (PySys_Audit("winreg.OpenKey", "nun", (Py_ssize_t)key, sub_key, - (Py_ssize_t)access, options) < 0) { + (Py_ssize_t)access) < 0) { return NULL; } if (options != 0) { From b8261bbe823a9c5d12362e2f2a12454a9b06609d Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 11 Feb 2025 17:13:29 +0900 Subject: [PATCH 10/25] Update comment --- PC/winreg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PC/winreg.c b/PC/winreg.c index cb844a82751003..dd643bf29f9f9d 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -992,7 +992,7 @@ winreg_CreateKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, if (disposition == REG_OPENED_EXISTING_KEY) { PyErr_SetString(PyExc_FileExistsError, ""); if (retKey != key) { - // This is predefined key and doesn't need close. + // This is not a predefined key and needs to be closed. RegCloseKey(key); } PySys_Audit("winreg.OpenKey/result", "n", NULL); From 2475c0b7780122fa743abb75abbee86009d3ca79 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 1 Mar 2025 21:56:49 +0900 Subject: [PATCH 11/25] Apply suggestions from code review Co-authored-by: Steve Dower --- PC/winreg.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/PC/winreg.c b/PC/winreg.c index dd643bf29f9f9d..32cad99bc24feb 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -988,14 +988,13 @@ winreg_CreateKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, PyErr_SetFromWindowsErrWithFunction(rc, "CreateKeyEx"); return NULL; } - if (create_only == TRUE) { + if (create_only) { if (disposition == REG_OPENED_EXISTING_KEY) { - PyErr_SetString(PyExc_FileExistsError, ""); + PyErr_SetFromWindowsErrWithFunction(ERROR_ALREADY_EXISTS, "CreateKeyEx"); if (retKey != key) { // This is not a predefined key and needs to be closed. RegCloseKey(key); } - PySys_Audit("winreg.OpenKey/result", "n", NULL); return NULL; } } From 913b21ab9c67edcc567836a799832b7c8c9f9783 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 1 Mar 2025 23:10:14 +0900 Subject: [PATCH 12/25] Update document for OpenKeyEx --- Doc/library/winreg.rst | 14 +++++++++++--- PC/winreg.c | 4 +++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index b3a824fb69a49f..a46cad8fb9592a 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -299,8 +299,8 @@ This module offers the following functions: .. audit-event:: winreg.LoadKey key,sub_key,file_name winreg.LoadKey -.. function:: OpenKey(key, sub_key, reserved=0, access=KEY_READ) - OpenKeyEx(key, sub_key, reserved=0, access=KEY_READ) +.. function:: OpenKey(key, sub_key, reserved=0, access=KEY_READ, options=0) + OpenKeyEx(key, sub_key, reserved=0, access=KEY_READ, options=0) Opens the specified key, returning a :ref:`handle object `. @@ -309,12 +309,20 @@ This module offers the following functions: *sub_key* is a string that identifies the sub_key to open. - *reserved* is a reserved integer, and must be zero. The default is zero. + *reserved* is a reserved integer and should be zero. + If it is not zero, it will be treated as the options parameter. + You should use the *options* parameter directly instead, + this parameter is only included for compatibility reasons. + The default value is zero. *access* is an integer that specifies an access mask that describes the desired security access for the key. Default is :const:`KEY_READ`. See :ref:`Access Rights ` for other allowed values. + *options* specifies the option to apply when opening the key. + Can be zero or one of the predefined + :ref:`REG_OPTION_* constants `. + The result is a new handle to the specified key. If the function fails, :exc:`OSError` is raised. diff --git a/PC/winreg.c b/PC/winreg.c index 32cad99bc24feb..96899e89edca49 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -1411,7 +1411,9 @@ winreg.OpenKey -> HKEY sub_key: Py_UNICODE(accept={str, NoneType}) A string that identifies the sub_key to open. reserved: int = 0 - A reserved integer that must be zero. Default is zero. + A reserved integer that be should zero. If it is not zero, + it will be used as the options parameter for compatibility reasons. + Default is zero. access: REGSAM(c_default='KEY_READ') = winreg.KEY_READ An integer that specifies an access mask that describes the desired security access for the key. Default is KEY_READ. From 483849abef3cb715344f11decb5ac1d4c19d2ec0 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 1 Mar 2025 23:25:01 +0900 Subject: [PATCH 13/25] Add document for CreateKeyEx --- Doc/library/winreg.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index a46cad8fb9592a..c149a0db9b44c3 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -85,7 +85,7 @@ This module offers the following functions: See :ref:`above `. -.. function:: CreateKeyEx(key, sub_key, reserved=0, access=KEY_WRITE) +.. function:: CreateKeyEx(key, sub_key, reserved=0, access=KEY_WRITE, options=0, create_only=False) Creates or opens the specified key, returning a :ref:`handle object `. @@ -101,6 +101,13 @@ This module offers the following functions: security access for the key. Default is :const:`KEY_WRITE`. See :ref:`Access Rights ` for other allowed values. + *options* is an interger and can be zero or one of the predefined + :ref:`REG_OPTION_* constants `. + + *create_only* is a boolean. + When set to True, a :exc:`FileExistsError`` will be raised + if the key is already exists. Default is ``False``. + 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. From bd57ba7080a59b053436de8606c88be8b8850c8e Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 1 Mar 2025 23:29:59 +0900 Subject: [PATCH 14/25] Fix CI --- Doc/library/winreg.rst | 2 +- PC/clinic/winreg.c.h | 10 +++++++--- PC/winreg.c | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index c149a0db9b44c3..3bcf4a50db488a 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -105,7 +105,7 @@ This module offers the following functions: :ref:`REG_OPTION_* constants `. *create_only* is a boolean. - When set to True, a :exc:`FileExistsError`` will be raised + When set to True, a :exc:`FileExistsError` will be raised if the key is already exists. Default is ``False``. If *key* is one of the predefined keys, *sub_key* may be ``None``. In that diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index 7d2d44491c1e20..e7fc6cc3a29c65 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -943,7 +943,9 @@ PyDoc_STRVAR(winreg_OpenKey__doc__, " sub_key\n" " A string that identifies the sub_key to open.\n" " reserved\n" -" A reserved integer that must be zero. Default is zero.\n" +" A reserved integer that be should zero. If it is not zero,\n" +" it will be used as the options parameter for compatibility reasons.\n" +" Default is zero.\n" " access\n" " An integer that specifies an access mask that describes the desired\n" " security access for the key. Default is KEY_READ.\n" @@ -1074,7 +1076,9 @@ PyDoc_STRVAR(winreg_OpenKeyEx__doc__, " sub_key\n" " A string that identifies the sub_key to open.\n" " reserved\n" -" A reserved integer that must be zero. Default is zero.\n" +" A reserved integer that be should zero. If it is not zero,\n" +" it will be used as the options parameter for compatibility reasons.\n" +" Default is zero.\n" " access\n" " An integer that specifies an access mask that describes the desired\n" " security access for the key. Default is KEY_READ.\n" @@ -1818,4 +1822,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) #ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF #define WINREG_QUERYREFLECTIONKEY_METHODDEF #endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */ -/*[clinic end generated code: output=e93a17f1faf11685 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d34ae631e9716f93 input=a9049054013a1b77]*/ diff --git a/PC/winreg.c b/PC/winreg.c index 96899e89edca49..c4e3903c33d645 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -1429,7 +1429,7 @@ If the function fails, an OSError exception is raised. static HKEY winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, int reserved, REGSAM access, int options) -/*[clinic end generated code: output=1cb0239fad9672e0 input=22143fbb7e9bd606]*/ +/*[clinic end generated code: output=1cb0239fad9672e0 input=2fff042272bfc4f6]*/ { HKEY retKey; long rc; From 6eae434f77caf8f0323eeb39cc321e62e9e55a21 Mon Sep 17 00:00:00 2001 From: AN Long Date: Wed, 12 Mar 2025 23:18:21 +0900 Subject: [PATCH 15/25] Split OpenKey and OpenKeyEx --- Lib/test/test_winreg.py | 3 +- PC/clinic/winreg.c.h | 69 +++++++++++++++++------------------------ PC/winreg.c | 62 +++++++++++++++++++++++------------- 3 files changed, 69 insertions(+), 65 deletions(-) diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py index 7debcdacf2d267..3d72025a340d81 100644 --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -233,8 +233,7 @@ def test_registry_works_with_options(self): options=REG_OPTION_VOLATILE) self._write_test_data(HKEY_CURRENT_USER, CreateKey=ckeo) - okeo = lambda key, sub_key: OpenKeyEx(key, sub_key, 0, KEY_READ, - options=REG_OPTION_VOLATILE) + okeo = lambda key, sub_key: OpenKeyEx(key, sub_key, REG_OPTION_VOLATILE, KEY_READ) self._read_test_data(HKEY_CURRENT_USER, OpenKey=okeo) self._delete_test_data(HKEY_CURRENT_USER) diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index e7fc6cc3a29c65..4d40d1293142b2 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -932,8 +932,7 @@ winreg_LoadKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) #if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) PyDoc_STRVAR(winreg_OpenKey__doc__, -"OpenKey($module, /, key, sub_key, reserved=0, access=winreg.KEY_READ,\n" -" options=0)\n" +"OpenKey($module, /, key, sub_key, reserved=0, access=winreg.KEY_READ)\n" "--\n" "\n" "Opens the specified key.\n" @@ -949,8 +948,6 @@ PyDoc_STRVAR(winreg_OpenKey__doc__, " access\n" " An integer that specifies an access mask that describes the desired\n" " security access for the key. Default is KEY_READ.\n" -" options\n" -" Can be one of the REG_OPTION_* constants.\n" "\n" "The result is a new handle to the specified key.\n" "If the function fails, an OSError exception is raised."); @@ -960,7 +957,7 @@ PyDoc_STRVAR(winreg_OpenKey__doc__, static HKEY winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, - int reserved, REGSAM access, int options); + int reserved, REGSAM access); static PyObject * winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -968,14 +965,14 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 5 + #define NUM_KEYWORDS 4 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(key), &_Py_ID(sub_key), &_Py_ID(reserved), &_Py_ID(access), &_Py_ID(options), }, + .ob_item = { &_Py_ID(key), &_Py_ID(sub_key), &_Py_ID(reserved), &_Py_ID(access), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -984,24 +981,23 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", "options", NULL}; + static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "OpenKey", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[5]; + PyObject *argsbuf[4]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HKEY key; const wchar_t *sub_key = NULL; int reserved = 0; REGSAM access = KEY_READ; - int options = 0; HKEY _return_value; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 2, /*maxpos*/ 5, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + /*minpos*/ 2, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } @@ -1033,21 +1029,12 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje goto skip_optional_pos; } } - if (args[3]) { - access = PyLong_AsInt(args[3]); - if (access == -1 && PyErr_Occurred()) { - goto exit; - } - if (!--noptargs) { - goto skip_optional_pos; - } - } - options = PyLong_AsInt(args[4]); - if (options == -1 && PyErr_Occurred()) { + access = PyLong_AsInt(args[3]); + if (access == -1 && PyErr_Occurred()) { goto exit; } skip_optional_pos: - _return_value = winreg_OpenKey_impl(module, key, sub_key, reserved, access, options); + _return_value = winreg_OpenKey_impl(module, key, sub_key, reserved, access); if (_return_value == NULL) { goto exit; } @@ -1065,8 +1052,8 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje #if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) PyDoc_STRVAR(winreg_OpenKeyEx__doc__, -"OpenKeyEx($module, /, key, sub_key, reserved=0, access=winreg.KEY_READ,\n" -" options=0)\n" +"OpenKeyEx($module, /, key, sub_key, options=0, access=winreg.KEY_READ,\n" +" reserved=0)\n" "--\n" "\n" "Opens the specified key.\n" @@ -1075,15 +1062,15 @@ PyDoc_STRVAR(winreg_OpenKeyEx__doc__, " An already open key, or any one of the predefined HKEY_* constants.\n" " sub_key\n" " A string that identifies the sub_key to open.\n" +" options\n" +" Can be one of the REG_OPTION_* constants.\n" +" access\n" +" An integer that specifies an access mask that describes the desired\n" +" security access for the key. Default is KEY_READ.\n" " reserved\n" " A reserved integer that be should zero. If it is not zero,\n" " it will be used as the options parameter for compatibility reasons.\n" " Default is zero.\n" -" access\n" -" An integer that specifies an access mask that describes the desired\n" -" security access for the key. Default is KEY_READ.\n" -" options\n" -" Can be one of the REG_OPTION_* constants.\n" "\n" "The result is a new handle to the specified key.\n" "If the function fails, an OSError exception is raised."); @@ -1093,7 +1080,7 @@ PyDoc_STRVAR(winreg_OpenKeyEx__doc__, static HKEY winreg_OpenKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, - int reserved, REGSAM access, int options); + int options, REGSAM access, int reserved); static PyObject * winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -1108,7 +1095,7 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(key), &_Py_ID(sub_key), &_Py_ID(reserved), &_Py_ID(access), &_Py_ID(options), }, + .ob_item = { &_Py_ID(key), &_Py_ID(sub_key), &_Py_ID(options), &_Py_ID(access), &_Py_ID(reserved), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -1117,7 +1104,7 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"key", "sub_key", "reserved", "access", "options", NULL}; + static const char * const _keywords[] = {"key", "sub_key", "options", "access", "reserved", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "OpenKeyEx", @@ -1128,9 +1115,9 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HKEY key; const wchar_t *sub_key = NULL; - int reserved = 0; - REGSAM access = KEY_READ; int options = 0; + REGSAM access = KEY_READ; + int reserved = 0; HKEY _return_value; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, @@ -1158,8 +1145,8 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb goto skip_optional_pos; } if (args[2]) { - reserved = PyLong_AsInt(args[2]); - if (reserved == -1 && PyErr_Occurred()) { + options = PyLong_AsInt(args[2]); + if (options == -1 && PyErr_Occurred()) { goto exit; } if (!--noptargs) { @@ -1175,12 +1162,12 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb goto skip_optional_pos; } } - options = PyLong_AsInt(args[4]); - if (options == -1 && PyErr_Occurred()) { + reserved = PyLong_AsInt(args[4]); + if (reserved == -1 && PyErr_Occurred()) { goto exit; } skip_optional_pos: - _return_value = winreg_OpenKeyEx_impl(module, key, sub_key, reserved, access, options); + _return_value = winreg_OpenKeyEx_impl(module, key, sub_key, options, access, reserved); if (_return_value == NULL) { goto exit; } @@ -1822,4 +1809,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) #ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF #define WINREG_QUERYREFLECTIONKEY_METHODDEF #endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */ -/*[clinic end generated code: output=d34ae631e9716f93 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2e7c0c73f6247000 input=a9049054013a1b77]*/ diff --git a/PC/winreg.c b/PC/winreg.c index c4e3903c33d645..b825ca9e052120 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -18,6 +18,7 @@ #include +#define MS_WINDOWS_DESKTOP #if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES) typedef struct { @@ -1417,8 +1418,37 @@ winreg.OpenKey -> HKEY access: REGSAM(c_default='KEY_READ') = winreg.KEY_READ An integer that specifies an access mask that describes the desired security access for the key. Default is KEY_READ. + +Opens the specified key. + +The result is a new handle to the specified key. +If the function fails, an OSError exception is raised. +[clinic start generated code]*/ + +static HKEY +winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, + int reserved, REGSAM access) +/*[clinic end generated code: output=5efbad23b3ffe2e7 input=7fb70c602dd114dd]*/ +{ + return winreg_OpenKeyEx_impl(module, key, sub_key, reserved, access, 0); +} + +/*[clinic input] +winreg.OpenKeyEx -> HKEY + + key: HKEY + An already open key, or any one of the predefined HKEY_* constants. + sub_key: Py_UNICODE(accept={str, NoneType}) + A string that identifies the sub_key to open. options: int = 0 Can be one of the REG_OPTION_* constants. + access: REGSAM(c_default='KEY_READ') = winreg.KEY_READ + An integer that specifies an access mask that describes the desired + security access for the key. Default is KEY_READ. + reserved: int = 0 + A reserved integer that be should zero. If it is not zero, + it will be used as the options parameter for compatibility reasons. + Default is zero. Opens the specified key. @@ -1427,9 +1457,9 @@ If the function fails, an OSError exception is raised. [clinic start generated code]*/ static HKEY -winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, - int reserved, REGSAM access, int options) -/*[clinic end generated code: output=1cb0239fad9672e0 input=2fff042272bfc4f6]*/ +winreg_OpenKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, + int options, REGSAM access, int reserved) +/*[clinic end generated code: output=db8d3dc70876a046 input=d997970b48ac2e30]*/ { HKEY retKey; long rc; @@ -1439,8 +1469,13 @@ winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, (Py_ssize_t)access) < 0) { return NULL; } - if (options != 0) { - reserved = options; + if (reserved != 0) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "reserved is deprecated, use options instead.", 1)) + { + return NULL; + } + options = reserved; } Py_BEGIN_ALLOW_THREADS rc = RegOpenKeyExW(key, sub_key, reserved, access, &retKey); @@ -1456,23 +1491,6 @@ winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, return retKey; } -/*[clinic input] -winreg.OpenKeyEx = winreg.OpenKey - -Opens the specified key. - -The result is a new handle to the specified key. -If the function fails, an OSError exception is raised. -[clinic start generated code]*/ - -static HKEY -winreg_OpenKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, - int reserved, REGSAM access, int options) -/*[clinic end generated code: output=08a607e6a6385ed4 input=c6c4972af8622959]*/ -{ - return winreg_OpenKey_impl(module, key, sub_key, reserved, access, options); -} - /*[clinic input] winreg.QueryInfoKey From 1b473ad8e027036bee72124d71abfed72cc3cd59 Mon Sep 17 00:00:00 2001 From: AN Long Date: Wed, 12 Mar 2025 23:57:14 +0900 Subject: [PATCH 16/25] Check deprecated warning in test --- Lib/test/test_winreg.py | 8 +++++++- PC/winreg.c | 4 +--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py index 3d72025a340d81..73885dc9ac74cd 100644 --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -233,9 +233,15 @@ def test_registry_works_with_options(self): options=REG_OPTION_VOLATILE) self._write_test_data(HKEY_CURRENT_USER, CreateKey=ckeo) - okeo = lambda key, sub_key: OpenKeyEx(key, sub_key, REG_OPTION_VOLATILE, KEY_READ) + okeo = lambda key, sub_key: OpenKeyEx(key, sub_key, REG_OPTION_VOLATILE, + KEY_READ) self._read_test_data(HKEY_CURRENT_USER, OpenKey=okeo) + with self.assertWarns(DeprecationWarning): + okeo = lambda key, sub_key: OpenKeyEx(key, sub_key, + reserved=REG_OPTION_VOLATILE) + self._read_test_data(HKEY_CURRENT_USER, OpenKey=okeo) + self._delete_test_data(HKEY_CURRENT_USER) def test_create_only(self): diff --git a/PC/winreg.c b/PC/winreg.c index b825ca9e052120..06b87d2e621a55 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -1412,9 +1412,7 @@ winreg.OpenKey -> HKEY sub_key: Py_UNICODE(accept={str, NoneType}) A string that identifies the sub_key to open. reserved: int = 0 - A reserved integer that be should zero. If it is not zero, - it will be used as the options parameter for compatibility reasons. - Default is zero. + A reserved integer that must be zero. Default is zero. access: REGSAM(c_default='KEY_READ') = winreg.KEY_READ An integer that specifies an access mask that describes the desired security access for the key. Default is KEY_READ. From 5badb7a32b2c57c9661ce519a63c984a3dba9a99 Mon Sep 17 00:00:00 2001 From: AN Long Date: Thu, 13 Mar 2025 00:38:16 +0900 Subject: [PATCH 17/25] Update document --- Doc/library/winreg.rst | 49 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index 3bcf4a50db488a..e0a9e54065408f 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -306,8 +306,7 @@ This module offers the following functions: .. audit-event:: winreg.LoadKey key,sub_key,file_name winreg.LoadKey -.. function:: OpenKey(key, sub_key, reserved=0, access=KEY_READ, options=0) - OpenKeyEx(key, sub_key, reserved=0, access=KEY_READ, options=0) +.. function:: OpenKey(key, sub_key, reserved=0, access=KEY_READ) Opens the specified key, returning a :ref:`handle object `. @@ -316,11 +315,34 @@ This module offers the following functions: *sub_key* is a string that identifies the sub_key to open. - *reserved* is a reserved integer and should be zero. - If it is not zero, it will be treated as the options parameter. - You should use the *options* parameter directly instead, - this parameter is only included for compatibility reasons. - The default value is zero. + *reserved* is a reserved integer, and must be zero. The default is zero. + + *access* is an integer that specifies an access mask that describes the desired + security access for the key. Default is :const:`KEY_READ`. See :ref:`Access + Rights ` for other allowed values. + + The result is a new handle to the specified key. + + If the function fails, :exc:`OSError` is raised. + + .. audit-event:: winreg.OpenKey key,sub_key,access winreg.OpenKey + + .. audit-event:: winreg.OpenKey/result key winreg.OpenKey + + .. versionchanged:: 3.2 + Allow the use of named arguments. + + .. versionchanged:: 3.3 + See :ref:`above `. + +.. function:: OpenKeyEx(key, sub_key, options=0, access=KEY_READ, reserved=0) + + Opens the specified key, returning a :ref:`handle object `. + + *key* is an already open key, or one of the predefined + :ref:`HKEY_* constants `. + + *sub_key* is a string that identifies the sub_key to open. *access* is an integer that specifies an access mask that describes the desired security access for the key. Default is :const:`KEY_READ`. See :ref:`Access @@ -330,6 +352,12 @@ This module offers the following functions: Can be zero or one of the predefined :ref:`REG_OPTION_* constants `. + *reserved* is a reserved integer and should be zero. + If it is not zero, it will be treated as the options parameter. + You should use the *options* parameter directly instead, + this parameter is only included for compatibility reasons. + The default value is zero. + The result is a new handle to the specified key. If the function fails, :exc:`OSError` is raised. @@ -343,6 +371,13 @@ This module offers the following functions: .. versionchanged:: 3.3 See :ref:`above `. + + .. versionchanged:: 3.14 + Added *options* parameter. + + .. deprecated-removed:: 3.14 3.16 + *reserved* is deprecated and will be removed in the future. + Please use *options* instead. .. function:: QueryInfoKey(key) From 7b9ffec8de46ec061c65d36ef4593f8700bb85b1 Mon Sep 17 00:00:00 2001 From: AN Long Date: Thu, 13 Mar 2025 00:40:12 +0900 Subject: [PATCH 18/25] Fix rst lint errors --- Doc/library/winreg.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index e0a9e54065408f..03577f7c6cebc0 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -371,10 +371,10 @@ This module offers the following functions: .. versionchanged:: 3.3 See :ref:`above `. - + .. versionchanged:: 3.14 Added *options* parameter. - + .. deprecated-removed:: 3.14 3.16 *reserved* is deprecated and will be removed in the future. Please use *options* instead. From b4e8d8b564e6f51ce36b3899770efda339988830 Mon Sep 17 00:00:00 2001 From: AN Long Date: Thu, 13 Mar 2025 00:44:54 +0900 Subject: [PATCH 19/25] Update generated files --- PC/clinic/winreg.c.h | 6 ++---- PC/winreg.c | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index 4d40d1293142b2..6c4afb62c93ce1 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -942,9 +942,7 @@ PyDoc_STRVAR(winreg_OpenKey__doc__, " sub_key\n" " A string that identifies the sub_key to open.\n" " reserved\n" -" A reserved integer that be should zero. If it is not zero,\n" -" it will be used as the options parameter for compatibility reasons.\n" -" Default is zero.\n" +" A reserved integer that must be zero. Default is zero.\n" " access\n" " An integer that specifies an access mask that describes the desired\n" " security access for the key. Default is KEY_READ.\n" @@ -1809,4 +1807,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) #ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF #define WINREG_QUERYREFLECTIONKEY_METHODDEF #endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */ -/*[clinic end generated code: output=2e7c0c73f6247000 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8112cdbe079ac8b8 input=a9049054013a1b77]*/ diff --git a/PC/winreg.c b/PC/winreg.c index 06b87d2e621a55..378a85023494c6 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -1426,7 +1426,7 @@ If the function fails, an OSError exception is raised. static HKEY winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, int reserved, REGSAM access) -/*[clinic end generated code: output=5efbad23b3ffe2e7 input=7fb70c602dd114dd]*/ +/*[clinic end generated code: output=5efbad23b3ffe2e7 input=a2fb7586bbed3b01]*/ { return winreg_OpenKeyEx_impl(module, key, sub_key, reserved, access, 0); } From 580a34834a0e8e79934d675ef21c46c05337eaa9 Mon Sep 17 00:00:00 2001 From: AN Long Date: Thu, 13 Mar 2025 23:54:20 +0900 Subject: [PATCH 20/25] Remove macro define by accident --- PC/winreg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/PC/winreg.c b/PC/winreg.c index 378a85023494c6..5d2b97d1d96385 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -18,7 +18,6 @@ #include -#define MS_WINDOWS_DESKTOP #if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES) typedef struct { From 9e64cb2ae5328ebc3f347f2c7eb64c8105899687 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 15 Mar 2025 20:55:45 +0900 Subject: [PATCH 21/25] Deprecate options in CreateKey too --- Doc/library/winreg.rst | 10 +++++++++- Lib/test/test_winreg.py | 5 +++++ PC/clinic/winreg.c.h | 6 ++++-- PC/winreg.c | 9 ++++++--- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index 03577f7c6cebc0..a566855ecaa42c 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -315,7 +315,11 @@ This module offers the following functions: *sub_key* is a string that identifies the sub_key to open. - *reserved* is a reserved integer, and must be zero. The default is zero. + *reserved* is a reserved integer and should be zero. If it is not zero, + it will be treated as the options parameter in :func:`OpenKeyEx`. + You should use the :func:`OpenKeyEx` directly instead in this case, + this parameter is only included for compatibility reasons. + The default value is zero. *access* is an integer that specifies an access mask that describes the desired security access for the key. Default is :const:`KEY_READ`. See :ref:`Access @@ -335,6 +339,10 @@ This module offers the following functions: .. versionchanged:: 3.3 See :ref:`above `. + .. deprecated-removed:: 3.14 3.16 + *reserved* is deprecated and will be removed in the future. + Please use :func:`OpenKeyEx` instead. + .. function:: OpenKeyEx(key, sub_key, options=0, access=KEY_READ, reserved=0) Opens the specified key, returning a :ref:`handle object `. diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py index 73885dc9ac74cd..7fb706f6b3577a 100644 --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -242,6 +242,11 @@ def test_registry_works_with_options(self): reserved=REG_OPTION_VOLATILE) self._read_test_data(HKEY_CURRENT_USER, OpenKey=okeo) + with self.assertWarns(DeprecationWarning): + ok = lambda key, sub_key: OpenKey(key, sub_key, + reserved=REG_OPTION_VOLATILE) + self._read_test_data(HKEY_CURRENT_USER, OpenKey=ok) + self._delete_test_data(HKEY_CURRENT_USER) def test_create_only(self): diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index 6c4afb62c93ce1..5c806b8e27da15 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -942,7 +942,9 @@ PyDoc_STRVAR(winreg_OpenKey__doc__, " sub_key\n" " A string that identifies the sub_key to open.\n" " reserved\n" -" A reserved integer that must be zero. Default is zero.\n" +" A reserved integer that be should zero. If it is not zero,\n" +" it will be used as the options parameter in OpenKeyEx.\n" +" You should use OpenKeyEx directly in this case.\n" " access\n" " An integer that specifies an access mask that describes the desired\n" " security access for the key. Default is KEY_READ.\n" @@ -1807,4 +1809,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) #ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF #define WINREG_QUERYREFLECTIONKEY_METHODDEF #endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */ -/*[clinic end generated code: output=8112cdbe079ac8b8 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=67346bb47df95b6b input=a9049054013a1b77]*/ diff --git a/PC/winreg.c b/PC/winreg.c index 5d2b97d1d96385..9d0a0ac1b24148 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -18,6 +18,7 @@ #include +#define MS_WINDOWS_GAMES // TODO(aisk): DELETE THIS #if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES) typedef struct { @@ -1411,7 +1412,9 @@ winreg.OpenKey -> HKEY sub_key: Py_UNICODE(accept={str, NoneType}) A string that identifies the sub_key to open. reserved: int = 0 - A reserved integer that must be zero. Default is zero. + A reserved integer that be should zero. If it is not zero, + it will be used as the options parameter in OpenKeyEx. + You should use OpenKeyEx directly in this case. access: REGSAM(c_default='KEY_READ') = winreg.KEY_READ An integer that specifies an access mask that describes the desired security access for the key. Default is KEY_READ. @@ -1425,9 +1428,9 @@ If the function fails, an OSError exception is raised. static HKEY winreg_OpenKey_impl(PyObject *module, HKEY key, const wchar_t *sub_key, int reserved, REGSAM access) -/*[clinic end generated code: output=5efbad23b3ffe2e7 input=a2fb7586bbed3b01]*/ +/*[clinic end generated code: output=5efbad23b3ffe2e7 input=8bafb91546317c8e]*/ { - return winreg_OpenKeyEx_impl(module, key, sub_key, reserved, access, 0); + return winreg_OpenKeyEx_impl(module, key, sub_key, 0, access, reserved); } /*[clinic input] From 5fab2218f43c46a7aac9d2829c63725e4533490c Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 15 Mar 2025 21:00:18 +0900 Subject: [PATCH 22/25] Remove the macro define again --- PC/winreg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/PC/winreg.c b/PC/winreg.c index 9d0a0ac1b24148..3ecac8a5df78a7 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -18,7 +18,6 @@ #include -#define MS_WINDOWS_GAMES // TODO(aisk): DELETE THIS #if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES) typedef struct { From 26b4e8242547734f8eb05339b7b813a300a17a91 Mon Sep 17 00:00:00 2001 From: AN Long Date: Thu, 13 Nov 2025 23:27:49 +0900 Subject: [PATCH 23/25] Update generate files --- Include/internal/pycore_unicodeobject_generated.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 3dd34d467fd51a..0907dedf788100 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1336,11 +1336,11 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(ctx); + string = &_Py_ID(create_only); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(create_only); + string = &_Py_ID(ctx); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); From 7900598a1cddb92b6854d1a644bb23fdc20adf47 Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 24 Nov 2025 21:37:36 +0900 Subject: [PATCH 24/25] Make options and create_only keyword-only for CreateKeyEx --- Doc/library/winreg.rst | 2 +- PC/clinic/winreg.c.h | 14 +++++++++----- PC/winreg.c | 3 ++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index 3907708e07719c..75cb53ca9ab71f 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -87,7 +87,7 @@ This module offers the following functions: See :ref:`above `. -.. function:: CreateKeyEx(key, sub_key, reserved=0, access=KEY_WRITE, options=0, create_only=False) +.. function:: CreateKeyEx(key, sub_key, reserved=0, access=KEY_WRITE, *, options=0, create_only=False) Creates or opens the specified key, returning a :ref:`handle object `. diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index 6e550c5f535f9a..a9c47e841c8fa9 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -284,7 +284,7 @@ winreg_CreateKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyDoc_STRVAR(winreg_CreateKeyEx__doc__, "CreateKeyEx($module, /, key, sub_key, reserved=0,\n" -" access=winreg.KEY_WRITE, options=0, create_only=False)\n" +" access=winreg.KEY_WRITE, *, options=0, create_only=False)\n" "--\n" "\n" "Creates or opens the specified key.\n" @@ -362,7 +362,7 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py HKEY _return_value; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 2, /*maxpos*/ 6, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + /*minpos*/ 2, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } @@ -403,20 +403,24 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py goto skip_optional_pos; } } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } if (args[4]) { options = PyLong_AsInt(args[4]); if (options == -1 && PyErr_Occurred()) { goto exit; } if (!--noptargs) { - goto skip_optional_pos; + goto skip_optional_kwonly; } } create_only = PyObject_IsTrue(args[5]); if (create_only < 0) { goto exit; } -skip_optional_pos: +skip_optional_kwonly: _return_value = winreg_CreateKeyEx_impl(module, key, sub_key, reserved, access, options, create_only); if (_return_value == NULL) { goto exit; @@ -1885,4 +1889,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) #ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF #define WINREG_QUERYREFLECTIONKEY_METHODDEF #endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */ -/*[clinic end generated code: output=e4015905d06f7360 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e32c46000e9d47b5 input=a9049054013a1b77]*/ diff --git a/PC/winreg.c b/PC/winreg.c index 817ac1f2191649..7bc090f7c4a460 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -931,6 +931,7 @@ winreg.CreateKeyEx -> HKEY access: REGSAM(c_default='KEY_WRITE') = winreg.KEY_WRITE An integer that specifies an access mask that describes the desired security access for the key. Default is KEY_WRITE. + * options: int = 0 Can be one of the REG_OPTION_* constants. create_only: bool = False @@ -952,7 +953,7 @@ static HKEY winreg_CreateKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, int reserved, REGSAM access, int options, int create_only) -/*[clinic end generated code: output=10c0a5f7beea07e3 input=23d740b8cd7fb0df]*/ +/*[clinic end generated code: output=10c0a5f7beea07e3 input=434f3dbac49bf638]*/ { HKEY retKey; long rc; From acc01c73928b3ac712d1da62bdf174e76601be22 Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 24 Nov 2025 23:41:03 +0900 Subject: [PATCH 25/25] Make reserved keyword-only for OpenKeyEx --- Doc/library/winreg.rst | 2 +- PC/clinic/winreg.c.h | 12 ++++++++---- PC/winreg.c | 3 ++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index 75cb53ca9ab71f..7621637b69006f 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -363,7 +363,7 @@ This module offers the following functions: *reserved* is deprecated and will be removed in the future. Please use :func:`OpenKeyEx` instead. -.. function:: OpenKeyEx(key, sub_key, options=0, access=KEY_READ, reserved=0) +.. function:: OpenKeyEx(key, sub_key, options=0, access=KEY_READ, *, reserved=0) Opens the specified key, returning a :ref:`handle object `. diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index a9c47e841c8fa9..4e1aded176e42e 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -1063,7 +1063,7 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje PyDoc_STRVAR(winreg_OpenKeyEx__doc__, "OpenKeyEx($module, /, key, sub_key, options=0, access=winreg.KEY_READ,\n" -" reserved=0)\n" +" *, reserved=0)\n" "--\n" "\n" "Opens the specified key.\n" @@ -1133,7 +1133,7 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb HKEY _return_value; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 2, /*maxpos*/ 5, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + /*minpos*/ 2, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } @@ -1174,11 +1174,15 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb goto skip_optional_pos; } } +skip_optional_pos: + if (!noptargs) { + goto skip_optional_kwonly; + } reserved = PyLong_AsInt(args[4]); if (reserved == -1 && PyErr_Occurred()) { goto exit; } -skip_optional_pos: +skip_optional_kwonly: _return_value = winreg_OpenKeyEx_impl(module, key, sub_key, options, access, reserved); if (_return_value == NULL) { goto exit; @@ -1889,4 +1893,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) #ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF #define WINREG_QUERYREFLECTIONKEY_METHODDEF #endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */ -/*[clinic end generated code: output=e32c46000e9d47b5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2d8704d0cd55051d input=a9049054013a1b77]*/ diff --git a/PC/winreg.c b/PC/winreg.c index 7bc090f7c4a460..4cb8cb8b6e507e 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -1430,6 +1430,7 @@ winreg.OpenKeyEx -> HKEY access: REGSAM(c_default='KEY_READ') = winreg.KEY_READ An integer that specifies an access mask that describes the desired security access for the key. Default is KEY_READ. + * reserved: int = 0 A reserved integer that be should zero. If it is not zero, it will be used as the options parameter for compatibility reasons. @@ -1444,7 +1445,7 @@ If the function fails, an OSError exception is raised. static HKEY winreg_OpenKeyEx_impl(PyObject *module, HKEY key, const wchar_t *sub_key, int options, REGSAM access, int reserved) -/*[clinic end generated code: output=db8d3dc70876a046 input=d997970b48ac2e30]*/ +/*[clinic end generated code: output=db8d3dc70876a046 input=c8b4acb92b668596]*/ { HKEY retKey; long rc;