Next, Network Security Monitor calls function getnumberofeventlogrecords to
retrieve the number of entries in the log. The code that accomplishes this call
is at B. The handle returned by openeventlog is passed as the first parameter.
The second parameter returns the number of records in the open Event Log. The
program uses this number to set up a progress bar that shows relatively how much
of the Event Log you have read. If no records appear in the Event Log, an error
occurs, and the program displays a message box.
The code that reads through the event logs is at C. A loop reads the
security Event Log for the number of entries retrieved previously with function
getnumberofeventlogrecords. The program increments the progress bar each time
the read loop is executed. The program calls function readeventlog, which
retrieves data from the security Event Log. readeventlog's first parameter takes
the Event Log handle that the call to openeventlog obtained earlier. The second
parameter controls whether the program reads the Event Log forward or backward.
To display the most current event first, the program must read the security
Event Log backward (i.e., from most recent to least recent), so you use the
eventlog_backwards_read flag with the eventlog_seek_read flag, which shows where
the read will begin. In this case, the flag is at the beginning of the file
because of the value of the lreadrecordoffset parameter. The program uses the
third parameter with the eventlog_seek_read flag, and the third parameter
specifies where in the security Event Log the readeventlog function starts
reading. (If you set this parameter to 0, readeventlog starts reading from the
beginning of the log.) The fourth parameter is a pointer to a buffer that
contains data that readeventlog returns.
readeventlog's fifth parameter sets the number of bytes to read, and the
sixth parameter returns the number of bytes that the program actually read. You
can read more than one security Event Log entry per call, but for simplicity,
this example reads only one record at a time. However, there's a gotcha in
reading one entry at a time. Event Log records vary in length, so you can't use
a fixed value for the number of bytes. Therefore, the program attempts the first
read using an event entry's minimum length. If the return code shows that the
call failed due to insufficient buffer space, the program resizes the buffer
according to the value returned in the sixth parameter and reattempts the call
to function readeventlog. If the call is successful, subroutine
readservereventlog calls the Win32 rtlmovememory function to copy the Event Log
data from the buffer to a VB string. This API is part of the NT kernel. Its
purpose is to copy data from one memory location to another. For convenience,
I've declared the rtlmovememory API in both the netapi.bas file and the
eventlog.bas file. This configuration lets you easily apply the rtlmovememory
function in other projects that use either the NetBIOS APIs or the Event Log
APIs.
The data returned by readeventlog follows a predefined layout or structure,
as shown in Table 2. The first part of the returned data
uses a fixed format. In contrast, the second portion of the returned data varies
in length. The offset data in the beginning of the structure identifies the
location of the variable data. The returned data includes the time stamp, Event
ID, username, computer name, and string data that may contain an informational
message.
One point is important to know about reading the Event Log string data that
function readeventlog returns: The function doesn't return the same string data
you see in NT's Event Viewer. Instead, the string data returned by the API
contains substitution parameters that you must convert and reformat before they
are meaningful. The substitution parameters don't affect Network Security
Monitor because it looks for a specific type of event with known string data.
However, if you want to write a more sophisticated application that interprets
and displays more types of Event Log data than Network Security Monitor, your
program must read the Services key of the NT Registry to retrieve the name of
the eventmessages library. It contains the formatmessage function. Then your
program must load that library and call the formatmessage function to fill in
the substitution parameters for each string entry. (This extra step accommodates
internationalization of the string data.)
Powerful APIs
As you've seen, creating a useful VB utility is easy with just a few Win32
APIs. I didn't have to master complex system internals or network coding to
develop Network Security Monitor--only call some Win32 API functions. Although
using the APIs isn't hard, I suggest you use the Microsoft Developer Network CD
to learn about the API functions--as I did.
Although I wrote Network Security Monitor to search for one type of Event
Log entry, you can easily modify this program to look for different Event Log
entries or to read through the other event logs. Enjoy using Network Security
Monitor--and stay tuned for more VB Solutions!
Editor's Note: For the complete source and executable code for this
solution, go to the Windows NT Magazine site, www.winntmag.com. Windows
NT Magazine wants to publish your VB solutions. If you've created some
interesting and useful VB solutions for your business' problems, send them to
us! If we agree that your VB solutions are interesting and useful to our
readers, we'll publish your code and pay you $100. You can send contributions or
ideas for VB solutions to me at mikeo@teca.com.