Event Logging in Windows
"Event Viewer" is one of the most frequently used application for developers. It's great to see all application writing debug information to a central location. What if you want your application to write to the Event Log to see it in this viewer.
The App object has a logevent method which can be utilised to achieve this.
App.LogEvent "The string containing message to be logged", < Error type >
error type above may be any of these
1 - Error event
2 - Warning event
4 - Information event
8 - Success Audit event
16- Failure Audit event
The event is logged with source mentioned as "VBRunTime". This method however has a drawback that App.LogEvent is not available in IDE, so doesnot log until you get it compiled and executed thereafter.
A full control on logging (even in IDE) can be achieved through ReportEvent function declared in advapi32.dll. To use it in your app you will need to declare it as below.
Declare Function ReportEvent Lib "advapi32.dll" Alias "ReportEventA" ( _
ByVal hEventLog As Long, _
ByVal wType As Integer, _
ByVal wCategory As Integer, _
ByVal dwEventID As Long, _
ByVal lpUserSid As Any, _
ByVal wNumStrings As Integer, _
ByVal dwDataSize As Long, _
plpStrings As Long, _
lpRawData As Any) As Boolean
hEventLog is handle to the event log you need to write to. You will need to use RegisterEventSource function to get this handle as described later.
wType is the type of event which may be :
1 - Error event
2 - Warning event
4 - Information event
8 - Success Audit event
16- Failure Audit event
wCategory is the category to further classify the events. The categories needs to be defined in a message file. Giving 0 for this parameter assigns "None" to category.
dwEventID is the Event Identifier. Each Application can choose to define its own Ids
lpUserID is the pointer to current user's security identifier. Can be Null if no identifier is required.
wNumStrings is the number of insert strings in the array pointed to by the lpStrings parameter.
dwDataSize is Number of bytes of event-specific raw (binary) data to write to the log. If this parameter is zero, no event-specific data is present.
lpStrings is the Pointer to a buffer containing an array of null-terminated strings that are merged into the message before Event Viewer displays the string to the user.
lpRawData is the Pointer to the buffer containing the binary data.
That's about ReportEvent. Now to get the first parameter hEventLog we will need to call RegisterEventSource function and DeregisterEventSource functions.
Declare Function RegisterEventSource Lib "advapi32.dll" Alias "RegisterEventSourceA" ( _
ByVal lpUNCServerName As String, _
ByVal lpSourceName As String) As Long
Declare Function DeregisterEventSource Lib "advapi32.dll" ( _
ByVal hEventLog As Long) As Long
RegisterEventSource retrieves the handle to specified event log and uses Application log if the source name is not found in the registry. DeregisterEventSource closes the write handle after the writing to log has completed.
lpUNCServerName specifies the UNC name of the server on which this operation is to be performed. Should be Null for Local Computer.
lpSourceName specifies the name of Event Source
hEventLog in DeregisterEventSource function is the handle to event log as retrieved from RegisterEventSource function.
That's all for above functions. Now the plpStrings parameter in ReportEvent function is the pointer to the buffer containing the Error MEssage to be logged. The intrinsic function StrPtr returns pointer to the first character of the string which itself is stored as a unicode string. Using it logs only the first charater as the Event logger stops logging after it encounters the Null character in unicode. In order to make function work properly we will need to call memory management functions defined in kernel32.dll
Declare Function GlobalAlloc Lib "kernel32" ( _
ByVal wFlags As Long, _
ByVal dwBytes As Long) As Long
Declare Function GlobalFree Lib "kernel32" ( _
ByVal hMem As Long) As Long
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
hpvDest As Any, _
hpvSource As Any, _
ByVal cbCopy As Long)
GlobalAlloc function allocates a buffer and return its pointer
wFlags is the memory allocation attribute.
0x0000 allocates fixed memory
0x0002 allocates movable memory
0x0040 allocates fixed memory and initialises memory contents to Zero
0x0042 allocates movable memory and initialises memory contents to Zero
dwBytes is the number of bytes to be allocated
GlobalFree function frees up the memory allocated
hMem is the pointer recieved from GlobalAlloc function
CopyMemory subroutine copies a block of memory from one location to another.
hpvDest is the pointer to destination buffer
hpvSource is the pointer to source buffer
cbCopy is the size in bytes.
Now that we are ready with all our requirements, lets create a Class Module in our project and name it "MyEventLogger" and copy the code below to it.
Private Declare Function ReportEvent Lib "advapi32.dll" Alias "ReportEventA" ( _
ByVal hEventLog As Long, _
ByVal wType As Integer, _
ByVal wCategory As Integer, _
ByVal dwEventID As Long, _
ByVal lpUserSid As Any, _
ByVal wNumStrings As Integer, _
ByVal dwDataSize As Long, _
plpStrings As Long, _
lpRawData As Any) As Boolean
Private Declare Function RegisterEventSource Lib "advapi32.dll" Alias "RegisterEventSourceA" ( _
ByVal lpUNCServerName As String, _
ByVal lpSourceName As String) As Long
Private Declare Function DeregisterEventSource Lib "advapi32.dll" ( _
ByVal hEventLog As Long) As Long
Private Declare Function GlobalAlloc Lib "kernel32" ( _
ByVal wFlags As Long, _
ByVal dwBytes As Long) As Long
Private Declare Function GlobalFree Lib "kernel32" ( _
ByVal hMem As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
hpvDest As Any, _
hpvSource As Any, _
ByVal cbCopy As Long)
Public Function LogEvent(sString As String, iLogType As Integer, iEventID As Long)
Dim iNumStrings As Integer
Dim hEventLog As Long
Dim hMsgs As Long
Dim cbStringSize As Long
hEventLog = RegisterEventSource("", App.Title)
cbStringSize = Len(sString) + 1
hMsgs = GlobalAlloc(&H0, cbStringSize)
CopyMemory ByVal hMsgs, ByVal sString, cbStringSize
iNumStrings = 1
LogEvent = ReportEvent(hEventLog, iLogType, 0, iEventID, 0&, 1, 0, hMsgs, Null)
GlobalFree hMsgs
DeregisterEventSource hEventLog
End Function
This class can be included with all your projects code similar to below can be added to utilise the Event Logging Capabilities of this class.
Dim elog As New MyEventLogger elog.LogEvent "Error/Warning/Information Message here", 1, 1
An event with your Application Title will be added to the Event Log and the message as passed above will get added to the Description of the event. Hope this post helps you in your projects.
Reference : Microsoft MSDN




May 24th, 2007 - 21:51
Hi, thanks for this info on logging events. This is a very good code sample.
I wanted to use this code to log events from Excel VBA. It’s working, but when I look at the event viewer (O/S WinServer 2003), the description is always prefixed with something like “The description for Event ID ( 65535 ) in Source ( blahblah ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer. You may be able to use the /AUXSOURCE= flag to retrieve this description; see Help and Support for details. The following information is part of the event: Test msg.”
Is there any way to remove this first description part? It totally obscures the message, to the point where I wonder if this is a good way to log stuff. Thank you!!
February 18th, 2008 - 11:31
I had the same ‘problem’ as Mercury.
Have gotten around it by creating a simple MessageDLL containing no categories and one message type (CategoryId 0, EventID 1).
I found the c++ code for this on http://www.codeproject.com/KB/system/eventlogging.aspx
You will have to connect this dll to your ‘source’ name in the event viewer. Code below links the dll to the source ‘Logger’, writeregistry is a wrapper module to write the registry (Created by E.Spencer)
Const MY_LOGGER_REG_PATH = “SYSTEM\CurrentControlSet\Services\Eventlog\Application\Logger”
WriteRegistry HKEY_LOCAL_MACHINE, MY_LOGGER_REG_PATH, “CategoryCount”, ValDWord, “1″
WriteRegistry HKEY_LOCAL_MACHINE, MY_LOGGER_REG_PATH, “CategoryMessageFile”, ValString, App.Path & “\MessageDLL.DLL”
WriteRegistry HKEY_LOCAL_MACHINE, MY_LOGGER_REG_PATH, “EventMessageFile”, ValString, App.Path & “\MessageDLL.DLL”
WriteRegistry HKEY_LOCAL_MACHINE, MY_LOGGER_REG_PATH, “File”, ValString, “%SystemRoot%\system32\config\Logger.evt”
WriteRegistry HKEY_LOCAL_MACHINE, MY_LOGGER_REG_PATH, “MaxSize”, ValDWord, “524288″
WriteRegistry HKEY_LOCAL_MACHINE, MY_LOGGER_REG_PATH, “TypesSupported”, ValDWord, “7″
March 16th, 2008 - 09:20
how to log in? this is a very unorganized competition…..
May 2nd, 2008 - 07:42
The first description part depend on EventID, let use 1 to have a custom description.
July 28th, 2008 - 13:03
Hi @ all,
how will I retrieve the contents of the event log – I am about to write some code to analyze past events and make some system statistics…
I guess that would be some peer routine of ‘ReportEvent’?
Thanks for your suggestions!