查詢事件
您可以從通道或記錄檔查詢事件。 通道或記錄檔可以存在於本機電腦或遠端電腦上。 若要指定您想要從通道或記錄檔取得的事件,請使用 XPath 查詢或結構 XML 查詢。 如需撰寫查詢的詳細資訊,請參閱 取用事件。
若要查詢事件,請呼叫 EvtQuery 函 式。 您可以指定傳回事件的順序, (最舊到最新的 (預設) 或最舊的) ,以及是否容許查詢 (中格式錯誤的 XPath 運算式,以取得函式如何忽略格式錯誤的運算式的詳細資訊,請參閱 evtQueryTolerateQueryErrors 旗標) 。
下列範例示範如何使用 XPath 運算式從通道查詢事件。
#include <windows.h>
#include <sddl.h>
#include <stdio.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib")
#define ARRAY_SIZE 10
#define TIMEOUT 1000 // 1 second; Set and use in place of INFINITE in EvtNext call
DWORD PrintResults(EVT_HANDLE hResults);
DWORD PrintEvent(EVT_HANDLE hEvent); // Shown in the Rendering Events topic
void main(void)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hResults = NULL;
LPWSTR pwsPath = L"<Name of the channel goes here>";
LPWSTR pwsQuery = L"Event/System[EventID=4]";
hResults = EvtQuery(NULL, pwsPath, pwsQuery, EvtQueryChannelPath | EvtQueryReverseDirection);
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);
goto cleanup;
}
PrintResults(hResults);
cleanup:
if (hResults)
EvtClose(hResults);
}
下列範例示範如何使用結構化 XML 查詢,從通道查詢事件。 事件會依最新到最舊的順序傳回。
#include <windows.h>
#include <sddl.h>
#include <stdio.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib")
#define ARRAY_SIZE 10
#define TIMEOUT 1000 // 1 second; Set and use in place of INFINITE in EvtNext call
// The structured XML query.
#define QUERY \
L"<QueryList>" \
L" <Query Path='Name of the channel goes here'>" \
L" <Select>Event/System[EventID=4]</Select>" \
L" </Query>" \
L"</QueryList>"
DWORD PrintQueryStatuses(EVT_HANDLE hResults);
DWORD GetQueryStatusProperty(EVT_QUERY_PROPERTY_ID Id, EVT_HANDLE hResults, PEVT_VARIANT& pProperty);
DWORD PrintResults(EVT_HANDLE hResults);
DWORD PrintEvent(EVT_HANDLE hEvent); // Shown in the Rendering Events topic
void main(void)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hResults = NULL;
hResults = EvtQuery(NULL, NULL, QUERY, EvtQueryChannelPath | EvtQueryTolerateQueryErrors);
if (NULL == hResults)
{
// Handle error.
goto cleanup;
}
// Print the status of each query. If all the queries succeeded,
// print the events in the result set. The status can be
// ERROR_EVT_CHANNEL_NOT_FOUND or ERROR_EVT_INVALID_QUERY among others.
if (ERROR_SUCCESS == PrintQueryStatuses(hResults))
PrintResults(hResults);
cleanup:
if (hResults)
EvtClose(hResults);
}
如果您使用結構化 XML 查詢,並將 EvtQueryTolerateQueryErrors 旗標傳遞至 EvtQuery,即使結構化查詢中的一或多個查詢實際上可能失敗,函式仍會成功。 若要判斷結構化查詢中的哪些查詢成功或失敗,請呼叫 EvtGetQueryInfo 函 式。 如果您未傳遞 EvtQueryTolerateQueryErrors 旗標, EvtQuery 函式將會失敗,並在查詢中找到的第一個錯誤。 如果查詢因ERROR_EVT_INVALID_QUERY而失敗,請呼叫 EvtGetExtendedStatus 函式來取得描述 XPath 錯誤的訊息字串。
下列範例示範如何將 EvtQueryTolerateQueryErrors 旗標傳遞至 EvtQuery時,判斷結構化查詢中每個查詢的成功或失敗。
// Get the list of paths in the query and the status for each path. Return
// the sum of the statuses, so the caller can decide whether to enumerate
// the results.
DWORD PrintQueryStatuses(EVT_HANDLE hResults)
{
DWORD status = ERROR_SUCCESS;
PEVT_VARIANT pPaths = NULL;
PEVT_VARIANT pStatuses = NULL;
wprintf(L"List of channels/logs that were queried and their status\n\n");
if (status = GetQueryStatusProperty(EvtQueryNames, hResults, pPaths))
goto cleanup;
if (status = GetQueryStatusProperty(EvtQueryStatuses, hResults, pStatuses))
goto cleanup;
for (DWORD i = 0; i < pPaths->Count; i++)
{
wprintf(L"%s (%lu)\n", pPaths->StringArr[i], pStatuses->UInt32Arr[i]);
status += pStatuses->UInt32Arr[i];
}
cleanup:
if (pPaths)
free(pPaths);
if (pStatuses)
free(pStatuses);
return status;
}
// Get the list of paths specified in the query or the list of status values
// for each path.
DWORD GetQueryStatusProperty(EVT_QUERY_PROPERTY_ID Id, EVT_HANDLE hResults, PEVT_VARIANT& pProperty)
{
DWORD status = ERROR_SUCCESS;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
if (!EvtGetQueryInfo(hResults, Id, dwBufferSize, pProperty, &dwBufferUsed))
{
status = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status)
{
dwBufferSize = dwBufferUsed;
pProperty = (PEVT_VARIANT)malloc(dwBufferSize);
if (pProperty)
{
EvtGetQueryInfo(hResults, Id, dwBufferSize, pProperty, &dwBufferUsed);
}
else
{
wprintf(L"realloc failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtGetQueryInfo failed with %d\n", GetLastError());
goto cleanup;
}
}
cleanup:
return status;
}
從結果集讀取事件
若要列舉結果集中的事件,請在迴圈中呼叫 EvtNext 函式,直到函式傳回 FALSE 且 GetLastError 函 式傳回ERROR_NO_MORE_ITEMS為止。 結果集中的事件不是靜態的;寫入通道的新事件將會包含在結果集中,直到設定ERROR_NO_MORE_ITEMS為止。 若要改善效能,請在判斷要擷取) 的事件數目時,以批次方式從結果集中擷取事件, (考慮每個事件的大小。
下列範例示範如何列舉結果集中的事件。
// Enumerate all the events in the result set.
DWORD PrintResults(EVT_HANDLE hResults)
{
DWORD status = ERROR_SUCCESS;
EVT_HANDLE hEvents[ARRAY_SIZE];
DWORD dwReturned = 0;
while (true)
{
// Get a block of events from the result set.
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 each event, call the PrintEvent function which renders the
// event for display. PrintEvent is shown in RenderingEvents.
for (DWORD i = 0; i < dwReturned; i++)
{
if (ERROR_SUCCESS == (status = PrintEvent(hEvents[i])))
{
EvtClose(hEvents[i]);
hEvents[i] = NULL;
}
else
{
goto cleanup;
}
}
}
cleanup:
for (DWORD i = 0; i < dwReturned; i++)
{
if (NULL != hEvents[i])
EvtClose(hEvents[i]);
}
return status;
}
如需從結果集轉譯事件的詳細資料,請參閱 轉譯事件。
如果您想要從離開的位置查詢事件,請建立您讀取的最後一個事件的書簽,並在下次執行查詢時使用它。 如需詳細資訊,請參閱 將事件加入書簽。