获取提供程序元数据
提供程序使用检测清单来标识自身、定义其写入的事件以及其他组件(如通道、任务和关键字)。 若要在运行时访问此信息,请调用 EvtOpenPublisherMetadata 函数以获取发布者元数据的句柄。
元数据在发布者元数据和事件元数据之间划分。 发布者元数据包含标识发布者的元数据及其定义的任何元数据,例如通道、级别、任务、操作码和关键字。 有关可以检索的提供程序元数据的列表,请参阅 EVT_PUBLISHER_METADATA_PROPERTY_ID 枚举。 若要获取元数据,请调用 EvtGetPublisherMetadataProperty 函数。 此函数返回用于标识通道、级别、任务、操作码和关键字组件的提供程序和句柄的属性的属性值。 若要访问这些组件的元数据,请调用 EvtGetObjectArrayProperty 函数。
若要获取事件元数据,请调用 EvtOpenEventMetadataEnum 函数以获取提供程序定义的事件列表。 然后在循环中调用 EvtNextEventMetadata 函数以枚举事件。 有关可以为事件获取的元数据列表,请参阅 EVT_EVENT_METADATA_PROPERTY_ID 枚举。 若要获取元数据,请调用 EvtGetEventMetadataProperty 函数。 这些属性返回事件定义的每个元素的整数值。 对于事件 ID 和版本,显示整数值是可以的,但对于其他元素(如通道和级别),显示整数值对用户可能没有任何意义。 这些元素的整数值是 value 属性的值。 可以使用整数值映射到提供程序的元数据中,并获取元素的消息字符串或名称值,并将其改为显示给用户。
有关演示如何枚举计算机上已注册的提供程序的示例,请参阅 枚举已注册的提供程序。
有关演示如何获取已注册提供程序的元数据的示例,请参阅 获取提供程序的元数据。
枚举已注册的提供程序
以下示例演示如何枚举计算机上注册的提供程序。
#include <windows.h>
#include <stdio.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib")
void main(void)
{
EVT_HANDLE hProviders = NULL;
LPWSTR pwcsProviderName = NULL;
LPWSTR pTemp = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD status = ERROR_SUCCESS;
// Get a handle to the list of providers.
hProviders = EvtOpenPublisherEnum(NULL, 0);
if (NULL == hProviders)
{
wprintf(L"EvtOpenPublisherEnum failed with %lu\n", GetLastError());
goto cleanup;
}
wprintf(L"List of registered providers:\n\n");
// Enumerate the providers in the list.
while (true)
{
// Get a provider from the list. If the buffer is not big enough
// to contain the provider's name, reallocate the buffer to the required size.
if (!EvtNextPublisherId(hProviders, dwBufferSize, pwcsProviderName, &dwBufferUsed))
{
status = GetLastError();
if (ERROR_NO_MORE_ITEMS == status)
{
break;
}
else if (ERROR_INSUFFICIENT_BUFFER == status)
{
dwBufferSize = dwBufferUsed;
pTemp = (LPWSTR)realloc(pwcsProviderName, dwBufferSize * sizeof(WCHAR));
if (pTemp)
{
pwcsProviderName = pTemp;
pTemp = NULL;
EvtNextPublisherId(hProviders, dwBufferSize, pwcsProviderName, &dwBufferUsed);
}
else
{
wprintf(L"realloc failed\n");
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtNextPublisherId failed with %d\n", status);
goto cleanup;
}
}
wprintf(L"%s\n", pwcsProviderName);
RtlZeroMemory(pwcsProviderName, dwBufferUsed * sizeof(WCHAR));
}
cleanup:
if (pwcsProviderName)
free(pwcsProviderName);
if (hProviders)
EvtClose(hProviders);
}
获取提供程序的元数据
以下示例演示如何获取提供程序及其定义的事件的元数据。
#include <windows.h>
#include <stdio.h>
#include <winevt.h>
#pragma comment(lib, "wevtapi.lib")
#pragma comment(lib, "ole32.lib")
// Contains the value and message string for a type, such as
// an opcode or task that the provider defines or uses. If the
// type does not specify a message string, the message member
// contains the value of the type's name attribute.
typedef struct _msgstring
{
union
{
DWORD dwValue; // Value attribute for opcode, task, and level
UINT64 ullMask; // Mask attribute for keyword
};
LPWSTR pwcsMessage; // Message string or name attribute
} MSG_STRING, *PMSG_STRING;
// Header for the block of value/message string pairs. The dwSize member
// is the size, in bytes, of the block of MSG_STRING structures to which
// the pMessage member points.
typedef struct _messages
{
DWORD dwSize;
PMSG_STRING pMessage;
} MESSAGES, *PMESSAGES;
DWORD PrintProviderEvents(EVT_HANDLE hMetadata);
DWORD PrintEventProperties(EVT_HANDLE hEvent);
DWORD PrintEventProperty(EVT_HANDLE hMetadata, int Id, PEVT_VARIANT pProperty);
LPWSTR GetPropertyName(EVT_HANDLE hMetadata, PMESSAGES pMessages, DWORD dwValue);
LPWSTR GetOpcodeName(EVT_HANDLE hMetadata, PMESSAGES pMessages, DWORD dwOpcodeValue, DWORD dwTaskValue);
LPWSTR GetKeywordName(EVT_HANDLE hMetadata, PMESSAGES pMessages, UINT64 ullKeyword);
DWORD PrintProviderProperties(EVT_HANDLE hMetadata);
DWORD PrintProviderProperty(EVT_HANDLE hMetadata, int Id, PEVT_VARIANT pProperty);
LPWSTR GetMessageString(EVT_HANDLE hMetadata, DWORD dwMessageId);
DWORD DumpChannelProperties(EVT_HANDLE hChannels, DWORD dwIndex, PMESSAGES pMessages);
DWORD DumpLevelProperties(EVT_HANDLE hLevels, DWORD dwIndex, PMESSAGES pMessages);
DWORD DumpTaskProperties(EVT_HANDLE hTasks, DWORD dwIndex, PMESSAGES pMessages);
DWORD DumpOpcodeProperties(EVT_HANDLE hOpcodes, DWORD dwIndex, PMESSAGES pMessages);
DWORD DumpKeywordProperties(EVT_HANDLE hKeywords, DWORD dwIndex, PMESSAGES pMessages);
void FreeMessages(PMESSAGES pMessages);
PEVT_VARIANT GetProperty(EVT_HANDLE handle, DWORD dwIndex, EVT_PUBLISHER_METADATA_PROPERTY_ID PropertyId);
// Global variables.
EVT_HANDLE g_hMetadata = NULL;
MESSAGES g_ChannelMessages = {0, NULL};
MESSAGES g_LevelMessages = {0, NULL};
MESSAGES g_TaskMessages = {0, NULL};
MESSAGES g_OpcodeMessages = {0, NULL};
MESSAGES g_KeywordMessages = {0, NULL};
void main(void)
{
LPWSTR pwszPublisherName = L"<name of the publisher goes here>";
DWORD status = ERROR_SUCCESS;
// Get a handle to the provider's metadata. You can specify the provider's name
// if the provider is registered on the computer or the full path to an archived
// log file (archived log files contain the provider's metadata). Specify the locale
// identifier if you want the localized strings returned in a locale other than
// the locale of the current thread.
g_hMetadata = EvtOpenPublisherMetadata(NULL,
pwszPublisherName,
NULL,
0, //MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH), 0),
0);
if (NULL == g_hMetadata)
{
wprintf(L"EvtOpenPublisherMetadata failed with %d\n", GetLastError());
goto cleanup;
}
wprintf(L"Provider Metadata for %s\n\n", pwszPublisherName);
status = PrintProviderProperties(g_hMetadata);
wprintf(L"\nEvent Metadata for %s\n\n", pwszPublisherName);
status = PrintProviderEvents(g_hMetadata);
cleanup:
if (g_hMetadata)
EvtClose(g_hMetadata);
if (g_ChannelMessages.pMessage)
FreeMessages(&g_ChannelMessages);
if (g_LevelMessages.pMessage)
FreeMessages(&g_LevelMessages);
if (g_TaskMessages.pMessage)
FreeMessages(&g_TaskMessages);
if (g_OpcodeMessages.pMessage)
FreeMessages(&g_OpcodeMessages);
if (g_KeywordMessages.pMessage)
FreeMessages(&g_KeywordMessages);
}
// Free the memory for each message string in the messages block
// and then free the messages block.
void FreeMessages(PMESSAGES pMessages)
{
DWORD dwCount = pMessages->dwSize / sizeof(MSG_STRING);
for (DWORD i = 0; i < dwCount; i++)
{
free(((pMessages->pMessage)+i)->pwcsMessage);
((pMessages->pMessage)+i)->pwcsMessage = NULL;
}
free(pMessages->pMessage);
}
// Get an enumerator to the provider's events and enumerate them.
// Call this function after first calling the PrintProviderProperties
// function to get the message strings that this section uses.
DWORD PrintProviderEvents(EVT_HANDLE hMetadata)
{
EVT_HANDLE hEvents = NULL;
EVT_HANDLE hEvent = NULL;
DWORD status = ERROR_SUCCESS;
// Get a handle to the provider's events.
hEvents = EvtOpenEventMetadataEnum(hMetadata, 0);
if (NULL == hEvents)
{
wprintf(L"EvtOpenEventMetadataEnum failed with %lu\n", GetLastError());
goto cleanup;
}
// Enumerate the events and print each event's metadata.
while (true)
{
hEvent = EvtNextEventMetadata(hEvents, 0);
if (NULL == hEvent)
{
if (ERROR_NO_MORE_ITEMS != (status = GetLastError()))
{
wprintf(L"EvtNextEventMetadata failed with %lu\n", status);
}
break;
}
if (status = PrintEventProperties(hEvent))
break;
EvtClose(hEvent);
hEvent = NULL;
}
cleanup:
if (hEvents)
EvtClose(hEvents);
if (hEvent)
EvtClose(hEvent);
return status;
}
// Print the metadata for the event.
DWORD PrintEventProperties(EVT_HANDLE hEvent)
{
PEVT_VARIANT pProperty = NULL; // Contains a metadata value
PEVT_VARIANT pTemp = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD status = ERROR_SUCCESS;
// Use the EVT_EVENT_METADATA_PROPERTY_ID's enumeration values to loop
// through all the metadata for the event.
for (int Id = 0; Id < EvtEventMetadataPropertyIdEND; Id++)
{
// Get the specified metadata property. If the pProperty buffer is not big enough, reallocate the buffer.
if (!EvtGetEventMetadataProperty(hEvent, (EVT_EVENT_METADATA_PROPERTY_ID)Id, 0, dwBufferSize, pProperty, &dwBufferUsed))
{
status = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status)
{
dwBufferSize = dwBufferUsed;
pTemp = (PEVT_VARIANT)realloc(pProperty, dwBufferSize);
if (pTemp)
{
pProperty = pTemp;
pTemp = NULL;
EvtGetEventMetadataProperty(hEvent, (EVT_EVENT_METADATA_PROPERTY_ID)Id, 0, dwBufferSize, pProperty, &dwBufferUsed);
}
else
{
wprintf(L"realloc failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtGetEventMetadataProperty failed with %d\n", GetLastError());
goto cleanup;
}
}
if (status = PrintEventProperty(g_hMetadata, Id, pProperty))
break;
RtlZeroMemory(pProperty, dwBufferUsed);
}
cleanup:
if (pProperty)
free(pProperty);
return status;
}
// Print the event property.
DWORD PrintEventProperty(EVT_HANDLE hMetadata, int Id, PEVT_VARIANT pProperty)
{
DWORD status = ERROR_SUCCESS;
static DWORD dwOpcode = 0;
LPWSTR pName = NULL; // The event's name property
LPWSTR pMessage = NULL; // The event's message string
switch(Id)
{
case EventMetadataEventID:
wprintf(L"ID: %lu\n", pProperty->UInt32Val);
break;
case EventMetadataEventVersion:
wprintf(L"Version: %lu\n", pProperty->UInt32Val);
break;
// The channel property contains the value of the channel's value attribute.
// Instead of printing the value attribute, use it to find the channel's
// message string or name and print it.
case EventMetadataEventChannel:
if (pProperty->UInt32Val > 0)
{
pName = GetPropertyName(hMetadata, &g_ChannelMessages, pProperty->UInt32Val);
wprintf(L"Channel: %s\n", pName);
}
else
{
wprintf(L"Channel: \n");
}
break;
// The level property contains the value of the level's value attribute.
// Instead of printing the value attribute, use it to find the level's
// message string or name and print it.
case EventMetadataEventLevel:
if (pProperty->UInt32Val > 0)
{
pName = GetPropertyName(hMetadata, &g_LevelMessages, pProperty->UInt32Val);
wprintf(L"Level: %s\n", pName);
}
else
{
wprintf(L"Level: \n");
}
break;
// The opcode property contains the value of the opcode's value attribute.
// Instead of printing the value attribute, use it to find the opcode's
// message string or name and print it.
// The opcode value contains the opcode in the high word. If the opcode is
// task-specific, the opcode value will contain the task value in the low word.
// Save the opcode in a static variable and print it when we get the task
// value, so we can decide if the opcode is task-specific.
case EventMetadataEventOpcode:
dwOpcode = pProperty->UInt32Val;
break;
// The task property contains the value of the task's value attribute.
// Instead of printing the value attribute, use it to find the task's
// message string or name and print it.
case EventMetadataEventTask:
if (pProperty->UInt32Val > 0)
{
pName = GetPropertyName(hMetadata, &g_TaskMessages, pProperty->UInt32Val);
wprintf(L"Task: %s\n", pName);
}
else
{
wprintf(L"Task: \n");
}
// Now that we know the task, get the opcode string and print it.
if (dwOpcode > 0)
{
pName = GetOpcodeName(hMetadata, &g_OpcodeMessages, dwOpcode, pProperty->UInt32Val);
wprintf(L"Opcode: %s\n", pName);
}
else
{
wprintf(L"Opcode: \n");
}
break;
// The keyword property contains a bit mask of all the keywords.
// Instead of printing the value attribute, use it to find the
// message string or name associated with each keyword and print them (space delimited).
case EventMetadataEventKeyword:
// The upper 8 bits can contain reserved bit values, so do not include them
// when checking to see if any keywords are set.
if ((pProperty->UInt32Val & 0x00FFFFFFFFFFFFFF) > 0)
{
pName = GetKeywordName(hMetadata, &g_KeywordMessages, pProperty->UInt32Val);
wprintf(L"Keyword: %s\n", pName);
if (pName)
free(pName);
}
else
{
wprintf(L"Keyword: \n");
}
break;
// If the message string is not specified, the value is -1.
case EventMetadataEventMessageID:
if (-1 == pProperty->UInt32Val)
{
wprintf(L"Message string: \n");
}
else
{
pMessage = GetMessageString(hMetadata, pProperty->UInt32Val);
wprintf(L"Message string: %s\n", (pMessage) ? pMessage : L"");
if (pMessage)
{
free(pMessage);
}
}
break;
// When you define the event, the template attribute contains the template
// identifier; however, the template metadata contains an XML string of the
// template (includes the data items, not the UserData section).
case EventMetadataEventTemplate:
wprintf(L"Template: %s\n\n", pProperty->StringVal);
break;
default:
wprintf(L"Unknown property Id: %d\n", Id);
}
return status;
}
// Used to get the message string or name for levels, tasks, and channels.
// Search the messages block sequentially for an item that has the same value
// and return a pointer to the message string.
LPWSTR GetPropertyName(EVT_HANDLE hMetadata, PMESSAGES pMessages, DWORD dwValue)
{
UNREFERENCED_PARAMETER(hMetadata);
LPWSTR pMessage = NULL;
DWORD dwCount = pMessages->dwSize / sizeof(MSG_STRING);
for (DWORD i = 0; i < dwCount; i++)
{
if (dwValue == ((pMessages->pMessage)+i)->dwValue)
{
pMessage = ((pMessages->pMessage)+i)->pwcsMessage;
break;
}
}
return pMessage;
}
// Used to get the message string or name for an opcode. Search the messages block sequentially
// for an item that has the same opcode value (high word). Opcodes can be defined globally or
// locally (task-specific). All global opcodes must be unique, but multiple tasks can specify the
// same opcode value, so we need to check the low word to see if the task on the event matches
// the task on the opcode.
LPWSTR GetOpcodeName(EVT_HANDLE hMetadata, PMESSAGES pMessages, DWORD dwOpcodeValue, DWORD dwTaskValue)
{
UNREFERENCED_PARAMETER(hMetadata);
LPWSTR pMessage = NULL;
DWORD dwCount = pMessages->dwSize / sizeof(MSG_STRING);
DWORD dwOpcodeIndex = 0; // Points to the global opcode (low word is zero)
BOOL fFound = FALSE;
for (DWORD i = 0; i < dwCount; i++)
{
if (dwOpcodeValue == HIWORD(((pMessages->pMessage)+i)->dwValue))
{
if (0 == LOWORD(((pMessages->pMessage)+i)->dwValue))
{
dwOpcodeIndex = i;
}
else if (dwTaskValue == LOWORD(((pMessages->pMessage)+i)->dwValue))
{
pMessage = ((pMessages->pMessage)+i)->pwcsMessage;
fFound = TRUE;
break;
}
}
}
if (FALSE == fFound)
{
pMessage = ((pMessages->pMessage)+dwOpcodeIndex)->pwcsMessage;
}
return pMessage;
}
// Used to get the message strings or names for the keywords specified on the event. The event
// contains a bit mask that has bits set for each keyword specified on the event. Search the
// messages block sequentially for items that have the same keyword bit set. Concatenate all the
// message strings.
LPWSTR GetKeywordName(EVT_HANDLE hMetadata, PMESSAGES pMessages, UINT64 ullKeywords)
{
UNREFERENCED_PARAMETER(hMetadata);
LPWSTR pMessage = NULL;
LPWSTR pTemp = NULL;
BOOL fFirstMessage = TRUE;
size_t dwStringLen = 0;
DWORD dwCount = pMessages->dwSize / sizeof(MSG_STRING);
for (DWORD i = 0; i < dwCount; i++)
{
if (ullKeywords & ((pMessages->pMessage)+i)->ullMask)
{
dwStringLen += wcslen(((pMessages->pMessage)+i)->pwcsMessage) + 1 + 1; // + space delimiter + null-terminator
pTemp = (LPWSTR)realloc(pMessage, dwStringLen * sizeof(WCHAR));
if (pTemp)
{
pMessage = pTemp;
pTemp = NULL;
if (fFirstMessage)
{
*pMessage = L'\0'; // Need so first wcscat_s call works
fFirstMessage = FALSE;
}
else
{
wcscat_s(pMessage, dwStringLen, L" "); // Space delimiter
}
wcscat_s(pMessage, dwStringLen, ((pMessages->pMessage)+i)->pwcsMessage);
}
else
{
wprintf(L"realloc failed for GetKeywordName\n");
if (pMessage)
{
free(pMessage);
pMessage = NULL;
}
break;
}
}
}
return pMessage;
}
// Use the EVT_PUBLISHER_METADATA_PROPERTY_ID enumeration values to enumerate all the
// provider's metadata excluding event metadata. Enumerates the metadata for channels,
// tasks, opcodes, levels, keywords, and the provider.
DWORD PrintProviderProperties(EVT_HANDLE hMetadata)
{
PEVT_VARIANT pProperty = NULL; // Contains the metadata property
PEVT_VARIANT pTemp = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD status = ERROR_SUCCESS;
for (int Id = 0; Id < EvtPublisherMetadataPropertyIdEND; Id++)
{
// Get the metadata property. If the buffer is not big enough, reallocate the buffer.
if (!EvtGetPublisherMetadataProperty(hMetadata, (EVT_PUBLISHER_METADATA_PROPERTY_ID)Id, 0, dwBufferSize, pProperty, &dwBufferUsed))
{
status = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status)
{
dwBufferSize = dwBufferUsed;
pTemp = (PEVT_VARIANT)realloc(pProperty, dwBufferSize);
if (pTemp)
{
pProperty = pTemp;
pTemp = NULL;
EvtGetPublisherMetadataProperty(hMetadata, (EVT_PUBLISHER_METADATA_PROPERTY_ID)Id, 0, dwBufferSize, pProperty, &dwBufferUsed);
}
else
{
wprintf(L"realloc failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtGetPublisherMetadataProperty failed with %d\n", GetLastError());
goto cleanup;
}
}
if (status = PrintProviderProperty(hMetadata, Id, pProperty))
break;
RtlZeroMemory(pProperty, dwBufferUsed);
// Skip the type-specific IDs, so the loop doesn't fail. For channels, levels,
// opcodes, tasks, and keywords, you use EvtGetPublisherMetadataProperty
// to get a handle to an array of those objects. You would then use the type
// specific ID (for example, EvtPublisherMetadataLevelValue) to access the metadata from
// the array. Do not call EvtGetPublisherMetadataProperty with a type specific ID or it
// will fail. The switch statement increments to the end of the type specific IDs for
// each type.
switch (Id)
{
case EvtPublisherMetadataChannelReferences:
Id = EvtPublisherMetadataChannelReferenceMessageID;
break;
case EvtPublisherMetadataLevels:
Id = EvtPublisherMetadataLevelMessageID;
break;
case EvtPublisherMetadataOpcodes:
Id = EvtPublisherMetadataOpcodeMessageID;
break;
case EvtPublisherMetadataTasks:
Id = EvtPublisherMetadataTaskMessageID;
break;
case EvtPublisherMetadataKeywords:
Id = EvtPublisherMetadataKeywordMessageID;
break;
}
}
cleanup:
if (pProperty)
free(pProperty);
return status;
}
// Print the metadata properties for the provider and the types that
// it defines or references.
DWORD PrintProviderProperty(EVT_HANDLE hMetadata, int Id, PEVT_VARIANT pProperty)
{
UNREFERENCED_PARAMETER(hMetadata);
DWORD status = ERROR_SUCCESS;
WCHAR wszProviderGuid[50];
DWORD dwArraySize = 0;
DWORD dwBlockSize = 0;
LPWSTR pMessage = NULL;
switch(Id)
{
case EvtPublisherMetadataPublisherGuid:
StringFromGUID2(*(pProperty->GuidVal), wszProviderGuid, sizeof(wszProviderGuid)/sizeof(WCHAR));
wprintf(L"Guid: %s\n", wszProviderGuid);
break;
case EvtPublisherMetadataResourceFilePath:
wprintf(L"ResourceFilePath: %s\n", pProperty->StringVal);
break;
case EvtPublisherMetadataParameterFilePath:
wprintf(L"ParameterFilePath: %s\n", (EvtVarTypeNull == pProperty->Type) ? L"" : pProperty->StringVal);
break;
case EvtPublisherMetadataMessageFilePath:
wprintf(L"MessageFilePath: %s\n", pProperty->StringVal);
break;
case EvtPublisherMetadataHelpLink:
wprintf(L"HelpLink: %s\n", pProperty->StringVal);
break;
// The message string ID is -1 if the provider element does not specify the message attribute.
case EvtPublisherMetadataPublisherMessageID:
if (-1 == pProperty->UInt32Val)
{
wprintf(L"Message string: \n");
}
else
{
pMessage = GetMessageString(g_hMetadata, pProperty->UInt32Val);
wprintf(L"Publisher message string: %s\n", (pMessage) ? pMessage : L"");
if (pMessage)
{
free(pMessage);
}
}
break;
// We got the handle to all the channels defined in the channels section
// of the manifest. Get the size of the array of channel objects and
// allocate the messages block that will contain the value and
// message string for each channel. The strings are used to retrieve
// display names for the channel referenced in an event definition.
case EvtPublisherMetadataChannelReferences:
wprintf(L"Channels:\n");
if (EvtGetObjectArraySize(pProperty->EvtHandleVal, &dwArraySize))
{
// You always get a handle to the array but the array can be empty.
if (dwArraySize > 0)
{
dwBlockSize = sizeof(MSG_STRING) * dwArraySize;
g_ChannelMessages.pMessage = (PMSG_STRING)malloc(dwBlockSize);
if (g_ChannelMessages.pMessage)
{
RtlZeroMemory(g_ChannelMessages.pMessage, dwBlockSize);
g_ChannelMessages.dwSize = dwBlockSize;
// For each channel, print its metadata.
for (DWORD i = 0; i < dwArraySize; i++)
{
if (status = DumpChannelProperties(pProperty->EvtHandleVal, i, &g_ChannelMessages))
break;
}
}
else
{
status = ERROR_OUTOFMEMORY;
wprintf(L"g_pChannelMessages allocation error\n");
}
}
}
else
{
status = GetLastError();
}
EvtClose(pProperty->EvtHandleVal);
break;
// These are handled by the EvtPublisherMetadataChannelReferences case;
// they are here for completeness but will never be exercised.
case EvtPublisherMetadataChannelReferencePath:
case EvtPublisherMetadataChannelReferenceIndex:
case EvtPublisherMetadataChannelReferenceID:
case EvtPublisherMetadataChannelReferenceFlags:
case EvtPublisherMetadataChannelReferenceMessageID:
break;
// We got the handle to all the levels defined in the channels section
// of the manifest. Get the size of the array of level objects and
// allocate the messages block that will contain the value and
// message string for each level. The strings are used to retrieve
// display names for the level referenced in an event definition.
// References to the levels defined in Winmeta.xml are included in
// the list.
case EvtPublisherMetadataLevels:
wprintf(L"Levels:\n");
if (EvtGetObjectArraySize(pProperty->EvtHandleVal, &dwArraySize))
{
// You always get a handle to the array but the array can be empty.
if (dwArraySize > 0)
{
dwBlockSize = sizeof(MSG_STRING) * dwArraySize;
g_LevelMessages.pMessage = (PMSG_STRING)malloc(dwBlockSize);
if (g_LevelMessages.pMessage)
{
RtlZeroMemory(g_LevelMessages.pMessage, dwBlockSize);
g_LevelMessages.dwSize = dwBlockSize;
// For each level, print its metadata.
for (DWORD i = 0; i < dwArraySize; i++)
{
if (status = DumpLevelProperties(pProperty->EvtHandleVal, i, &g_LevelMessages))
break;
}
}
else
{
status = ERROR_OUTOFMEMORY;
wprintf(L"g_pLevelMessages allocation error\n");
}
}
}
else
{
status = GetLastError();
}
EvtClose(pProperty->EvtHandleVal);
break;
// These are handled by the EvtPublisherMetadataLevels case;
// they are here for completeness but will never be exercised.
case EvtPublisherMetadataLevelName:
case EvtPublisherMetadataLevelValue:
case EvtPublisherMetadataLevelMessageID:
break;
// We got the handle to all the tasks defined in the channels section
// of the manifest. Get the size of the array of task objects and
// allocate the messages block that will contain the value and
// message string for each task. The strings are used to retrieve
// display names for the task referenced in an event definition.
case EvtPublisherMetadataTasks:
wprintf(L"Tasks:\n");
if (EvtGetObjectArraySize(pProperty->EvtHandleVal, &dwArraySize))
{
// You always get a handle to the array but the array can be empty.
if (dwArraySize > 0)
{
dwBlockSize = sizeof(MSG_STRING) * dwArraySize;
g_TaskMessages.pMessage = (PMSG_STRING)malloc(dwBlockSize);
if (g_TaskMessages.pMessage)
{
RtlZeroMemory(g_TaskMessages.pMessage, dwBlockSize);
g_TaskMessages.dwSize = dwBlockSize;
// For each task, print its metadata.
for (DWORD i = 0; i < dwArraySize; i++)
{
if (status = DumpTaskProperties(pProperty->EvtHandleVal, i, &g_TaskMessages))
break;
}
}
else
{
status = ERROR_OUTOFMEMORY;
wprintf(L"g_pTaskMessages allocation error\n");
}
}
}
else
{
status = GetLastError();
}
EvtClose(pProperty->EvtHandleVal);
break;
// These are handled by the EvtPublisherMetadataTasks case;
// they are here for completeness but will never be exercised.
case EvtPublisherMetadataTaskName:
case EvtPublisherMetadataTaskEventGuid:
case EvtPublisherMetadataTaskValue:
case EvtPublisherMetadataTaskMessageID:
break;
// We got the handle to all the opcodes defined in the channels section
// of the manifest. Get the size of the array of opcode objects and
// allocate the messages block that will contain the value and
// message string for each opcode. The strings are used to retrieve
// display names for the opcode referenced in an event definition.
case EvtPublisherMetadataOpcodes:
wprintf(L"Opcodes:\n");
if (EvtGetObjectArraySize(pProperty->EvtHandleVal, &dwArraySize))
{
// You always get a handle to the array but the array can be empty.
if (dwArraySize > 0)
{
dwBlockSize = sizeof(MSG_STRING) * dwArraySize;
g_OpcodeMessages.pMessage = (PMSG_STRING)malloc(dwBlockSize);
if (g_OpcodeMessages.pMessage)
{
RtlZeroMemory(g_OpcodeMessages.pMessage, dwBlockSize);
g_OpcodeMessages.dwSize = dwBlockSize;
// For each opcode, print its metadata.
for (DWORD i = 0; i < dwArraySize; i++)
{
if (status = DumpOpcodeProperties(pProperty->EvtHandleVal, i, &g_OpcodeMessages))
break;
}
}
else
{
status = ERROR_OUTOFMEMORY;
wprintf(L"g_pOpcodeMessages allocation error\n");
}
}
}
else
{
status = GetLastError();
}
EvtClose(pProperty->EvtHandleVal);
break;
// These are handled by the EvtPublisherMetadataOpcodes case;
// they are here for completeness but will never be exercised.
case EvtPublisherMetadataOpcodeName:
case EvtPublisherMetadataOpcodeValue:
case EvtPublisherMetadataOpcodeMessageID:
break;
// We got the handle to all the keywords defined in the channels section
// of the manifest. Get the size of the array of keyword objects and
// allocate the messages block that will contain the value and
// message string for each keyword. The strings are used to retrieve
// display names for the keyword referenced in an event definition.
case EvtPublisherMetadataKeywords:
wprintf(L"Keywords:\n");
if (EvtGetObjectArraySize(pProperty->EvtHandleVal, &dwArraySize))
{
// You always get a handle to the array but the array can be empty.
if (dwArraySize > 0)
{
dwBlockSize = sizeof(MSG_STRING) * dwArraySize;
g_KeywordMessages.pMessage = (PMSG_STRING)malloc(dwBlockSize);
if (g_KeywordMessages.pMessage)
{
RtlZeroMemory(g_KeywordMessages.pMessage, dwBlockSize);
g_KeywordMessages.dwSize = dwBlockSize;
// For each keyword, print its metadata.
for (DWORD i = 0; i < dwArraySize; i++)
{
if (status = DumpKeywordProperties(pProperty->EvtHandleVal, i, &g_KeywordMessages))
break;
}
}
else
{
status = ERROR_OUTOFMEMORY;
wprintf(L"g_pKeywordMessages allocation error\n");
}
}
}
else
{
status = GetLastError();
}
EvtClose(pProperty->EvtHandleVal);
break;
// These are handled by the EvtPublisherMetadataKeywords case;
// they are here for completeness but will never be exercised.
case EvtPublisherMetadataKeywordName:
case EvtPublisherMetadataKeywordValue:
case EvtPublisherMetadataKeywordMessageID:
break;
default:
wprintf(L"Unknown property Id: %d\n", Id);
}
return status;
}
// Print the metadata for a channel. Capture the message string and value for use later.
DWORD DumpChannelProperties(EVT_HANDLE hChannels, DWORD dwIndex, PMESSAGES pMessages)
{
LPWSTR pMessage = NULL;
DWORD status = ERROR_SUCCESS;
size_t dwStringLen = 0;
PEVT_VARIANT pvBuffer = NULL;
pvBuffer = GetProperty(hChannels, dwIndex, EvtPublisherMetadataChannelReferenceMessageID);
if (pvBuffer)
{
// The value is -1 if the channel did not specify a message attribute.
if (-1 != pvBuffer->UInt32Val)
{
pMessage = GetMessageString(g_hMetadata, pvBuffer->UInt32Val);
}
wprintf(L"\tChannel message string: %s\n", (pMessage) ? pMessage : L"");
}
else
{
status = GetLastError();
goto cleanup;
}
// This is the channel name. You can use it to call the EvtOpenChannelConfig function
// to get the channel's configuration information.
pvBuffer = GetProperty(hChannels, dwIndex, EvtPublisherMetadataChannelReferencePath);
if (pvBuffer)
{
wprintf(L"\tChannel path is %s\n", pvBuffer->StringVal);
}
else
{
status = GetLastError();
goto cleanup;
}
// Capture the message string if the channel specified a message string; otherwise,
// capture the channel's name.
if (pMessage)
{
dwStringLen = wcslen(pMessage) + 1;
((pMessages->pMessage)+dwIndex)->pwcsMessage = (LPWSTR)malloc(dwStringLen * sizeof(WCHAR));
wcscpy_s(((pMessages->pMessage)+dwIndex)->pwcsMessage, dwStringLen, pMessage);
}
else
{
dwStringLen = wcslen(pvBuffer->StringVal) + 1;
((pMessages->pMessage)+dwIndex)->pwcsMessage = (LPWSTR)malloc(dwStringLen * sizeof(WCHAR));
wcscpy_s(((pMessages->pMessage)+dwIndex)->pwcsMessage, dwStringLen, pvBuffer->StringVal);
}
pvBuffer = GetProperty(hChannels, dwIndex, EvtPublisherMetadataChannelReferenceIndex);
if (pvBuffer)
{
wprintf(L"\tChannel index is %lu\n", pvBuffer->UInt32Val);
}
else
{
status = GetLastError();
goto cleanup;
}
// Capture the channel's value attribute, which is used to look up the channel's
// message string.
pvBuffer = GetProperty(hChannels, dwIndex, EvtPublisherMetadataChannelReferenceID);
if (pvBuffer)
{
wprintf(L"\tChannel ID is %lu\n", pvBuffer->UInt32Val);
((pMessages->pMessage)+dwIndex)->dwValue = pvBuffer->UInt32Val;
}
else
{
status = GetLastError();
goto cleanup;
}
pvBuffer = GetProperty(hChannels, dwIndex, EvtPublisherMetadataChannelReferenceFlags);
if (pvBuffer)
{
if (EvtChannelReferenceImported == (EvtChannelReferenceImported & pvBuffer->UInt32Val))
wprintf(L"\tChannel is imported\n");
}
else
{
status = GetLastError();
goto cleanup;
}
cleanup:
if (pvBuffer)
free(pvBuffer);
if (pMessage)
free(pMessage);
return status;
}
// Print the metadata for a level. Capture the message string and value for use later.
DWORD DumpLevelProperties(EVT_HANDLE hLevels, DWORD dwIndex, PMESSAGES pMessages)
{
LPWSTR pMessage = NULL;
DWORD status = ERROR_SUCCESS;
size_t dwStringLen = 0;
PEVT_VARIANT pvBuffer = NULL;
pvBuffer = GetProperty(hLevels, dwIndex, EvtPublisherMetadataLevelMessageID);
if (pvBuffer)
{
// The value is -1 if the level did not specify a message attribute.
if (-1 != pvBuffer->UInt32Val)
{
pMessage = GetMessageString(g_hMetadata, pvBuffer->UInt32Val);
}
wprintf(L"\tLevel message string: %s\n", (pMessage) ? pMessage : L"");
}
else
{
status = GetLastError();
goto cleanup;
}
pvBuffer = GetProperty(hLevels, dwIndex, EvtPublisherMetadataLevelName);
if (pvBuffer)
{
wprintf(L"\tLevel name is %s\n", pvBuffer->StringVal);
}
else
{
status = GetLastError();
goto cleanup;
}
// Capture the message string if the level specified a message string; otherwise,
// capture the level's name.
if (pMessage)
{
dwStringLen = wcslen(pMessage) + 1;
((pMessages->pMessage)+dwIndex)->pwcsMessage = (LPWSTR)malloc(dwStringLen * sizeof(WCHAR));
wcscpy_s(((pMessages->pMessage)+dwIndex)->pwcsMessage, dwStringLen, pMessage);
}
else
{
dwStringLen = wcslen(pvBuffer->StringVal) + 1;
((pMessages->pMessage)+dwIndex)->pwcsMessage = (LPWSTR)malloc(dwStringLen * sizeof(WCHAR));
wcscpy_s(((pMessages->pMessage)+dwIndex)->pwcsMessage, dwStringLen, pvBuffer->StringVal);
}
// Capture the level's value attribute, which is used to look up the level's
// message string.
pvBuffer = GetProperty(hLevels, dwIndex, EvtPublisherMetadataLevelValue);
if (pvBuffer)
{
wprintf(L"\tLevel value is %lu\n", pvBuffer->UInt32Val);
((pMessages->pMessage)+dwIndex)->dwValue = pvBuffer->UInt32Val;
}
else
{
status = GetLastError();
goto cleanup;
}
cleanup:
if (pvBuffer)
free(pvBuffer);
if (pMessage)
free(pMessage);
return status;
}
// Print the metadata for a task. Capture the message string and value for use later.
DWORD DumpTaskProperties(EVT_HANDLE hTasks, DWORD dwIndex, PMESSAGES pMessages)
{
LPWSTR pMessage = NULL;
DWORD status = ERROR_SUCCESS;
size_t dwStringLen = 0;
PEVT_VARIANT pvBuffer = NULL;
WCHAR wszEventGuid[50];
pvBuffer = GetProperty(hTasks, dwIndex, EvtPublisherMetadataTaskMessageID);
if (pvBuffer)
{
// The value is -1 if the task did not specify a message attribute.
if (-1 != pvBuffer->UInt32Val)
{
pMessage = GetMessageString(g_hMetadata, pvBuffer->UInt32Val);
}
wprintf(L"\tTask message string: %s\n", (pMessage) ? pMessage : L"");
}
else
{
status = GetLastError();
goto cleanup;
}
pvBuffer = GetProperty(hTasks, dwIndex, EvtPublisherMetadataTaskName);
if (pvBuffer)
{
wprintf(L"\tTask name is %s\n", pvBuffer->StringVal);
}
else
{
status = GetLastError();
goto cleanup;
}
// Capture the message string if the task specified a message string; otherwise,
// capture the task's name.
if (pMessage)
{
dwStringLen = wcslen(pMessage) + 1;
((pMessages->pMessage)+dwIndex)->pwcsMessage = (LPWSTR)malloc(dwStringLen * sizeof(WCHAR));
wcscpy_s(((pMessages->pMessage)+dwIndex)->pwcsMessage, dwStringLen, pMessage);
}
else
{
dwStringLen = wcslen(pvBuffer->StringVal) + 1;
((pMessages->pMessage)+dwIndex)->pwcsMessage = (LPWSTR)malloc(dwStringLen * sizeof(WCHAR));
wcscpy_s(((pMessages->pMessage)+dwIndex)->pwcsMessage, dwStringLen, pvBuffer->StringVal);
}
pvBuffer = GetProperty(hTasks, dwIndex, EvtPublisherMetadataTaskEventGuid);
if (pvBuffer)
{
if (!IsEqualGUID(GUID_NULL, *(pvBuffer->GuidVal)))
{
StringFromGUID2(*(pvBuffer->GuidVal), wszEventGuid, sizeof(wszEventGuid)/sizeof(WCHAR));
wprintf(L"\tTask event GUID is %s\n", wszEventGuid);
}
}
else
{
status = GetLastError();
goto cleanup;
}
// Capture the task's value attribute, which is used to look up the task's
// message string.
pvBuffer = GetProperty(hTasks, dwIndex, EvtPublisherMetadataTaskValue);
if (pvBuffer)
{
wprintf(L"\tTask value is %lu\n", pvBuffer->UInt32Val);
((pMessages->pMessage)+dwIndex)->dwValue = pvBuffer->UInt32Val;
}
else
{
status = GetLastError();
goto cleanup;
}
cleanup:
if (pvBuffer)
free(pvBuffer);
if (pMessage)
free(pMessage);
return status;
}
// Print the metadata for a opcode. Capture the message string and value for use later.
DWORD DumpOpcodeProperties(EVT_HANDLE hOpcodes, DWORD dwIndex, PMESSAGES pMessages)
{
LPWSTR pMessage = NULL;
DWORD status = ERROR_SUCCESS;
size_t dwStringLen = 0;
PEVT_VARIANT pvBuffer = NULL;
pvBuffer = GetProperty(hOpcodes, dwIndex, EvtPublisherMetadataOpcodeMessageID);
if (pvBuffer)
{
// The value is -1 if the opcode did not specify a message attribute.
if (-1 != pvBuffer->UInt32Val)
{
pMessage = GetMessageString(g_hMetadata, pvBuffer->UInt32Val);
}
wprintf(L"\tOpcode message string: %s\n", (pMessage) ? pMessage : L"");
}
else
{
status = GetLastError();
goto cleanup;
}
pvBuffer = GetProperty(hOpcodes, dwIndex, EvtPublisherMetadataOpcodeName);
if (pvBuffer)
{
wprintf(L"\tOpcode name is %s\n", pvBuffer->StringVal);
}
else
{
status = GetLastError();
goto cleanup;
}
// Capture the message string if the opcode specified a message string; otherwise,
// capture the opcode's name.
if (pMessage)
{
dwStringLen = wcslen(pMessage) + 1;
((pMessages->pMessage)+dwIndex)->pwcsMessage = (LPWSTR)malloc(dwStringLen * sizeof(WCHAR));
wcscpy_s(((pMessages->pMessage)+dwIndex)->pwcsMessage, dwStringLen, pMessage);
}
else
{
dwStringLen = wcslen(pvBuffer->StringVal) + 1;
((pMessages->pMessage)+dwIndex)->pwcsMessage = (LPWSTR)malloc(dwStringLen * sizeof(WCHAR));
wcscpy_s(((pMessages->pMessage)+dwIndex)->pwcsMessage, dwStringLen, pvBuffer->StringVal);
}
// Capture the opcode's value attribute, which is used to look up the opcode's
// message string.
pvBuffer = GetProperty(hOpcodes, dwIndex, EvtPublisherMetadataOpcodeValue);
if (pvBuffer)
{
wprintf(L"\tOpcode value is %hu (task: %hu)\n", HIWORD(pvBuffer->UInt32Val), LOWORD(pvBuffer->UInt32Val));
((pMessages->pMessage)+dwIndex)->dwValue = pvBuffer->UInt32Val;
}
else
{
status = GetLastError();
goto cleanup;
}
cleanup:
if (pvBuffer)
free(pvBuffer);
if (pMessage)
free(pMessage);
return status;
}
// Print the metadata for a keyword. Capture the message string and mask for use later.
DWORD DumpKeywordProperties(EVT_HANDLE hKeywords, DWORD dwIndex, PMESSAGES pMessages)
{
LPWSTR pMessage = NULL;
DWORD status = ERROR_SUCCESS;
size_t dwStringLen = 0;
PEVT_VARIANT pvBuffer = NULL;
pvBuffer = GetProperty(hKeywords, dwIndex, EvtPublisherMetadataKeywordMessageID);
if (pvBuffer)
{
// The value is -1 if the keyword did not specify a message attribute.
if (-1 != pvBuffer->UInt32Val)
{
pMessage = GetMessageString(g_hMetadata, pvBuffer->UInt32Val);
}
wprintf(L"\tKeyword message string: %s\n", (pMessage) ? pMessage : L"");
}
else
{
status = GetLastError();
goto cleanup;
}
pvBuffer = GetProperty(hKeywords, dwIndex, EvtPublisherMetadataKeywordName);
if (pvBuffer)
{
wprintf(L"\tKeyword name is %s\n", pvBuffer->StringVal);
}
else
{
status = GetLastError();
goto cleanup;
}
// Capture the message string if the keyword specified a message string; otherwise,
// capture the keyword's name.
if (pMessage)
{
dwStringLen = wcslen(pMessage) + 1;
((pMessages->pMessage)+dwIndex)->pwcsMessage = (LPWSTR)malloc(dwStringLen * sizeof(WCHAR));
wcscpy_s(((pMessages->pMessage)+dwIndex)->pwcsMessage, dwStringLen, pMessage);
}
else
{
dwStringLen = wcslen(pvBuffer->StringVal) + 1;
((pMessages->pMessage)+dwIndex)->pwcsMessage = (LPWSTR)malloc(dwStringLen * sizeof(WCHAR));
wcscpy_s(((pMessages->pMessage)+dwIndex)->pwcsMessage, dwStringLen, pvBuffer->StringVal);
}
// Capture the keyword's mask attribute, which is used to look up the keyword's
// message string.
pvBuffer = GetProperty(hKeywords, dwIndex, EvtPublisherMetadataKeywordValue);
if (pvBuffer)
{
wprintf(L"\tKeyword value is %I64u\n", pvBuffer->UInt64Val);
((pMessages->pMessage)+dwIndex)->ullMask = pvBuffer->UInt32Val;
}
else
{
status = GetLastError();
goto cleanup;
}
cleanup:
if (pvBuffer)
free(pvBuffer);
if (pMessage)
free(pMessage);
return status;
}
// Get the metadata property for an object in the array.
PEVT_VARIANT GetProperty(EVT_HANDLE handle, DWORD dwIndex, EVT_PUBLISHER_METADATA_PROPERTY_ID PropertyId)
{
DWORD status = ERROR_SUCCESS;
PEVT_VARIANT pvBuffer = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
if (!EvtGetObjectArrayProperty(handle, PropertyId, dwIndex, 0, dwBufferSize, pvBuffer, &dwBufferUsed))
{
status = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status)
{
dwBufferSize = dwBufferUsed;
pvBuffer = (PEVT_VARIANT)malloc(dwBufferSize);
if (pvBuffer)
{
EvtGetObjectArrayProperty(handle, PropertyId, dwIndex, 0, dwBufferSize, pvBuffer, &dwBufferUsed);
}
else
{
wprintf(L"malloc failed\n");
status = ERROR_OUTOFMEMORY;
goto cleanup;
}
}
if (ERROR_SUCCESS != (status = GetLastError()))
{
wprintf(L"EvtGetObjectArrayProperty failed with %d\n", status);
}
}
cleanup:
return pvBuffer;
}
// Get the formatted message string.
LPWSTR GetMessageString(EVT_HANDLE hMetadata, DWORD dwMessageId)
{
LPWSTR pBuffer = NULL;
DWORD dwBufferSize = 0;
DWORD dwBufferUsed = 0;
DWORD status = 0;
if (!EvtFormatMessage(hMetadata, NULL, dwMessageId, 0, NULL, EvtFormatMessageId, dwBufferSize, pBuffer, &dwBufferUsed))
{
status = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == status)
{
dwBufferSize = dwBufferUsed;
pBuffer = (LPWSTR)malloc(dwBufferSize * sizeof(WCHAR));
if (pBuffer)
{
EvtFormatMessage(hMetadata, NULL, dwMessageId, 0, NULL, EvtFormatMessageId, dwBufferSize, pBuffer, &dwBufferUsed);
}
else
{
wprintf(L"malloc failed\n");
}
}
else
{
wprintf(L"EvtFormatMessage failed with %u\n", status);
}
}
return pBuffer;
}