Evenementen opvragen
U kunt query's uitvoeren op gebeurtenissen vanuit een kanaal of een logboekbestand. Het kanaal of logboekbestand kan bestaan op de lokale computer of een externe computer. Als u de gebeurtenissen wilt opgeven die u wilt ophalen uit het kanaal of logboekbestand, gebruikt u een XPath-query of een structuur-XML-query. Zie Gebeurtenissen gebruikenvoor meer informatie over het schrijven van de query.
Als u query's wilt uitvoeren op gebeurtenissen, roept u de functie EvtQuery aan. U kunt de volgorde opgeven waarin de gebeurtenissen worden geretourneerd (oud naar nieuw (de standaardinstelling) of van nieuw naar oud) en of u ongeldige XPath-expressies in de query wilt tolereren (zie de EvtQueryTolerateQueryErrors vlag voor meer informatie over hoe de functie de verkeerd gevormde expressies negeert.
In het volgende voorbeeld ziet u hoe u query's kunt uitvoeren op gebeurtenissen uit een kanaal met behulp van een XPath-expressie.
#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);
}
In het volgende voorbeeld ziet u hoe u query's uitvoert op gebeurtenissen uit een kanaal met behulp van een gestructureerde XML-query. De gebeurtenissen worden geretourneerd in volgorde van nieuw naar oud.
#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);
}
Als u een gestructureerde XML-query gebruikt en de vlag EvtQueryTolerateQueryErrors doorgeeft aan EvtQuery-, slaagt de functie, zelfs als een of meer van de query's in de gestructureerde query daadwerkelijk zijn mislukt. Als u wilt bepalen welke query's in de gestructureerde query zijn geslaagd of mislukt, roept u de EvtGetQueryInfo aan functie. Als u de vlag EvtQueryTolerateQueryErrors niet doorgeeft, mislukt de functie EvtQuery met de eerste fout die in de query wordt gevonden. Als de query mislukt met ERROR_EVT_INVALID_QUERY, roept u de functie EvtGetExtendedStatus aan om een berichttekenreeks op te halen die de XPath-fout beschrijft.
In het volgende voorbeeld ziet u hoe u het slagen of mislukken van elke query in een gestructureerde query kunt bepalen bij het doorgeven van de vlag EvtQueryTolerateQueryErrors aan 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;
}
Gebeurtenissen uit de resultatenset lezen
Als u de gebeurtenissen in de resultatenset wilt inventariseren, roept u de functie EvtNext in een lus aan totdat de functie ONWAAR retourneert en de functie GetLastError ERROR_NO_MORE_ITEMS retourneert. De gebeurtenissen in de resultatenset zijn niet statisch; nieuwe gebeurtenissen die naar het kanaal worden geschreven, worden opgenomen in de resultatenset totdat ERROR_NO_MORE_ITEMS is ingesteld. Om de prestaties te verbeteren, haalt u gebeurtenissen op uit de resultatenset in batches (rekening houdend met de grootte van elke gebeurtenis bij het bepalen van het aantal gebeurtenissen dat moet worden opgehaald).
In het volgende voorbeeld ziet u hoe u de gebeurtenissen in een resultatenset opsommen.
// 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;
}
Zie Rendering Eventsvoor meer informatie over het weergeven van de gebeurtenissen die u krijgt uit de resultatenset.
Als u een query wilt uitvoeren op gebeurtenissen van waaruit u was gebleven, maakt u een bladwijzer van de laatste gebeurtenis die u hebt gelezen en gebruikt u deze wanneer u de query de volgende keer uitvoert. Voor meer informatie, zie Bladwijzeren van gebeurtenissen.