Developing Event Publishers

Before publishing events, event publishers must perform steps to identify the type of events to publish, the publishing location, and the information the events should contain.

Developers should consider the following design questions before creating an event publisher:

  • What scenario is the event trying to give information about?
  • Which target audience can best solve this scenario?

    For information about the Event Log audience, see About Windows Event Log.

  • What data does that audience need to solve the scenario?

Take the following steps to design, develop, and deploy an event publisher.

Aa382690.wedge(en-us,VS.85).gifTo develop an event publisher

  1. Decide the type of event to raise and where to publish the events (which channel).

    At runtime, the type of event (Admin, Operational, Analytic, or Debug) is identified by the type of the channel it is in. Thus, the process of deciding event type is ultimately a way to determine the event destination. For more information about event types and channels, see Event Logs and Channels in Windows Event Log.

  2. Define the publisher, events, channels, and metadata in an instrumentation manifest.

    Instrumentation manifests contain the event publisher metadata, event definitions and templates, channel definitions, and the localized event messages. For more information, see Instrumentation Manifests for Event Publishers.

    The following XML example shows a manifest that contains the event definitions and publisher metadata for the event publisher that is implemented by the code in step 4.

    <!-- <?xml version="1.0" encoding="UTF-16"?> -->
                <!--Publisher Info -->
                <provider name="Microsoft-Windows-EventLogSamplePublisher" 
                    <!--Channel to which this Publisher can publish -->
                        <!--Pre-Existing channel can be imported, but not required. -->
                        <importChannel chid="C1" name="Application"/> 
                        <!--New Channel can be declared for this Publisher-->
                        <channel chid="MyChannel" 
                            isolation="Application" enabled="true"/>
                    <!--Event Templates -->
                       <template tid="MyEventTemplate">
                            <data name="Prop_UnicodeString" inType="win:UnicodeString" />
                            <data name="Prop_AnsiString" inType="win:AnsiString" outtype="xs:string" />
                            <data name="Prop_Int8" inType="win:Int8" />
                            <data name="Prop_UInt8" inType="win:UInt8" />
                            <data name="Prop_Int16" inType="win:Int16" />
                            <data name="Prop_UInt16" inType="win:UInt16" />
                            <data name="Prop_Int32" inType="win:Int32" />
                            <data name="Prop_UInt32" inType="win:UInt32" />
                            <data name="Prop_Int64" inType="win:Int64" />
                            <data name="Prop_UInt64" inType="win:UInt64" />
                            <data name="Prop_Float" inType="win:Float" />
                            <data name="Prop_Double" inType="win:Double" />
                            <data name="Prop_Boolean" inType="win:Boolean" />
                            <data name="Prop_GUID" inType="win:GUID" />
                            <data name="Prop_Pointer" inType="win:Pointer" />
                            <data name="Prop_FILETIME" inType="win:FILETIME" />
                            <data name="Prop_SYSTEMTIME" inType="win:SYSTEMTIME" />
                            <data name="Prop_SID_Length" inType="win:UInt32" />
                            <data name="Prop_SID" inType="win:SID" length="Prop_SID_Length"/>
                            <data name="Prop_Binary" inType="win:Binary" length="11" />
                                <MyEvent2 xmlns="myNs">
                                    <Prop_UnicodeString> %1 </Prop_UnicodeString>
                                    <Prop_AnsiString> %2 </Prop_AnsiString>
                                    <Prop_Int8> %3 </Prop_Int8>
                                    <Prop_UInt8> %4 </Prop_UInt8>
                                    <Prop_Int16> %5 </Prop_Int16>
                                    <Prop_UInt16> %6 </Prop_UInt16>
                                    <Prop_Int32> %7 </Prop_Int32>
                                    <Prop_UInt32> %8 </Prop_UInt32>
                                    <Prop_Int64> %9 </Prop_Int64>
                                    <Prop_UInt64> %10 </Prop_UInt64>
                                    <Prop_Float> %11 </Prop_Float>
                                    <Prop_Double> %12 </Prop_Double>
                                    <Prop_Boolean> %13 </Prop_Boolean>                                
                                    <Prop_GUID> %14 </Prop_GUID>
                                    <Prop_Pointer> %15 </Prop_Pointer>
                                    <Prop_FILETIME> %16 </Prop_FILETIME>
                                    <Prop_SYSTEMTIME> %17 </Prop_SYSTEMTIME>
                                    <Prop_SID_Length> %18 </Prop_SID_Length>
                                    <Prop_SID> %19 </Prop_SID>
                                    <Prop_Binary> %20 </Prop_Binary>
                    <!--All the Events that can be published by this Publisher -->
                        <event value="1" 
            <resources culture="en-US">
                    <!--This is how event data can be used as part of Message String -->
                    <string id="Publisher.EventMessage" 
  3. Use the Message Compiler (MC.exe) on the manifest to generate a header and binary resource files.

    MC.exe is used to produce development files which are required for compiling the source files that raise events. If MC.exe is used on the instrumentation manifest ( in the Instrumentation Manifests for Event Publishers topic, then the following Publisher.h file is generated.

    The Publisher.h header file contains an EVENT_DESCRIPTOR variable definition that was defined in the instrumentation manifest. This variable will be used in the EventWrite function call to publish the event.

    // publisher.h
    #pragma once
    __declspec(selectany) GUID MICROSOFT_SAMPLE_PUBLISHER = {0x1db28f2e, 0x8f80, 0x4027, {0x8c, 0x5a,0xa1,0x1f,0x7f,0x10,0xf6,0x2d}};
    #define SAMPLE_PUBLISHER 0x10
    __declspec(selectany) EVENT_DESCRIPTOR PROCESS_INFO_EVENT = {0x1, 0x0, 0x10, 0x4, 0x0, 0x0, 0x8000000000000000};
    #define MSG_Publisher_EventMessage       0x00000000L
    // end of publisher.h
  4. Write code to raise the events.

    The following C++ code example shows how to raise an event defined in an event publisher. The Publisher.h file included at the top of the code is generated by MC.exe from the manifest; assuming that the manifest is named

    // publisher.cpp
    #include <windows.h>
    #include <comdef.h>
    #include <sddl.h>
    #include <iostream>
    #include <tchar.h>
    #include <string>
    #include <vector>
    #include <evntprov.h>           // ETW Publishing header
    # pragma comment(lib, "advapi32.lib")
    #include <winevt.h>             // EventLog Header.
    # pragma comment(lib, "wevtapi.lib") 
    #include "publisher.h"    // Header genearted by mc.exe
                              // from manifest (
    using namespace std;
    void __cdecl wmain()
        REGHANDLE hPublisher = NULL;    //Handle to Publisher
        wprintf(L"Publishing Event to Microsoft-Windows-EventLogSamplePublisher/Operational Channel... \n");
        // Register a Publisher
        ULONG ulResult = EventRegister( 
        &MICROSOFT_SAMPLE_PUBLISHER,       // provider guid
            NULL,                          // callback; unused for now
            NULL,                          // context
            &hPublisher);                  // handle required to unregister
        if ( ulResult != ERROR_SUCCESS) 
            wprintf(L"Publisher Registration Failed!. Error = 0x%x", ulResult);
        // EventData
        std::vector<EVENT_DATA_DESCRIPTOR> EventDataDesc;
        // inType="win:UnicodeString"
        PWSTR pws = L"Sample Unicode string";
        EventDataDescCreate(&EvtData, pws, ((ULONG)wcslen(pws)+1)*sizeof(WCHAR));
        EventDataDesc.push_back( EvtData );
        // inType="win:AnsiString"
        CHAR * ps = "Sample ANSI string";
        EventDataDescCreate(&EvtData, ps, ((ULONG)strlen(ps)+1)*sizeof(CHAR));
        EventDataDesc.push_back( EvtData );
        // inType="win:Int8"
        INT8 i8 = 0x7F;
        EventDataDescCreate(&EvtData, &i8, sizeof(i8));
        EventDataDesc.push_back( EvtData );
        // inType="win:UInt8"
        UINT8 ui8 = 0xFF;
        EventDataDescCreate(&EvtData, &ui8, sizeof(ui8));
        EventDataDesc.push_back( EvtData );
        // inType="win:Int16"
        INT16 i16 = 0x7FFF;
        EventDataDescCreate(&EvtData, &i16, sizeof(i16));
        EventDataDesc.push_back( EvtData );
        // inType="win:UInt16"
        UINT16 ui16 = 0xFFFF;
        EventDataDescCreate(&EvtData, &ui16, sizeof(ui16));
        EventDataDesc.push_back( EvtData );
        // inType="win:Int32"
        INT32 i32 = 0x7FFFFFFF;
        EventDataDescCreate(&EvtData, &i32, sizeof(i32));
        EventDataDesc.push_back( EvtData );
        // inType="win:UInt32"
        UINT32 ui32 = 0xFFFFFFFF;
        EventDataDescCreate(&EvtData, &ui32, sizeof(ui32));
        EventDataDesc.push_back( EvtData );
        // inType="win:Int64"
        INT64 i64 = 0x7FFFFFFFFFFFFFFFi64;
        EventDataDescCreate(&EvtData, &i64, sizeof(i64));
        EventDataDesc.push_back( EvtData );
        // inType="win:UInt64"
        UINT64 ui64 = 0xFFFFFFFFFFFFFFFFui64;
        EventDataDescCreate(&EvtData, &ui64, sizeof(ui64));
        EventDataDesc.push_back( EvtData );
        // inType="win:Float"
        FLOAT f = -3.1415926e+23f;
        EventDataDescCreate(&EvtData, &f, sizeof(f));
        EventDataDesc.push_back( EvtData );
        // inType="win:Double"
        DOUBLE d = -2.7182818284590452353602874713527e-101;
        EventDataDescCreate(&EvtData, &d, sizeof(d));
        EventDataDesc.push_back( EvtData );
        // inType="win:Boolean"
        BOOL b = TRUE;
        EventDataDescCreate(&EvtData, &b, sizeof(b));
        EventDataDesc.push_back( EvtData );
        // inType="win:GUID"
        GUID guid;  
        EventDataDescCreate(&EvtData, &guid, sizeof(guid));
        EventDataDesc.push_back( EvtData );
        // inType="win:Pointer"
        PVOID p = NULL;
        EventDataDescCreate(&EvtData, &p, sizeof(p));
        EventDataDesc.push_back( EvtData );
        // inType="win:FILETIME"
        SYSTEMTIME st;
        FILETIME ft;
        SystemTimeToFileTime(&st, &ft);
        EventDataDescCreate(&EvtData, &ft, sizeof(ft));
        EventDataDesc.push_back( EvtData );
        // inType="win:SYSTEMTIME"
        EventDataDescCreate(&EvtData, &st, sizeof(st));
        EventDataDesc.push_back( EvtData );
        // inType="win:SID"
        PSID pSid = NULL;
        ConvertStringSidToSidW(L"S-1-5-19", &pSid); // LocalService
        UINT32 sidLength = GetLengthSid(pSid);
        EventDataDescCreate(&EvtData, &sidLength, sizeof(sidLength));
        EventDataDesc.push_back( EvtData );
        EventDataDescCreate(&EvtData, pSid, GetLengthSid(pSid));
        EventDataDesc.push_back( EvtData );
        // inType="win:Binary"
        // Note: if you change the size of this array 
        // you'll have to change the
        // "length" attribute in the manifest too.
        BYTE ab[] = {0,1,2,3,4,5,4,3,2,1,0};
        EventDataDescCreate(&EvtData, ab, sizeof(ab));
        EventDataDesc.push_back( EvtData );
        if ( EventEnabled(hPublisher, &PROCESS_INFO_EVENT) ) 
            ulResult = EventWrite(hPublisher,
            if (ulResult != ERROR_SUCCESS) 
                //Get Extended Error Information
                wprintf(L"EvtWrite Failed. Not able to fire event. Error = 0x%x", ulResult);
                //Close the Publisher Handle
        else {
        //Close the Publisher Handle
    // end of publisher.cpp
  5. Compile and link your event publisher source code.

    The resource script that is generated by the Message Compiler tool is included in the resource script of the program built, and the result is compiled by the Resource Compiler (RC.exe) tool to produce .res files. These files are then linked into a project binary during its link phase (using CL.exe or Link.exe).

    The commands for this step are as follows:

    • rc.exe publisher.rc
    • cl.exe publisher.cpp /link publisher.res

    The Publisher.cpp file is shown in the preceding example (it includes the generated Publisher.h). The Publisher.res file is the resource file generated from the Publisher.rc file.

  6. (Optional) Localize the event publisher event messages.

    The event messages defined in the event manifest can be localized (written in different languages). This is done by adding the localized strings to the localization element of the instrumentation manifest.

  7. Deploy the publisher files.

    Publisher files, including the manifest, must be installed on the target system. You install the manifest using the Wevtutil.exe utility.

    wevtutil install-manifest

    This command is normally limited to members of the Administrators group and must be run with elevated privileges.

Send comments about this topic to Microsoft

Build date: 5/7/2009

Community Additions