c-从事件日志中读取任务调度程序事件



我想列出C/C++中任务调度器的自定义任务的所有执行运行。因此,我访问事件日志并尝试提取TaskScheduler日志条目,如下所示(为了简单起见,删除了所有错误处理(:

HANDLE hEv = OpenEventLogA(NULL, "Microsoft-Windows-TaskScheduler/Operational");
DWORD nrRead = 0x10000, status = ERROR_SUCCESS, nrMin = 0, nrDone;
PBYTE buf = (PBYTE) malloc(nrRead);
while (status == ERROR_SUCCESS) {
if (!ReadEventLog(hEv, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ, 
0, buf, nrRead, &nrDone, &nrMin)) status = GetLastError();
for (PBYTE pRec = buf, pEnd = buf + nrRead; pRec < pEnd;) {
(void) (pRec + sizeof(EVENTLOGRECORD));     // Store record
pRec += ((PEVENTLOGRECORD) pRec)->Length;
if (((PEVENTLOGRECORD) pRec)->Length == 0) break; // Avoid endless loop
}
}

事实上,我可以从日志中读取事件(例如WiFi日志(。但我无法打开TaskScheduler日志。然后,它将按照文档中的描述进行操作,并返回到应用程序日志。

我为日志的名称尝试了不同的字符串:

  • 事件日志中的协议名称
  • 用斜线分隔的协议路径
  • 英文和本地化名称

这些似乎都不起作用。那么,如何打开TaskScheduler日志?日志名称是否本地化,是否需要根据当前操作系统语言进行调整?是否有其他方法可以检索TaskScheduler执行?

我试过你的代码,似乎OpenEventLog只能打开一些常用的日志(不确定(。但是,还有另一种方法可以列出TaskScheduler事件:

使用EvtSubscribe()添加回调函数,当查询记录时,以XML格式打印出来。以下是代码示例:

#include <windows.h>
#include <sddl.h>
#include <stdio.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib")
const int SIZE_DATA = 4096;
TCHAR XMLDataCurrent[SIZE_DATA];
TCHAR XMLDataUser[SIZE_DATA];
#define ARRAY_SIZE 10
#define TIMEOUT 1000  // 1 second; Set and use in place of INFINITE in EvtNext call
DWORD PrintEvent(EVT_HANDLE hEvent); // Shown in the Rendering Events topic
DWORD WINAPI SubscriptionCallback(EVT_SUBSCRIBE_NOTIFY_ACTION action, PVOID pContext, EVT_HANDLE hEvent);
void main(void)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hResults = NULL;
//hResults = EvtQuery(NULL, pwsPath, pwsQuery, EvtQueryChannelPath );// EvtQueryReverseDirection);
hResults = EvtSubscribe(NULL, NULL, L"Microsoft-Windows-TaskScheduler/Operational", NULL, NULL, NULL, (EVT_SUBSCRIBE_CALLBACK)SubscriptionCallback, EvtSubscribeStartAtOldestRecord);
if (NULL == hResults)
{
status = GetLastError();
if (ERROR_EVT_CHANNEL_NOT_FOUND == status)
wprintf(L"The channel was not found.n");
else if (ERROR_EVT_INVALID_QUERY == status)
// You can call the EvtGetExtendedStatus function to try to get 
// additional information as to what is wrong with the query.
wprintf(L"The query is not valid.n");
else
wprintf(L"EvtQuery failed with %lu.n", status);
}
Sleep(1000);
cleanup:
if (hResults)
EvtClose(hResults);
}
// The callback that receives the events that match the query criteria. 
DWORD WINAPI SubscriptionCallback(EVT_SUBSCRIBE_NOTIFY_ACTION action, PVOID pContext, EVT_HANDLE hEvent)
{
UNREFERENCED_PARAMETER(pContext);
DWORD status = ERROR_SUCCESS;
switch (action)
{
// You should only get the EvtSubscribeActionError action if your subscription flags 
// includes EvtSubscribeStrict and the channel contains missing event records.
case EvtSubscribeActionError:
if (ERROR_EVT_QUERY_RESULT_STALE == (DWORD)hEvent)
{
wprintf(L"The subscription callback was notified that event records are missing.n");
// Handle if this is an issue for your application.
}
else
{
wprintf(L"The subscription callback received the following Win32 error: %lun", (DWORD)hEvent);
}
break;
case EvtSubscribeActionDeliver:
if (ERROR_SUCCESS != (status = PrintEvent(hEvent)))
{
goto cleanup;
}
break;
default:
wprintf(L"SubscriptionCallback: Unknown action.n");
}
cleanup:
if (ERROR_SUCCESS != status)
{
// End subscription - Use some kind of IPC mechanism to signal
// your application to close the subscription handle.
}
return status; // The service ignores the returned status.
}

DWORD PrintEvent(EVT_HANDLE hEvent)
{
DWORD status = ERROR_SUCCESS;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD dwPropertyCount = 0;
LPWSTR pRenderedContent = NULL;
if (!EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount))
{
if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError()))
{
dwBufferSize = dwBufferUsed;
pRenderedContent = (LPWSTR)malloc(dwBufferSize);
if (pRenderedContent)
{
EvtRender(NULL, hEvent, EvtRenderEventXml, dwBufferSize, pRenderedContent, &dwBufferUsed, &dwPropertyCount);
}
else
{
wprintf(L"malloc failedn");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtRender failed with %dn", status);
goto cleanup;
}
}
ZeroMemory(XMLDataCurrent, SIZE_DATA);
lstrcpyW(XMLDataCurrent, pRenderedContent);
wprintf(L"EvtRender data %sn", XMLDataCurrent);
cleanup:
if (pRenderedContent)
free(pRenderedContent);
return status;
}

希望它能帮助你!

感谢@zett42为我指明了正确的方向,感谢@Drake Wu提供了详细的代码示例。但由于我不需要任何未来的事件或异步检索,我现在实现了一个简单的同步功能:

#define EVT_SIZE 10
int GetEvents(LPCWSTR query) {
DWORD xmlLen = 0;
LPCWSTR xml = NULL;
EVT_HANDLE hQuery = EvtQuery(NULL, NULL, query, EvtQueryChannelPath | EvtQueryTolerateQueryErrors));
while (true) {
EVT_HANDLE hEv[EVT_SIZE];
DWORD dwReturned = 0;
if (!EvtNext(hQuery, EVT_SIZE, hEv, INFINITE, 0, &dwReturned)) return 0;
// Loop over all events
for (DWORD i = 0; i < dwReturned; i++) {
DWORD nrRead = 0, nrProps = 0;
if (!EvtRender(NULL, hEv[i], EvtRenderEventXml, xmlLen, xml, &nrRead, &nrProps)) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
xmlLen = nrRead;
xml = (LPWSTR) realloc(xml, xmlLen);
if (xml) {
EvtRender(NULL, hEv[i], EvtRenderEventXml, xmlLen, xml, &nrRead, &nrProps);
} else {
return -1;
}
}
if (GetLastError() != ERROR_SUCCESS) return -1;
}
// Store event data
EvtClose(hEv[i]);
hEv[i] = NULL;
}
}
return 0;
}

为了简化示例,我再次删除了大多数错误处理。Evt*函数确实用于检索TaskScheduler数据(独立于语言(。

最新更新