Delen via


MOF-gebeurtenissen (klassiek) schrijven

Voordat u gebeurtenissen naar een traceringssessie kunt schrijven, moet u uw provider registreren. Als u een provider registreert, vertelt ETW dat uw provider gereed is om gebeurtenissen naar een traceringssessie te schrijven. Een proces kan maximaal 1024 provider-GUID's registreren; U moet echter het aantal providers beperken dat uw proces registreert op een of twee.

Vóór Windows Vista: Er is geen limiet voor het aantal providers dat een proces kan registreren.

Als u een klassieke provider wilt registreren, roept u de functie RegisterTraceGuids aan. De functie registreert de GUID van de provider, GUID's van gebeurtenistraceklassen, en identificeert de callbackfunctie die ETW oproept wanneer een controller de provider in- of uitschakelt.

Als de provider de functie TraceEvent aanroept om gebeurtenissen te registreren, hoeft u de matrix met klasse-GUID's (kan worden NULL-) op te nemen bij het aanroepen van de RegisterTraceGuids--functie. U hoeft alleen de matrix op te nemen als de provider de TraceEventInstance functie aanroept om gebeurtenissen te registreren.

Windows XP en Windows 2000: U moet altijd de matrix van klasse-GUID's opnemen (kan niet worden NULL-).

Nadat een provider zichzelf heeft geregistreerd en is ingeschakeld door de controller, kan de provider gebeurtenissen registreren bij de traceringssessie van de controller.

Voordat de provider wordt afgesloten, roept u de UnregisterTraceGuids functie aan om de registratie van de provider uit ETW te verwijderen. De functie RegisterTraceGuids retourneert de registratie-handle die u doorgeeft aan de functie UnregisterTraceGuids.

Als uw provider alleen gebeurtenissen registreert bij de Global Logger-sessie, hoeft u uw provider niet te registreren bij ETW omdat de Global Logger-controller providers niet inschakelt of uitschakelt. Zie De algemene logboekregistratiesessie configureren en startenvoor meer informatie.

Alle klassieke-providers (met uitzondering van providers die gebeurtenissen traceren naar de Global Logger-sessie) moeten de ControlCallback--functie implementeren. De provider gebruikt de informatie in de callback om te bepalen of deze is ingeschakeld of uitgeschakeld en welke gebeurtenissen moeten worden geschreven.

De provider geeft de naam van de callback-functie op wanneer deze de RegisterTraceGuids functie aanroept om zichzelf te registreren. ETW roept de callback-functie aan wanneer de controller de functie EnableTrace aanroept om de provider in of uit te schakelen.

In uw ControlCallback--implementatie moet u de functie GetTraceLoggerHandle aanroepen om de sessie-handle op te halen; u de sessiehandgreep gebruikt bij het aanroepen van de functie TraceEvent. U hoeft alleen de GetTraceEnableFlags-functie of de GetTraceEnableLevel-functie aan te roepen in uwControlCallback-implementatie als uw provider gebruikmaakt van het inschakelniveau of inschakelvlaggen.

Een provider kan traceringsgebeurtenissen in slechts één sessie vastleggen, maar er is niets om te voorkomen dat meerdere controllers één provider inschakelen. Als u wilt voorkomen dat een andere controller uw traceringsgebeurtenissen omleidt naar zijn sessie, kunt u logica toevoegen aan uw ControlCallback-implementatie om sessiegrepen te vergelijken en aanvragen van andere controllers te negeren.

De functie TraceEvent wordt aangeroepen door klassieke-providers om gebeurtenissen te registreren. Een gebeurtenis bestaat uit de EVENT_TRACE_HEADER structuur en eventuele gebeurtenisspecifieke gegevens die aan de header worden toegevoegd.

De header moet de volgende informatie bevatten:

  • De Grootte lid moet het totale aantal bytes bevatten dat moet worden vastgelegd voor de gebeurtenis (inclusief de grootte van de EVENT_TRACE_HEADER structuur en van eventuele gebeurtenisspecifieke gegevens die aan de header worden toegevoegd).

  • De guid- lid moet de klasse-GUID van de gebeurtenis bevatten (of het GuidPtr- lid moet een aanwijzer naar de klasse-GUID bevatten).

    Windows XP en Windows 2000: De klasse-GUID moet eerder zijn geregistreerd met de functie RegisterTraceGuids.

  • De Flags lid moet de WNODE_FLAG_TRACED_GUID vlag bevatten. Als u de klasse-GUID opgeeft met behulp van de GuidPtr lid, voegt u ook de WNODE_FLAG_USE_GUID_PTR vlag toe.

  • Het Class.Type lid moet het gebeurtenistype bevatten als u MOF gebruikt om de indeling van uw gebeurtenisgegevens te publiceren.

  • Het Class.Version- lid moet de gebeurtenisversie bevatten als u MOF gebruikt om de indeling van uw gebeurtenisgegevens te publiceren. De versie wordt gebruikt om onderscheid te maken tussen revisies van de gebeurtenisgegevens. Stel het eerste versienummer in op 0.

Als u zowel de provider als de consument schrijft, kunt u een structuur gebruiken om de gebeurtenisspecifieke gegevens te vullen die aan de header worden toegevoegd. Als u echter MOF gebruikt om de gebeurtenisspecifieke gegevens te publiceren, zodat elke consument de gebeurtenis kan verwerken, moet u geen structuur gebruiken om de gebeurtenisspecifieke gegevens toe te voegen aan de header. Dit komt doordat de compiler extra bytes kan toevoegen aan de gebeurtenisspecifieke gegevens voor byte-uitlijning. Omdat de MOF-definitie geen rekening houdt met de extra bytes, kan de consument gegevens ophalen die niet geldig zijn.

U moet een blok geheugen voor de gebeurtenis toewijzen en elk gebeurtenisgegevensitem naar het geheugen kopiëren of een structuur maken die een matrix van MOF_FIELD structuren bevat; De meeste toepassingen maken een structuur die een matrix van MOF_FIELD structuren bevat. Zorg ervoor dat Header.Size het werkelijke aantal MOF_FIELD structuren weerspiegelt dat daadwerkelijk is ingesteld voordat de gebeurtenis wordt vastgelegd. Als de gebeurtenis bijvoorbeeld drie gegevensvelden bevat, stelt u Header.Size in op sizeof(EVENT_TRACE_HEADER) + (sizeof(MOF_FIELD) * 3).

Zie Gerelateerde gebeurtenissen schrijven in een end-to-end scenariovoor meer informatie over het traceren van gerelateerde gebeurtenissen.

In het volgende voorbeeld ziet u hoe u de functie TraceEvent aanroept om gebeurtenissen te registreren. Het voorbeeld verwijst naar de gebeurtenissen die zijn gedefinieerd in Uw gebeurtenisschema publiceren voor een klassieke provider.

#include <windows.h>
#include <stdio.h>
#include <wmistr.h>
#include <evntrace.h>

// GUID that identifies the category of events that the provider can log. 
// The GUID is also used in the event MOF class. 
// Remember to change this GUID if you copy and paste this example.

// {B49D5931-AD85-4070-B1B1-3F81F1532875}
static const GUID MyCategoryGuid = 
{ 0xb49d5931, 0xad85, 0x4070, { 0xb1, 0xb1, 0x3f, 0x81, 0xf1, 0x53, 0x28, 0x75 } };

// GUID that identifies the provider that you are registering.
// The GUID is also used in the provider MOF class. 
// Remember to change this GUID if you copy and paste this example.

// {7C214FB1-9CAC-4b8d-BAED-7BF48BF63BB3}
static const GUID ProviderGuid = 
{ 0x7c214fb1, 0x9cac, 0x4b8d, { 0xba, 0xed, 0x7b, 0xf4, 0x8b, 0xf6, 0x3b, 0xb3 } };

// Identifies the event type within the MyCategoryGuid category 
// of events to be logged. This is the same value as the EventType 
// qualifier that is defined in the event type MOF class for one of 
// the MyCategoryGuid category of events.

#define MY_EVENT_TYPE 1

// Event passed to TraceEvent

typedef struct _event
{
    EVENT_TRACE_HEADER Header;
    MOF_FIELD Data[MAX_MOF_FIELDS];  // Event-specific data
} MY_EVENT, *PMY_EVENT;

#define MAX_INDICES            3
#define MAX_SIGNATURE_LEN      32
#define EVENT_DATA_FIELDS_CNT  6

// Application data to be traced for Version 1 of the MOF class.

typedef struct _evtdata
{
    LONG Cost;
    DWORD Indices[MAX_INDICES];
    WCHAR Signature[MAX_SIGNATURE_LEN];
    BOOL IsComplete;
    GUID ID;
    DWORD Size;
}EVENT_DATA, *PEVENT_DATA;

// GUID used as the value for EVENT_DATA.ID.

// {25BAEDA9-C81A-4889-8764-184FE56750F2}
static const GUID tempID = 
{ 0x25baeda9, 0xc81a, 0x4889, { 0x87, 0x64, 0x18, 0x4f, 0xe5, 0x67, 0x50, 0xf2 } };

// Global variables to store tracing state information.

TRACEHANDLE g_SessionHandle = 0; // The handle to the session that enabled the provider.
ULONG g_EnableFlags = 0; // Determines which class of events to log.
UCHAR g_EnableLevel = 0; // Determines the severity of events to log.
BOOL g_TraceOn = FALSE;  // Used by the provider to determine whether it should log events.

ULONG WINAPI ControlCallback(WMIDPREQUESTCODE RequestCode, PVOID Context, ULONG* Reserved, PVOID Header);

// For this example to log the event, run the session example
// to enable the provider before running this example.

void wmain(void)
{
    ULONG status = ERROR_SUCCESS;
    EVENT_DATA EventData;
    MY_EVENT MyEvent; 
    TRACEHANDLE RegistrationHandle = 0; 
    TRACE_GUID_REGISTRATION EventClassGuids[] = {
        (LPGUID)&MyCategoryGuid, NULL
        };

    // Register the provider and specify the control callback function
    // that receives the enable/disable notifications.

    status = RegisterTraceGuids(
        (WMIDPREQUEST)ControlCallback,
        NULL,
        (LPGUID)&ProviderGuid,
        sizeof(EventClassGuids)/sizeof(TRACE_GUID_REGISTRATION),
        EventClassGuids,
        NULL,
        NULL,
        &RegistrationHandle
        );

    if (ERROR_SUCCESS != status)
    {
        wprintf(L"RegisterTraceGuids failed with %lu\n", status);
        goto cleanup;
    }

    // Set the event-specific data.

    EventData.Cost = 32;
    EventData.ID = tempID;
    EventData.Indices[0] = 4;
    EventData.Indices[1] = 5;
    EventData.Indices[2] = 6;
    EventData.IsComplete = TRUE;
    wcscpy_s(EventData.Signature, MAX_SIGNATURE_LEN, L"Signature");
    EventData.Size = 1024;

    // Log the event if the provider is enabled and the session
    // passed a severity level value >= TRACE_LEVEL_ERROR (or zero).
    // If your provider generates more than one class of events, you
    // would also need to check g_EnableFlags.

    if (g_TraceOn && (0 == g_EnableLevel || TRACE_LEVEL_ERROR <= g_EnableLevel))
    {
        // Initialize the event data structure.

        ZeroMemory(&MyEvent, sizeof(MY_EVENT));
        MyEvent.Header.Size = sizeof(EVENT_TRACE_HEADER) + (sizeof(MOF_FIELD) * EVENT_DATA_FIELDS_CNT);
        MyEvent.Header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
        MyEvent.Header.Guid = MyCategoryGuid;
        MyEvent.Header.Class.Type = MY_EVENT_TYPE;
        MyEvent.Header.Class.Version = 1;
        MyEvent.Header.Class.Level = g_EnableLevel;

        // Load the event data. You can also use the DEFINE_TRACE_MOF_FIELD
        // macro defined in evntrace.h to set the MOF_FIELD members. For example,
        // DEFINE_TRACE_MOF_FIELD(&EventData.Data[0], &EventData.Cost, sizeof(EventData.Cost), 0);

        MyEvent.Data[0].DataPtr = (ULONG64) &(EventData.Cost);
        MyEvent.Data[0].Length = sizeof(EventData.Cost);
        MyEvent.Data[1].DataPtr = (ULONG64) &(EventData.Indices);
        MyEvent.Data[1].Length = sizeof(EventData.Indices);
        MyEvent.Data[2].DataPtr = (ULONG64) &(EventData.Signature);
        MyEvent.Data[2].Length = (ULONG)(wcslen(EventData.Signature) + 1) * sizeof(WCHAR);
        MyEvent.Data[3].DataPtr = (ULONG64) &(EventData.IsComplete);
        MyEvent.Data[3].Length = sizeof(EventData.IsComplete);
        MyEvent.Data[4].DataPtr = (ULONG64) &(EventData.ID);
        MyEvent.Data[4].Length = sizeof(EventData.ID);
        MyEvent.Data[5].DataPtr = (ULONG64) &(EventData.Size);
        MyEvent.Data[5].Length = sizeof(EventData.Size);

        // Write the event.

        status = TraceEvent(g_SessionHandle, &(MyEvent.Header));

        if (ERROR_SUCCESS != status)
        {
            // Decide how you want to handle failures. Typically, you do not
            // want to terminate the application because you failed to
            // log an event. If the error is a memory failure, you may
            // may want to log a message to the system event log or turn
            // off logging.

            wprintf(L"TraceEvent() event failed with %lu\n", status);
            g_TraceOn = FALSE;
        }
    }

cleanup:

    if (RegistrationHandle)
    {
        UnregisterTraceGuids(RegistrationHandle);
    }
}


// The callback function that receives enable/disable notifications
// from one or more ETW sessions. Because more than one session
// can enable the provider, this example ignores requests from other 
// sessions if it is already enabled.

ULONG WINAPI ControlCallback(
    WMIDPREQUESTCODE RequestCode,
    PVOID Context,
    ULONG* Reserved, 
    PVOID Header
    )
{
    UNREFERENCED_PARAMETER(Context);
    UNREFERENCED_PARAMETER(Reserved);

    ULONG status = ERROR_SUCCESS;
    TRACEHANDLE TempSessionHandle = 0; 

    switch (RequestCode)
    {
        case WMI_ENABLE_EVENTS:  // Enable the provider.
        {
            SetLastError(0);

            // If the provider is already enabled to a provider, ignore 
            // the request. Get the session handle of the enabling session.
            // You need the session handle to call the TraceEvent function.
            // The session could be enabling the provider or it could be
            // updating the level and enable flags.

            TempSessionHandle = GetTraceLoggerHandle(Header);
            if (INVALID_HANDLE_VALUE == (HANDLE)TempSessionHandle)
            {
                wprintf(L"GetTraceLoggerHandle failed. Error code is %lu.\n", status = GetLastError());
                break;
            }

            if (0 == g_SessionHandle)
            {
                g_SessionHandle = TempSessionHandle;
            }
            else if (g_SessionHandle != TempSessionHandle)
            {
                break;
            }

            // Get the severity level of the events that the
            // session wants you to log.

            g_EnableLevel = GetTraceEnableLevel(g_SessionHandle); 
            if (0 == g_EnableLevel)
            {
                // If zero, determine whether the session passed zero
                // or an error occurred.

                if (ERROR_SUCCESS == (status = GetLastError()))
                {
                    // Decide what a zero enable level means to your provider.
                    // For this example, it means log all events.
                    ; 
                }
                else
                {
                    wprintf(L"GetTraceEnableLevel failed with, %lu.\n", status);
                    break;
                } 
            }

            // Get the enable flags that indicate the events that the
            // session wants you to log. The provider determines the
            // flags values. How it articulates the flag values and 
            // meanings to perspective sessions is up to it.

            g_EnableFlags = GetTraceEnableFlags(g_SessionHandle);
            if (0 == g_EnableFlags)
            {
                // If zero, determine whether the session passed zero
                // or an error occurred.

                if (ERROR_SUCCESS == (status = GetLastError()))
                {
                    // Decide what a zero enable flags value means to your provider.
                    ; 
                }
                else
                {
                    wprintf(L"GetTraceEnableFlags failed with, %lu.\n", status);
                    break;
                }
            }

            g_TraceOn = TRUE;
            break;
        }
 
        case WMI_DISABLE_EVENTS:  // Disable the provider.
        {
            // Disable the provider only if the request is coming from the
            // session that enabled the provider.

            TempSessionHandle = GetTraceLoggerHandle(Header);
            if (INVALID_HANDLE_VALUE == (HANDLE)TempSessionHandle)
            {
                wprintf(L"GetTraceLoggerHandle failed. Error code is %lu.\n", status = GetLastError());
                break;
            }

            if (g_SessionHandle == TempSessionHandle)
            {
                g_TraceOn = FALSE;
                g_SessionHandle = 0;
            }
            break;
        }

        default:
        {
            status = ERROR_INVALID_PARAMETER;
            break;
        }
    }

    return status;
}