Mengkueri untuk Peristiwa
Anda bisa mengkueri peristiwa dari saluran atau file log. Saluran atau file log bisa ada pada komputer lokal atau komputer jarak jauh. Untuk menentukan peristiwa yang ingin Anda dapatkan dari saluran atau file log, Anda menggunakan kueri JalurX atau kueri XML struktur. Untuk detail tentang menulis kueri, lihat Menggunakan Peristiwa.
Untuk mengkueri peristiwa, panggil fungsi EvtQuery . Anda dapat menentukan urutan di mana peristiwa dikembalikan (terlama ke terbaru (default) atau terbaru ke terlama) dan apakah akan mentolerir ekspresi XPath yang salah format dalam kueri (untuk detail tentang bagaimana fungsi mengabaikan ekspresi cacat, lihat bendera EvtQueryTolerateQueryErrors ).
Contoh berikut menunjukkan cara mengkueri peristiwa dari saluran menggunakan ekspresi JalurX.
#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);
}
Contoh berikut menunjukkan cara mengkueri peristiwa dari saluran menggunakan kueri XML terstruktur. Peristiwa dikembalikan secara berurutan dari yang terbaru ke terlama.
#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);
}
Jika Anda menggunakan kueri XML terstruktur dan meneruskan bendera EvtQueryTolerateQueryErrors ke EvtQuery, fungsi berhasil meskipun satu atau beberapa kueri dalam kueri terstruktur mungkin benar-benar gagal. Untuk menentukan kueri mana dalam kueri terstruktur yang berhasil atau gagal, panggil fungsi EvtGetQueryInfo . Jika Anda tidak meneruskan bendera EvtQueryTolerateQueryErrors, fungsi EvtQuery akan gagal dengan kesalahan pertama yang ditemukannya dalam kueri. Jika kueri gagal dengan ERROR_EVT_INVALID_QUERY, panggil fungsi EvtGetExtendedStatus untuk mendapatkan string pesan yang menjelaskan kesalahan JalurX.
Contoh berikut menunjukkan cara menentukan keberhasilan atau kegagalan setiap kueri dalam kueri terstruktur saat meneruskan bendera EvtQueryTolerateQueryErrors ke 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;
}
Membaca peristiwa dari kumpulan hasil
Untuk menghitung peristiwa dalam kumpulan hasil, panggil fungsi EvtNext dalam perulangan hingga fungsi mengembalikan FALSE dan fungsi GetLastError mengembalikan ERROR_NO_MORE_ITEMS. Peristiwa dalam tataan hasil tidak statis; peristiwa baru yang ditulis ke saluran akan disertakan dalam tataan hasil hingga ERROR_NO_MORE_ITEMS diatur. Untuk meningkatkan performa, ambil peristiwa dari hasil yang ditetapkan dalam batch (dengan mempertimbangkan ukuran setiap peristiwa saat menentukan jumlah peristiwa yang akan diambil).
Contoh berikut menunjukkan cara menghitung peristiwa dalam tataan hasil.
// 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;
}
Untuk detail tentang penyajian peristiwa yang Anda dapatkan dari kumpulan hasil, lihat Merender Peristiwa.
Jika Anda ingin mengkueri peristiwa dari tempat Anda meninggalkannya, buat bookmark peristiwa terakhir yang Anda baca dan gunakan saat berikutnya Anda menjalankan kueri Anda. Untuk detailnya, lihat Peristiwa Bookmarking.