
Code After a Call to Form
Unload will Prevent the Form from Closing
If you use control arrays to handle common button or menu activities, you might be tempted
to make one of the buttons call the "Unload Me" event to end the form execution,
as follows:
Private Sub cmdAction_Click(Index As Integer)
'
' *** this doesn't work!
'
Select Case Index
Case 0: Me.WindowState = vbMaximized
Case 1: Me.WindowState = vbNormal
Case 2: Unload Me
End Select
'
MsgBox "Current state: " & CStr(Me.WindowState)
'
End Sub
However, this code won't work. Since there's a line of executing code after the
"Unload Me" statement, the form will hide, but never unload!
To fix this, you must replace the call to "Unload Me" with a flag variable and
execute the "Unload Me" as the very last action in the method:
Private Sub cmdAction_Click(Index As Integer)
'
' *** this works!
'
Dim blnUnload As Boolean
'
Select Case Index
Case 0: Me.WindowState = vbMaximized
Case 1: Me.WindowState = vbNormal
Case 2: blnUnload = True
End Select
'
MsgBox "Current state: " & CStr(Me.WindowState)
'
If blnUnload = True Then
Unload Me
End If
'
End Sub
Be sure to Close all Data
Objects upon Exit
If you use any data objects in your code (DAO, RDO, or ADO), you should be sure to
explicitly close all open recordsets, databases, and workspaces before you exit. Even
though the pointers to these objects are automatically destroyed when you exit the
program, if you fail to explicitly close all open items, your database connections may not
be immediately released and the memory used by these objects may never be re-allocated by
the operating system.
Here's a short routine you can add to your Form_Unload event (or some other terminating
code module) that will close all open DAO workspaces, databases, and recordsets and
release the memory reserved by these objects. This code will work whether you have 1, 100,
or even no connections open when you attempt to exit the form.
Private Sub Form_Unload(Cancel As Integer)
'
' *** close out db objects
' *** and release all memory
'
On Error Resume Next
'
Dim ws As Workspace
Dim db As Database
Dim rs As Recordset
'
For Each ws In Workspaces
For Each db In ws.Databases
For Each rs In
db.Recordsets
rs.Close
Set rs = Nothing
Next
db.Close
Set db = Nothing
Next
ws.Close
Set ws = Nothing
Next
'
End Sub
Sure-Fire Way to Allow Users
to Cancel Form Unloads
There are a number of different ways a user can unload a form. Click the Exit button or
menu item; click on the X in the upper-right corner of the form; select Close from the
form window's pop-up menu in the upper-left corner; even cancel the program from the task
manager or reboot the machine. The best way to give your users the power to cancel a
form-unload activity, whatever its source, is to place all your form-unload checking code
in the QueryUnload event of the form. This event fires no matter which
method is used to unload your form.
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
'
' *** universal unload check
'
Dim strQuestion As String
Dim intAnswer As Integer
Dim aryMode As Variant
'
aryMode = Array("vbFormControlMenu", _
"vbFormCode", "vbAppWindows", _
"vbAppTaskManager", "vbFormMDIForm")
'
strQuestion = "Ready to unload this form?"
'
intAnswer = MsgBox(strQuestion, vbQuestion + vbYesNo, _
aryMode(UnloadMode))
If intAnswer = vbNo Then
Cancel = -1
End If
'
End Sub
Labeling your forms
Do you have a ton of screens in your application? Do you also have plenty of users who
want to "help you" by pointing out buttons that are one twip
out of place? Sometimes it's hard to know what screen users are talking about when they're
trying to communicate a problem--particularly if they're
in a different location than you.
To reduce the pain of this process, I add a label (called lblHeader) to the top of each
GUI window, nominally to hold start-up information for users when they first open the
window. You can also use this label to hold the name of the window the user is looking at,
by using the following code:
Private Sub Form_Load()
SetupScreen me
End Sub
Public SetupScreen (frm as Form)
' Do other set-up stuff here (fonts, colors).
HookInFormName frm
End Sub
Public Sub HookInFormName(frm As Form)
' The Resume Next on Error allows forms that do not use a standard
' header label to get past this.
On Error Resume Next
frm.lblHeader.Caption = "(" & frm.Name & ")
" & frm.lblHeader.Caption
End Sub
Note that if you don't want to use a label, that you can also use code like
frm.print frm.name
to print to the back of the window itself.
Importing Registry settings
You can use just a few lines of code to import Registry settings. If you have an
application called myapp.exe and a Registry file called myapp.reg, the following code will
put those settings into the Registry without bothering the user.
Dim strFile As String
strFile = App.Path & "\" & opts.AppExeName & ".reg"
If Len(Dir$(strFile)) > 1 Then
lngRet = Shell("Regedit.exe /s " & strFile,
vbNormalFocus)
End If
Quick Text Select On
GotFocus
When working with data entry controls, the current value in the control often needs to be
selected when the control received focus. This allows the user to immediately begin typing
over any previous value. Here's a quick subroutine to do just that:
Public Sub FocusMe(ctlName As Control)
'
With ctlName
.SelStart = 0
.SelLength = Len(ctlName)
End With
'
End Sub
Now add a call to this subroutine in the GotFocus event of the input controls:
Private Sub txtFocusMe_GotFocus()
Call FocusMe(txtFocusMe)
End Sub
Using the Alias Option to
Prevent API Crashes
A number of Windows APIs have parameters that can be more than one data type. For example,
the WinHelp API call
can accept the last parameter as a Long or String data type depending on the
service requested.
Visual Basic allows you to declare this data type as "Any" in the API call, but
this can lead to type mismatch errors or
even system crashes if the value is not the proper form.
You can prevent the errors and improve the run-time type checking by declaring multiple
versions of the same API function
in your program. By adding a function declaration for each possible parameter type,
you can continue to use strong data type
checking. To illustrate this technique, add the following APIs and constants to a
Visual Basic form. Notice that the two API
declarations differ only in their initial name ("WinHelp" and
"WinHelpSearch") and the type declaration of the last parameter
("dwData as Long" and "dwData as String").
' WinHelp APIs
Private Declare Function WinHelp Lib "user32" Alias "WinHelpA" (ByVal
hwnd As Long, ByVal lpHelpFile As String, ByVal
wCommand As Long, ByVal dwData As Long) As Long
Private Declare Function WinHelpSearch Lib "user32" Alias "WinHelpA"
(ByVal hwnd As Long, ByVal lpHelpFile As String, ByVal
wCommand As Long, ByVal dwData As String) As Long
'
Private Const HELP_PARTIALKEY = &H105&
Private Const HELP_HELPONHELP = &H4
Private Const HelpFile = "c:\program files\devstudio\vb5\help\vb5.hlp"
Now add two command buttons to your form (cmdHelpAbout and cmdHelpSearch) and place the
following code behind the buttons.
Be sure to edit the location of the help file to match your installation of Visual
Basic.
Private Sub cmdHelpAbout_Click()
'
WinHelp Me.hwnd, HelpFile, HELP_HELPONHELP, &H0
'
End Sub
Private Sub cmdHelpSearch_Click()
'
WinHelpSearch Me.hwnd, HelpFile, HELP_PARTIALKEY, "option"
'
End Sub
When you press on the HelpAbout button, you'll see help about using the help system.
When you press on the HelpSearch button, you'll see a list of help entries on the
"option" topic.
Quick Custom Dialogs for DBGrid Cells
It's easy to add custom input dialogs to al the cells in the Microsoft Data Bound Grid
control.
First, add a DBGrid control and Data control to your form. Next, set the DatabaseName and
RecordSource properties of the data control to a valid
database and table ("biblio.mdb" and "Publishers" for example). Then
set the DataSource property of the DBGrid control to Data1 (the data control).
Now add the following code to your form.
' general declaration area
Dim strDBGridCell As String
Private Sub DBGrid1_AfterColEdit(ByVal ColIndex As Integer)
'
DBGrid1.Columns(ColIndex) = strDBGridCell
'
End Sub
Private Sub DBGrid1_BeforeColEdit(ByVal ColIndex As Integer, ByVal KeyAscii As Integer,
Cancel As Integer)
'
strDBGridCell = InputBox("Edit DBGrid Cell:", , DBGrid1.Columns(ColIndex))
'
End Sub
Now whenever you attempt to edit any cell in the DBGrid, you'll see the InputBox prompt
you for input.
You can replace the InputBox with any other custom dialog you wish to build.
Creating a new context menu in editable controls
This routine will permit you to replace the original context menu with your private
context menu in an editable control.
Add the following code to your form or to a BAS module:
Private Const WM_RBUTTONDOWN = &H204
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA"
(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Sub OpenContextMenu(FormName As Form, MenuName As Menu)
'Tell system we did a right-click on the mdi
Call SendMessage(FormName.hwnd, WM_RBUTTONDOWN, 0, 0&)
'Show my context menu
FormName.PopupMenu MenuName
'
End Sub
Next, use the Visual Basic Menu Editor and the table below to create a simple menu.
Caption Name
Visible
Context Menu mnuContext NO
...First Item mnuContext1
...Second Item mnuContext2
Note that the last two items in the menu are indented (...) one level and that only the
first item in the list ("Context Menu")
has the Visible property set to NO.
Now add a text box to your form and enter the code below in the MouseDown event of the
text box.
Private Sub Text1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbRightButton Then
Call OpenContextMenu(Me, Me.mnuContext)
End If
End Sub
Note: If you just want to kill the system context menu, just comment out the line:
FormName.PopupMenu MenuName
in the OpenContextMenu routine.
Simple file checking from
anywhere
To keep my applications running smoothly, I often need to check that certain files exist.
So, I've written a simple routine to make sure they do. Here it is:
Public Sub VerifyFile(FileName As String)
'
On Error Resume Next
'Open a specified existing file
Open FileName For Input As #1
'Error handler generates error message with file and exits the routine
If Err Then
MsgBox ("The file " & FileName & " cannot be found.")
Exit Sub
End If
Close #1
'
End Sub
Now add a button to your form and place the code below behind the "Click" event.
Private Sub cmdVerify_Click()
'
Call VerifyFile("MyFile.txt")
'
End Sub
Manipulate your controls
from the keyboard
If you're not comfortable using your mouse--or can't achieve the precise results you'd
like--these tips will come in handy.
First, you can resize controls at design time by using the [Shift] and arrow keys, as
follows:
SHIFT + RIGHT ARROW increases the width of the control
SHIFT + LEFT ARROW decreases the width of the control
SHIFT + DOWN ARROW increases the height of the control
SHIFT + UP ARROW decreases the height of the control
Note: The target control must have focus, so click on the control before manipulating it
from the keyboard.
Second, by using the [Control] key and the arrow keys, you can move your controls at
design time, as follows:
CONTROL + RIGHT ARROW to move the control to the right
CONTROL + LEFT ARROW to move the control to the left
CONTROL + DOWN ARROW to move the control downwards
CONTROL + UP ARROW to move the control upwards
If you select more than one control (by clicking on the first and shift-clicking on the
others), the above procedures will affect all the selected controls.
Creating Win32 region
windows
The Win32 API includes a really amazing feature called region windows. A window under
Win32 no longer has to be rectangular! In fact,
it can be any shape that may be constructed using Win32 region functions.
Using the SetWindowRgn Win32 function from within VB is so
simple, but the results are unbelievable!
The following example shows a VB form that is NOT rectangular!! Here is the code.
Enjoy!
' This goes into the General Declarations section:
Private Declare Function CreateEllipticRgn Lib "gdi32" _
(ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, _ByVal Y2 As Long) As Long
Private Declare Function SetWindowRgn Lib "user32" _
(ByVal hWnd As Long, ByVal hRgn As Long, _ByVal bRedraw As Boolean) As Long
Private Sub Form_Load()
Show 'The form!
SetWindowRgn hWnd, _
CreateEllipticRgn(0, 0, 300, 200), _
True
End Sub
Add Dithered Backgrounds to
your VB Forms
Ever wonder how the SETUP.EXE screen gets its cool shaded background coloring? This color
shading is called dithering, and you can easily
incorporate it into your forms. Add the following routine to a form:
Sub Dither(vForm As Form)
Dim intLoop As Integer
vForm.DrawStyle = vbInsideSolid
vForm.DrawMode = vbCopyPen
vForm.ScaleMode = vbPixels
vForm.DrawWidth = 2
vForm.ScaleHeight = 256
For intLoop = 0 To 255
vForm.Line (0, intLoop)-(Screen.Width, intLoop - 1), RGB(0, 0,
255 -intLoop), B
Next intLoop
End Sub
Now, add to the Form_Activate event the line
Dither ME
This version creates a fading blue background by adjusting the blue value in the RGB
function. (RGB stands for Red-Green-Blue.) You can create a
fading red background by changing the RGB call to
RGB(255 - intLoop, 0, 0).
Confirm Screen Resolution
Here's a great way to stop the user from running your application in the wrong screen
resolution. First, create a function called CheckRez:
Public Function CheckRez(pixelWidth As Long, pixelHeight As Long) As Boolean
'
Dim lngTwipsX As Long
Dim lngTwipsY As Long
'
' convert pixels to twips
lngTwipsX = pixelWidth * 15
lngTwipsY = pixelHeight * 15
'
' check against current settings
If lngTwipsX <> Screen.Width Then
CheckRez = False
Else
If lngTwipsY <> Screen.Height Then
CheckRez = False
Else
CheckRez = True
End If
End If
'
End Function
Next, run the following code at the start of the program:
If CheckRez(640, 480) = False Then
MsgBox "Incorrect screen size!"
Else
MsgBox "Screen Resolution Matches!"
End If
Use FreeFile to Prevent File
Open Conflicts
Both Access and VB let you hard code the file numbers when using the File Open statement.
For example:
Open "myfile.txt" for Append as #1
Print #1,"a line of text"
Close #1
The problem with this method of coding is that you never know which file numbers may be in
use somewhere else in your program. If you attempt to use
a file number already occupied, you'll get a file error. To prevent this problem, you
should always use the FreeFile function. This function will return the next available file
number for your use. For example:
IntFile=FreeFile()
Open "myfile.txt" for Append as #intFile
Print #intFile,"a line of text"
Close #intFile
Measuring a text extent
It's very simple to determine the extent of a string in VB. You can do so with WinAPI
functions, but there's an easier way: Use the AutoSize property
of a Label component. First, insert a label on a form (labMeasure) and set its AutoSize
property to True and Visible property to False. Then write
this simple routine:
Private Function TextExtent(txt as String) as Integer
labMeasure.Caption = txt
TextExtent = labMeasure.Width
End Function
When you want to find out the extent of some text, simply call this function with the
string as a parameter.
In my case it turned out that the measure was too short. I just added some blanks to the
string. For example:
Private Function TextExtent(txt As String) As Integer
labMeasure.Caption = " " & txt
TextExtent = labMeasure.Width
End Function
Use ParamArray to Accept an
Arbitrary Number of Parameters
You can use the ParamArray keyword in the declaration line of a method to create a
subroutine or function that accepts an arbitrary number of parameters at runtime. For
example, you can create a method that will fill a list box with some number of items even
if you do not know the number of
items you will be sent. Add the method below to a form:
Public Sub FillList(ListControl As ListBox, ParamArray Items())
'
Dim i As Variant
'
With ListControl
.Clear
For Each i In Items
.AddItem i
Next
End With
'
End Sub
Note that the ParamArray keyword comes BEFORE the parameter in the declaration line. Now
add a list box to your form and a command button. Add
the code below in the "Click" event of the command button.
Private Sub Command1_Click()
'
FillList List1, "TiffanyT", "MikeS", "RochesterNY"
'
End Sub
Use FileDSNs to ease ODBC
Installs
If you're using an ODBC connection to your database, you can ease the process of
installing the application on workstations by using the FileDSN
(data source name) instead of the more-common UserDSN. You define your ODBC connection as
you normally would with UserDSNs. However, the resulting definition is not stored in the
workstation registry. Instead it gets stored in a text file with the name of the DSN
followed by ".dsn" (i.e.
"MyFileDSN.dsn").
The default folder for all FileDSNs is "c:\program files\common
files\Odbc\data sources". Now, when you want to install the VB application that uses
the FileDSN, all you need to do is add the FileDSN to the Install package and run the
install as usual. No more setting up DSNs manually!
NOTE: FileDSNs are available with ODBC 3.0 and higher.
Increase Your RAD-ness by
creating your own VB5 Templates
You can create your own VB Templates quickly and easily. If you find that you are adding
the same routines to your forms, classes, BAS modules, etc.
you can build generic versions and place them in the Templates folder tree of VB5. By
placing the coding module (frm, bas.cls, etc.) in the proper
subfolder of the Templates folder, you'll see the new item appear whenever you select the
Add... dialog box. You can add as many controls, library
references, and lines of code as you wish to the templates.
CAUTION: If you uninstall VB5, you may loose your Templates folder and all its contents.
Be sure to keep a secured copy of all your template files in
a safe location.
Opening a browser to your
homepage
You can use code like the following to open a browser to your homepage.
Modify filenames, paths, and URLs as necessary to match the values on your system.
Dim FileName As String, Dummy As String
Dim BrowserExec As String * 255
Dim RetVal As Long
Dim FileNumber As Integer
Const SW_SHOWNORMAL = 1 ' Restores Window if Minimized or
Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA"
_
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As Long
Declare Function FindExecutable Lib "shell32.dll" Alias
"FindExecutableA" _
(ByVal lpFile As String, ByVal lpDirectory As String, ByVal lpResult As _
String) As Long
'<Code> ---------
BrowserExec = Space(255)
FileName = "C:\temphtm.HTM"
FileNumber = FreeFile() ' Get unused file number
Open FileName For Output As #FileNumber ' Create temp HTML file
Write #FileNumber, "<HTML> <\HTML>" ' Output text
Close #FileNumber ' Close file
' Then find the application associated with it.
RetVal = FindExecutable(FileName, Dummy, BrowserExec)
BrowserExec = Trim$(BrowserExec)
' If an application is found, launch it!
If RetVal <= 32 Or IsEmpty(BrowserExec) Then ' Error
Msgbox "Could not find a browser"
Else
RetVal = ShellExecute(frmMain.hwnd, "open", BrowserExec, _
"www.myurl.com", Dummy, SW_SHOWNORMAL)
If RetVal <= 32 Then ' Error
Msgbox "Web Page not Opened"
End If
End If
Kill FileName ' delete temp HTML file
A function for
numbers beginning with 0
Here is a function that is very helpful when you need some number that begins
with 0's and has to be a certain number of digits:
Function PadToString(intValue, intDigits)
PadToString = String(intDigits - Len(intValue), "0") & intValue
End Function
Usage:
myNewStr = PadToString(702, 6)
myNewStr would be "000702"
Convert NULL values to empty strings to avoid errors
When retrieving NULL values from a recordset object, errors can occur. One way
to avoid this is to inspect the value of the field, and if it's NULL, convert it
to an empty string or zero. For example:
If isnull(rs("Field")) then tmp="" else
tmp=rs("Field")
form.textfield=tmp
An even simpler way is to use the format function, which will convert a NULL
value to an empty string automatically, avoiding any error messages. It will
look like this:
form.textfield=format(rs("Field"))
Creating professional documents with code
Have you ever wanted to create polished, professional documents, like those
created in Microsoft Word, through the use of code? Follow these easy steps to
make it happen:
1.) Add a reference to your project for "Microsoft Word 8.0 Object
Library" (MSWORD8.OLB).
2.) Add the following code to create an instance of Word and add text to a
new document:
Dim objWord As New Word.Application
'-- Show Microsoft Word
objWord.Visible = True
'-- Add new Document
objWord.Documents.Add
'-- Add text to Document
objWord.Selection.TypeText "Visual Basic!"
'-- Select all Text
objWord.Selection.WholeStory
'-- Change Font Size
objWord.Selection.Font.Size = 50
Set objWord = Nothing
3.) Be sure to check out the Object Browser for more properties and
methods exposed by the Word Object.
Launch your default web browser from a VB app
Here is a nice function to launch the default web browser from a VB application.
Add the following code to the general section of a module:
Declare Function ShellExecute Lib "shell32.dll" _
Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, _
ByVal lpFile As String, ByVal lpParameters As String, _
ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Public Const SW_SHOWNORMAL As Long = 1
Public Const SW_SHOWMAXIMIZED As Long = 3
Public Const SW_SHOWDEFAULT As Long = 10
Add the following code to a form, which spawns off the default browser:
Public Sub RunBrowser(strURL As String, iWindowStyle As Integer)
Dim lSuccess As Long
'-- Shell to default browser
lSuccess = ShellExecute(Me.hwnd, "Open", strURL, 0&, 0&,
iWindowStyle)
End Sub
To launch the VBCE.com web site, use the following function call:
Call RunBrowser ("www.vbce.com", SW_SHOWNORMAL)
Tip for finding a leap year
Here is a nice function for finding a leap year. The trick is to not only
dividing the year by 4, but also test for division by 100 and 400.
Public Function IsLeapYear(iYear As Integer)
'-- Check for leap year
If (iYear Mod 4 = 0) And _
((iYear Mod 100 <> 0) Or (iYear Mod 400 = 0)) Then
IsLeapYear = True
Else
IsLeapYear = False
End If
End Function
Using the Base Address for In-Process Components to
speed up the loading phase
When you create an in-process component and load it in your Visual Basic
application, the process loads at a base address in memory.
How can you change the Base Address of your In-Process Component?
To enter the base address for your component, open the Project Properties dialog
box and select the Compile tab. The address is entered in the DLL Base Address
box as an unsigned decimal or hexadecimal integer.
The default value is &H11000000 (285,212,672). If you neglect to change this
value, your component will conflict with every other in-process component
compiled using the default. Staying well away from this address is recommended.
Choose a base address between 16 megabytes (16,777,216 or &H1000000) and two
gigabytes (2,147,483,648 or &H80000000). The base address must be a multiple
of 64K. The memory used by your component begins at the initial
base address and is the size of the compiled file, rounded up to the next
multiple of 64K.
Your program cannot extend above two gigabytes, so the maximum base address is
actually two gigabytes minus the memory used by your component. Executables will
usually load at the 4 megabyte logical address. The region below 4 megabytes is
reserved under Windows 95, and regions above two gigabytes are reserved by both
Windows 95 and Windows NT.
A good way to make sure all your components have a different base address is to
keep track of all them, and create a random selective tool to create new unique
base addresses. This way your components will not conflict with each other.
Using the Win32 API
to write to the NT EventLog
Recently a tip went out that showed you how to write to the NT EventLog using
the App object. This method has 2 limitations:
1) You cannot use the code during a debug session.
2) The source entry in the Event Log is always VBRuntime
Using the Win32 API alleviates these problems. Enter the following code in
the General Declarations of a module:
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
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
Declare Function GetLastError Lib "kernel32" () As
Long
Declare Sub CopyMemory Lib "kernel32" Alias
"RtlMoveMemory" ( _
hpvDest As Any, hpvSource As Any, _
ByVal cbCopy As Long)
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
'-- Public Constants
Public Const EVENTLOG_SUCCESS = 0
Public Const EVENTLOG_ERROR_TYPE = 1
Public Const EVENTLOG_WARNING_TYPE = 2
Public Const EVENTLOG_INFORMATION_TYPE = 4
Public Const EVENTLOG_AUDIT_SUCCESS = 8
Public Const EVENTLOG_AUDIT_FAILURE = 10
Public Function WriteToEventLog(sMessage As String, _
sSource As String, _
iLogType As Integer, _
vEventID As Integer) As Boolean
Dim bRC
As Boolean
Dim iNumStrings As Integer
Dim hEventLog As
Long
Dim hMsgs
As Long
Dim cbStringSize As Long
Dim iEventID
As Integer
hEventLog = RegisterEventSource("", sSource)
cbStringSize = Len(sMessage) + 1
hMsgs = GlobalAlloc(&H40, cbStringSize)
CopyMemory ByVal hMsgs, ByVal sMessage, cbStringSize
iNumStrings = 1
'-- ReportEvent returns 0 if failed,
'-- Any other number indicates success
If ReportEvent(hEventLog, _
iLogType, 0, _
iEventID, 0&, _
iNumStrings, cbStringSize, _
hMsgs, hMsgs) = 0 Then
'-- Failed
WriteToEventLog = False
Else
'-- Sucessful
WriteToEventLog = True
End If
Call GlobalFree(hMsgs)
DeregisterEventSource (hEventLog)
End Function
An example of how to write to the NT EventLog:
Call WriteToEventLog("Warning, file exceeded recommended limit.", _
"Test App", _
EVENTLOG_WARNING_TYPE, 1003)
Legal Disclaimer
THE INFORMATION IN THIS PUBLICATION IS
PROVIDED "AS IS". WE EXPRESSLY DISCLAIMS ALL REPRESENTATIONS AND WARRANTIES OF
ANY KIND REGARDING THE CONTENTS OR USE OF THE INFORMATION INCLUDING, BUT NOT LIMITED TO,
EXPRESS AND IMPLIED WARRANTIES OF ACCURACY, COMPLETENESS, MERCHANTABILITY, FITNESS FOR A
PARTICULAR USE, OR NON-INFRINGEMENT. IN NO EVENT SHALL WE BE LIABLE FOR ANY DIRECT,
INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, LOST
BUSINESS OR LOST DATA, RESULTING FROM THE USE OR RELIANCE UPON THE INFORMATION, EVEN IF WE
HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS DO NOT ALLOW THE
EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT APPLY TO YOU.