Skip to content

gh-135852: Add NTEventLog related functions to _winapi #137860

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Include/internal/pycore_global_objects_fini_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ 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)
Expand Down Expand Up @@ -681,6 +682,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)
Expand Down Expand Up @@ -759,6 +761,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)
Expand Down
3 changes: 3 additions & 0 deletions Include/internal/pycore_runtime_init_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions Include/internal/pycore_unicodeobject_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions Lib/test/test_winapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,41 @@ 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)

with self.assertRaisesRegex(OSError, '[WinError 87]'):
_winapi.RegisterEventSource(None, "")

with self.assertRaisesRegex(OSError, '[WinError 6]'):
_winapi.DeregisterEventSource(_winapi.INVALID_HANDLE_VALUE)

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, _winapi.EVENTLOG_SUCCESS, 1, 1002,
test_strings, test_data)

# Test with empty strings list
_winapi.ReportEvent(handle, _winapi.EVENTLOG_AUDIT_FAILURE ,2, 0, 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_ERROR_TYPE, 0, 1001,
["string", 123])
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add :func:`!_winapi.RegisterEventSource`,
:func:`!_winapi.DeregisterEventSource` and :func:`!_winapi.ReportEvent`.
155 changes: 155 additions & 0 deletions Modules/_winapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -2977,6 +2977,152 @@ _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.
/

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=9642e69236d0a14e]*/
{
HANDLE handle;

Py_BEGIN_ALLOW_THREADS
handle = RegisterEventSourceW(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.
/

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=947593cf67641f16]*/
{
BOOL success;

Py_BEGIN_ALLOW_THREADS
success = DeregisterEventSource(handle);
Py_END_ALLOW_THREADS

if (!success)
return PyErr_SetFromWindowsErr(0);

Py_RETURN_NONE;
}

/*[clinic input]
_winapi.ReportEvent

handle: HANDLE
The handle to the event log.
type: int
The type of event being reported.
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 = 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 type,
int category, int event_id, PyObject *strings,
Py_buffer *raw_data)
/*[clinic end generated code: output=62348d38f92d26e8 input=4ac507ddabbf91ca]*/
{
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, type, 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
Expand All @@ -2989,6 +3135,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
Expand All @@ -3005,6 +3152,8 @@ static PyMethodDef winapi_functions[] = {
_WINAPI_OPENMUTEXW_METHODDEF
_WINAPI_OPENPROCESS_METHODDEF
_WINAPI_PEEKNAMEDPIPE_METHODDEF
_WINAPI_REGISTEREVENTSOURCE_METHODDEF
_WINAPI_REPORTEVENT_METHODDEF
_WINAPI_LCMAPSTRINGEX_METHODDEF
_WINAPI_READFILE_METHODDEF
_WINAPI_RELEASEMUTEX_METHODDEF
Expand Down Expand Up @@ -3077,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);
Expand Down
Loading
Loading