[pywin32-checkins] /hgrepo/p/py/pywin32/pywin32: 2 new changesets
OLD project page for the Python extensions for Windows
Brought to you by:
mhammond
From: <pyw...@li...> - 2011-06-07 03:21:10
|
changeset 90fec908e944 in /hgrepo/p/py/pywin32/pywin32 details: http://pywin32.hg.sourceforge.net/hgweb/pywin32/pywin32/hgrepo/p/py/pywin32/pywin32?cmd=changeset;node=90fec908e944 summary: Add some more Vista/Win7 event log functions changeset 8cf199233556 in /hgrepo/p/py/pywin32/pywin32 details: http://pywin32.hg.sourceforge.net/hgweb/pywin32/pywin32/hgrepo/p/py/pywin32/pywin32?cmd=changeset;node=8cf199233556 summary: Demos showing how to use EvtSubscribe diffstat: win32/Demos/EvtSubscribe_pull.py | 21 +++ win32/Demos/EvtSubscribe_push.py | 16 ++ win32/src/win32evtlog.i | 290 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 323 insertions(+), 4 deletions(-) diffs (truncated from 388 to 300 lines): diff -r abb91f8e9851 -r 8cf199233556 win32/Demos/EvtSubscribe_pull.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/Demos/EvtSubscribe_pull.py Mon Jun 06 09:02:34 2011 -0400 @@ -0,0 +1,21 @@ +## Demonstrates how to create a "pull" subscription +import win32evtlog, win32event, win32con +query_text='*[System[Provider[@Name="Microsoft-Windows-Winlogon"]]]' + +h=win32event.CreateEvent(None, 0, 0, None) +s=win32evtlog.EvtSubscribe('System', win32evtlog.EvtSubscribeStartAtOldestRecord, SignalEvent=h, Query=query_text) + +while 1: + while 1: + events=win32evtlog.EvtNext(s, 10) + if len(events)==0: + break + ##for event in events: + ## print (win32evtlog.EvtRender(event, win32evtlog.EvtRenderEventXml)) + print ('retrieved %s events' %len(events)) + while 1: + print ('waiting...') + w=win32event.WaitForSingleObjectEx(h, 2000, True) + if w==win32con.WAIT_OBJECT_0: + break + diff -r abb91f8e9851 -r 8cf199233556 win32/Demos/EvtSubscribe_push.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/win32/Demos/EvtSubscribe_push.py Mon Jun 06 09:02:34 2011 -0400 @@ -0,0 +1,16 @@ +## Demonstrates a "push" subscription with a callback function +import win32evtlog +query_text='*[System[Provider[@Name="Microsoft-Windows-Winlogon"]]]' + +def c(reason, context, evt): + if reason==win32evtlog.EvtSubscribeActionError: + print ('EvtSubscribeActionError') + elif reason==win32evtlog.EvtSubscribeActionDeliver: + print ('EvtSubscribeActionDeliver') + else: + print ('??? Unknown action ???', reason) + context.append(win32evtlog.EvtRender(evt, win32evtlog.EvtRenderEventXml)) + return 0 + +evttext=[] +s=win32evtlog.EvtSubscribe('System', win32evtlog.EvtSubscribeStartAtOldestRecord, Query='*', Callback=c, Context=evttext) diff -r abb91f8e9851 -r 8cf199233556 win32/src/win32evtlog.i --- a/win32/src/win32evtlog.i Fri Jun 03 23:52:26 2011 -0400 +++ b/win32/src/win32evtlog.i Mon Jun 06 09:02:34 2011 -0400 @@ -57,17 +57,25 @@ class PyEVT_HANDLE: public PyHANDLE { public: - PyEVT_HANDLE(HANDLE hInit) : PyHANDLE(hInit) {} + PyEVT_HANDLE(HANDLE hInit, PyObject *context) : PyHANDLE(hInit){ + callback_objects = context; + Py_XINCREF(callback_objects); + } virtual BOOL Close(void){ BOOL ret=EvtClose(m_handle); if (!ret) PyWin_SetAPIError("EvtClose"); m_handle = 0; + Py_XDECREF(callback_objects); + callback_objects=NULL; return ret; } virtual const char *GetTypeName(){ return "PyEVT_HANDLE"; } + // Only used with push subscription handles. Will be a 2-tuple + // that keeps references to the callback function and context object + PyObject *callback_objects; }; #define PyHANDLE HANDLE @@ -80,9 +88,9 @@ return ret; } -PyObject *PyWinObject_FromEVT_HANDLE(HANDLE h) +PyObject *PyWinObject_FromEVT_HANDLE(HANDLE h, PyObject *context=NULL) { - PyObject *ret=new PyEVT_HANDLE(h); + PyObject *ret=new PyEVT_HANDLE(h, context); if (ret==NULL){ EvtClose(h); PyErr_NoMemory(); @@ -686,6 +694,240 @@ free(msg); return ret; } + +// @pyswig <o PyEVT_HANDLE>|EvtQuery|Opens a query over a log channel or exported log file +// @comm Accepts keyword args +static PyObject *PyEvtQuery(PyObject *self, PyObject *args, PyObject *kwargs) +{ + static char *keywords[]={"Path", "Flags", "Query", "Session", NULL}; + EVT_HANDLE ret, session=NULL; + DWORD flags; + TmpWCHAR path, query; + PyObject *obpath, *obquery=Py_None; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Ol|OO&:EvtQuery", keywords, + &obpath, // @pyparm str|Path||Log channel or exported log file, depending on Flags + &flags, // @pyparm int|Flags||Combination of EVT_QUERY_FLAGS (EvtQuery*) + &obquery, // @pyparm str|Query|None|Selects events to return, None or '*' for all events + PyWinObject_AsHANDLE, &session)) // @pyparm <o PyEVT_HANDLE>|Session|None|Handle to a remote session (see <om win32evtlog.EvtOpenSession>), or None for local machine. + return NULL; + if (!PyWinObject_AsWCHAR(obpath, &path, FALSE)) + return NULL; + if (!PyWinObject_AsWCHAR(obquery, &query, TRUE)) + return NULL; + + ret = EvtQuery(session, path, query, flags); + if (ret == NULL) + return PyWin_SetAPIError("EvtQuery"); + return PyWinObject_FromEVT_HANDLE(ret); +} +PyCFunction pfnPyEvtQuery = (PyCFunction) PyEvtQuery; + +// @pyswig (<o PyEVT_HANDLE>,...)|EvtNext|Returns events from a query +// @rdesc Returns a tuple of handles to events. If no items are available, returns +// an empty tuple instead of raising an exception. +// @comm Accepts keyword args +static PyObject *PyEvtNext(PyObject *self, PyObject *args, PyObject *kwargs) +{ + static char *keywords[]={"ResultSet", "Count", "Timeout", "Flags", NULL}; + EVT_HANDLE query; + EVT_HANDLE *events =NULL; + DWORD nbr_requested, nbr_returned, flags=0, timeout=(DWORD)-1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&k|kk:EvtNext", keywords, + PyWinObject_AsHANDLE, &query, // @pyparm <o PyEVT_HANDLE>|ResultSet||Handle to event query or subscription + &nbr_requested, // @pyparm int|Count||Number of events to return + &timeout, // @pyparm int|Timeout|-1|Time to wait in milliseconds, use -1 for infinite + &flags)) // @pyparm int|Flags|0|Reserved, use only 0 + return NULL; + events = (EVT_HANDLE *)malloc(nbr_requested * sizeof(EVT_HANDLE *)); + if (events==NULL){ + PyErr_NoMemory(); + return NULL; + } + + if (!EvtNext(query, nbr_requested, events, timeout, flags, &nbr_returned)){ + free(events); + DWORD err=GetLastError(); + if (err == ERROR_NO_MORE_ITEMS) + return PyTuple_New(0); + return PyWin_SetAPIError("EvtNext", err); + } + + // If tuple construction fails, any handle not yet wrapped in a PyEVT_HANDLE + // will be orphaned and remain open. Should be a rare occurence, though. + PyObject *ret=PyTuple_New(nbr_returned); + if (ret){ + for (DWORD i=0;i<nbr_returned;i++){ + PyObject *obevt=PyWinObject_FromEVT_HANDLE(events[i]); + if (obevt==NULL){ + Py_DECREF(ret); + ret=NULL; + break; + } + PyTuple_SET_ITEM(ret, i, obevt); + } + } + free(events); + return ret; +} +PyCFunction pfnPyEvtNext = (PyCFunction) PyEvtNext; + +// @pyswig |EvtSeek|Changes the current position in a result set +// @comm Accepts keyword args +static PyObject *PyEvtSeek(PyObject *self, PyObject *args, PyObject *kwargs) +{ + static char *keywords[]={"ResultSet", "Position", "Flags", "Bookmark", "Timeout", NULL}; + EVT_HANDLE query, bookmark=NULL; + DWORD flags, timeout=0; + LONGLONG position; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&Lk|O&k:EvtSeek", keywords, + PyWinObject_AsHANDLE, &query, // @pyparm <o PyEVT_HANDLE>|ResultSet||Handle to event query or subscription + &position, // @pyparm int|Position||Offset (base from which to seek is specified by Flags) + &flags, // @pyparm int|Flags||EvtSeekRelative* flag indicating seek origin + PyWinObject_AsHANDLE, &bookmark, // @pyparm <o PyEVT_HANDLE>|Bookmark|None|Used as seek origin only if Flags contains EvtSeekRelativeToBookmark + &timeout)) // @pyparm int|Timeout|0|Reserved, use only 0 + return NULL; + if (!EvtSeek(query, position, bookmark, timeout, flags)) + return PyWin_SetAPIError("EvtSeek"); + Py_INCREF(Py_None); + return Py_None;; +} +PyCFunction pfnPyEvtSeek = (PyCFunction) PyEvtSeek; + +// @pyswig str|EvtRender|Formats an event into XML text +// @comm Accepts keyword args +// @comm Rendering event values (Flags=EvtRenderEventValues) is not currently supported +static PyObject *PyEvtRender(PyObject *self, PyObject *args, PyObject *kwargs) +{ + static char *keywords[]={"Event", "Flags", NULL}; + EVT_HANDLE event; + void *buf=NULL; + DWORD flags, bufsize=2048, bufneeded, propcount; + PyObject *ret=NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&k:EvtRender", keywords, + PyWinObject_AsHANDLE, &event, // @pyparm <o PyEVT_HANDLE>|Event||Handle to an event or bookmark + &flags)) // @pyparm int|Flags||EvtRenderEventXml or EvtRenderBookmark indicating type of handle + return NULL; + if (flags==EvtRenderEventValues){ + // Requires yet another type of VARIANT + PyErr_Format(PyExc_NotImplementedError,"Rendering values is not yet supported"); + return NULL; + } + while(1){ + if (buf) + free(buf); + buf=malloc(bufsize); + if (buf==NULL){ + PyErr_NoMemory(); + return NULL; + } + if (EvtRender(NULL, event, flags, bufsize, buf, &bufneeded, &propcount)){ + ret=PyWinObject_FromWCHAR((WCHAR *)buf); + break; + } + DWORD err=GetLastError(); + if (err==ERROR_INSUFFICIENT_BUFFER) + bufsize=bufneeded; + else{ + PyWin_SetAPIError("EvtRender", err); + break; + } + } + free(buf); + return ret; +} +PyCFunction pfnPyEvtRender = (PyCFunction) PyEvtRender; + + +DWORD CALLBACK PyEvtSubscribe_callback( + EVT_SUBSCRIBE_NOTIFY_ACTION action, + void *context, + EVT_HANDLE event) +{ + CEnterLeavePython celp; + DWORD err=0; + PyObject *func = PyTuple_GET_ITEM((PyObject *)context, 0); + PyObject *obcontext = PyTuple_GET_ITEM((PyObject *)context, 1); + PyObject *args=Py_BuildValue("kOO", action, obcontext, PyWinLong_FromHANDLE(event)); + if (args==NULL){ + // ??? Docs don't specify what happens when you return an error from callback + // Need to check if subscription handle is closed ??? + PyErr_Print(); + return ERROR_OUTOFMEMORY; + } + PyObject *ret=PyObject_Call(func, args, NULL); + if (ret==NULL){ + // Nothing to be done about an exception raised by the python callback + PyErr_Print(); + err = ERROR_OUTOFMEMORY; + } + else if (ret!=Py_None){ + // Allow the callback to return an error + err=PyLong_AsUnsignedLong(ret); + if (err==(DWORD)-1 && PyErr_Occurred()){ + PyErr_Print(); + err = 0; + } + } + + Py_DECREF(args); + Py_XDECREF(ret); + return err; +} + +// @pyswig <o PyEVT_HANDLE>|EvtSubscribe|Requests notification for events +// @comm Accepts keyword args +// @comm The method used to receive events is determined by the parameters passed in. +// To create a push subscription, define a callback function that will be called with each event. +// The function will receive 3 args: +// First is an integer specifying why the function was called (EvtSubscribeActionError or EvtSubscribeActionDeliver) +// Second is the context object passed to EvtSubscribe. +// Third is the handle to an event log record (if not called due to an error) +// If an event handle is passed in, a pull subscription is created. The event handle will be +// signalled when events are available, and the subscription handle can be +// passed to <om win32evtlog.EvtNext> to obtain the events. + +static PyObject *PyEvtSubscribe(PyObject *self, PyObject *args, PyObject *kwargs) +{ + static char *keywords[]={"ChannelPath", "Flags", "SignalEvent", "Callback", "Context", + "Query", "Session", "Bookmark", NULL}; + EVT_HANDLE session=NULL, bookmark=NULL, ret; + HANDLE signalevent=NULL; + TmpWCHAR path, query; + PyObject *obpath, *obcallback=Py_None, *obquery=Py_None, *obcontext=Py_None; + TmpPyObject obuserdata; // actual context passed to C++ callback - tuple of (function, context object) + DWORD flags; + EVT_SUBSCRIBE_CALLBACK pfncallback=NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Ok|O&OOOO&O&:EvtSubscribe", keywords, + &obpath, // @pyparm str|ChannelPath||Name of an event log channel + &flags, // @pyparm int|Flags||Combination of EvtSubscribe* flags determining how subscription is initiated + PyWinObject_AsHANDLE, &signalevent, // @pyparm <o Py_HANDLE>|SignalEvent|None|An event handle to be set when events are available (see <om win32event.CreateEvent>) |