How to use the Grove OLE Automation Class in Visual Basic 5.0
Registering DLLs
To get started you must copy all the dll files distributed with Jade except for groveoa.dll into the NT Windows\System32 or 95 Windows\System directory. Copy groveoa.dll into the directory named \Program Files\Common Files\OleSvr on the same drive that Windows was installed on (if the OleSvr directory doesn't exist then create it). While in that directory type regsrv32 groveoa.dll. Alternately download the sample program and the setup installation program will do all of the above for you.
What it is good at
The Grove OLE Automation Class is basically intended for parsing and fully supports the 9401 catalog.
It is extremely fast and easy to use.What it is not so good at
The majority of the properties and methods needed for SPAM type functionality are not available in the grove.
The Grove API does not allow access to the doctype declaration or document type declaration subset.
Unconditionally substitutes general entities with a space unless explicit numeric character references are made (with the exception of & and < which are unconditionally substituted to & and < respectively).The sample source code touches on normalization and does output the doctype declaration (when in the document instance) and document type declaration subset. There are a few bugs in the normalization that you will have to Band-Aid if you intend to use it (lost data in buffer). If you really want to normalize you can try my SP OLE Automation wrapper around SPAM which comes with SP Wizard.
Classes not availble, but show in the object browser
This information is based on my experimentation and may not be completely accurate. A red line indicates that the class is not accessible.Here are the basic steps involved in using the grove to parse documents:
Create an instance.
Set the catalog paths and input document file name.
Set Warning toggles.
Call the parser to parse the instance.
Display error messages.Partial code to Create a Parser:
Note this code is only partial, download the sample program if you want to use the code in VB5. The sample program uses EMEDIT32.OCX the Early Morning Editor Version 2.0, you will have to purchase this OCX if you want to get rid of the nag screen.Create a command button on the main form named cmdbuttonParse and place the following code in its click event:
Create a module and place the following code in the General Declarations section.Option Explicit
'**************************************
'* Debug
'**************************************
#Const MODULE_SPOLEA_DEBUG = "YES"
' #Const MODULE_SPOLEA_DEBUG = "NO"
'**************************************
'* Prevent 16 bit compile
'**************************************
#If Win16 Then
You Can 't compile this application for 16 bit platform
#End If
'**************************************
'* Grove
'**************************************
'------------------------
'Classes/Modules (cm prefix)
Public cmGroveBuilder As New GroveBuilder
Public cmExternalID As ExternalIdNode
Public cmMessageNode As MessageNode
Public cmSgmlDocumentNode As SgmlDocumentNode
Public cmStoragePos As StoragePos
'Methods/Properties (mp prefix)
Public mpDocumentElement As ElementNode
Public mpFirstChild As Node
Public mpFirst As Node
Public mpNextSibling As Node
'------------------------
'Constants
Public Const ENTITY_TYPE_CDATA = 1
Public Const ENTITY_TYPE_NDATA = 3
Public Const ENTITY_TYPE_PI = 5
Public Const ENTITY_TYPE_SDATA = 2
Public Const ENTITY_TYPE_SUBDOCUMENT = 4
Public Const ENTITY_TYPE_TEXT = 0
Public Const ERROR_TYPE_AFDR = 2
Public Const ERROR_TYPE_IDREF = 0
Public Const ERROR_TYPE_LPDNOTATION = 3
Public Const ERROR_TYPE_SIGNIFICANT = 1
Public Const ERROR_TYPE_VALID = 4
Public Const SEVERITY_ERROR = 2
Public Const SEVERITY_INFO = 0
Public Const SEVERITY_WARNING = 1
Public Const WARNING_SGMLDECL = 0
Public Const WARNING_DUPLICATE_ENTITY = 1
Public Const WARNING_SHOULD = 2
Public Const WARNING_UNDEFINED_ELEMENT = 3
Public Const WARNING_DEFAULT_ENTITY_REFERENCE = 4
Public Const WARNING_MIXED_CONTENT = 5
Public Const WARNING_UNCLOSED_TAG = 6
Public Const WARNING_NET = 7
Public Const WARNING_EMPTY_TAG = 8
Public Const WARNING_UNUSED_MAP = 9
Public Const WARNING_UNUSED_PARAM = 10
Public Const WARNING_NOTATION_SYSTEM_ID = 11
'**************************************
'* Windows API
'**************************************
Private Const WM_USER = &H400
Private Const LB_SETHORIZONTALEXTENT = &H194
Private HighTextSize As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, lParam As Long) As Long
Public Declare Function WritePrivateProfileString Lib "kernel32" _
Alias "WritePrivateProfileStringA" (ByVal AppName As String, _
ByVal KeyName As String, ByVal keydefault As String, _
ByVal FileName As String) As Long
Public Declare Function GetPrivateProfileString Lib "kernel32" _
Alias "GetPrivateProfileStringA" (ByVal AppName As String, _
ByVal KeyName As String, ByVal keydefault As String, _
ByVal ReturnString As String, ByVal NumBytes As Long, _
ByVal FileName As String) As Long
'---------------------------
'Error Constants and variables
'---------------------------
Public DriveError As Integer
Public Const DEVICE_NOT_AVAILABLE = 4
Public Const MOUSE_POINTER_HOURGLASS = 11
Public Const MOUSE_POINTER_NORMAL = 0'---------------------------
'Misc Objects
'---------------------------
'Public objErrorFile As New TextFile
' Public objPassedParse As New TextFile
'Public iFileIndex As Integer'Public sPassword As String
Public GID As String
cmdbuttonParseClickAdd the following code to the General Declarations section of the module you previously created.Public Sub cmdbuttonParseClick()
'Trap all Errors local to this Sub.
On Error GoTo cmdbuttonParseClickErr
'Local variables.
Dim lSiblingIndex As Long
Dim lWidthOfText As Long
Dim iFileIndex As Integer
Dim lEventsAllowed As Long
Dim sMessageLine As String
Dim Ret As Variant
formViewFile.Hide
If formSPOLEA.listboxPassed.ListCount Then
Ret = MsgBox(" Do you want to clear the list of files that passed the parse from the previous press of the parse button?", 36, "Clear")
If Ret = 6 Then
formSPOLEA.listboxPassed.Clear
End If
End If
formSPOLEA.MousePointer = MOUSE_POINTER_HOURGLASS
'Disable command buttons so the user doesn't prees them twice.
formSPOLEA.cmdbuttonParse.Enabled = False
formSPOLEA.cmdButtonNormalize.Enabled = False
'Clear out anything that may be loaded in the listbox
'from a previous press of the Parse button.
formSPOLEA.listboxResults.Clear
ClearHorizontalScrollBars formSPOLEA.listboxResults
'Clear out the error message text box.
formSPOLEA.tbErrMessage.Text = ""
'Begin Processing all file(s) selected
For iFileIndex = 0 To formSPOLEA.File1.ListCount - 1
lEventsAllowed = DoEvents()
If formSPOLEA.File1.Selected(iFileIndex) = True Then
If Dir$(formSPOLEA.File1.List(iFileIndex)) <> "" Then
SetSPToggles
Set cmSgmlDocumentNode = cmGroveBuilder.parse(formSPOLEA.File1.List(iFileIndex))
Else
MsgBox "File " & formSPOLEA.File1.List(iFileIndex) & " not found in current directory."
Exit Sub
End If
'****************************
'Parse and display error messages
'****************************
DisplayMessages cmSgmlDocumentNode, iFileIndex
End If
Next iFileIndex
'Turn on horizontal scroll bars for the list box.
lWidthOfText = WidestEntryWidth(formSPOLEA.listboxResults) * 0.1
HorizontalScrollBars formSPOLEA.listboxResults, lWidthOfText
formSPOLEA.listboxPassed.Refresh
lWidthOfText = WidestEntryWidth(formSPOLEA.listboxPassed) * 0.1
HorizontalScrollBars formSPOLEA.listboxPassed, lWidthOfText
'Enable command buttons.
formSPOLEA.cmdbuttonParse.Enabled = True
formSPOLEA.cmdButtonNormalize.Enabled = True
formSPOLEA.MousePointer = MOUSE_POINTER_NORMAL
Exit Sub'Error Handler
cmdbuttonParseClickErr:
formSPOLEA.MousePointer = MOUSE_POINTER_NORMAL
'Enable command buttons.
formSPOLEA.cmdbuttonParse.Enabled = True
formSPOLEA.cmdButtonNormalize.Enabled = True
'Display error to user
MsgBox "Error: " + Date$ + " " + Time$ + " in moduleSPOLEA/cmdbuttonParseClick Sub, " + Error(Err)
'Turn on horizontal scroll bars for the list boxes
'just in case the parser returned something.
lWidthOfText = WidestEntryWidth(formSPOLEA.listboxResults) * 0.1
HorizontalScrollBars formSPOLEA.listboxResults, lWidthOfText
lWidthOfText = WidestEntryWidth(formSPOLEA.listboxPassed) * 0.1
HorizontalScrollBars formSPOLEA.listboxPassed, lWidthOfText
#If MODULE_SPOLEA_DEBUG = "YES" Then
Dim DB
DB = FreeFile
'Write errors to a file if debug mode.
Open App.Path + "\debug.txt" For Append As #DB
Print #DB, "Error: " + Date$ + " " + Time$ + " in moduleSPOLEA/cmdbuttonParseClick Sub, " + Error(Err)
Close #DB
#End If
Exit Sub
End Sub
Public Sub DisplayMessages(cmSgmlDocumentNode As SgmlDocumentNode, iFileIndex As Integer)
'Trap all Errors local to this Sub.
On Error GoTo DisplayMessagesErr
'Local variables.
Dim lSiblingIndex As Long
Dim sMessageLine As String
'See if there were any error(s)/warning(s)
If cmSgmlDocumentNode.Messages Is Nothing Then
'Add to the passed parse list.
'There were no error(s)/warning(s) so process next file.
formSPOLEA.listboxPassed.AddItem formSPOLEA.Dir1.Path + "\" + formSPOLEA.File1.List(iFileIndex)
Else
'Yes there were error(s)/warning(s).
'Iterate through messages
Set cmMessageNode = cmSgmlDocumentNode.Messages.[First]
cmGroveBuilder.DefaultCatalogs = ".\catalog;" + formEnvironment.Text1.Text
cmGroveBuilder.DefaultDirectories = formEnvironment.Text2.Text
formSPOLEA.Caption = "SP Parser/Normalizer (SGML) [" + formSPOLEA.File1.List(iFileIndex) + "]"
Do While Not (cmMessageNode Is Nothing)
Set cmStoragePos = cmMessageNode.StoragePos
'Build a message line. Note that square brackets are used to avoid
'conflicts between VB reserved words, when not sure use them anyway
'see Microsoft Knowledge Base article Q115859.
Select Case cmMessageNode.Severity
Case Is = SEVERITY_INFO
sMessageLine = "Information for file::"
Case Is = SEVERITY_WARNING
sMessageLine = "Warning in file::"
Case Is = SEVERITY_ERROR
sMessageLine = "Error in file::"
End Select
' sMessageLine = sMessageLine + formSPOLEA.Dir1.Path + "\" + cmStoragePos.StorageObjectId + "::"
sMessageLine = sMessageLine + cmStoragePos.StorageObjectId + "::"
'Problem 001:Q125749
'Calling cmStoragePos.StorageManagerName results in a R6025 runtime,
'error (pure virtual function call) see Microsoft Knowledge base
'article Q125749.
' sMessageLine = sMessageLine + cmStoragePos.StorageManagerName + "::"
sMessageLine = sMessageLine + "Message Text::" + cmMessageNode.[Text] + "::"
sMessageLine = sMessageLine + "Line Number::" + Trim(Str(cmStoragePos.[LineNumber])) + "::"
sMessageLine = sMessageLine + "ByteIndex::" + Trim(Str(cmStoragePos.[ByteIndex])) + "::"
sMessageLine = sMessageLine + "Character Index::" + Trim(Str(cmStoragePos.[CharacterIndex])) + "::"
sMessageLine = sMessageLine + "Column Number::" + Trim(Str(cmStoragePos.[ColumnNumber]))
'Add the current error/warning message to the list box.
formSPOLEA.listboxResults.AddItem sMessageLine
'Problem 002:
'There is a problem with SiblingIndex. It always returns 0.
lSiblingIndex = cmMessageNode.[SiblingIndex]
'Go get the next error/warning message.
Set cmMessageNode = cmMessageNode.[NextSibling]
Loop
End If
Exit Sub'Error Handler
DisplayMessagesErr:
'Display error to user.
MsgBox "Error: " + Date$ + " " + Time$ + " in moduleSPOLEA/DisplayMessagesErr Sub, " + Error(Err)
'Debug
#If MODULE_SPOLEA_DEBUG = "YES" Then
Dim DB
DB = FreeFile
'Write errors to a file if debug mode.
Open App.Path + "\debug.txt" For Append As #DB
Print #DB, "Error: " + Date$ + " " + Time$ + " in moduleSPOLEA/DisplayMessagesErr Sub, " + Error(Err)
Close #DB
#End If
Exit Sub
End Sub
Public Sub SetSPToggles()
Dim i As Integer
'Values are listed below for your information.
'WARNING_SGMLDECL = 0
'WARNING_DUPLICATE_ENTITY = 1
'WARNING_SHOULD = 2
'WARNING_UNDEFINED_ELEMENT = 3
'WARNING_DEFAULT_ENTITY_REFERENCE = 4
'WARNING_MIXED_CONTENT = 5
'WARNING_UNCLOSED_TAG = 6
'WARNING_NET = 7
'WARNING_EMPTY_TAG = 8
'WARNING_UNUSED_MAP = 9
'WARNING_UNUSED_PARAM = 10
'WARNING_NOTATION_SYSTEM_ID = 11
For i = 0 To 11
If formSPSettings.SSCheck1(i).Value Then
cmGroveBuilder.Warning(i) = True
Else
cmGroveBuilder.Warning(i) = False
End If
Next i
End Sub
Disclaimer
Permission is hereby granted, free of charge, to any person obtaining a copy of SPOLEA and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use and to permit persons to whom the Software is furnished to do so., subject to the following conditions:THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL LARRY ROBERTSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
PLEASE BACKUP ALL OF YOUR FILES BEFORE USING THIS PRODUCT!
The sample program includes:Download the latest SP Grove OLE Automation Sample with Source Code Now
Parse sgml and html files.The html dtds are included along with some html sample files in the data directory that have parsing errors.
It will print reports indicating the files that passed and did not pass the parse.
Multiple files may be selected.
Double click on the error message and the document is opened in an editor and the nearest word to the error is highlighted.
Built in debugging code that records system and error information.
A normalize function is also provided but it has some bugs. If you should get the bugs fixed let me know so I can fix them on my end as well.NOTE: This sample program has a menu item named Security. When you click this item you will be prompted for a password, the password is the word "password". This was installed to prevent the average user from having access to the Setup menu item which allows you to set the warning toggles for the parser. You might want to remove the code that prompts for a password if it does not apply to your needs.