イベントのブックマーク
ブックマークは、チャネルまたはログ ファイル内のイベントを識別します。 ブックマークを使用すると、イベントに対してクエリを実行したり、イベントをサブスクライブしたりして、そのブックマーク付きイベントからイベントの読み取りを開始できます。 通常、結果セット内の最後のイベントのブックマークを作成します (結果セット内のすべてのイベントを列挙したと仮定します)。
次の手順では、イベントからブックマークを作成する方法について説明します。
イベントからブックマークを作成するには
- 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;
}