Reading in Crimson Logs

Crimson logs can be read in through c# by use of some bindings to the APIs.  Crimson is a new logging protocol in Windows Vista.

I will start by including all the bindings to the actual apis, then talk about the specific classes than can wrap around them to get useful information out of Crimson.

This has all the crimson functions divided up into sections, when I go through each part of the session I will talk about what Crimson can support for the various types of logging.

///////////////////////////////////////////////////////////////////////////
///
/// <summary>
/// CrimsonEventLog: The structures and functions using P/Invoke for
/// accessing the CrimsonEventLog (Crimson).
/// </summary>
///
///////////////////////////////////////////////////////////////////////////
internal static class CrimsonEventLog
{
    //-----------------------------------------------------------------

    #region Cluster channels

    internal const string ClusterChannelRoot = "Microsoft-Windows-FailoverClustering";
    internal const string ClusterChannelAdmin = "Microsoft-Windows-FailoverClustering/Admin";
    internal const string ClusterChannelOperational = "Microsoft-Windows-FailoverClustering/Operational";

    #endregion

    //-----------------------------------------------------------------

    #region Utility routines

    [DllImport("wevtapi.dll", EntryPoint = "EvtClose",
                             CallingConvention = CallingConvention.Winapi,
                             SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool EventClose(IntPtr handlePtr);

#if DEBUG_TEST
    [DllImport( "wevtapi.dll", EntryPoint = "EvtGetExtendedStatus",
                             CallingConvention = CallingConvention.Winapi,
                             CharSet = CharSet.Auto,
                             SetLastError = true )]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool EventGetExtendedStatus( int size,
                                                     StringBuilder buffer,
                                                 ref int charsWritten );
#endif

    #endregion

    //-----------------------------------------------------------------

    #region Session routines

    public enum EventLoginClass
    {
        EvtRpcLogin = 1
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct EventRPCLogin
    {
        // all str params are optional
        internal String server;
        internal String user;
        internal String domain;
        internal String password;
        internal Int32 flags; // currently must be 0.
    }

    [DllImport("wevtapi.dll", EntryPoint = "EvtOpenSession",
                             CallingConvention = CallingConvention.Winapi,
                             CharSet = CharSet.Auto,
                             SetLastError = true)]
    public static extern IntPtr EventOpenSession(EventLoginClass loginClass,
                                             ref EventRPCLogin Login,
                                                 int timeout,
                                                 int flags);

    #endregion

    //-----------------------------------------------------------------

    #region Log Maintence routines
    [DllImport("wevtapi.dll", EntryPoint = "EvtClearLog",
                             CallingConvention = CallingConvention.Winapi,
                             CharSet = CharSet.Auto,
                             SetLastError = true)]
    public static extern bool EventClearLog(EventSafeHandle sessionHandle,
                                             string path,
                                             string targetPath,
                                             int flags);

    public enum EventExportLogFlags
    {
        ChannelPath = 1,
        LogFilePath = 2
    };

    [DllImport("wevtapi.dll", EntryPoint = "EvtExportLog",
                             CallingConvention = CallingConvention.Winapi,
                             CharSet = CharSet.Auto,
                             SetLastError = true)]
    public static extern bool EventExportLog(EventSafeHandle sessionHandle,
                                             string path,
                                             string query,
                                             string targetPath,
                                             [MarshalAs(UnmanagedType.I4)]EventExportLogFlags flags);

    [DllImport("wevtapi.dll", EntryPoint = "EvtArchiveExportedLog",
                     CallingConvention = CallingConvention.Winapi,
                     CharSet = CharSet.Auto,
                     SetLastError = true)]
    public static extern bool EventArchiveLog(EventSafeHandle sessionHandle,
                                             string path,
                                             int lcid,
                                             int flags);

    public enum EventLogOpenFlags
    {
        ChannelPath = 1,
        FilePath = 2
    };

    [DllImport("wevtapi.dll", EntryPoint = "EvtOpenLog",
             CallingConvention = CallingConvention.Winapi,
             CharSet = CharSet.Auto,
             SetLastError = true)]
    public static extern IntPtr EventOpenLog(EventSafeHandle sessionHandle,
                                             string path,
                                             [MarshalAs(UnmanagedType.I4)]EventLogOpenFlags flags);

    public enum EventLogPropertyId
    {
        CreationTime = 0,
        LastAccessTime = 1,
        LastWriteTime = 2,
        FileSize = 3,
        Attributes = 4,
        NumberOfLogRecords = 5,
        OldestRecordNumber = 6,
        Full = 7
    };

    [DllImport("wevtapi.dll", EntryPoint = "EvtGetLogInfo",
             CallingConvention = CallingConvention.Winapi,
             CharSet = CharSet.Auto,
             SetLastError = true)]
    public static extern bool EventGetLogInfo(EventSafeHandle logHandle,
                                             [MarshalAs(UnmanagedType.I4)]EventLogPropertyId propId,
                                             int bufferSize,
                                             ref EventVariant propertyValueBuffer,
                                             ref int propertyValueBufferUsed);

    #endregion

    //-----------------------------------------------------------------

    #region Subscription routines

    public enum EventSubscribeFlags
    {
        EvtSubscribeToFutureEvents = 0x1,
        EvtSubscribeStartAtOldestRecord = 0x2,
        EvtSubscribeStartAfterBookmark = 0x3,
        EvtSubscribeInternal = 0x4
    }

    public enum EventSubscribeNotifyAction
    {
        EvtSubscribeActionError = 0x0,
        EvtSubscribeActionDeliver = 0x1
    }

    public enum EventEventPropertyId
    {
        EvtEventQueryIDs = 0x0,
        EvtEventPath = 0x1
    }

    public delegate Int32 EventSubscribeCallback([MarshalAs(UnmanagedType.I4)]EventSubscribeNotifyAction action,
                                                    IntPtr context,
                                                    IntPtr eventPtr);

    [DllImport("wevtapi.dll", EntryPoint = "EvtSubscribe",
                             CallingConvention = CallingConvention.Winapi,
                             CharSet = CharSet.Auto,
                             SetLastError = true)]
    public static extern IntPtr EventSubscribe(EventSafeHandle sessionHandle,
                                                IntPtr signalEvent,
                                                String channelPath,
                                                String query,
                                                IntPtr bookMark,
                                                IntPtr context,
                                                [MarshalAs(UnmanagedType.I4)]EventSubscribeCallback eventCallback,
                                                int flags);

    #endregion

    //-----------------------------------------------------------------

    #region Query routines

    public enum EventQueryFlags
    {
        EvtQueryChannelPath = 0x1,
        EvtQueryFilePath = 0x2,
        EvtQueryForwardDirection = 0x100,
        EvtQueryReverseDirection = 0x200,
    }

    [DllImport("wevtapi.dll", EntryPoint = "EvtQuery", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr EventQuery(
        EventSafeHandle sessionHandle,
        String path,
        String query,
        [MarshalAs(UnmanagedType.I4)]EventQueryFlags flags);

    [DllImport("wevtapi.dll", EntryPoint = "EvtNext", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool EventNext(
        EventSafeHandle resultSet,
        int eventsSize,
        IntPtr[] events,
        int timeout,
        int flags,
        ref int returned);

    #endregion

    //-----------------------------------------------------------------

    #region Channel enumeration routines

    [DllImport("wevtapi.dll", EntryPoint = "EvtOpenChannelEnum", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr EventOpenChannelEnum(
        EventSafeHandle session,
        int flags);

    [DllImport("wevtapi.dll", EntryPoint = "EvtNextChannelPath", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool EventNextChannelPath(
        EventSafeHandle channelEnum,
        int channelPathBufferSize,
        StringBuilder channelPathBuffer,
        out int channelPathBufferUsed);

    #endregion

    //-----------------------------------------------------------------

    #region Channel config routines

    public enum ChannelConfigPropertyID
    {
        ChannelConfigEnabled = 0,
        ChannelConfigIsolation = 1,
        ChannelConfigType = 2,
        ChannelConfigIsClassicChannel = 3,
        ChannelConfigAccess = 4,
        ChannelLoggingConfigRetention = 5,
        ChannelLoggingConfigAutoBackup = 6,
        ChannelLoggingConfigMaxSize = 7,
        ChannelLoggingConfigLogFilePath = 8,
        ChannelPublishingConfigLevel = 9,
        ChannelPublishingConfigKeywords = 10,
        ChannelPublishingConfigControlGuid = 11,
        ChannelConfigPropertyIdEND
    };

    public enum ChannelType
    {
        Admin = 0,
        Operational = 1,
        Analytic = 2,
        Debug = 3,
        Unknown = 4
    };

    [DllImport("wevtapi.dll", EntryPoint = "EvtOpenChannelConfig", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern IntPtr EventOpenChannelConfig(
        EventSafeHandle session,
        string channelPath,
        int flags);

    [DllImport("wevtapi.dll", EntryPoint = "EvtGetChannelConfigProperty", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool EventGetChannelConfigProperty(
        EventSafeHandle channelConfig,
        [MarshalAs(UnmanagedType.I4)]ChannelConfigPropertyID propertyId,
        int flags,
        int propertyValueBufferSize,
        ref EventVariant propertyValueBuffer,
        out int propertyValueBufferUsed);

    [DllImport("wevtapi.dll", EntryPoint = "EvtSetChannelConfigProperty", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool EventSetChannelConfigProperty(
        EventSafeHandle channelConfig,
        [MarshalAs(UnmanagedType.I4)]ChannelConfigPropertyID propertyId,
        int flags,
        ref EventVariant propertyValueBuffer);

    [DllImport("wevtapi.dll", EntryPoint = "EvtSaveChannelConfig", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool EventSaveChannelConfig(
        EventSafeHandle channelConfig,
        int Flags
        );
    #endregion

    //-----------------------------------------------------------------

    #region Rendering routines

    public enum EventRenderContextFlags
    {
        EvtRenderContextValues = 0x0, // Render specific properties
        EvtRenderContextSystem = 0x1,    // Render all system properties (System)
        EvtRenderContextUser = 0x2     // Render all user properties (User/EventData)
    }

    public enum EventRenderFlags
    {
        EvtRenderEventValues = 0x0,     // Variants
        EvtRenderEventXml = 0x1,         // System properties, ForwardingInfo, User/EventData
        EvtRenderBookmark = 0x2
    }

    [DllImport("wevtapi.dll", EntryPoint = "EvtCreateRenderContext",
                             CallingConvention = CallingConvention.Winapi,
                             CharSet = CharSet.Auto,
                             SetLastError = true)]
    public static extern IntPtr EventCreateRenderContext(Int32 countOfValues,
                                                         String[] valuePaths,
                                                         Int32 flags);

    [DllImport("wevtapi.dll", EntryPoint = "EvtRender",
                             CallingConvention = CallingConvention.Winapi,
                             CharSet = CharSet.Auto,
                             SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool EventRender(IntPtr context,
                                         PushEventHandle eventHandle,
                                         int flags,
                                         int buffSize,
                                         byte[] buffer,
                                     ref int buffUsed,
                                     ref int propCount);

#if DEBUG_TEST

    [DllImport( "wevtapi.dll", EntryPoint = "EvtRender",
                             CallingConvention = CallingConvention.Winapi,
                             CharSet = CharSet.Auto,
                             SetLastError = true )]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool EventRender( IntPtr context,
                                         PushEventHandle eventHandle,
                                         int flags,
                                         int buffSize,
                                         StringBuilder buffer,
                                     ref int buffUsed,
                                     ref int propCount );

#endif

    #endregion

    //-----------------------------------------------------------------

    #region Formatting routines

    public enum EventFormatMessageFlags
    {
        EvtFormatMessageEvent = 0x1,
        EvtFormatMessageLevel = 0x2,
        EvtFormatMessageTask = 0x3,
        EvtFormatMessageOpcode = 0x4,
        EvtFormatMessageKeyword = 0x5
    }

    [DllImport("wevtapi.dll", EntryPoint = "EvtFormatMessage",
                     CallingConvention = CallingConvention.Winapi,
                     CharSet = CharSet.Auto,
                     SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool EventFormatMessage(EventSafeHandle publisherHandle,
                                                 PushEventHandle eventHandle,
                                                 int messageId,
                                                 int valueCount,
                                                 [In] byte[] valueBuffer,
                                                 int flags,
                                                 int buffSize,
                                                 StringBuilder buffer,
                                             ref int buffUsed);
#endregion

    //-----------------------------------------------------------------

    #region Publisher routines
    internal enum EventPublisherMetadataId
    {
        EvtPublisherMetadataPublisherGuid = 0,     // EvtVarTypeGuid
        EvtPublisherMetadataResourceFilePath,     // EvtVarTypeString
        EvtPublisherMetadataParameterFilePath,     // EvtVarTypeString
        EvtPublisherMetadataMessageFilePath,        // EvtVarTypeString
        EvtPublisherMetadataHelpLink,             // EvtVarTypeString
        EvtPublisherMetadataPublisherMessageID,     // EvtVarTypeUInt32

        EvtPublisherMetadataChannelReferences,     // EvtVarTypeEvtHandle, ObjectArray
        EvtPublisherMetadataChannelReferencePath, // EvtVarTypeString
        EvtPublisherMetadataChannelReferenceIndex, // EvtVarTypeUInt32
        EvtPublisherMetadataChannelReferenceID,     // EvtVarTypeUInt32
        EvtPublisherMetadataChannelReferenceFlags, // EvtVarTypeUInt32
        EvtPublisherMetadataChannelReferenceMessageID, // EvtVarTypeUInt32

        EvtPublisherMetadataLevels,                 // EvtVarTypeEvtHandle, ObjectArray
        EvtPublisherMetadataLevelName,             // EvtVarTypeString
        EvtPublisherMetadataLevelValue,             // EvtVarTypeUInt32
        EvtPublisherMetadataLevelMessageID,         // EvtVarTypeUInt32

        EvtPublisherMetadataTasks,                 // EvtVarTypeEvtHandle, ObjectArray
        EvtPublisherMetadataTaskName,             // EvtVarTypeString
        EvtPublisherMetadataTaskEventGuid,         // EvtVarTypeGuid
        EvtPublisherMetadataTaskValue,             // EvtVarTypeUInt32
        EvtPublisherMetadataTaskMessageID,         // EvtVarTypeUInt32

        EvtPublisherMetadataOpcodes,                // EvtVarTypeEvtHandle, ObjectArray
        EvtPublisherMetadataOpcodeName,             // EvtVarTypeString
        EvtPublisherMetadataOpcodeValue,            // EvtVarTypeUInt32
        EvtPublisherMetadataOpcodeMessageID,        // EvtVarTypeUInt32

        EvtPublisherMetadataKeywords,             // EvtVarTypeEvtHandle, ObjectArray
        EvtPublisherMetadataKeywordName,            // EvtVarTypeString
        EvtPublisherMetadataKeywordValue,         // EvtVarTypeUInt64
        EvtPublisherMetadataKeywordMessageID,     // EvtVarTypeUInt32
    };

    [DllImport("wevtapi.dll", EntryPoint = "EvtOpenPublisherMetadata",
             CallingConvention = CallingConvention.Winapi,
             CharSet = CharSet.Auto,
             SetLastError = true)]
    public static extern IntPtr EventOpenPublisherMetadata(EventSafeHandle sessionHandle,
                                                            string publisherId,
                                                            string logFilePath,
                                                            int locale,
                                                            int flags);

    [DllImport("wevtapi.dll", EntryPoint = "EvtGetPublisherMetadataProperty",
             CallingConvention = CallingConvention.Winapi,
             CharSet = CharSet.Auto,
             SetLastError = true)]
    public static extern bool EventGetPublisherMetadataProperty(
        EventSafeHandle publisherHandle,
        [MarshalAs(UnmanagedType.I4)]EventPublisherMetadataId propId,
        int flags,
        int buffsize,
        ref EventVariant buffer,
        ref int buffUsed);

    [DllImport("wevtapi.dll", EntryPoint = "EvtGetObjectArraySize",
             CallingConvention = CallingConvention.Winapi,
             CharSet = CharSet.Auto,
             SetLastError = true)]
    public static extern bool EventGetObjectArraySize(PushEventHandle arrayHandle,
                                                         ref int count);

    [DllImport("wevtapi.dll", EntryPoint = "EvtGetObjectArrayProperty",
             CallingConvention = CallingConvention.Winapi,
             CharSet = CharSet.Auto,
             SetLastError = true)]
    public static extern bool EventGetObjectArrayProperty(
        PushEventHandle arrayHandle,
        [MarshalAs(UnmanagedType.I4)]EventPublisherMetadataId propId,
        int arrayIndex,
        int flags,
        int buffSize,
        ref EventVariant buffer,
        ref int buffUsed);

    [DllImport("wevtapi.dll", EntryPoint = "EvtGetObjectArrayProperty",
             CallingConvention = CallingConvention.Winapi,
             CharSet = CharSet.Auto,
             SetLastError = true)]
    public static extern bool EventGetObjectArrayProperty(
        PushEventHandle arrayHandle,
        [MarshalAs(UnmanagedType.I4)]EventPublisherMetadataId propId,
        int arrayIndex,
        int flags,
        int buffSize,
        ref EventVariantString buffer,
        ref int buffUsed);
    #endregion

    //-----------------------------------------------------------------

    #region Variant structures

    public enum EventVariantType
    {
        EvtVarTypeNull = 0,
        EvtVarTypeString = 1,
        EvtVarTypeAnsiString = 2,
        EvtVarTypeSByte = 3,
        EvtVarTypeByte = 4,
        EvtVarTypeInt16 = 5,
        EvtVarTypeUInt16 = 6,
        EvtVarTypeInt32 = 7,
        EvtVarTypeUInt32 = 8,
        EvtVarTypeInt64 = 9,
        EvtVarTypeUInt64 = 10,
        EvtVarTypeSingle = 11,
        EvtVarTypeDouble = 12,
        EvtVarTypeBoolean = 13,
        EvtVarTypeBinary = 14,
        EvtVarTypeGuid = 15,
        EvtVarTypeSizeT = 16,
        EvtVarTypeFileTime = 17,
        EvtVarTypeSysTime = 18,
        EvtVarTypeSid = 19,
        EvtVarTypeHexInt32 = 20,
        EvtVarTypeHexInt64 = 21,

        // These types used internally
        EvtVarTypeEvtHandle = 32,
        EvtVarTypeEvtXml = 35
    }

    public enum EventVariantTypeMask
    {
        EvtVarTypeMask = 0x7f,
        EvtVarTypeArray = 128
    }

    //Commenting some members to reduce the number
    // of fxcop errors
    [ComVisible(false)]
    [StructLayout(LayoutKind.Explicit)]
    unsafe public struct EventVariant
    {
        [FieldOffset(0)]
        public int BooleanVal;
        [FieldOffset(0)]
        public sbyte SByteVal;
        [FieldOffset(0)]
        public Int16 Int16Val;
        [FieldOffset(0)]
        public Int32 Int32Val;
        [FieldOffset(0)]
        public Int64 Int64Val;
        [FieldOffset(0)]
        public byte ByteVal;
        [FieldOffset(0)]
        public UInt16 UInt16Val;
        [FieldOffset(0)]
        public UInt32 UInt32Val;
        [FieldOffset(0)]
        public UInt64 UInt64Val;
        [FieldOffset(0)]
        public float SingleVal;
        [FieldOffset(0)]
        public double DoubleVal;
        [FieldOffset(0)]
        public UInt64 FileTimeVal;
        [FieldOffset(0)]
        public UInt64 SysTimeVal;
        [FieldOffset(0)]
        public IntPtr ByteArr;

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
        [FieldOffset(0)]
        public IntPtr StringVal;

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
        [FieldOffset(0)]
        public IntPtr SidVal;

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
        [FieldOffset(0)]
        public IntPtr EvtHandleVal;

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
        [FieldOffset(8)]
        public int ItemCount; // number of elements (not length) in bytes.
        [FieldOffset(12)]
        public int Type;
    }

    /// <summary>
    /// Use this structure to deal with variants that require strings.
    /// </summary>
    [ComVisible(false)]
    [StructLayout(LayoutKind.Explicit)]
    unsafe public struct EventVariantString
    {
        [FieldOffset(0)]
        public EventVariant var;
        [FieldOffset(16)]
        public fixed byte data[2000];
    }
    #endregion

    //-----------------------------------------------------------------
}