2025-11-28 00:35:46 +09:00

487 lines
13 KiB
C++

//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
/*++
Module Name:
PushSubscription.cpp
Abstract:
This module implements a sample demonstrating how to use the push mode
Event Subscription.
Environment:
Windows vista or above.
--*/
#include <windows.h>
#include <winevt.h>
#include <wchar.h>
#define BUFFER_SIZE 512
//
// Memory Allocation Macros.
//
#define G_ALLOC(Size) HeapAlloc(GetProcessHeap(), 0, Size)
#define G_REALLOC(PreviousAddress, Size) HeapReAlloc(GetProcessHeap(), 0, PreviousAddress, Size)
#define G_FREE(Address) if (Address != NULL) HeapFree(GetProcessHeap(), 0, Address)
//
// User defined context to pass to the callback.
//
typedef struct _RENDER_CONTEXT {
DWORD PropertiesCount;
EVT_HANDLE RenderContext;
DWORD EventCount;
} RENDER_CONTEXT, *PRENDER_CONTEXT;
//
// Event properties to render.
//
typedef enum _SYSTEM_PROPERTY_ID
{
SystemProviderName = 0,
SystemEventID,
SystemTimeCreated
} SYSTEM_PROPERTY_ID;
VOID
DisplayHelp (
__in PCWSTR ExeName
)
/*++
Routine Description:
This function displays the usage of the sample tool.
Parameters:
ExeName - Supplies the sample tool executable name.
Return Value:
None.
--*/
{
wprintf(L"%s [ChannelName XPathQueryString]\n\n",
ExeName);
wprintf(L"Example:\n %s Application *[System[(Level=2)]]\n",
ExeName);
wprintf(L"\tAbove example shows to subscribe to all the error events in Application channel.\n");
}
DWORD
RenderMessage(
__in_opt EVT_HANDLE PublisherMetadata,
__in EVT_HANDLE Event,
__in DWORD Flags,
__out PWSTR& Buffer)
/*++
Routine Description:
This function generates message string associated with the flag
for given provider.
Parameters:
PublisherMetadata - Supplies provider handle obtained through EvtOpenPublisherMetadata.
Event - Supplies event handle obtained through subscription callback.
Flags - Supplies flag associated with provider event property.
Buffer - Receives Output buffer that receives the resulting message string.
Return Value:
Win32 Errorcode.
--*/
{
DWORD Error = ERROR_SUCCESS;
DWORD BufferSize = BUFFER_SIZE;
PWSTR PreviousBuffer;
Buffer = (PWSTR)G_ALLOC(BufferSize*sizeof(WCHAR));
if (Buffer == NULL) {
return ERROR_OUTOFMEMORY;
}
if (!EvtFormatMessage(PublisherMetadata,
Event,
0,
0,
NULL,
Flags,
BufferSize,
(LPWSTR)Buffer,
&BufferSize)) {
Error = GetLastError();
if (Error == ERROR_INSUFFICIENT_BUFFER) {
PreviousBuffer = Buffer;
Buffer = (PWSTR)G_REALLOC(PreviousBuffer,
BufferSize * sizeof(WCHAR));
if (Buffer == NULL) {
G_FREE(PreviousBuffer);
return ERROR_OUTOFMEMORY;
}
Error = ERROR_SUCCESS;
if (!EvtFormatMessage(PublisherMetadata,
Event,
0,
0,
NULL,
Flags,
BufferSize,
(LPWSTR)Buffer,
&BufferSize)) {
Error = GetLastError();
G_FREE(Buffer);
Buffer = NULL;
}
} else {
G_FREE(Buffer);
Buffer = NULL;
}
}
return Error;
}
DWORD WINAPI
SubscriptionCallBack(
__in EVT_SUBSCRIBE_NOTIFY_ACTION Action,
__in PVOID Context,
__in EVT_HANDLE Event
)
/*++
Routine Description:
This function provides Subscription callback used by the push
subscription model.
Parameters:
Action - Supplies value that specifies whether or not event was retrieved.
Context - Supplies User context.
Event - Supplies handle to the event for which the callback was invoked.
Return Value:
Win32 Errorcode.
--*/
{
PBYTE EventPropertyBuffer;
PBYTE PreviousEventPropertyBuffer;
DWORD BufferSize = BUFFER_SIZE;
DWORD BufferUsed = 0;
DWORD Error = ERROR_SUCCESS;
DWORD PropertyCount = 0;
PRENDER_CONTEXT Callbackcontext;
PEVT_VARIANT EventPropertyValues;
SYSTEMTIME EventTimeStampSystemTime;
FILETIME EventTimeStampFileTime;
ULONGLONG Temp;
PWSTR PropertyDescription;
EVT_HANDLE Provider = NULL;
//
// When the callback cannot retrieve event, the event
// handle returns win32 errorcode specifying why retrieving
// event failed.
//
if (Action == EvtSubscribeActionError) {
Error = reinterpret_cast<DWORD>(Event);
wprintf(L"Could not get Event!. Error = 0x%x", Error);
return Error;
}
Callbackcontext = (PRENDER_CONTEXT)Context;
EventPropertyBuffer = (PBYTE)G_ALLOC(BufferSize);
if (EventPropertyBuffer == NULL) {
return ERROR_OUTOFMEMORY;
}
//
// Get the Event properties.
//
if (!EvtRender(Callbackcontext->RenderContext,
Event,
EvtRenderEventValues,
BufferSize,
EventPropertyBuffer,
&BufferUsed,
&PropertyCount)) {
Error = GetLastError();
if (Error == ERROR_INSUFFICIENT_BUFFER) {
//
// Allocate the buffer size needed to for the properties.
//
BufferSize = BufferUsed;
PreviousEventPropertyBuffer = EventPropertyBuffer;
EventPropertyBuffer = (PBYTE)G_REALLOC(PreviousEventPropertyBuffer,
BufferSize);
if (EventPropertyBuffer == NULL) {
G_FREE(PreviousEventPropertyBuffer);
return ERROR_OUTOFMEMORY;
}
Error = ERROR_SUCCESS;
//
// Get the Event properties.
//
if (!EvtRender(Callbackcontext->RenderContext,
Event,
EvtRenderEventValues,
BufferSize,
EventPropertyBuffer,
&BufferUsed,
&PropertyCount)) {
Error = GetLastError();
wprintf(L"Could not Render Event Properties!. Error = 0x%x",
Error);
G_FREE(EventPropertyBuffer);
return Error;
}
} else {
G_FREE(EventPropertyBuffer);
}
}
EventPropertyValues = (PEVT_VARIANT)EventPropertyBuffer;
if (PropertyCount < Callbackcontext->PropertiesCount) {
wprintf(L"Could not Render Events Properties!. Error = 0x%x",
ERROR_INVALID_DATA);
G_FREE(EventPropertyBuffer);
return ERROR_INVALID_DATA;
}
wprintf(L"Event[%d]:\n",
Callbackcontext->EventCount++);
wprintf(L" Provider: %s\n",
EventPropertyValues[SystemProviderName].StringVal);
wprintf(L" Event ID: %u\n",
EventPropertyValues[SystemEventID].UInt16Val);
Temp = EventPropertyValues[SystemTimeCreated].FileTimeVal;
EventTimeStampFileTime.dwHighDateTime = (DWORD)((Temp >> 32) & 0xFFFFFFFF);
EventTimeStampFileTime.dwLowDateTime = (DWORD)(Temp & 0xFFFFFFFF);
if (FileTimeToSystemTime(&EventTimeStampFileTime,&EventTimeStampSystemTime)) {
wprintf(L" Date: %02d/%02d/%d %02d:%02d\n",
EventTimeStampSystemTime.wMonth,
EventTimeStampSystemTime.wDay,
EventTimeStampSystemTime.wYear,
EventTimeStampSystemTime.wHour,
EventTimeStampSystemTime.wMinute);
} else {
wprintf(L" Date: N/A\n");
}
//
// If we cannot open provider handle, we use default provider by passing NULL
// to RenderMessage. Also, it is recommended to use some sort of cache for
// provider handle, for the sake of simplicity this example does not add cache.
//
Provider = EvtOpenPublisherMetadata(NULL,
EventPropertyValues[SystemProviderName].StringVal,
NULL,
0,
0);
G_FREE(EventPropertyBuffer);
Error = RenderMessage(Provider,
Event,
EvtFormatMessageLevel,
PropertyDescription);
if (Error == ERROR_SUCCESS) {
wprintf(L" Level: %s\n",
PropertyDescription);
G_FREE(PropertyDescription);
} else {
wprintf(L" Level: N/A\n");
}
Error = RenderMessage(Provider,
Event,
EvtFormatMessageTask,
PropertyDescription);
if (Error == ERROR_SUCCESS) {
wprintf(L" Task: %s\n",
PropertyDescription);
G_FREE(PropertyDescription);
} else {
wprintf(L" Task: N/A\n");
}
Error = RenderMessage(Provider,
Event,
EvtFormatMessageEvent,
PropertyDescription);
if (Error == ERROR_SUCCESS) {
wprintf(L" Event Description: %s\n\n",
PropertyDescription);
G_FREE(PropertyDescription);
} else {
wprintf(L" Event Description: N/A\n\n");
}
if (Provider != NULL) {
EvtClose(Provider);
}
return Error;
}
DWORD __cdecl
wmain(
__in int argc,
__in_ecount(argc) PWSTR *argv
)
/*++
Routine Description:
The function is a main routine of the push
subscription example.
Parameters:
argc - Supplies total argument in commandline.
argv - Supplies argument array for the commandline.
Return Value:
Win32 Errorcode.
--*/
{
EVT_HANDLE SubscrptionHandle;
RENDER_CONTEXT UserContext;
WCHAR* Channel = L"Application";
WCHAR* Query = L"*";
WCHAR CommandlineInput;
DWORD Error = ERROR_SUCCESS;
PCWSTR RenderContextProperties[] = {
L"Event/System/Provider/@Name",
L"Event/System/EventID",
L"Event/System/TimeCreated/@SystemTime"
};
//
// If two arguments are passed to the executable, we assume
// the first one is channel and second one is query else we
// print help.
//
if (argc == 3) {
Channel = argv[1];
Query = argv[2];
} else if (argc != 1) {
DisplayHelp(argv[0]);
return ERROR_INVALID_DATA;
}
//
// Create User context.
//
UserContext.PropertiesCount = sizeof(RenderContextProperties)/sizeof(PWSTR);
UserContext.EventCount = 0;
UserContext.RenderContext = EvtCreateRenderContext(UserContext.PropertiesCount,
RenderContextProperties,
EvtRenderContextValues);
if (UserContext.RenderContext == NULL) {
Error = GetLastError();
wprintf(L"Could not create RenderContext. Error = 0x%x",
Error);
return Error;
}
//
// Register the subscription.
//
SubscrptionHandle = EvtSubscribe(NULL,
NULL,
Channel,
Query,
NULL,
&UserContext,
(EVT_SUBSCRIBE_CALLBACK) SubscriptionCallBack,
EvtSubscribeToFutureEvents);
if (SubscrptionHandle == NULL) {
Error = GetLastError();
EvtClose(UserContext.RenderContext);
wprintf(L"Could not Subscribe to Events!. Error = 0x%x",
Error);
return Error;
}
wprintf(L"NOTE: Hit 'Q' or 'q' to stop the event subscription\n");
wprintf(L"Subscribing to %s channel with %s query\n\n",
Channel,
Query);
do {
CommandlineInput = _getwch();
CommandlineInput = towupper(CommandlineInput);
} while(CommandlineInput != 'Q');
//
// Close the subscriber handle first followed by RenderContext.
// This gurantees that rendercontext does not go away while subscription
// callback is using it.
//
EvtClose(SubscrptionHandle);
EvtClose(UserContext.RenderContext);
return Error;
}