为事件添加书签
书签标识通道或日志文件中的事件。 查询或订阅事件时,可以使用书签开始从该已添加书签的事件中读取事件。 通常,创建结果集中最后一个事件的书签 (假定已枚举结果集中的所有事件) 。
以下过程介绍如何从事件创建书签。
从事件创建书签
- 调用 EvtCreateBookmark 函数以创建书签。 为参数传递 NULL 。
- 调用 EvtUpdateBookmark 函数以使用 事件更新书签。 将句柄作为 参数传递给事件。
- 调用 EvtRender 函数以创建表示书签的 XML 字符串。 将 EvtRenderBookmark 作为呈现标志传递。
- 保留 XML 字符串以供以后使用 (例如,可以将 XML 字符串保存在文件或注册表) 中。
以下过程介绍如何使用在上一过程中保留的 XML 书签字符串创建书签。
使用 XML 书签字符串创建书签
- 获取表示之前保留的书签的 XML 字符串。
- 调用 EvtCreateBookmark 函数以创建书签。 传递参数的 XML 字符串。
以下过程介绍如何在查询中使用书签。
在查询中使用书签
- 调用 EvtQuery 函数以获取与查询匹配的事件。
- 调用 EvtSeek 函数以查找带书签的事件。 将句柄传递给书签和 EvtSeekRelativeToBookmark 标志。
- 在循环中调用 EvtNext 函数,根据在 EvtSeek) 中指定的偏移量,枚举书签事件 (之后开始的事件。
有关示例,请参阅 在查询中使用书签。
以下过程介绍如何在订阅中使用书签。
在订阅中使用书签
- 调用 EvtSubscribe 函数以订阅与查询匹配的事件。 将句柄传递给书签和 EvtSubscribeStartAfterBookmark 标志。
- 如果实现了 EVT_SUBSCRIBE_CALLBACK 函数,回调将接收在带书签的事件之后开始的事件。
- 如果未实现回调,请在循环中调用 EvtNext 函数以枚举在书签事件之后开始的事件。
有关示例,请参阅 在订阅中使用书签。
在查询中使用书签
以下示例演示如何在查询中使用书签。 该示例扩展了 查询事件中的示例。
// Enumerate all the events in the result set beginning with the bookmarked event.
DWORD PrintResults(EVT_HANDLE hResults)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hEvents[ARRAY_SIZE];
DWORD dwReturned = 0;
LPWSTR pwsBookmarkXml = NULL;
EVT_HANDLE hBookmark = NULL;
// Get the persisted bookmark XML string.
pwsBookmarkXml = GetBookmarkedString();
// If the bookmark string was persisted, create a bookmark and
// seek to the bookmarked event in the result set.
if (pwsBookmarkXml)
{
hBookmark = EvtCreateBookmark(pwsBookmarkXml);
if (NULL == hBookmark)
{
wprintf(L"EvtCreateBookmark failed with %lu\n", GetLastError());
goto cleanup;
}
if (!EvtSeek(hResults, 1, hBookmark, 0, EvtSeekRelativeToBookmark))
{
wprintf(L"EvtSeek failed with %lu\n", GetLastError());
goto cleanup;
}
}
// Enumerate the events in the result set after the bookmarked event.
while (true)
{
if (!EvtNext(hResults, ARRAY_SIZE, hEvents, INFINITE, 0, &dwReturned))
{
if (ERROR_NO_MORE_ITEMS != (status = GetLastError()))
{
wprintf(L"EvtNext failed with %lu\n", status);
}
goto cleanup;
}
for (DWORD i = 0; i < dwReturned; i++)
{
if (status = PrintEvent(hEvents[i]))
{
EvtClose(hEvents[i]);
hEvents[i] = NULL;
}
else
{
goto cleanup;
}
}
}
cleanup:
if (ERROR_NO_MORE_ITEMS == status)
{
// Get the last event in the result set, use it to create a
// bookmark, render the bookmark as an XML string, and persist the string.
if (ERROR_SUCCESS != (status = SaveBookmark(hResults)))
wprintf(L"\nFailed to save bookmark\n");
}
else
{
for (DWORD i = 0; i < dwReturned; i++)
{
if (NULL != hEvents[i])
EvtClose(hEvents[i]);
}
}
if (pwsBookmarkXml)
free(pwsBookmarkXml);
return status;
}
// Get the bookmark XML string from wherever you persisted it.
LPWSTR GetBookmarkedString(void)
{
LPWSTR pwsBookmarkXML = NULL;
// TODO: Add the code to get the bookmark XML string from storage.
return pwsBookmarkXML;
}
// Persist the bookmark XML string. This example assumes that we've read through
// the result set and are persisting the last event as the bookmark.
DWORD SaveBookmark(EVT_HANDLE hResults)
{
DWORD status = ERROR_SUCCESS;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD dwPropertyCount = 0;
DWORD dwReturned = 0;
LPWSTR pBookmarkXml = NULL;
EVT_HANDLE hBookmark = NULL;
EVT_HANDLE hEvent = NULL;
// Seek to the last event in the result set and get the event.
if (!EvtSeek(hResults, 0, NULL, 0, EvtSeekRelativeToLast))
{
wprintf(L"EvtSeek failed with %lu\n", status = GetLastError());
goto cleanup;
}
if (!EvtNext(hResults, 1, &hEvent, INFINITE, 0, &dwReturned))
{
wprintf(L"EvtNext failed with %lu\n", status = GetLastError());
goto cleanup;
}
// Create a bookmark and update it with the last event in the result set.
hBookmark = EvtCreateBookmark(NULL);
if (NULL == hBookmark)
{
wprintf(L"EvtCreateBookmark failed with %lu\n", GetLastError());
goto cleanup;
}
if (!EvtUpdateBookmark(hBookmark, hEvent))
{
wprintf(L"EvtUpdateBookmark failed with %lu\n", GetLastError());
goto cleanup;
}
// Render the bookmark as an XML string that you can then persist.
if (!EvtRender(NULL, hBookmark, EvtRenderBookmark, dwBufferSize, pBookmarkXml, &dwBufferUsed, &dwPropertyCount))
{
if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError()))
{
dwBufferSize = dwBufferUsed;
pBookmarkXml = (LPWSTR)malloc(dwBufferSize);
if (pBookmarkXml)
{
EvtRender(NULL, hBookmark, EvtRenderBookmark, dwBufferSize, pBookmarkXml, &dwBufferUsed, &dwPropertyCount);
}
else
{
wprintf(L"malloc failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtRender failed with %d\n", GetLastError());
goto cleanup;
}
}
// TODO: Add code to persist bookmark XML string.
cleanup:
if (pBookmarkXml)
free(pBookmarkXml);
if (hBookmark)
EvtClose(hBookmark);
if (hEvent)
EvtClose(hEvent);
return status;
}
在订阅中使用书签
以下示例演示如何在推送订阅中使用书签。
#include <windows.h>
#include <conio.h>
#include <stdio.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib")
DWORD WINAPI SubscriptionCallback(EVT_SUBSCRIBE_NOTIFY_ACTION action, PVOID pContext, EVT_HANDLE hEvent);
DWORD PrintEvent(EVT_HANDLE hEvent);
EVT_HANDLE GetBookmark();
DWORD SaveBookmark(EVT_HANDLE hBookmark);
void main(void)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hSubscription = NULL;
EVT_HANDLE hBookmark = NULL;
LPWSTR pwsPath = L"<channel name goes here>";
LPWSTR pwsQuery = L"<xpath query goes here>";
// Get the saved bookmark.
hBookmark = GetBookmark();
// Subscribe to existing and furture events beginning with the bookmarked event.
// If the bookmark has not been persisted, pass an empty bookmark and the subscription
// will begin with the second event that matches the query criteria.
hSubscription = EvtSubscribe(NULL, NULL, pwsPath, pwsQuery, hBookmark, (PVOID)hBookmark,
(EVT_SUBSCRIBE_CALLBACK)SubscriptionCallback, EvtSubscribeStartAfterBookmark);
if (NULL == hSubscription)
{
wprintf(L"EvtSubscribe failed with %lu.\n", GetLastError());
goto cleanup;
}
wprintf(L"Hit any key to quit\n\n");
while (!_kbhit())
Sleep(10);
status = SaveBookmark(hBookmark);
cleanup:
if (hSubscription)
EvtClose(hSubscription);
if (hBookmark)
EvtClose(hBookmark);
}
// The callback that receives the events that match the query criteria. Use the
// context parameter to pass the handle to the bookmark, so you can update the bookmark
// with each event that you receive.
DWORD WINAPI SubscriptionCallback(EVT_SUBSCRIBE_NOTIFY_ACTION action, PVOID pContext, EVT_HANDLE hEvent)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hBookmark = (EVT_HANDLE)pContext;
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: %lu\n", (DWORD)hEvent);
}
break;
case EvtSubscribeActionDeliver:
if (ERROR_SUCCESS != (status = PrintEvent(hEvent)))
{
goto cleanup;
}
if (!EvtUpdateBookmark(hBookmark, hEvent))
{
wprintf(L"EvtUpdateBookmark failed with %lu\n", status = GetLastError());
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.
}
EVT_HANDLE GetBookmark(void)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hBookmark = NULL;
LPWSTR pBookmarkXml = NULL;
// Set pBookmarkXml to the XML string that you persisted in SaveBookmark.
hBookmark = EvtCreateBookmark(pBookmarkXml);
if (NULL == hBookmark)
{
wprintf(L"EvtCreateBookmark failed with %lu\n", GetLastError());
goto cleanup;
}
cleanup:
if (pBookmarkXml)
free(pBookmarkXml);
return hBookmark;
}
DWORD SaveBookmark(EVT_HANDLE hBookmark)
{
DWORD status = ERROR_SUCCESS;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD dwPropertyCount = 0;
LPWSTR pBookmarkXml = NULL;
if (!EvtRender(NULL, hBookmark, EvtRenderBookmark, dwBufferSize, pBookmarkXml, &dwBufferUsed, &dwPropertyCount))
{
if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError()))
{
dwBufferSize = dwBufferUsed;
pBookmarkXml = (LPWSTR)malloc(dwBufferSize);
if (pBookmarkXml)
{
EvtRender(NULL, hBookmark, EvtRenderBookmark, dwBufferSize, pBookmarkXml, &dwBufferUsed, &dwPropertyCount);
}
else
{
wprintf(L"malloc failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtRender failed with %d\n", status);
goto cleanup;
}
}
// Persist bookmark to a file or the registry.
cleanup:
if (pBookmarkXml)
free(pBookmarkXml);
return status;
}
// Render the event as an XML string and print it.
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 failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtRender failed with %d\n", status);
goto cleanup;
}
}
wprintf(L"%s\n\n", pRenderedContent);
cleanup:
if (pRenderedContent)
free(pRenderedContent);
return status;
}