Esecuzione di query per gli eventi

È possibile eseguire una query per gli eventi da un canale o da un file di log. Il canale o il file di log può esistere nel computer locale o in un computer remoto. Per specificare gli eventi che si desidera ottenere dal canale o dal file di log, utilizzare una query XPath o una query XML di struttura. Per informazioni dettagliate sulla scrittura della query, vedere Utilizzo di eventi.

Per eseguire query sugli eventi, chiamare la funzione EvtQuery . È possibile specificare l'ordine in cui gli eventi vengono restituiti (dal meno recente al più recente (impostazione predefinita) o dal più recente al meno recente) e se tollerare espressioni XPath in formato non valido nella query (per informazioni dettagliate su come la funzione ignora le espressioni in formato non valido, vedere il flag EvtQueryTolerateQueryErrors ).

Nell'esempio seguente viene illustrato come eseguire query sugli eventi da un canale usando un'espressione 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);

}

Nell'esempio seguente viene illustrato come eseguire query sugli eventi da un canale usando una query XML strutturata. Gli eventi vengono restituiti in ordine dal più recente al meno recente.

#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);

}

Se si usa una query XML strutturata e si passa il flag EvtQueryTolerateQueryErrors a EvtQuery, la funzione ha esito positivo anche se una o più query nella query strutturata potrebbero effettivamente non riuscire. Per determinare quali query nella query strutturata hanno avuto esito positivo o negativo, chiamare la funzione EvtGetQueryInfo . Se non si passa il flag EvtQueryTolerateQueryErrors, la funzione EvtQuery avrà esito negativo con il primo errore trovato nella query. Se la query ha esito negativo con ERROR_EVT_INVALID_QUERY, chiamare la funzione EvtGetExtendedStatus per ottenere una stringa di messaggio che descrive l'errore XPath.

Nell'esempio seguente viene illustrato come determinare l'esito positivo o negativo di ogni query in una query strutturata quando si passa il flag EvtQueryTolerateQueryErrors a 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;
}

Lettura di eventi dal set di risultati

Per enumerare gli eventi nel set di risultati, chiamare la funzione EvtNext in un ciclo finché la funzione non restituisce FALSE e la funzione GetLastError restituisce ERROR_NO_MORE_ITEMS. Gli eventi nel set di risultati non sono statici; i nuovi eventi scritti nel canale verranno inclusi nel set di risultati fino a quando non viene impostato ERROR_NO_MORE_ITEMS. Per migliorare le prestazioni, recuperare gli eventi dal set di risultati in batch (tenendo conto delle dimensioni di ogni evento quando si determina il numero di eventi da recuperare).

Nell'esempio seguente viene illustrato come enumerare gli eventi in un set di risultati.

// 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;
}

Per informazioni dettagliate sul rendering degli eventi che si ottengono dal set di risultati, vedere Eventi di rendering.

Se si desidera eseguire una query per gli eventi da dove è stata interrotta, creare un segnalibro dell'ultimo evento letto e usarlo alla successiva esecuzione della query. Per informazioni dettagliate, vedere Bookmarking Events .For details, see Bookmarking Events.