'' -----------------------------------------------------------------------------
'' Copyright (c) Microsoft Corporation. All rights reserved.
'' -----------------------------------------------------------------------------
Imports System.Runtime.InteropServices
Namespace ____DiagHubTrace
Friend NotInheritable Class DiagHubTrace : Implements IDisposable
Public Shared DiagHubProviderId As Guid = New Guid("F9189F8A-0753-4A70-AD66-D622D88DB986")
Public Shared FirstValidId As UShort = 1
Public Shared MaxValidId As UShort = &H7FFF
Private Const SuccessErrorCode As Integer = 0
' The max size limit of an ETW payload is 64k, but that includes the header.
' We take off a bit for ourselves.
Private Const MaxMsgSizeInBytes As Integer = 63 * 1024
Private regHandle As Long
Private started As Boolean = False
'''
''' Initializes a new instance of the class.
'''
Public Sub New()
Me.Initialize()
End Sub
'''
''' Insert mapping from ID to name
'''
''' ID to name
''' Name of ID
Public Sub DefineIdName(id As UShort, name As String)
If (Me.started) Then
Debug.Assert(id <= MaxValidId, "Invalid ID")
Me.FireUserEventIdNameMap(id, name)
End If
End Sub
'''
''' Insert mark into the collection stream
'''
''' ID of mark
Public Sub InsertMark(id As UShort)
If (Me.started) Then
Debug.Assert(FirstValidId <= id And id <= MaxValidId, "Invalid ID")
Me.FireUserEventWithString(id, Nothing)
End If
End Sub
'''
''' Insert mark with message into the collection stream
'''
''' ID of mark
''' Message of mark
Public Sub InsertMarkWithMessage(id As UShort, message As String)
If (Me.started) Then
Debug.Assert(FirstValidId <= id And id <= MaxValidId, "Invalid ID")
Me.FireUserEventWithString(id, message)
End If
End Sub
'''
''' Insert message into the collection stream
'''
''' Message to insert
Public Sub InsertMessage(message As String)
If (Me.started) Then
Me.FireUserEventWithString(0, message)
End If
End Sub
'''
Public Sub Dispose() Implements IDisposable.Dispose
Me.Shutdown()
End Sub
Private Sub Initialize()
Dim localId As Guid = DiagHubTrace.DiagHubProviderId
If (SuccessErrorCode = NativeMethods.EventRegister(localId, IntPtr.Zero, IntPtr.Zero, Me.regHandle)) Then
Me.started = True
End If
End Sub
Private Sub Shutdown()
If (Me.started) Then
Me.started = False
NativeMethods.EventUnregister(Me.regHandle)
End If
End Sub
Private Sub FireUserEventIdNameMap(id As UShort, name As String)
Debug.Assert(id <= MaxValidId, "Invalid ID")
Debug.Assert(name Is Nothing And (2 * name.Length) < MaxMsgSizeInBytes, "Invalid string argument")
Dim evtDesc As NativeMethods.EVENT_DESCRIPTOR = New NativeMethods.EVENT_DESCRIPTOR With
{
.Id = &HFFFF,
.Version = 1,
.Channel = 0,
.Level = 4, ' TRACE_LEVEL_INFORMATION
.Opcode = 0,
.Task = 0,
.Keyword = 1
}
Dim idPinned As GCHandle = GCHandle.Alloc(id, GCHandleType.Pinned)
Dim nameLenInBytes = 2 * (name.Length + 1)
Dim namePinned = GCHandle.Alloc(name, GCHandleType.Pinned)
Dim userData(2) As NativeMethods.EVENT_DATA_DESCRIPTOR
userData(0).DataPointer = idPinned.AddrOfPinnedObject().ToInt64()
userData(0).Size = Len(id)
userData(1).DataPointer = namePinned.AddrOfPinnedObject().ToInt64()
userData(1).Size = nameLenInBytes
Dim userDataPinned = GCHandle.Alloc(userData, GCHandleType.Pinned)
NativeMethods.EventWrite(Me.regHandle, evtDesc, userData.Length, userDataPinned.AddrOfPinnedObject().ToInt64())
userDataPinned.Free()
namePinned.Free()
idPinned.Free()
End Sub
Private Sub FireUserEventWithString(id As UShort, message As String)
Debug.Assert(id <= MaxValidId, "Invalid ID")
Dim evtDesc As NativeMethods.EVENT_DESCRIPTOR = New NativeMethods.EVENT_DESCRIPTOR With
{
.Id = id,
.Version = 1,
.Channel = 0,
.Level = 4, ' TRACE_LEVEL_INFORMATION
.Opcode = 0,
.Task = 0,
.Keyword = 1
}
Dim nameLenInBytes = If(message Is Nothing, 0, 2 * (message.Length + 1))
Debug.Assert(nameLenInBytes < MaxMsgSizeInBytes, "Invalid DiagHub mark")
Dim msgPinned = GCHandle.Alloc(message, GCHandleType.Pinned)
Dim userData As NativeMethods.EVENT_DATA_DESCRIPTOR = New NativeMethods.EVENT_DATA_DESCRIPTOR With
{
.DataPointer = msgPinned.AddrOfPinnedObject().ToInt64(),
.Size = nameLenInBytes
}
Dim userDataPinned = GCHandle.Alloc(userData, GCHandleType.Pinned)
NativeMethods.EventWrite(Me.regHandle, evtDesc, 1, userDataPinned.AddrOfPinnedObject().ToInt64())
userDataPinned.Free()
msgPinned.Free()
End Sub
Private Class NativeMethods
Public Shared Function EventRegister(
ByRef guid As Guid,
enableCallback As IntPtr,
callbackContext As IntPtr,
<[In]> ByRef regHandle As Long) As Integer
End Function
Public Shared Function EventWrite(
<[In]> regHandle As Long,
<[In]> ByRef evtDesc As EVENT_DESCRIPTOR,
<[In]> userDataCount As Int32,
<[In]> userData As IntPtr) As Integer
End Function
Public Shared Function EventUnregister(<[In]> regHandle As Long) As Integer
End Function
Public Structure EVENT_DESCRIPTOR
Public Id As UShort
Public Version As Byte
Public Channel As Byte
Public Level As Byte
Public Opcode As Byte
Public Task As UShort
Public Keyword As ULong
End Structure
Public Structure EVENT_DATA_DESCRIPTOR
Public DataPointer As Int64
Public Size As Int32
Public Reserved As Int32
End Structure
End Class
End Class
End Namespace