매니페스트 기반 이벤트 작성

추적 세션에 이벤트를 작성하려면 먼저 공급자를 등록해야 합니다. 공급자를 등록하면 공급자가 추적 세션에 이벤트를 쓸 준비가 되었다는 것을 ETW에 알릴 수 있습니다. 프로세스는 최대 1,024개의 공급자 GUID를 등록할 수 있습니다. 그러나 프로세스가 등록하는 공급자 수를 한두 개로 제한해야 합니다.

Windows Vista 이전: 프로세스가 등록할 수 있는 공급자 수에는 제한이 없습니다.

매니페스트 기반 공급자를 등록하려면 EventRegister 함수를 호출합니다. 함수는 공급자의 GUID를 등록하고 컨트롤러가 공급자를 사용하거나 사용하지 않도록 설정할 때 ETW에서 호출하는 선택적 콜백을 식별합니다.

공급자가 종료되기 전에 EventUnregister 함수를 호출하여 ETW에서 공급자 등록을 제거합니다. EventRegister 함수는 EventUnregister 함수에 전달하는 등록 핸들을 반환합니다.

매니페스트 기반 공급자는 세션이 공급자를 사용하거나 사용하지 않도록 설정할 때 알림을 수신하기 위해 EnableCallback 함수를 구현할 필요가 없습니다. 콜백은 선택 사항이며 정보 목적으로 사용됩니다. 공급자를 등록할 때 콜백을 지정하거나 구현할 필요가 없습니다. 매니페스트 기반 공급자는 단순히 이벤트를 작성할 수 있으며 ETW는 이벤트가 추적 세션에 기록되는지 여부를 결정합니다. 이벤트가 이벤트의 데이터를 생성하기 위해 광범위한 작업을 수행해야 하는 경우 먼저 EventEnabled 또는 EventProviderEnabled 함수를 호출하여 작업을 수행하기 전에 이벤트가 세션에 기록되는지 확인할 수 있습니다.

일반적으로 공급자가 공급자가 공급자 정의 필터 데이터를 공급자에게 전달하도록 요구하거나(EnableCallbackFilterData 매개 변수 참조) 공급자가 자신을 등록할 때 지정한 컨텍스트 정보를 사용하는 경우 콜백을 구현합니다(EventRegisterCallbackContext 매개 변수 참조).

매니페스트 기반 공급자는 EventWrite 또는 EventWriteString 함수 를 호출하여 세션에 이벤트를 씁니다. 이벤트 데이터가 문자열이거나 공급자에 대한 매니페스트를 정의하지 않고 이벤트 데이터가 단일 문자열인 경우 EventWriteString 함수를 호출하여 이벤트를 작성합니다. 숫자 또는 복합 데이터 형식을 포함하는 이벤트 데이터의 경우 EventWrite 함수를 호출하여 이벤트를 기록합니다.

다음 예제에서는 EventWrite 함수를 사용하여 기록할 이벤트 데이터를 준비하는 방법을 보여줍니다. 이 예제에서는 매니페스트 기반 공급자에 대한 이벤트 스키마 게시에 정의된 이벤트를 참조합니다.

#include <windows.h>
#include <stdio.h>
#include <evntprov.h>
#include "provider.h"  // Generated from manifest

#define SUNDAY     0X1
#define MONDAY     0X2
#define TUESDAY    0X4
#define WEDNESDAY  0X8
#define THURSDAY   0X10
#define FRIDAY     0X20
#define SATURDAY   0X40

enum TRANSFER_TYPE {
  Download = 1,
  Upload,
  UploadReply
};

#define MAX_NAMEDVALUES          5  // Maximum array size
#define MAX_PAYLOAD_DESCRIPTORS  9 + (2 * MAX_NAMEDVALUES)

typedef struct _namedvalue {
  LPWSTR name;
  USHORT value;
} NAMEDVALUE, *PNAMEDVALUE;

void wmain(void)
{
    DWORD status = ERROR_SUCCESS;
    REGHANDLE RegistrationHandle = NULL; 
    EVENT_DATA_DESCRIPTOR Descriptors[MAX_PAYLOAD_DESCRIPTORS]; 
    DWORD i = 0;

    // Data to load into event descriptors

    USHORT Scores[3] = {45, 63, 21};
    ULONG pImage = (ULONG)&Scores;
    DWORD TransferType = Upload;
    DWORD Day = MONDAY | TUESDAY;
    LPWSTR Path = L"c:\\path\\folder\\file.ext";
    BYTE Cert[11] = {0x2, 0x4, 0x8, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x0, 0x1};
    PBYTE Guid = (PBYTE) &ProviderGuid;
    USHORT ArraySize = MAX_NAMEDVALUES;
    BOOL IsLocal = TRUE;
    NAMEDVALUE NamedValues[MAX_NAMEDVALUES] = { 
        {L"Bill", 1},
        {L"Bob", 2},
        {L"William", 3},
        {L"Robert", 4},
        {L"", 5}
        };

    status = EventRegister(
        &ProviderGuid,      // GUID that identifies the provider
        NULL,               // Callback not used
        NULL,               // Context noot used
        &RegistrationHandle // Used when calling EventWrite and EventUnregister
        );

    if (ERROR_SUCCESS != status)
    {
        wprintf(L"EventRegister failed with %lu\n", status);
        goto cleanup;
    }
  
    // Load the array of data descriptors for the TransferEvent event. 
    // Add the data to the array in the order of the <data> elements
    // defined in the event's template. 
   
    EventDataDescCreate(&Descriptors[i++], &pImage, sizeof(ULONG));
    EventDataDescCreate(&Descriptors[i++], Scores, sizeof(Scores));
    EventDataDescCreate(&Descriptors[i++], Guid, sizeof(GUID));
    EventDataDescCreate(&Descriptors[i++], Cert, sizeof(Cert));
    EventDataDescCreate(&Descriptors[i++], &IsLocal, sizeof(BOOL));
    EventDataDescCreate(&Descriptors[i++], Path, (ULONG)(wcslen(Path) + 1) * sizeof(WCHAR));
    EventDataDescCreate(&Descriptors[i++], &ArraySize, sizeof(USHORT));

    // If your event contains a structure, you should write each member
    // of the structure separately. If the structure contained integral data types
    // such as DWORDs and the data types were aligned on an 8-byte boundary, you 
    // could use the following call to write the structure, however, you are 
    // encouraged to write the members separately.
    //
    // EventDataDescCreate(&EvtData, struct, sizeof(struct));
    //
    // Because the array of structures in this example contains both strings 
    // and numbers, you must write each member of the structure separately.

    for (int j = 0; j < MAX_NAMEDVALUES; j++)
    {
        EventDataDescCreate(&Descriptors[i++], NamedValues[j].name, (ULONG)(wcslen(NamedValues[j].name)+1) * sizeof(WCHAR) );
        EventDataDescCreate(&Descriptors[i++], &(NamedValues[j].value), sizeof(USHORT) );
    }

    EventDataDescCreate(&Descriptors[i++], &Day, sizeof(DWORD));
    EventDataDescCreate(&Descriptors[i++], &TransferType, sizeof(DWORD));

    // Write the event. You do not have to verify if your provider is enabled before
    // writing the event. ETW will write the event to any session that enabled
    // the provider. If no session enabled the provider, the event is not 
    // written. If you need to perform extra work to write an event that you
    // would not otherwise do, you may want to call the EventEnabled function
    // before performing the extra work. The EventEnabled function tells you if a
    // session has enabled your provider, so you know if you need to perform the 
    // extra work or not.

    status = EventWrite(
        RegistrationHandle,              // From EventRegister
        &TransferEvent,                  // EVENT_DESCRIPTOR generated from the manifest
        (ULONG)MAX_PAYLOAD_DESCRIPTORS,  // Size of the array of EVENT_DATA_DESCRIPTORs
        &Descriptors[0]                  // Array of descriptors that contain the event data
        );

    if (status != ERROR_SUCCESS) 
    {
        wprintf(L"EventWrite failed with 0x%x", status);
    }

cleanup:

    EventUnregister(RegistrationHandle);
}

위의 예제에서 사용하는 매니페스트( 계측 매니페스트 컴파일 참조)를 컴파일하면 다음 헤더 파일(위 예제에서 참조됨)이 만들어집니다.

//**********************************************************************`
//* This is an include file generated by Message Compiler.             *`
//*                                                                    *`
//* Copyright (c) Microsoft Corporation. All Rights Reserved.          *`
//**********************************************************************`
#pragma once
//+
// Provider Microsoft-Windows-ETWProvider Event Count 1
//+
EXTERN_C __declspec(selectany) const GUID ProviderGuid = {0xd8909c24, 0x5be9, 0x4502, {0x98, 0xca, 0xab, 0x7b, 0xdc, 0x24, 0x89, 0x9d}};
//
// Keyword
//
#define READ_KEYWORD 0x1
#define WRITE_KEYWORD 0x2
#define LOCAL_KEYWORD 0x4
#define REMOTE_KEYWORD 0x8

//
// Event Descriptors
//
EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR TransferEvent = {0x1, 0x0, 0x0, 0x4, 0x0, 0x0, 0x5};
#define TransferEvent_value 0x1
#define MSG_Provider_Name                    0x90000001L
#define MSG_Event_WhenToTransfer             0xB0000001L
#define MSG_Map_Download                     0xD0000001L
#define MSG_Map_Upload                       0xD0000002L
#define MSG_Map_UploadReply                  0xD0000003L
#define MSG_Map_Sunday                       0xF0000001L
#define MSG_Map_Monday                       0xF0000002L
#define MSG_Map_Tuesday                      0xF0000003L
#define MSG_Map_Wednesday                    0xF0000004L
#define MSG_Map_Thursday                     0xF0000005L
#define MSG_Map_Friday                       0xF0000006L
#define MSG_Map_Saturday                     0xF0000007L