From 54016b13aa3620b95d1382719d7aa8cda967266e Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 16 Aug 2025 18:36:45 +0900 Subject: [PATCH 01/26] Add RegisterEventSource and DeregisterEventSource in _winapi --- .../pycore_global_objects_fini_generated.h | 2 + Include/internal/pycore_global_strings.h | 2 + .../internal/pycore_runtime_init_generated.h | 2 + .../internal/pycore_unicodeobject_generated.h | 8 + Lib/test/test_winapi.py | 14 ++ Modules/_winapi.c | 54 ++++++ Modules/clinic/_winapi.c.h | 159 +++++++++++++++++- 7 files changed, 240 insertions(+), 1 deletion(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 6c8ce475c69842..0e679416d06abe 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -1249,6 +1249,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sock)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sort)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(source)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(source_name)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(source_traceback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(spam)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(src)); @@ -1308,6 +1309,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tzinfo)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tzname)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(uid)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(unc_server_name)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(unlink)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(unraisablehook)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(updates)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 55e48214728153..74fb70c216d78b 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -740,6 +740,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(sock) STRUCT_FOR_ID(sort) STRUCT_FOR_ID(source) + STRUCT_FOR_ID(source_name) STRUCT_FOR_ID(source_traceback) STRUCT_FOR_ID(spam) STRUCT_FOR_ID(src) @@ -799,6 +800,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(tzinfo) STRUCT_FOR_ID(tzname) STRUCT_FOR_ID(uid) + STRUCT_FOR_ID(unc_server_name) STRUCT_FOR_ID(unlink) STRUCT_FOR_ID(unraisablehook) STRUCT_FOR_ID(updates) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index ea188d4f2bf8ed..bf2fb1c2a91e5b 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1247,6 +1247,7 @@ extern "C" { INIT_ID(sock), \ INIT_ID(sort), \ INIT_ID(source), \ + INIT_ID(source_name), \ INIT_ID(source_traceback), \ INIT_ID(spam), \ INIT_ID(src), \ @@ -1306,6 +1307,7 @@ extern "C" { INIT_ID(tzinfo), \ INIT_ID(tzname), \ INIT_ID(uid), \ + INIT_ID(unc_server_name), \ INIT_ID(unlink), \ INIT_ID(unraisablehook), \ INIT_ID(updates), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 044fdafef246ed..45fef0b1936300 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -2748,6 +2748,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(source_name); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(source_traceback); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2984,6 +2988,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(unc_server_name); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(unlink); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index e64208330ad2f9..563e0ca5b636b9 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -156,3 +156,17 @@ def test_namedpipe(self): pipe2.write(b'testdata') pipe2.flush() self.assertEqual((b'testdata', 8), _winapi.PeekNamedPipe(pipe, 8)[:2]) + + def test_event_source_registration(self): + source_name = "PythonTestEventSource" + + handle = _winapi.RegisterEventSource(None, source_name) + self.assertNotEqual(handle, _winapi.INVALID_HANDLE_VALUE) + + _winapi.DeregisterEventSource(handle) + + with self.assertRaises(OSError): + _winapi.RegisterEventSource(None, "") + + with self.assertRaises(OSError): + _winapi.DeregisterEventSource(_winapi.INVALID_HANDLE_VALUE) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index b4cfbebcb1bb5e..cb12cbefdfcbfe 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -2977,6 +2977,58 @@ _winapi_CopyFile2_impl(PyObject *module, LPCWSTR existing_file_name, Py_RETURN_NONE; } +/*[clinic input] +_winapi.RegisterEventSource -> HANDLE + + unc_server_name: LPCWSTR(accept={str, NoneType}) + The UNC name of the server on which the event source should be registered. + If NULL, registers the event source on the local computer. + source_name: LPCWSTR + The name of the event source to register. +[clinic start generated code]*/ + +static HANDLE +_winapi_RegisterEventSource_impl(PyObject *module, LPCWSTR unc_server_name, + LPCWSTR source_name) +/*[clinic end generated code: output=e376c8950a89ae8f input=ee83ab132b89b99c]*/ +{ + HANDLE handle; + + Py_BEGIN_ALLOW_THREADS + handle = RegisterEventSource(unc_server_name, source_name); + Py_END_ALLOW_THREADS + + if (handle == NULL) { + PyErr_SetFromWindowsErr(0); + return INVALID_HANDLE_VALUE; + } + + return handle; +} + +/*[clinic input] +_winapi.DeregisterEventSource + + handle: HANDLE + The handle to the event log to be deregistered. +[clinic start generated code]*/ + +static PyObject * +_winapi_DeregisterEventSource_impl(PyObject *module, HANDLE handle) +/*[clinic end generated code: output=7387ff34c7358bce input=07d42083b03ba7b0]*/ +{ + BOOL success; + + Py_BEGIN_ALLOW_THREADS + success = DeregisterEventSource(handle); + Py_END_ALLOW_THREADS + + if (!success) + return PyErr_SetFromWindowsErr(0); + + Py_RETURN_NONE; +} + static PyMethodDef winapi_functions[] = { _WINAPI_CLOSEHANDLE_METHODDEF @@ -2989,6 +3041,7 @@ static PyMethodDef winapi_functions[] = { _WINAPI_CREATEPIPE_METHODDEF _WINAPI_CREATEPROCESS_METHODDEF _WINAPI_CREATEJUNCTION_METHODDEF + _WINAPI_DEREGISTEREVENTSOURCE_METHODDEF _WINAPI_DUPLICATEHANDLE_METHODDEF _WINAPI_EXITPROCESS_METHODDEF _WINAPI_GETCURRENTPROCESS_METHODDEF @@ -3005,6 +3058,7 @@ static PyMethodDef winapi_functions[] = { _WINAPI_OPENMUTEXW_METHODDEF _WINAPI_OPENPROCESS_METHODDEF _WINAPI_PEEKNAMEDPIPE_METHODDEF + _WINAPI_REGISTEREVENTSOURCE_METHODDEF _WINAPI_LCMAPSTRINGEX_METHODDEF _WINAPI_READFILE_METHODDEF _WINAPI_RELEASEMUTEX_METHODDEF diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index bd685e75d9344f..f6f515331de450 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -2184,7 +2184,164 @@ _winapi_CopyFile2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO return return_value; } +PyDoc_STRVAR(_winapi_RegisterEventSource__doc__, +"RegisterEventSource($module, /, unc_server_name, source_name)\n" +"--\n" +"\n" +"\n" +"\n" +" unc_server_name\n" +" The UNC name of the server on which the event source should be registered.\n" +" If NULL, registers the event source on the local computer.\n" +" source_name\n" +" The name of the event source to register."); + +#define _WINAPI_REGISTEREVENTSOURCE_METHODDEF \ + {"RegisterEventSource", _PyCFunction_CAST(_winapi_RegisterEventSource), METH_FASTCALL|METH_KEYWORDS, _winapi_RegisterEventSource__doc__}, + +static HANDLE +_winapi_RegisterEventSource_impl(PyObject *module, LPCWSTR unc_server_name, + LPCWSTR source_name); + +static PyObject * +_winapi_RegisterEventSource(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(unc_server_name), &_Py_ID(source_name), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"unc_server_name", "source_name", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "RegisterEventSource", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + LPCWSTR unc_server_name = NULL; + LPCWSTR source_name = NULL; + HANDLE _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (args[0] == Py_None) { + unc_server_name = NULL; + } + else if (PyUnicode_Check(args[0])) { + unc_server_name = PyUnicode_AsWideCharString(args[0], NULL); + if (unc_server_name == NULL) { + goto exit; + } + } + else { + _PyArg_BadArgument("RegisterEventSource", "argument 'unc_server_name'", "str or None", args[0]); + goto exit; + } + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("RegisterEventSource", "argument 'source_name'", "str", args[1]); + goto exit; + } + source_name = PyUnicode_AsWideCharString(args[1], NULL); + if (source_name == NULL) { + goto exit; + } + _return_value = _winapi_RegisterEventSource_impl(module, unc_server_name, source_name); + if ((_return_value == INVALID_HANDLE_VALUE) && PyErr_Occurred()) { + goto exit; + } + if (_return_value == NULL) { + Py_RETURN_NONE; + } + return_value = HANDLE_TO_PYNUM(_return_value); + +exit: + /* Cleanup for unc_server_name */ + PyMem_Free((void *)unc_server_name); + /* Cleanup for source_name */ + PyMem_Free((void *)source_name); + + return return_value; +} + +PyDoc_STRVAR(_winapi_DeregisterEventSource__doc__, +"DeregisterEventSource($module, /, handle)\n" +"--\n" +"\n" +"\n" +"\n" +" handle\n" +" The handle to the event log to be deregistered."); + +#define _WINAPI_DEREGISTEREVENTSOURCE_METHODDEF \ + {"DeregisterEventSource", _PyCFunction_CAST(_winapi_DeregisterEventSource), METH_FASTCALL|METH_KEYWORDS, _winapi_DeregisterEventSource__doc__}, + +static PyObject * +_winapi_DeregisterEventSource_impl(PyObject *module, HANDLE handle); + +static PyObject * +_winapi_DeregisterEventSource(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(handle), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"handle", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .format = "" F_HANDLE ":DeregisterEventSource", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + HANDLE handle; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &handle)) { + goto exit; + } + return_value = _winapi_DeregisterEventSource_impl(module, handle); + +exit: + return return_value; +} + #ifndef _WINAPI_GETSHORTPATHNAME_METHODDEF #define _WINAPI_GETSHORTPATHNAME_METHODDEF #endif /* !defined(_WINAPI_GETSHORTPATHNAME_METHODDEF) */ -/*[clinic end generated code: output=4581fd481c3c6293 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=560f833b2c156b1e input=a9049054013a1b77]*/ From 427587f4323cdb227491c2986d285021d3c6ad0d Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 16 Aug 2025 21:56:45 +0900 Subject: [PATCH 02/26] Add ReportEvent to _winapi --- .../pycore_global_objects_fini_generated.h | 7 +- Include/internal/pycore_global_strings.h | 7 +- .../internal/pycore_runtime_init_generated.h | 7 +- .../internal/pycore_unicodeobject_generated.h | 28 +++-- Lib/test/test_winapi.py | 24 +++- Modules/_winapi.c | 95 ++++++++++++++- Modules/clinic/_winapi.c.h | 115 +++++++++++------- 7 files changed, 219 insertions(+), 64 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 0e679416d06abe..4f3ee26ed656ce 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -937,6 +937,9 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(env)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(errors)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event_category)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event_id)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event_type)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(eventmask)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exc)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exc_type)); @@ -1190,6 +1193,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(query)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(quotetabs)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(raw)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(raw_data)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(read)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(read1)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(readable)); @@ -1249,7 +1253,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sock)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sort)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(source)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(source_name)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(source_traceback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(spam)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(src)); @@ -1269,6 +1272,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(strict)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(strict_mode)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(string)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(strings)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sub_key)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(subcalls)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(symmetric_difference_update)); @@ -1309,7 +1313,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tzinfo)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tzname)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(uid)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(unc_server_name)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(unlink)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(unraisablehook)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(updates)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 74fb70c216d78b..e333b8be9fff0d 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -428,6 +428,9 @@ struct _Py_global_strings { STRUCT_FOR_ID(env) STRUCT_FOR_ID(errors) STRUCT_FOR_ID(event) + STRUCT_FOR_ID(event_category) + STRUCT_FOR_ID(event_id) + STRUCT_FOR_ID(event_type) STRUCT_FOR_ID(eventmask) STRUCT_FOR_ID(exc) STRUCT_FOR_ID(exc_type) @@ -681,6 +684,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(query) STRUCT_FOR_ID(quotetabs) STRUCT_FOR_ID(raw) + STRUCT_FOR_ID(raw_data) STRUCT_FOR_ID(read) STRUCT_FOR_ID(read1) STRUCT_FOR_ID(readable) @@ -740,7 +744,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(sock) STRUCT_FOR_ID(sort) STRUCT_FOR_ID(source) - STRUCT_FOR_ID(source_name) STRUCT_FOR_ID(source_traceback) STRUCT_FOR_ID(spam) STRUCT_FOR_ID(src) @@ -760,6 +763,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(strict) STRUCT_FOR_ID(strict_mode) STRUCT_FOR_ID(string) + STRUCT_FOR_ID(strings) STRUCT_FOR_ID(sub_key) STRUCT_FOR_ID(subcalls) STRUCT_FOR_ID(symmetric_difference_update) @@ -800,7 +804,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(tzinfo) STRUCT_FOR_ID(tzname) STRUCT_FOR_ID(uid) - STRUCT_FOR_ID(unc_server_name) STRUCT_FOR_ID(unlink) STRUCT_FOR_ID(unraisablehook) STRUCT_FOR_ID(updates) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index bf2fb1c2a91e5b..b3a6648ceff2de 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -935,6 +935,9 @@ extern "C" { INIT_ID(env), \ INIT_ID(errors), \ INIT_ID(event), \ + INIT_ID(event_category), \ + INIT_ID(event_id), \ + INIT_ID(event_type), \ INIT_ID(eventmask), \ INIT_ID(exc), \ INIT_ID(exc_type), \ @@ -1188,6 +1191,7 @@ extern "C" { INIT_ID(query), \ INIT_ID(quotetabs), \ INIT_ID(raw), \ + INIT_ID(raw_data), \ INIT_ID(read), \ INIT_ID(read1), \ INIT_ID(readable), \ @@ -1247,7 +1251,6 @@ extern "C" { INIT_ID(sock), \ INIT_ID(sort), \ INIT_ID(source), \ - INIT_ID(source_name), \ INIT_ID(source_traceback), \ INIT_ID(spam), \ INIT_ID(src), \ @@ -1267,6 +1270,7 @@ extern "C" { INIT_ID(strict), \ INIT_ID(strict_mode), \ INIT_ID(string), \ + INIT_ID(strings), \ INIT_ID(sub_key), \ INIT_ID(subcalls), \ INIT_ID(symmetric_difference_update), \ @@ -1307,7 +1311,6 @@ extern "C" { INIT_ID(tzinfo), \ INIT_ID(tzname), \ INIT_ID(uid), \ - INIT_ID(unc_server_name), \ INIT_ID(unlink), \ INIT_ID(unraisablehook), \ INIT_ID(updates), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 45fef0b1936300..e76fefc7427b7f 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1500,6 +1500,18 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(event_category); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(event_id); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(event_type); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(eventmask); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2512,6 +2524,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(raw_data); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(read); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2748,10 +2764,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(source_name); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(source_traceback); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2828,6 +2840,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(strings); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(sub_key); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2988,10 +3004,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(unc_server_name); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(unlink); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index 563e0ca5b636b9..dccf85d887cd15 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -163,10 +163,32 @@ def test_event_source_registration(self): handle = _winapi.RegisterEventSource(None, source_name) self.assertNotEqual(handle, _winapi.INVALID_HANDLE_VALUE) - _winapi.DeregisterEventSource(handle) + # Test ReportEvent with the registered event source + try: + # Test with strings and raw data + test_strings = ["Test message 1", "Test message 2"] + test_data = b"test raw data" + _winapi.ReportEvent(handle, 4, 1, 1002, test_strings, test_data) + + # Test with empty strings list + # _winapi.ReportEvent(handle, 2, 0, 1003, [], None) # TODO + finally: + _winapi.DeregisterEventSource(handle) with self.assertRaises(OSError): _winapi.RegisterEventSource(None, "") with self.assertRaises(OSError): _winapi.DeregisterEventSource(_winapi.INVALID_HANDLE_VALUE) + + # Test ReportEvent with invalid handle + with self.assertRaises(OSError): + _winapi.ReportEvent(_winapi.INVALID_HANDLE_VALUE, 1, 0, 1001, [], test_data) + + # Test ReportEvent with invalid string types + handle2 = _winapi.RegisterEventSource(None, "PythonTestEventSource2") + try: + with self.assertRaises(TypeError): + _winapi.ReportEvent(handle2, 1, 0, 1001, ["string", 123], test_data) + finally: + _winapi.DeregisterEventSource(handle2) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index cb12cbefdfcbfe..d795d4e24a8a9c 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -2985,17 +2985,18 @@ _winapi.RegisterEventSource -> HANDLE If NULL, registers the event source on the local computer. source_name: LPCWSTR The name of the event source to register. + / [clinic start generated code]*/ static HANDLE _winapi_RegisterEventSource_impl(PyObject *module, LPCWSTR unc_server_name, LPCWSTR source_name) -/*[clinic end generated code: output=e376c8950a89ae8f input=ee83ab132b89b99c]*/ +/*[clinic end generated code: output=e376c8950a89ae8f input=16ae3c812a905cab]*/ { HANDLE handle; Py_BEGIN_ALLOW_THREADS - handle = RegisterEventSource(unc_server_name, source_name); + handle = RegisterEventSourceW(unc_server_name, source_name); Py_END_ALLOW_THREADS if (handle == NULL) { @@ -3011,11 +3012,12 @@ _winapi.DeregisterEventSource handle: HANDLE The handle to the event log to be deregistered. + / [clinic start generated code]*/ static PyObject * _winapi_DeregisterEventSource_impl(PyObject *module, HANDLE handle) -/*[clinic end generated code: output=7387ff34c7358bce input=07d42083b03ba7b0]*/ +/*[clinic end generated code: output=7387ff34c7358bce input=0973c68eddcfd5a7]*/ { BOOL success; @@ -3029,6 +3031,92 @@ _winapi_DeregisterEventSource_impl(PyObject *module, HANDLE handle) Py_RETURN_NONE; } +/*[clinic input] +_winapi.ReportEvent + + handle: HANDLE + The handle to the event log. + event_type: int + The type of event being reported. + event_category: int + The event category. + event_id: int + The event identifier. + strings: object(subclass_of='&PyList_Type') + A list of strings to be inserted into the event message. + raw_data: Py_buffer + The raw data for the event. +[clinic start generated code]*/ + +static PyObject * +_winapi_ReportEvent_impl(PyObject *module, HANDLE handle, int event_type, + int event_category, int event_id, PyObject *strings, + Py_buffer *raw_data) +/*[clinic end generated code: output=9066f114cdfdf5f2 input=fc37cfe1816d02d7]*/ +{ + BOOL success; + LPCWSTR *string_array = NULL; + WORD num_strings = 0; + LPVOID data = NULL; + DWORD data_size = 0; + + // Handle strings list + if (strings != Py_None && PyList_Check(strings)) { + Py_ssize_t size = PyList_Size(strings); + num_strings = (WORD)size; + + if (num_strings > 0) { + string_array = (LPCWSTR *)PyMem_Malloc(num_strings * sizeof(LPCWSTR)); + if (!string_array) { + return PyErr_NoMemory(); + } + + for (WORD i = 0; i < num_strings; i++) { + PyObject *item = PyList_GetItem(strings, i); + if (!PyUnicode_Check(item)) { + PyMem_Free(string_array); + PyErr_SetString(PyExc_TypeError, "All strings must be unicode"); + return NULL; + } + string_array[i] = PyUnicode_AsWideCharString(item, NULL); + if (!string_array[i]) { + // Clean up already allocated strings + for (WORD j = 0; j < i; j++) { + PyMem_Free((void *)string_array[j]); + } + PyMem_Free(string_array); + return NULL; + } + } + } + } + + // Handle raw data + if (raw_data->buf != NULL) { + data = raw_data->buf; + data_size = (DWORD) raw_data->len; + } + + Py_BEGIN_ALLOW_THREADS + success = ReportEventW(handle, event_type, event_category, event_id, + NULL, num_strings, data_size, + string_array, data); + Py_END_ALLOW_THREADS + + // Clean up allocated strings + if (string_array) { + for (WORD i = 0; i < num_strings; i++) { + PyMem_Free((void *)string_array[i]); + } + PyMem_Free(string_array); + } + + if (!success) + return PyErr_SetFromWindowsErr(0); + + Py_RETURN_NONE; +} + static PyMethodDef winapi_functions[] = { _WINAPI_CLOSEHANDLE_METHODDEF @@ -3059,6 +3147,7 @@ static PyMethodDef winapi_functions[] = { _WINAPI_OPENPROCESS_METHODDEF _WINAPI_PEEKNAMEDPIPE_METHODDEF _WINAPI_REGISTEREVENTSOURCE_METHODDEF + _WINAPI_REPORTEVENT_METHODDEF _WINAPI_LCMAPSTRINGEX_METHODDEF _WINAPI_READFILE_METHODDEF _WINAPI_RELEASEMUTEX_METHODDEF diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index f6f515331de450..75586ba1e80c24 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -2185,7 +2185,7 @@ _winapi_CopyFile2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO } PyDoc_STRVAR(_winapi_RegisterEventSource__doc__, -"RegisterEventSource($module, /, unc_server_name, source_name)\n" +"RegisterEventSource($module, unc_server_name, source_name, /)\n" "--\n" "\n" "\n" @@ -2197,51 +2197,21 @@ PyDoc_STRVAR(_winapi_RegisterEventSource__doc__, " The name of the event source to register."); #define _WINAPI_REGISTEREVENTSOURCE_METHODDEF \ - {"RegisterEventSource", _PyCFunction_CAST(_winapi_RegisterEventSource), METH_FASTCALL|METH_KEYWORDS, _winapi_RegisterEventSource__doc__}, + {"RegisterEventSource", _PyCFunction_CAST(_winapi_RegisterEventSource), METH_FASTCALL, _winapi_RegisterEventSource__doc__}, static HANDLE _winapi_RegisterEventSource_impl(PyObject *module, LPCWSTR unc_server_name, LPCWSTR source_name); static PyObject * -_winapi_RegisterEventSource(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_winapi_RegisterEventSource(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 2 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(unc_server_name), &_Py_ID(source_name), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"unc_server_name", "source_name", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .fname = "RegisterEventSource", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE - PyObject *argsbuf[2]; LPCWSTR unc_server_name = NULL; LPCWSTR source_name = NULL; HANDLE _return_value; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, - /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); - if (!args) { + if (!_PyArg_CheckPositional("RegisterEventSource", nargs, 2, 2)) { goto exit; } if (args[0] == Py_None) { @@ -2254,11 +2224,11 @@ _winapi_RegisterEventSource(PyObject *module, PyObject *const *args, Py_ssize_t } } else { - _PyArg_BadArgument("RegisterEventSource", "argument 'unc_server_name'", "str or None", args[0]); + _PyArg_BadArgument("RegisterEventSource", "argument 1", "str or None", args[0]); goto exit; } if (!PyUnicode_Check(args[1])) { - _PyArg_BadArgument("RegisterEventSource", "argument 'source_name'", "str", args[1]); + _PyArg_BadArgument("RegisterEventSource", "argument 2", "str", args[1]); goto exit; } source_name = PyUnicode_AsWideCharString(args[1], NULL); @@ -2284,7 +2254,7 @@ _winapi_RegisterEventSource(PyObject *module, PyObject *const *args, Py_ssize_t } PyDoc_STRVAR(_winapi_DeregisterEventSource__doc__, -"DeregisterEventSource($module, /, handle)\n" +"DeregisterEventSource($module, handle, /)\n" "--\n" "\n" "\n" @@ -2293,18 +2263,61 @@ PyDoc_STRVAR(_winapi_DeregisterEventSource__doc__, " The handle to the event log to be deregistered."); #define _WINAPI_DEREGISTEREVENTSOURCE_METHODDEF \ - {"DeregisterEventSource", _PyCFunction_CAST(_winapi_DeregisterEventSource), METH_FASTCALL|METH_KEYWORDS, _winapi_DeregisterEventSource__doc__}, + {"DeregisterEventSource", (PyCFunction)_winapi_DeregisterEventSource, METH_O, _winapi_DeregisterEventSource__doc__}, static PyObject * _winapi_DeregisterEventSource_impl(PyObject *module, HANDLE handle); static PyObject * -_winapi_DeregisterEventSource(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_winapi_DeregisterEventSource(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + HANDLE handle; + + if (!PyArg_Parse(arg, "" F_HANDLE ":DeregisterEventSource", &handle)) { + goto exit; + } + return_value = _winapi_DeregisterEventSource_impl(module, handle); + +exit: + return return_value; +} + +PyDoc_STRVAR(_winapi_ReportEvent__doc__, +"ReportEvent($module, /, handle, event_type, event_category, event_id,\n" +" strings, raw_data=None)\n" +"--\n" +"\n" +"\n" +"\n" +" handle\n" +" The handle to the event log.\n" +" event_type\n" +" The type of event being reported.\n" +" event_category\n" +" The event category.\n" +" event_id\n" +" The event identifier.\n" +" strings\n" +" A list of strings to be inserted into the event message.\n" +" raw_data\n" +" The raw data for the event."); + +#define _WINAPI_REPORTEVENT_METHODDEF \ + {"ReportEvent", _PyCFunction_CAST(_winapi_ReportEvent), METH_FASTCALL|METH_KEYWORDS, _winapi_ReportEvent__doc__}, + +static PyObject * +_winapi_ReportEvent_impl(PyObject *module, HANDLE handle, int event_type, + int event_category, int event_id, PyObject *strings, + Py_buffer *raw_data); + +static PyObject * +_winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 1 + #define NUM_KEYWORDS 6 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD @@ -2313,7 +2326,7 @@ _winapi_DeregisterEventSource(PyObject *module, PyObject *const *args, Py_ssize_ } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(handle), }, + .ob_item = { &_Py_ID(handle), &_Py_ID(event_type), &_Py_ID(event_category), &_Py_ID(event_id), &_Py_ID(strings), &_Py_ID(raw_data), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2322,26 +2335,36 @@ _winapi_DeregisterEventSource(PyObject *module, PyObject *const *args, Py_ssize_ # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"handle", NULL}; + static const char * const _keywords[] = {"handle", "event_type", "event_category", "event_id", "strings", "raw_data", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "" F_HANDLE ":DeregisterEventSource", + .format = "" F_HANDLE "iiiO!|y*:ReportEvent", .kwtuple = KWTUPLE, }; #undef KWTUPLE HANDLE handle; + int event_type; + int event_category; + int event_id; + PyObject *strings; + Py_buffer raw_data = {NULL, NULL}; if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &handle)) { + &handle, &event_type, &event_category, &event_id, &PyList_Type, &strings, &raw_data)) { goto exit; } - return_value = _winapi_DeregisterEventSource_impl(module, handle); + return_value = _winapi_ReportEvent_impl(module, handle, event_type, event_category, event_id, strings, &raw_data); exit: + /* Cleanup for raw_data */ + if (raw_data.obj) { + PyBuffer_Release(&raw_data); + } + return return_value; } #ifndef _WINAPI_GETSHORTPATHNAME_METHODDEF #define _WINAPI_GETSHORTPATHNAME_METHODDEF #endif /* !defined(_WINAPI_GETSHORTPATHNAME_METHODDEF) */ -/*[clinic end generated code: output=560f833b2c156b1e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9a69b9d704c7d138 input=a9049054013a1b77]*/ From d78e2db38ecb1668a443a057a9a976f26fe717a6 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 16 Aug 2025 22:44:32 +0900 Subject: [PATCH 03/26] Update test --- Lib/test/test_winapi.py | 43 ++++++++++++++++++-------------------- Modules/_winapi.c | 2 +- Modules/clinic/_winapi.c.h | 6 +++--- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index dccf85d887cd15..6f8b3c91df19d6 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -163,32 +163,29 @@ def test_event_source_registration(self): handle = _winapi.RegisterEventSource(None, source_name) self.assertNotEqual(handle, _winapi.INVALID_HANDLE_VALUE) - # Test ReportEvent with the registered event source - try: - # Test with strings and raw data - test_strings = ["Test message 1", "Test message 2"] - test_data = b"test raw data" - _winapi.ReportEvent(handle, 4, 1, 1002, test_strings, test_data) - - # Test with empty strings list - # _winapi.ReportEvent(handle, 2, 0, 1003, [], None) # TODO - finally: - _winapi.DeregisterEventSource(handle) - - with self.assertRaises(OSError): + with self.assertRaisesRegex(OSError, '[WinError 87]'): _winapi.RegisterEventSource(None, "") - with self.assertRaises(OSError): + with self.assertRaisesRegex(OSError, '[WinError 6]'): _winapi.DeregisterEventSource(_winapi.INVALID_HANDLE_VALUE) - # Test ReportEvent with invalid handle - with self.assertRaises(OSError): + def test_report_event(self): + source_name = "PythonTestEventSource" + + handle = _winapi.RegisterEventSource(None, source_name) + self.assertNotEqual(handle, _winapi.INVALID_HANDLE_VALUE) + self.addCleanup(_winapi.DeregisterEventSource, handle) + + # Test with strings and raw data + test_strings = ["Test message 1", "Test message 2"] + test_data = b"test raw data" + _winapi.ReportEvent(handle, 4, 1, 1002, test_strings, test_data) + + # Test with empty strings list + _winapi.ReportEvent(handle, 2, 0, 1003, [], b'') + + with self.assertRaisesRegex(OSError, '[WinError 6]'): _winapi.ReportEvent(_winapi.INVALID_HANDLE_VALUE, 1, 0, 1001, [], test_data) - # Test ReportEvent with invalid string types - handle2 = _winapi.RegisterEventSource(None, "PythonTestEventSource2") - try: - with self.assertRaises(TypeError): - _winapi.ReportEvent(handle2, 1, 0, 1001, ["string", 123], test_data) - finally: - _winapi.DeregisterEventSource(handle2) + with self.assertRaisesRegex(TypeError, 'All strings must be unicode'): + _winapi.ReportEvent(handle, 1, 0, 1001, ["string", 123], test_data) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index d795d4e24a8a9c..439ac656833e1b 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -3052,7 +3052,7 @@ static PyObject * _winapi_ReportEvent_impl(PyObject *module, HANDLE handle, int event_type, int event_category, int event_id, PyObject *strings, Py_buffer *raw_data) -/*[clinic end generated code: output=9066f114cdfdf5f2 input=fc37cfe1816d02d7]*/ +/*[clinic end generated code: output=9066f114cdfdf5f2 input=fade978a0b25e611]*/ { BOOL success; LPCWSTR *string_array = NULL; diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index 75586ba1e80c24..cf27c3b6d1e646 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -2285,7 +2285,7 @@ _winapi_DeregisterEventSource(PyObject *module, PyObject *arg) PyDoc_STRVAR(_winapi_ReportEvent__doc__, "ReportEvent($module, /, handle, event_type, event_category, event_id,\n" -" strings, raw_data=None)\n" +" strings, raw_data)\n" "--\n" "\n" "\n" @@ -2338,7 +2338,7 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P static const char * const _keywords[] = {"handle", "event_type", "event_category", "event_id", "strings", "raw_data", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "" F_HANDLE "iiiO!|y*:ReportEvent", + .format = "" F_HANDLE "iiiO!y*:ReportEvent", .kwtuple = KWTUPLE, }; #undef KWTUPLE @@ -2367,4 +2367,4 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P #ifndef _WINAPI_GETSHORTPATHNAME_METHODDEF #define _WINAPI_GETSHORTPATHNAME_METHODDEF #endif /* !defined(_WINAPI_GETSHORTPATHNAME_METHODDEF) */ -/*[clinic end generated code: output=9a69b9d704c7d138 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c9e1bd2714bd8269 input=a9049054013a1b77]*/ From 30242e09da5cc8ea30873af8744f2c60fd622d6e Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 17 Aug 2025 00:12:27 +0900 Subject: [PATCH 04/26] Update test --- Lib/test/test_winapi.py | 4 ++-- Modules/_winapi.c | 2 +- Modules/clinic/_winapi.c.h | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index 6f8b3c91df19d6..775b15f618f3c4 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -182,10 +182,10 @@ def test_report_event(self): _winapi.ReportEvent(handle, 4, 1, 1002, test_strings, test_data) # Test with empty strings list - _winapi.ReportEvent(handle, 2, 0, 1003, [], b'') + _winapi.ReportEvent(handle, 2, 0, 1003, []) with self.assertRaisesRegex(OSError, '[WinError 6]'): _winapi.ReportEvent(_winapi.INVALID_HANDLE_VALUE, 1, 0, 1001, [], test_data) with self.assertRaisesRegex(TypeError, 'All strings must be unicode'): - _winapi.ReportEvent(handle, 1, 0, 1001, ["string", 123], test_data) + _winapi.ReportEvent(handle, 1, 0, 1001, ["string", 123]) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 439ac656833e1b..e1faec39c598fc 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -3044,7 +3044,7 @@ _winapi.ReportEvent The event identifier. strings: object(subclass_of='&PyList_Type') A list of strings to be inserted into the event message. - raw_data: Py_buffer + raw_data: Py_buffer = None The raw data for the event. [clinic start generated code]*/ diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index cf27c3b6d1e646..75586ba1e80c24 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -2285,7 +2285,7 @@ _winapi_DeregisterEventSource(PyObject *module, PyObject *arg) PyDoc_STRVAR(_winapi_ReportEvent__doc__, "ReportEvent($module, /, handle, event_type, event_category, event_id,\n" -" strings, raw_data)\n" +" strings, raw_data=None)\n" "--\n" "\n" "\n" @@ -2338,7 +2338,7 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P static const char * const _keywords[] = {"handle", "event_type", "event_category", "event_id", "strings", "raw_data", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "" F_HANDLE "iiiO!y*:ReportEvent", + .format = "" F_HANDLE "iiiO!|y*:ReportEvent", .kwtuple = KWTUPLE, }; #undef KWTUPLE @@ -2367,4 +2367,4 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P #ifndef _WINAPI_GETSHORTPATHNAME_METHODDEF #define _WINAPI_GETSHORTPATHNAME_METHODDEF #endif /* !defined(_WINAPI_GETSHORTPATHNAME_METHODDEF) */ -/*[clinic end generated code: output=c9e1bd2714bd8269 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9a69b9d704c7d138 input=a9049054013a1b77]*/ From 3a7aca41cd91d9ae6f0baa483400391b472388ab Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 17 Aug 2025 00:25:01 +0900 Subject: [PATCH 05/26] Add constants --- .../pycore_global_objects_fini_generated.h | 2 -- Include/internal/pycore_global_strings.h | 2 -- .../internal/pycore_runtime_init_generated.h | 2 -- .../internal/pycore_unicodeobject_generated.h | 8 ----- Lib/test/test_winapi.py | 13 +++++--- Modules/_winapi.c | 28 +++++++++++----- Modules/clinic/_winapi.c.h | 32 +++++++++---------- 7 files changed, 45 insertions(+), 42 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 4f3ee26ed656ce..bf1fddc97bf95f 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -937,9 +937,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(env)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(errors)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event_category)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event_id)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event_type)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(eventmask)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exc)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exc_type)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index e333b8be9fff0d..f35dc76deac38f 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -428,9 +428,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(env) STRUCT_FOR_ID(errors) STRUCT_FOR_ID(event) - STRUCT_FOR_ID(event_category) STRUCT_FOR_ID(event_id) - STRUCT_FOR_ID(event_type) STRUCT_FOR_ID(eventmask) STRUCT_FOR_ID(exc) STRUCT_FOR_ID(exc_type) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index b3a6648ceff2de..61dbceb3e312d8 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -935,9 +935,7 @@ extern "C" { INIT_ID(env), \ INIT_ID(errors), \ INIT_ID(event), \ - INIT_ID(event_category), \ INIT_ID(event_id), \ - INIT_ID(event_type), \ INIT_ID(eventmask), \ INIT_ID(exc), \ INIT_ID(exc_type), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index e76fefc7427b7f..ea40a59606077d 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1500,18 +1500,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(event_category); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(event_id); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(event_type); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(eventmask); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index 775b15f618f3c4..7f99268dda624a 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -179,13 +179,18 @@ def test_report_event(self): # Test with strings and raw data test_strings = ["Test message 1", "Test message 2"] test_data = b"test raw data" - _winapi.ReportEvent(handle, 4, 1, 1002, test_strings, test_data) + _winapi.ReportEvent(handle, _winapi.EVENTLOG_SUCCESS, 1, 1002, + test_strings, test_data) # Test with empty strings list - _winapi.ReportEvent(handle, 2, 0, 1003, []) + _winapi.ReportEvent(handle, _winapi.EVENTLOG_AUDIT_FAILURE ,2, 0, 1003, + []) with self.assertRaisesRegex(OSError, '[WinError 6]'): - _winapi.ReportEvent(_winapi.INVALID_HANDLE_VALUE, 1, 0, 1001, [], test_data) + _winapi.ReportEvent(_winapi.INVALID_HANDLE_VALUE, + _winapi.EVENTLOG_AUDIT_SUCCESS, 0, 1001, [], + test_data) with self.assertRaisesRegex(TypeError, 'All strings must be unicode'): - _winapi.ReportEvent(handle, 1, 0, 1001, ["string", 123]) + _winapi.ReportEvent(handle, _winapi.EVENTLOG_ERROR_TYPE, 0, 1001, + ["string", 123]) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index e1faec39c598fc..04f36ea856ced0 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -2986,12 +2986,14 @@ _winapi.RegisterEventSource -> HANDLE source_name: LPCWSTR The name of the event source to register. / + +Retrieves a registered handle to the specified event log. [clinic start generated code]*/ static HANDLE _winapi_RegisterEventSource_impl(PyObject *module, LPCWSTR unc_server_name, LPCWSTR source_name) -/*[clinic end generated code: output=e376c8950a89ae8f input=16ae3c812a905cab]*/ +/*[clinic end generated code: output=e376c8950a89ae8f input=9642e69236d0a14e]*/ { HANDLE handle; @@ -3013,11 +3015,13 @@ _winapi.DeregisterEventSource handle: HANDLE The handle to the event log to be deregistered. / + +Closes the specified event log. [clinic start generated code]*/ static PyObject * _winapi_DeregisterEventSource_impl(PyObject *module, HANDLE handle) -/*[clinic end generated code: output=7387ff34c7358bce input=0973c68eddcfd5a7]*/ +/*[clinic end generated code: output=7387ff34c7358bce input=947593cf67641f16]*/ { BOOL success; @@ -3036,9 +3040,9 @@ _winapi.ReportEvent handle: HANDLE The handle to the event log. - event_type: int + type: int The type of event being reported. - event_category: int + category: int The event category. event_id: int The event identifier. @@ -3046,13 +3050,15 @@ _winapi.ReportEvent A list of strings to be inserted into the event message. raw_data: Py_buffer = None The raw data for the event. + +Writes an entry at the end of the specified event log. [clinic start generated code]*/ static PyObject * -_winapi_ReportEvent_impl(PyObject *module, HANDLE handle, int event_type, - int event_category, int event_id, PyObject *strings, +_winapi_ReportEvent_impl(PyObject *module, HANDLE handle, int type, + int category, int event_id, PyObject *strings, Py_buffer *raw_data) -/*[clinic end generated code: output=9066f114cdfdf5f2 input=fade978a0b25e611]*/ +/*[clinic end generated code: output=62348d38f92d26e8 input=4ac507ddabbf91ca]*/ { BOOL success; LPCWSTR *string_array = NULL; @@ -3098,7 +3104,7 @@ _winapi_ReportEvent_impl(PyObject *module, HANDLE handle, int event_type, } Py_BEGIN_ALLOW_THREADS - success = ReportEventW(handle, event_type, event_category, event_id, + success = ReportEventW(handle, type, category, event_id, NULL, num_strings, data_size, string_array, data); Py_END_ALLOW_THREADS @@ -3220,6 +3226,12 @@ static int winapi_exec(PyObject *m) WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED); WINAPI_CONSTANT(F_DWORD, ERROR_PRIVILEGE_NOT_HELD); WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT); + WINAPI_CONSTANT(F_DWORD, EVENTLOG_SUCCESS); + WINAPI_CONSTANT(F_DWORD, EVENTLOG_AUDIT_FAILURE); + WINAPI_CONSTANT(F_DWORD, EVENTLOG_AUDIT_SUCCESS); + WINAPI_CONSTANT(F_DWORD, EVENTLOG_ERROR_TYPE); + WINAPI_CONSTANT(F_DWORD, EVENTLOG_INFORMATION_TYPE); + WINAPI_CONSTANT(F_DWORD, EVENTLOG_WARNING_TYPE); WINAPI_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE); WINAPI_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED); WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_READ); diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index 75586ba1e80c24..74011834ee2a04 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -2188,7 +2188,7 @@ PyDoc_STRVAR(_winapi_RegisterEventSource__doc__, "RegisterEventSource($module, unc_server_name, source_name, /)\n" "--\n" "\n" -"\n" +"Retrieves a registered handle to the specified event log.\n" "\n" " unc_server_name\n" " The UNC name of the server on which the event source should be registered.\n" @@ -2257,7 +2257,7 @@ PyDoc_STRVAR(_winapi_DeregisterEventSource__doc__, "DeregisterEventSource($module, handle, /)\n" "--\n" "\n" -"\n" +"Closes the specified event log.\n" "\n" " handle\n" " The handle to the event log to be deregistered."); @@ -2284,17 +2284,17 @@ _winapi_DeregisterEventSource(PyObject *module, PyObject *arg) } PyDoc_STRVAR(_winapi_ReportEvent__doc__, -"ReportEvent($module, /, handle, event_type, event_category, event_id,\n" -" strings, raw_data=None)\n" +"ReportEvent($module, /, handle, type, category, event_id, strings,\n" +" raw_data=None)\n" "--\n" "\n" -"\n" +"Writes an entry at the end of the specified event log.\n" "\n" " handle\n" " The handle to the event log.\n" -" event_type\n" +" type\n" " The type of event being reported.\n" -" event_category\n" +" category\n" " The event category.\n" " event_id\n" " The event identifier.\n" @@ -2307,8 +2307,8 @@ PyDoc_STRVAR(_winapi_ReportEvent__doc__, {"ReportEvent", _PyCFunction_CAST(_winapi_ReportEvent), METH_FASTCALL|METH_KEYWORDS, _winapi_ReportEvent__doc__}, static PyObject * -_winapi_ReportEvent_impl(PyObject *module, HANDLE handle, int event_type, - int event_category, int event_id, PyObject *strings, +_winapi_ReportEvent_impl(PyObject *module, HANDLE handle, int type, + int category, int event_id, PyObject *strings, Py_buffer *raw_data); static PyObject * @@ -2326,7 +2326,7 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(handle), &_Py_ID(event_type), &_Py_ID(event_category), &_Py_ID(event_id), &_Py_ID(strings), &_Py_ID(raw_data), }, + .ob_item = { &_Py_ID(handle), &_Py_ID(type), &_Py_ID(category), &_Py_ID(event_id), &_Py_ID(strings), &_Py_ID(raw_data), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -2335,7 +2335,7 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"handle", "event_type", "event_category", "event_id", "strings", "raw_data", NULL}; + static const char * const _keywords[] = {"handle", "type", "category", "event_id", "strings", "raw_data", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .format = "" F_HANDLE "iiiO!|y*:ReportEvent", @@ -2343,17 +2343,17 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P }; #undef KWTUPLE HANDLE handle; - int event_type; - int event_category; + int type; + int category; int event_id; PyObject *strings; Py_buffer raw_data = {NULL, NULL}; if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &handle, &event_type, &event_category, &event_id, &PyList_Type, &strings, &raw_data)) { + &handle, &type, &category, &event_id, &PyList_Type, &strings, &raw_data)) { goto exit; } - return_value = _winapi_ReportEvent_impl(module, handle, event_type, event_category, event_id, strings, &raw_data); + return_value = _winapi_ReportEvent_impl(module, handle, type, category, event_id, strings, &raw_data); exit: /* Cleanup for raw_data */ @@ -2367,4 +2367,4 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P #ifndef _WINAPI_GETSHORTPATHNAME_METHODDEF #define _WINAPI_GETSHORTPATHNAME_METHODDEF #endif /* !defined(_WINAPI_GETSHORTPATHNAME_METHODDEF) */ -/*[clinic end generated code: output=9a69b9d704c7d138 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c9830656556b2fc9 input=a9049054013a1b77]*/ From 545657d2116ba65eb54df762800bd7eade4adecc Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 17 Aug 2025 00:29:05 +0900 Subject: [PATCH 06/26] Add news entry --- .../next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst diff --git a/Misc/NEWS.d/next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst b/Misc/NEWS.d/next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst new file mode 100644 index 00000000000000..242f3e8b4cbe91 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst @@ -0,0 +1,2 @@ +Add :func:`_winapi.RegisterEventSource`, +:func:`_winapi.DeregisterEventSource` and :func:`_winapi.ReportEvent`. From f6ce06cfd9fb0fce89fb647ad3fba883598b81b9 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 17 Aug 2025 00:34:38 +0900 Subject: [PATCH 07/26] Fix news entry --- .../Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst b/Misc/NEWS.d/next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst index 242f3e8b4cbe91..a95cbc58bfeab9 100644 --- a/Misc/NEWS.d/next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst +++ b/Misc/NEWS.d/next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst @@ -1,2 +1,2 @@ -Add :func:`_winapi.RegisterEventSource`, -:func:`_winapi.DeregisterEventSource` and :func:`_winapi.ReportEvent`. +Add :func:`!_winapi.RegisterEventSource`, +:func:`!_winapi.DeregisterEventSource` and :func:`!_winapi.ReportEvent`. From bfa41e5b1dc0febdf648a2c135898720d3dec4c7 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 19 Aug 2025 00:43:47 +0900 Subject: [PATCH 08/26] Fix test --- Lib/test/test_winapi.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index 7f99268dda624a..54e2a4718cf9f8 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -183,8 +183,7 @@ def test_report_event(self): test_strings, test_data) # Test with empty strings list - _winapi.ReportEvent(handle, _winapi.EVENTLOG_AUDIT_FAILURE ,2, 0, 1003, - []) + _winapi.ReportEvent(handle, _winapi.EVENTLOG_AUDIT_FAILURE, 2, 1003, []) with self.assertRaisesRegex(OSError, '[WinError 6]'): _winapi.ReportEvent(_winapi.INVALID_HANDLE_VALUE, From 093d2482c9385ff0647d455e9b44afd899ba5756 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 19 Aug 2025 21:49:26 +0900 Subject: [PATCH 09/26] Debug the test --- Lib/test/test_winapi.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index 54e2a4718cf9f8..177d12fbf71ec4 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -182,14 +182,14 @@ def test_report_event(self): _winapi.ReportEvent(handle, _winapi.EVENTLOG_SUCCESS, 1, 1002, test_strings, test_data) - # Test with empty strings list - _winapi.ReportEvent(handle, _winapi.EVENTLOG_AUDIT_FAILURE, 2, 1003, []) + # # Test with empty strings list + # _winapi.ReportEvent(handle, _winapi.EVENTLOG_AUDIT_FAILURE, 2, 1003, []) - with self.assertRaisesRegex(OSError, '[WinError 6]'): - _winapi.ReportEvent(_winapi.INVALID_HANDLE_VALUE, - _winapi.EVENTLOG_AUDIT_SUCCESS, 0, 1001, [], - test_data) + # with self.assertRaisesRegex(OSError, '[WinError 6]'): + # _winapi.ReportEvent(_winapi.INVALID_HANDLE_VALUE, + # _winapi.EVENTLOG_AUDIT_SUCCESS, 0, 1001, [], + # test_data) - with self.assertRaisesRegex(TypeError, 'All strings must be unicode'): - _winapi.ReportEvent(handle, _winapi.EVENTLOG_ERROR_TYPE, 0, 1001, - ["string", 123]) + # with self.assertRaisesRegex(TypeError, 'All strings must be unicode'): + # _winapi.ReportEvent(handle, _winapi.EVENTLOG_ERROR_TYPE, 0, 1001, + # ["string", 123]) From a186b71827f905261214233f3e41f9a04f53dbe7 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 19 Aug 2025 22:28:59 +0900 Subject: [PATCH 10/26] Debug test --- Lib/test/test_winapi.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index 177d12fbf71ec4..37cd8a745399cb 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -182,13 +182,13 @@ def test_report_event(self): _winapi.ReportEvent(handle, _winapi.EVENTLOG_SUCCESS, 1, 1002, test_strings, test_data) - # # Test with empty strings list - # _winapi.ReportEvent(handle, _winapi.EVENTLOG_AUDIT_FAILURE, 2, 1003, []) + # Test with empty strings list + _winapi.ReportEvent(handle, _winapi.EVENTLOG_AUDIT_FAILURE, 2, 1003, []) - # with self.assertRaisesRegex(OSError, '[WinError 6]'): - # _winapi.ReportEvent(_winapi.INVALID_HANDLE_VALUE, - # _winapi.EVENTLOG_AUDIT_SUCCESS, 0, 1001, [], - # test_data) + with self.assertRaisesRegex(OSError, '[WinError 6]'): + _winapi.ReportEvent(_winapi.INVALID_HANDLE_VALUE, + _winapi.EVENTLOG_AUDIT_SUCCESS, 0, 1001, [], + test_data) # with self.assertRaisesRegex(TypeError, 'All strings must be unicode'): # _winapi.ReportEvent(handle, _winapi.EVENTLOG_ERROR_TYPE, 0, 1001, From 1e3479a877d26402862e8f178498c1de7c5938f6 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 19 Aug 2025 22:33:38 +0900 Subject: [PATCH 11/26] Change log type to sucess type in test --- Lib/test/test_winapi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index 37cd8a745399cb..bc1a185b66b2d7 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -190,6 +190,6 @@ def test_report_event(self): _winapi.EVENTLOG_AUDIT_SUCCESS, 0, 1001, [], test_data) - # with self.assertRaisesRegex(TypeError, 'All strings must be unicode'): - # _winapi.ReportEvent(handle, _winapi.EVENTLOG_ERROR_TYPE, 0, 1001, - # ["string", 123]) + with self.assertRaisesRegex(TypeError, 'All strings must be unicode'): + _winapi.ReportEvent(handle, _winapi.EVENTLOG_SUCESS_TYPE, 0, 1001, + ["string", 123]) From b16720416123e4e57a3f1ded49ff95b473ce8769 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 19 Aug 2025 22:55:24 +0900 Subject: [PATCH 12/26] Fix log type --- Lib/test/test_winapi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index bc1a185b66b2d7..b8068023949951 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -191,5 +191,5 @@ def test_report_event(self): test_data) with self.assertRaisesRegex(TypeError, 'All strings must be unicode'): - _winapi.ReportEvent(handle, _winapi.EVENTLOG_SUCESS_TYPE, 0, 1001, + _winapi.ReportEvent(handle, _winapi.EVENTLOG_SUCCESS, 0, 1001, ["string", 123]) From 7d26942046e108f660413c9bb6a10f552562f2ff Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 19 Aug 2025 23:20:39 +0900 Subject: [PATCH 13/26] Remove ReportEvent with invalid handle cuz it will crash the process on some environment --- Lib/test/test_winapi.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index b8068023949951..4f1abd2913adf1 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -185,11 +185,6 @@ def test_report_event(self): # Test with empty strings list _winapi.ReportEvent(handle, _winapi.EVENTLOG_AUDIT_FAILURE, 2, 1003, []) - with self.assertRaisesRegex(OSError, '[WinError 6]'): - _winapi.ReportEvent(_winapi.INVALID_HANDLE_VALUE, - _winapi.EVENTLOG_AUDIT_SUCCESS, 0, 1001, [], - test_data) - with self.assertRaisesRegex(TypeError, 'All strings must be unicode'): - _winapi.ReportEvent(handle, _winapi.EVENTLOG_SUCCESS, 0, 1001, + _winapi.ReportEvent(handle, _winapi.EVENTLOG_ERROR_TYPE, 0, 1001, ["string", 123]) From 89e7cf86f851b296cf1f75a51ee36ae3988605b5 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 9 Sep 2025 00:49:54 +0900 Subject: [PATCH 14/26] Apply suggestions from code review Co-authored-by: Serhiy Storchaka --- Modules/_winapi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 04f36ea856ced0..e6db8ab4898a5d 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -3040,11 +3040,11 @@ _winapi.ReportEvent handle: HANDLE The handle to the event log. - type: int + type: unsigned_short(bitwise=False) The type of event being reported. - category: int + category: unsigned_short(bitwise=False) The event category. - event_id: int + event_id: unsigned_int(bitwise=False) The event identifier. strings: object(subclass_of='&PyList_Type') A list of strings to be inserted into the event message. From 696ca3dd12c1c4aaa4362c15e749a57b886d3184 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 9 Sep 2025 00:52:07 +0900 Subject: [PATCH 15/26] Update generated file --- Modules/_winapi.c | 7 ++++--- Modules/clinic/_winapi.c.h | 17 +++++++++-------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index e6db8ab4898a5d..cdac483f8d6ab7 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -3055,10 +3055,11 @@ Writes an entry at the end of the specified event log. [clinic start generated code]*/ static PyObject * -_winapi_ReportEvent_impl(PyObject *module, HANDLE handle, int type, - int category, int event_id, PyObject *strings, +_winapi_ReportEvent_impl(PyObject *module, HANDLE handle, + unsigned short type, unsigned short category, + unsigned int event_id, PyObject *strings, Py_buffer *raw_data) -/*[clinic end generated code: output=62348d38f92d26e8 input=4ac507ddabbf91ca]*/ +/*[clinic end generated code: output=fc3bbbde78cffd6c input=d4159129e760b095]*/ { BOOL success; LPCWSTR *string_array = NULL; diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index 74011834ee2a04..d5e542ee61556b 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -2307,8 +2307,9 @@ PyDoc_STRVAR(_winapi_ReportEvent__doc__, {"ReportEvent", _PyCFunction_CAST(_winapi_ReportEvent), METH_FASTCALL|METH_KEYWORDS, _winapi_ReportEvent__doc__}, static PyObject * -_winapi_ReportEvent_impl(PyObject *module, HANDLE handle, int type, - int category, int event_id, PyObject *strings, +_winapi_ReportEvent_impl(PyObject *module, HANDLE handle, + unsigned short type, unsigned short category, + unsigned int event_id, PyObject *strings, Py_buffer *raw_data); static PyObject * @@ -2338,19 +2339,19 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P static const char * const _keywords[] = {"handle", "type", "category", "event_id", "strings", "raw_data", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "" F_HANDLE "iiiO!|y*:ReportEvent", + .format = "" F_HANDLE "O&O&O&O!|y*:ReportEvent", .kwtuple = KWTUPLE, }; #undef KWTUPLE HANDLE handle; - int type; - int category; - int event_id; + unsigned short type; + unsigned short category; + unsigned int event_id; PyObject *strings; Py_buffer raw_data = {NULL, NULL}; if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &handle, &type, &category, &event_id, &PyList_Type, &strings, &raw_data)) { + &handle, _PyLong_UnsignedShort_Converter, &type, _PyLong_UnsignedShort_Converter, &category, _PyLong_UnsignedInt_Converter, &event_id, &PyList_Type, &strings, &raw_data)) { goto exit; } return_value = _winapi_ReportEvent_impl(module, handle, type, category, event_id, strings, &raw_data); @@ -2367,4 +2368,4 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P #ifndef _WINAPI_GETSHORTPATHNAME_METHODDEF #define _WINAPI_GETSHORTPATHNAME_METHODDEF #endif /* !defined(_WINAPI_GETSHORTPATHNAME_METHODDEF) */ -/*[clinic end generated code: output=c9830656556b2fc9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9476451acfd0f43d input=a9049054013a1b77]*/ From 0e9953e2c891f79d9888ef40726d4b95464fdb71 Mon Sep 17 00:00:00 2001 From: AN Long Date: Wed, 10 Sep 2025 01:34:11 +0900 Subject: [PATCH 16/26] Update by review --- Lib/test/test_winapi.py | 2 +- Modules/_winapi.c | 83 +++++++++++++++++++++++--------------- Modules/clinic/_winapi.c.h | 4 +- 3 files changed, 54 insertions(+), 35 deletions(-) diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index 4f1abd2913adf1..4b0da771e7cebe 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -185,6 +185,6 @@ def test_report_event(self): # Test with empty strings list _winapi.ReportEvent(handle, _winapi.EVENTLOG_AUDIT_FAILURE, 2, 1003, []) - with self.assertRaisesRegex(TypeError, 'All strings must be unicode'): + with self.assertRaisesRegex(TypeError, 'expected a list of strings, not int'): _winapi.ReportEvent(handle, _winapi.EVENTLOG_ERROR_TYPE, 0, 1001, ["string", 123]) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index cdac483f8d6ab7..088d48b2ee7a6a 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -2982,7 +2982,7 @@ _winapi.RegisterEventSource -> HANDLE unc_server_name: LPCWSTR(accept={str, NoneType}) The UNC name of the server on which the event source should be registered. - If NULL, registers the event source on the local computer. + If None, registers the event source on the local computer. source_name: LPCWSTR The name of the event source to register. / @@ -2993,7 +2993,7 @@ Retrieves a registered handle to the specified event log. static HANDLE _winapi_RegisterEventSource_impl(PyObject *module, LPCWSTR unc_server_name, LPCWSTR source_name) -/*[clinic end generated code: output=e376c8950a89ae8f input=9642e69236d0a14e]*/ +/*[clinic end generated code: output=e376c8950a89ae8f input=9d01059ac2156d0c]*/ { HANDLE handle; @@ -3068,40 +3068,58 @@ _winapi_ReportEvent_impl(PyObject *module, HANDLE handle, DWORD data_size = 0; // Handle strings list - if (strings != Py_None && PyList_Check(strings)) { - Py_ssize_t size = PyList_Size(strings); - num_strings = (WORD)size; - - if (num_strings > 0) { - string_array = (LPCWSTR *)PyMem_Malloc(num_strings * sizeof(LPCWSTR)); - if (!string_array) { - return PyErr_NoMemory(); - } - - for (WORD i = 0; i < num_strings; i++) { - PyObject *item = PyList_GetItem(strings, i); - if (!PyUnicode_Check(item)) { - PyMem_Free(string_array); - PyErr_SetString(PyExc_TypeError, "All strings must be unicode"); - return NULL; - } - string_array[i] = PyUnicode_AsWideCharString(item, NULL); - if (!string_array[i]) { - // Clean up already allocated strings - for (WORD j = 0; j < i; j++) { - PyMem_Free((void *)string_array[j]); - } - PyMem_Free(string_array); - return NULL; - } - } - } + Py_ssize_t size = PyList_Size(strings); + if (size > USHRT_MAX) { + PyErr_SetString(PyExc_ValueError, "strings is too long"); + return NULL; } + num_strings = (WORD)size; // Handle raw data + if (raw_data->len > PY_DWORD_MAX) { + PyErr_SetString(PyExc_ValueError, "raw_data is too large"); + return NULL; + } if (raw_data->buf != NULL) { data = raw_data->buf; - data_size = (DWORD) raw_data->len; + data_size = (DWORD)raw_data->len; + } + + if (num_strings > 0) { + string_array = (LPCWSTR *)PyMem_New(LPCWSTR, num_strings); + if (string_array == NULL) { + return PyErr_NoMemory(); + } + + for (WORD i = 0; i < num_strings; i++) { + PyObject *item = PyList_GetItemRef(strings, i); + if (item == NULL) { + // Clean up already allocated strings + for (WORD j = 0; j < i; j++) { + PyMem_Free((void *)string_array[j]); + } + PyMem_Free(string_array); + return NULL; + } + if (!PyUnicode_Check(item)) { + for (WORD j = 0; j < i; j++) { + PyMem_Free((void *)string_array[j]); + } + PyMem_Free(string_array); + PyErr_Format(PyExc_TypeError, + "expected a list of strings, not %T", item); + return NULL; + } + string_array[i] = PyUnicode_AsWideCharString(item, NULL); + Py_DECREF(item); + if (!string_array[i]) { + for (WORD j = 0; j < i; j++) { + PyMem_Free((void *)string_array[j]); + } + PyMem_Free(string_array); + return NULL; + } + } } Py_BEGIN_ALLOW_THREADS @@ -3110,6 +3128,7 @@ _winapi_ReportEvent_impl(PyObject *module, HANDLE handle, string_array, data); Py_END_ALLOW_THREADS + int ret = GetLastError(); // Clean up allocated strings if (string_array) { for (WORD i = 0; i < num_strings; i++) { @@ -3119,7 +3138,7 @@ _winapi_ReportEvent_impl(PyObject *module, HANDLE handle, } if (!success) - return PyErr_SetFromWindowsErr(0); + return PyErr_SetFromWindowsErr(ret); Py_RETURN_NONE; } diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index d5e542ee61556b..5081d94244b069 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -2192,7 +2192,7 @@ PyDoc_STRVAR(_winapi_RegisterEventSource__doc__, "\n" " unc_server_name\n" " The UNC name of the server on which the event source should be registered.\n" -" If NULL, registers the event source on the local computer.\n" +" If None, registers the event source on the local computer.\n" " source_name\n" " The name of the event source to register."); @@ -2368,4 +2368,4 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P #ifndef _WINAPI_GETSHORTPATHNAME_METHODDEF #define _WINAPI_GETSHORTPATHNAME_METHODDEF #endif /* !defined(_WINAPI_GETSHORTPATHNAME_METHODDEF) */ -/*[clinic end generated code: output=9476451acfd0f43d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=abf84ca3df2c8fd9 input=a9049054013a1b77]*/ From a0e331ae890933f64a033fd6a4a94c5ffa1bcdce Mon Sep 17 00:00:00 2001 From: AN Long Date: Wed, 10 Sep 2025 02:25:51 +0900 Subject: [PATCH 17/26] Fix raw_data signature --- Modules/_winapi.c | 6 +++--- Modules/clinic/_winapi.c.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 088d48b2ee7a6a..212e8bfa6f2119 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -3048,7 +3048,7 @@ _winapi.ReportEvent The event identifier. strings: object(subclass_of='&PyList_Type') A list of strings to be inserted into the event message. - raw_data: Py_buffer = None + raw_data: Py_buffer(accept={str, buffer, NoneType}) = None The raw data for the event. Writes an entry at the end of the specified event log. @@ -3059,7 +3059,7 @@ _winapi_ReportEvent_impl(PyObject *module, HANDLE handle, unsigned short type, unsigned short category, unsigned int event_id, PyObject *strings, Py_buffer *raw_data) -/*[clinic end generated code: output=fc3bbbde78cffd6c input=d4159129e760b095]*/ +/*[clinic end generated code: output=fc3bbbde78cffd6c input=abcc01d4fc284975]*/ { BOOL success; LPCWSTR *string_array = NULL; @@ -3080,7 +3080,7 @@ _winapi_ReportEvent_impl(PyObject *module, HANDLE handle, PyErr_SetString(PyExc_ValueError, "raw_data is too large"); return NULL; } - if (raw_data->buf != NULL) { + if (raw_data->obj != NULL) { data = raw_data->buf; data_size = (DWORD)raw_data->len; } diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index 5081d94244b069..7e5a8a626d6d81 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -2339,7 +2339,7 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P static const char * const _keywords[] = {"handle", "type", "category", "event_id", "strings", "raw_data", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "" F_HANDLE "O&O&O&O!|y*:ReportEvent", + .format = "" F_HANDLE "O&O&O&O!|z*:ReportEvent", .kwtuple = KWTUPLE, }; #undef KWTUPLE @@ -2368,4 +2368,4 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P #ifndef _WINAPI_GETSHORTPATHNAME_METHODDEF #define _WINAPI_GETSHORTPATHNAME_METHODDEF #endif /* !defined(_WINAPI_GETSHORTPATHNAME_METHODDEF) */ -/*[clinic end generated code: output=abf84ca3df2c8fd9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ce2a43d4766a0d4c input=a9049054013a1b77]*/ From d691c6cdb52528cd78c7e70cf000a12ba8af6c22 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 19 Oct 2025 23:33:22 +0900 Subject: [PATCH 18/26] Update NTEventLogHandler to use _winapi to emit event logs --- Lib/logging/handlers.py | 80 +++++++++++++++++++++++----------------- Lib/test/test_logging.py | 13 ++++++- 2 files changed, 59 insertions(+), 34 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 2748b5941eade2..87bcc3cd217dc6 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1125,7 +1125,7 @@ class NTEventLogHandler(logging.Handler): """ A handler class which sends events to the NT Event Log. Adds a registry entry for the specified application name. If no dllname is - provided, win32service.pyd (which contains some basic message + provided and pywin32 installed, win32service.pyd (which contains some basic message placeholders) is used. Note that use of these placeholders will make your event logs big, as the entire message source is held in the log. If you want slimmer logs, you have to pass in the name of your own DLL @@ -1133,38 +1133,45 @@ class NTEventLogHandler(logging.Handler): """ def __init__(self, appname, dllname=None, logtype="Application"): logging.Handler.__init__(self) - try: - import win32evtlogutil, win32evtlog - self.appname = appname - self._welu = win32evtlogutil - if not dllname: - dllname = os.path.split(self._welu.__file__) + import _winapi + self._winapi = _winapi + self.appname = appname + if not dllname: + # backward compatibility + try: + import win32evtlogutil + dllname = os.path.split(win32evtlogutil.__file__) dllname = os.path.split(dllname[0]) dllname = os.path.join(dllname[0], r'win32service.pyd') - self.dllname = dllname - self.logtype = logtype - # Administrative privileges are required to add a source to the registry. - # This may not be available for a user that just wants to add to an - # existing source - handle this specific case. - try: - self._welu.AddSourceToRegistry(appname, dllname, logtype) - except Exception as e: - # This will probably be a pywintypes.error. Only raise if it's not - # an "access denied" error, else let it pass - if getattr(e, 'winerror', None) != 5: # not access denied - raise - self.deftype = win32evtlog.EVENTLOG_ERROR_TYPE - self.typemap = { - logging.DEBUG : win32evtlog.EVENTLOG_INFORMATION_TYPE, - logging.INFO : win32evtlog.EVENTLOG_INFORMATION_TYPE, - logging.WARNING : win32evtlog.EVENTLOG_WARNING_TYPE, - logging.ERROR : win32evtlog.EVENTLOG_ERROR_TYPE, - logging.CRITICAL: win32evtlog.EVENTLOG_ERROR_TYPE, - } - except ImportError: - print("The Python Win32 extensions for NT (service, event "\ - "logging) appear not to be available.") - self._welu = None + except ImportError: + pass + self.dllname = dllname + self.logtype = logtype + # Administrative privileges are required to add a source to the registry. + # This may not be available for a user that just wants to add to an + # existing source - handle this specific case. + try: + self._add_source_to_registry(appname, dllname, logtype) + except PermissionError: + pass + self.deftype = _winapi.EVENTLOG_ERROR_TYPE + self.typemap = { + logging.DEBUG : _winapi.EVENTLOG_INFORMATION_TYPE, + logging.INFO : _winapi.EVENTLOG_INFORMATION_TYPE, + logging.WARNING : _winapi.EVENTLOG_WARNING_TYPE, + logging.ERROR : _winapi.EVENTLOG_ERROR_TYPE, + logging.CRITICAL: _winapi.EVENTLOG_ERROR_TYPE, + } + + def _add_source_to_registry(self, appname, dllname, logtype): + import winreg + + key_path = f"SYSTEM\\CurrentControlSet\\Services\\EventLog\\{logtype}\\{appname}" + + with winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, key_path) as key: + if dllname: + winreg.SetValueEx(key, "EventMessageFile", 0, winreg.REG_EXPAND_SZ, dllname) + winreg.SetValueEx(key, "TypesSupported", 0, winreg.REG_DWORD, 7) # All types are supported def getMessageID(self, record): """ @@ -1205,13 +1212,20 @@ def emit(self, record): Determine the message ID, event category and event type. Then log the message in the NT event log. """ - if self._welu: + if self._winapi: try: id = self.getMessageID(record) cat = self.getEventCategory(record) type = self.getEventType(record) msg = self.format(record) - self._welu.ReportEvent(self.appname, id, cat, type, [msg]) + + # Get a handle to the event log + handle = self._winapi.RegisterEventSource(None, self.appname) + if handle != self._winapi.INVALID_HANDLE_VALUE: + try: + self._winapi.ReportEvent(handle, type, cat, id, [msg]) + finally: + self._winapi.DeregisterEventSource(handle) except Exception: self.handleError(record) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 275f7ce47d09b5..4df0db49af398a 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -7185,8 +7185,8 @@ def test_compute_rollover(self, when=when, interval=interval, exp=exp): setattr(TimedRotatingFileHandlerTest, name, test_compute_rollover) -@unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.') class NTEventLogHandlerTest(BaseTest): + @unittest.skipUnless(win32evtlog, 'win32evtlog/win32evtlogutil/pywintypes required for this test.') def test_basic(self): logtype = 'Application' elh = win32evtlog.OpenEventLog(None, logtype) @@ -7220,6 +7220,17 @@ def test_basic(self): msg = 'Record not found in event log, went back %d records' % GO_BACK self.assertTrue(found, msg=msg) + @unittest.skipUnless(sys.platform == "win32", "Windows required for this test") + def test_updated_implementation(self): + h = logging.handlers.NTEventLogHandler('test_updated') + self.addCleanup(h.close) + + # Verify that the handler uses _winapi module + self.assertIsNotNone(h._winapi, "_winapi module should be available") + + r = logging.makeLogRecord({'msg': 'Test Updated Implementation'}) + h.emit(r) + class MiscTestCase(unittest.TestCase): def test__all__(self): From 14a9b86e0f0e74e71a162c3191823b1add653db5 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 19 Oct 2025 23:42:45 +0900 Subject: [PATCH 19/26] Update news entry --- .../next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Misc/NEWS.d/next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst b/Misc/NEWS.d/next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst index a95cbc58bfeab9..7527cac330d5c4 100644 --- a/Misc/NEWS.d/next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst +++ b/Misc/NEWS.d/next/Library/2025-08-17-00-28-50.gh-issue-135852.lQqOjQ.rst @@ -1,2 +1,4 @@ Add :func:`!_winapi.RegisterEventSource`, :func:`!_winapi.DeregisterEventSource` and :func:`!_winapi.ReportEvent`. +Using these functions in :class:`~logging.handlers.NTEventLogHandler` +to replace :mod:`!pywin32`. From 3d065037ecc5d85bde5945e51dd72535b9066175 Mon Sep 17 00:00:00 2001 From: AN Long Date: Thu, 23 Oct 2025 23:30:04 +0900 Subject: [PATCH 20/26] Update NTEventLogHandler by review comments --- Lib/logging/handlers.py | 42 ++++++++++++++++++++-------------------- Lib/test/test_logging.py | 6 +++--- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 87bcc3cd217dc6..6553178cb52e18 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1156,14 +1156,15 @@ def __init__(self, appname, dllname=None, logtype="Application"): pass self.deftype = _winapi.EVENTLOG_ERROR_TYPE self.typemap = { - logging.DEBUG : _winapi.EVENTLOG_INFORMATION_TYPE, - logging.INFO : _winapi.EVENTLOG_INFORMATION_TYPE, - logging.WARNING : _winapi.EVENTLOG_WARNING_TYPE, - logging.ERROR : _winapi.EVENTLOG_ERROR_TYPE, + logging.DEBUG: _winapi.EVENTLOG_INFORMATION_TYPE, + logging.INFO: _winapi.EVENTLOG_INFORMATION_TYPE, + logging.WARNING: _winapi.EVENTLOG_WARNING_TYPE, + logging.ERROR: _winapi.EVENTLOG_ERROR_TYPE, logging.CRITICAL: _winapi.EVENTLOG_ERROR_TYPE, } - def _add_source_to_registry(self, appname, dllname, logtype): + @staticmethod + def _add_source_to_registry(appname, dllname, logtype): import winreg key_path = f"SYSTEM\\CurrentControlSet\\Services\\EventLog\\{logtype}\\{appname}" @@ -1212,22 +1213,21 @@ def emit(self, record): Determine the message ID, event category and event type. Then log the message in the NT event log. """ - if self._winapi: - try: - id = self.getMessageID(record) - cat = self.getEventCategory(record) - type = self.getEventType(record) - msg = self.format(record) - - # Get a handle to the event log - handle = self._winapi.RegisterEventSource(None, self.appname) - if handle != self._winapi.INVALID_HANDLE_VALUE: - try: - self._winapi.ReportEvent(handle, type, cat, id, [msg]) - finally: - self._winapi.DeregisterEventSource(handle) - except Exception: - self.handleError(record) + try: + id = self.getMessageID(record) + cat = self.getEventCategory(record) + type = self.getEventType(record) + msg = self.format(record) + + # Get a handle to the event log + handle = self._winapi.RegisterEventSource(None, self.appname) + if handle != self._winapi.INVALID_HANDLE_VALUE: + try: + self._winapi.ReportEvent(handle, type, cat, id, [msg]) + finally: + self._winapi.DeregisterEventSource(handle) + except Exception: + self.handleError(record) def close(self): """ diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 4df0db49af398a..20058787080e89 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -7221,14 +7221,14 @@ def test_basic(self): self.assertTrue(found, msg=msg) @unittest.skipUnless(sys.platform == "win32", "Windows required for this test") - def test_updated_implementation(self): - h = logging.handlers.NTEventLogHandler('test_updated') + def test_without_pywin32(self): + h = logging.handlers.NTEventLogHandler('python_test') self.addCleanup(h.close) # Verify that the handler uses _winapi module self.assertIsNotNone(h._winapi, "_winapi module should be available") - r = logging.makeLogRecord({'msg': 'Test Updated Implementation'}) + r = logging.makeLogRecord({'msg': 'Hello!'}) h.emit(r) From 9d3f66e46a663daeb44a7d7a3b515d5c73709449 Mon Sep 17 00:00:00 2001 From: AN Long Date: Fri, 24 Oct 2025 01:28:22 +0900 Subject: [PATCH 21/26] Only support one single string for _winapi.ReposrtEvent --- .../pycore_global_objects_fini_generated.h | 3 - Include/internal/pycore_global_strings.h | 3 - .../internal/pycore_runtime_init_generated.h | 3 - .../internal/pycore_unicodeobject_generated.h | 12 --- Lib/logging/handlers.py | 2 +- Modules/_winapi.c | 89 ++++--------------- Modules/clinic/_winapi.c.h | 59 +++--------- 7 files changed, 29 insertions(+), 142 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 8345a33496785b..2078c201b4558d 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -944,7 +944,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(env)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(errors)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event_id)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(eventmask)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exc)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exc_type)); @@ -1201,7 +1200,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(query)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(quotetabs)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(raw)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(raw_data)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(read)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(read1)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(readable)); @@ -1282,7 +1280,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(strict)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(strict_mode)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(string)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(strings)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(sub_key)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(subcalls)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(symmetric_difference_update)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index f670d215886778..a7ebaf76c908c8 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -435,7 +435,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(env) STRUCT_FOR_ID(errors) STRUCT_FOR_ID(event) - STRUCT_FOR_ID(event_id) STRUCT_FOR_ID(eventmask) STRUCT_FOR_ID(exc) STRUCT_FOR_ID(exc_type) @@ -692,7 +691,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(query) STRUCT_FOR_ID(quotetabs) STRUCT_FOR_ID(raw) - STRUCT_FOR_ID(raw_data) STRUCT_FOR_ID(read) STRUCT_FOR_ID(read1) STRUCT_FOR_ID(readable) @@ -773,7 +771,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(strict) STRUCT_FOR_ID(strict_mode) STRUCT_FOR_ID(string) - STRUCT_FOR_ID(strings) STRUCT_FOR_ID(sub_key) STRUCT_FOR_ID(subcalls) STRUCT_FOR_ID(symmetric_difference_update) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 6aa652b48e4c8d..27669c50cd6101 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -942,7 +942,6 @@ extern "C" { INIT_ID(env), \ INIT_ID(errors), \ INIT_ID(event), \ - INIT_ID(event_id), \ INIT_ID(eventmask), \ INIT_ID(exc), \ INIT_ID(exc_type), \ @@ -1199,7 +1198,6 @@ extern "C" { INIT_ID(query), \ INIT_ID(quotetabs), \ INIT_ID(raw), \ - INIT_ID(raw_data), \ INIT_ID(read), \ INIT_ID(read1), \ INIT_ID(readable), \ @@ -1280,7 +1278,6 @@ extern "C" { INIT_ID(strict), \ INIT_ID(strict_mode), \ INIT_ID(string), \ - INIT_ID(strings), \ INIT_ID(sub_key), \ INIT_ID(subcalls), \ INIT_ID(symmetric_difference_update), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 15b7329f78cf31..c9b8a8b50510a2 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1528,10 +1528,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(event_id); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(eventmask); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2556,10 +2552,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(raw_data); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(read); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2880,10 +2872,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(strings); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(sub_key); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 6553178cb52e18..134bf79ce57aa9 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1223,7 +1223,7 @@ def emit(self, record): handle = self._winapi.RegisterEventSource(None, self.appname) if handle != self._winapi.INVALID_HANDLE_VALUE: try: - self._winapi.ReportEvent(handle, type, cat, id, [msg]) + self._winapi.ReportEvent(handle, type, cat, id, msg) finally: self._winapi.DeregisterEventSource(handle) except Exception: diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 212e8bfa6f2119..93ab4c9909d6d3 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -3046,10 +3046,9 @@ _winapi.ReportEvent The event category. event_id: unsigned_int(bitwise=False) The event identifier. - strings: object(subclass_of='&PyList_Type') - A list of strings to be inserted into the event message. - raw_data: Py_buffer(accept={str, buffer, NoneType}) = None - The raw data for the event. + string: object + A string to be inserted into the event message. + / Writes an entry at the end of the specified event log. [clinic start generated code]*/ @@ -3057,88 +3056,34 @@ Writes an entry at the end of the specified event log. static PyObject * _winapi_ReportEvent_impl(PyObject *module, HANDLE handle, unsigned short type, unsigned short category, - unsigned int event_id, PyObject *strings, - Py_buffer *raw_data) -/*[clinic end generated code: output=fc3bbbde78cffd6c input=abcc01d4fc284975]*/ + unsigned int event_id, PyObject *string) +/*[clinic end generated code: output=8eb5e919369c9c6d input=6db2c51252f95b93]*/ { BOOL success; - LPCWSTR *string_array = NULL; - WORD num_strings = 0; - LPVOID data = NULL; - DWORD data_size = 0; - - // Handle strings list - Py_ssize_t size = PyList_Size(strings); - if (size > USHRT_MAX) { - PyErr_SetString(PyExc_ValueError, "strings is too long"); - return NULL; - } - num_strings = (WORD)size; + LPCWSTR wide_string = NULL; - // Handle raw data - if (raw_data->len > PY_DWORD_MAX) { - PyErr_SetString(PyExc_ValueError, "raw_data is too large"); + if (!PyUnicode_Check(string)) { + PyErr_SetString(PyExc_TypeError, "string must be a str"); return NULL; } - if (raw_data->obj != NULL) { - data = raw_data->buf; - data_size = (DWORD)raw_data->len; - } - - if (num_strings > 0) { - string_array = (LPCWSTR *)PyMem_New(LPCWSTR, num_strings); - if (string_array == NULL) { - return PyErr_NoMemory(); - } - for (WORD i = 0; i < num_strings; i++) { - PyObject *item = PyList_GetItemRef(strings, i); - if (item == NULL) { - // Clean up already allocated strings - for (WORD j = 0; j < i; j++) { - PyMem_Free((void *)string_array[j]); - } - PyMem_Free(string_array); - return NULL; - } - if (!PyUnicode_Check(item)) { - for (WORD j = 0; j < i; j++) { - PyMem_Free((void *)string_array[j]); - } - PyMem_Free(string_array); - PyErr_Format(PyExc_TypeError, - "expected a list of strings, not %T", item); - return NULL; - } - string_array[i] = PyUnicode_AsWideCharString(item, NULL); - Py_DECREF(item); - if (!string_array[i]) { - for (WORD j = 0; j < i; j++) { - PyMem_Free((void *)string_array[j]); - } - PyMem_Free(string_array); - return NULL; - } - } + wide_string = PyUnicode_AsWideCharString(string, NULL); + if (!wide_string) { + return NULL; } Py_BEGIN_ALLOW_THREADS - success = ReportEventW(handle, type, category, event_id, - NULL, num_strings, data_size, - string_array, data); + success = ReportEventW(handle, type, category, event_id, NULL, 1, 0, + &wide_string, NULL); Py_END_ALLOW_THREADS int ret = GetLastError(); - // Clean up allocated strings - if (string_array) { - for (WORD i = 0; i < num_strings; i++) { - PyMem_Free((void *)string_array[i]); - } - PyMem_Free(string_array); - } - if (!success) + PyMem_Free((void *)wide_string); + + if (!success) { return PyErr_SetFromWindowsErr(ret); + } Py_RETURN_NONE; } diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index 7e5a8a626d6d81..a5fded900ffcb3 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -2284,8 +2284,7 @@ _winapi_DeregisterEventSource(PyObject *module, PyObject *arg) } PyDoc_STRVAR(_winapi_ReportEvent__doc__, -"ReportEvent($module, /, handle, type, category, event_id, strings,\n" -" raw_data=None)\n" +"ReportEvent($module, handle, type, category, event_id, string, /)\n" "--\n" "\n" "Writes an entry at the end of the specified event log.\n" @@ -2298,74 +2297,38 @@ PyDoc_STRVAR(_winapi_ReportEvent__doc__, " The event category.\n" " event_id\n" " The event identifier.\n" -" strings\n" -" A list of strings to be inserted into the event message.\n" -" raw_data\n" -" The raw data for the event."); +" string\n" +" A string to be inserted into the event message."); #define _WINAPI_REPORTEVENT_METHODDEF \ - {"ReportEvent", _PyCFunction_CAST(_winapi_ReportEvent), METH_FASTCALL|METH_KEYWORDS, _winapi_ReportEvent__doc__}, + {"ReportEvent", _PyCFunction_CAST(_winapi_ReportEvent), METH_FASTCALL, _winapi_ReportEvent__doc__}, static PyObject * _winapi_ReportEvent_impl(PyObject *module, HANDLE handle, unsigned short type, unsigned short category, - unsigned int event_id, PyObject *strings, - Py_buffer *raw_data); + unsigned int event_id, PyObject *string); static PyObject * -_winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 6 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(handle), &_Py_ID(type), &_Py_ID(category), &_Py_ID(event_id), &_Py_ID(strings), &_Py_ID(raw_data), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE - # define KWTUPLE NULL - #endif // !Py_BUILD_CORE - - static const char * const _keywords[] = {"handle", "type", "category", "event_id", "strings", "raw_data", NULL}; - static _PyArg_Parser _parser = { - .keywords = _keywords, - .format = "" F_HANDLE "O&O&O&O!|z*:ReportEvent", - .kwtuple = KWTUPLE, - }; - #undef KWTUPLE HANDLE handle; unsigned short type; unsigned short category; unsigned int event_id; - PyObject *strings; - Py_buffer raw_data = {NULL, NULL}; + PyObject *string; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &handle, _PyLong_UnsignedShort_Converter, &type, _PyLong_UnsignedShort_Converter, &category, _PyLong_UnsignedInt_Converter, &event_id, &PyList_Type, &strings, &raw_data)) { + if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "O&O&O&O:ReportEvent", + &handle, _PyLong_UnsignedShort_Converter, &type, _PyLong_UnsignedShort_Converter, &category, _PyLong_UnsignedInt_Converter, &event_id, &string)) { goto exit; } - return_value = _winapi_ReportEvent_impl(module, handle, type, category, event_id, strings, &raw_data); + return_value = _winapi_ReportEvent_impl(module, handle, type, category, event_id, string); exit: - /* Cleanup for raw_data */ - if (raw_data.obj) { - PyBuffer_Release(&raw_data); - } - return return_value; } #ifndef _WINAPI_GETSHORTPATHNAME_METHODDEF #define _WINAPI_GETSHORTPATHNAME_METHODDEF #endif /* !defined(_WINAPI_GETSHORTPATHNAME_METHODDEF) */ -/*[clinic end generated code: output=ce2a43d4766a0d4c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=63733d12831693e1 input=a9049054013a1b77]*/ From 7503e18ca0a52afa569ad07e98461f1d19a0dd67 Mon Sep 17 00:00:00 2001 From: AN Long Date: Fri, 24 Oct 2025 23:21:29 +0900 Subject: [PATCH 22/26] Update by review comments --- Lib/logging/handlers.py | 9 ++++----- Lib/test/test_winapi.py | 25 ++++++++++++++----------- Modules/_winapi.c | 3 ++- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 134bf79ce57aa9..cfdc8f295b0da1 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1221,11 +1221,10 @@ def emit(self, record): # Get a handle to the event log handle = self._winapi.RegisterEventSource(None, self.appname) - if handle != self._winapi.INVALID_HANDLE_VALUE: - try: - self._winapi.ReportEvent(handle, type, cat, id, msg) - finally: - self._winapi.DeregisterEventSource(handle) + try: + self._winapi.ReportEvent(handle, type, cat, id, msg) + finally: + self._winapi.DeregisterEventSource(handle) except Exception: self.handleError(record) diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index 4b0da771e7cebe..08a15c468ff001 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -161,13 +161,16 @@ def test_event_source_registration(self): source_name = "PythonTestEventSource" handle = _winapi.RegisterEventSource(None, source_name) + self.addCleanup(_winapi.DeregisterEventSource, handle) self.assertNotEqual(handle, _winapi.INVALID_HANDLE_VALUE) - with self.assertRaisesRegex(OSError, '[WinError 87]'): + with self.assertRaises(OSError) as cm: _winapi.RegisterEventSource(None, "") + self.assertEqual(cm.exception.winerror, 87) - with self.assertRaisesRegex(OSError, '[WinError 6]'): + with self.assertRaises(OSError) as cm: _winapi.DeregisterEventSource(_winapi.INVALID_HANDLE_VALUE) + self.assertEqual(cm.exception.winerror, 6) def test_report_event(self): source_name = "PythonTestEventSource" @@ -176,15 +179,15 @@ def test_report_event(self): self.assertNotEqual(handle, _winapi.INVALID_HANDLE_VALUE) self.addCleanup(_winapi.DeregisterEventSource, handle) - # Test with strings and raw data - test_strings = ["Test message 1", "Test message 2"] - test_data = b"test raw data" _winapi.ReportEvent(handle, _winapi.EVENTLOG_SUCCESS, 1, 1002, - test_strings, test_data) + "Test message 1") + + with self.assertRaises(TypeError): + _winapi.ReportEvent(handle, _winapi.EVENTLOG_SUCCESS, 1, 1002, 42) - # Test with empty strings list - _winapi.ReportEvent(handle, _winapi.EVENTLOG_AUDIT_FAILURE, 2, 1003, []) + with self.assertRaises(TypeError): + _winapi.ReportEvent(handle, _winapi.EVENTLOG_SUCCESS, 1, 1002, None) - with self.assertRaisesRegex(TypeError, 'expected a list of strings, not int'): - _winapi.ReportEvent(handle, _winapi.EVENTLOG_ERROR_TYPE, 0, 1001, - ["string", 123]) + with self.assertRaises(ValueError): + _winapi.ReportEvent(handle, _winapi.EVENTLOG_SUCCESS, 1, 1002, + "Test message \0 with embedded null character") diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 93ab4c9909d6d3..02c887eca257ee 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -3029,8 +3029,9 @@ _winapi_DeregisterEventSource_impl(PyObject *module, HANDLE handle) success = DeregisterEventSource(handle); Py_END_ALLOW_THREADS - if (!success) + if (!success) { return PyErr_SetFromWindowsErr(0); + } Py_RETURN_NONE; } From 7aa607a2f083af73522ddfd64c72b9fb0e354126 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 25 Oct 2025 00:26:07 +0900 Subject: [PATCH 23/26] Update Lib/test/test_winapi.py Co-authored-by: Serhiy Storchaka --- Lib/test/test_winapi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index 08a15c468ff001..2b972c2127dc43 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -166,7 +166,7 @@ def test_event_source_registration(self): with self.assertRaises(OSError) as cm: _winapi.RegisterEventSource(None, "") - self.assertEqual(cm.exception.winerror, 87) + self.assertEqual(cm.exception.errno, errno.EINVAL) with self.assertRaises(OSError) as cm: _winapi.DeregisterEventSource(_winapi.INVALID_HANDLE_VALUE) From d4a8a33604c9d5081372cb2220eaefbb404fee93 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 25 Oct 2025 00:28:20 +0900 Subject: [PATCH 24/26] Using errno --- Lib/test/test_winapi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_winapi.py b/Lib/test/test_winapi.py index 2b972c2127dc43..a1c0b80d47e4d4 100644 --- a/Lib/test/test_winapi.py +++ b/Lib/test/test_winapi.py @@ -1,5 +1,6 @@ # Test the Windows-only _winapi module +import errno import os import pathlib import re @@ -170,7 +171,7 @@ def test_event_source_registration(self): with self.assertRaises(OSError) as cm: _winapi.DeregisterEventSource(_winapi.INVALID_HANDLE_VALUE) - self.assertEqual(cm.exception.winerror, 6) + self.assertEqual(cm.exception.errno, errno.EBADF) def test_report_event(self): source_name = "PythonTestEventSource" From 4df7da4377bbcefa166a23333ce8d48b96015f24 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 25 Oct 2025 00:30:20 +0900 Subject: [PATCH 25/26] Update Modules/_winapi.c Co-authored-by: Serhiy Storchaka --- Modules/_winapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 02c887eca257ee..46f50bb53ee45c 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -3047,7 +3047,7 @@ _winapi.ReportEvent The event category. event_id: unsigned_int(bitwise=False) The event identifier. - string: object + string: LPCWSTR A string to be inserted into the event message. / From c82e5ac9cd9bdc81611df0eb6b2b97557cbf6a81 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 25 Oct 2025 00:31:16 +0900 Subject: [PATCH 26/26] Using LPCWSTR convertor --- Modules/_winapi.c | 23 ++++------------------- Modules/clinic/_winapi.c.h | 13 ++++++++----- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 46f50bb53ee45c..6f7d7514de5b0f 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -3057,33 +3057,18 @@ Writes an entry at the end of the specified event log. static PyObject * _winapi_ReportEvent_impl(PyObject *module, HANDLE handle, unsigned short type, unsigned short category, - unsigned int event_id, PyObject *string) -/*[clinic end generated code: output=8eb5e919369c9c6d input=6db2c51252f95b93]*/ + unsigned int event_id, LPCWSTR string) +/*[clinic end generated code: output=4281230b70a2470a input=8fb3385b8e7a6d3d]*/ { BOOL success; - LPCWSTR wide_string = NULL; - - if (!PyUnicode_Check(string)) { - PyErr_SetString(PyExc_TypeError, "string must be a str"); - return NULL; - } - - wide_string = PyUnicode_AsWideCharString(string, NULL); - if (!wide_string) { - return NULL; - } Py_BEGIN_ALLOW_THREADS success = ReportEventW(handle, type, category, event_id, NULL, 1, 0, - &wide_string, NULL); + &string, NULL); Py_END_ALLOW_THREADS - int ret = GetLastError(); - - PyMem_Free((void *)wide_string); - if (!success) { - return PyErr_SetFromWindowsErr(ret); + return PyErr_SetFromWindowsErr(0); } Py_RETURN_NONE; diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index a5fded900ffcb3..00cce91dca43b1 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -2306,7 +2306,7 @@ PyDoc_STRVAR(_winapi_ReportEvent__doc__, static PyObject * _winapi_ReportEvent_impl(PyObject *module, HANDLE handle, unsigned short type, unsigned short category, - unsigned int event_id, PyObject *string); + unsigned int event_id, LPCWSTR string); static PyObject * _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs) @@ -2316,19 +2316,22 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs) unsigned short type; unsigned short category; unsigned int event_id; - PyObject *string; + LPCWSTR string = NULL; - if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "O&O&O&O:ReportEvent", - &handle, _PyLong_UnsignedShort_Converter, &type, _PyLong_UnsignedShort_Converter, &category, _PyLong_UnsignedInt_Converter, &event_id, &string)) { + if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "O&O&O&O&:ReportEvent", + &handle, _PyLong_UnsignedShort_Converter, &type, _PyLong_UnsignedShort_Converter, &category, _PyLong_UnsignedInt_Converter, &event_id, _PyUnicode_WideCharString_Converter, &string)) { goto exit; } return_value = _winapi_ReportEvent_impl(module, handle, type, category, event_id, string); exit: + /* Cleanup for string */ + PyMem_Free((void *)string); + return return_value; } #ifndef _WINAPI_GETSHORTPATHNAME_METHODDEF #define _WINAPI_GETSHORTPATHNAME_METHODDEF #endif /* !defined(_WINAPI_GETSHORTPATHNAME_METHODDEF) */ -/*[clinic end generated code: output=63733d12831693e1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=4ab94eaee93a0a90 input=a9049054013a1b77]*/