This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
Before You Create a VB Add-In, Learn the IDE's Object Model
by Mike D. Jones
By now, you probably know Visual Basic 6.0's IDE backwards and forwards. After all, it's the staging point for all of your VB projects--you make your living with it every day. But what do you do when you want to create procedures that effect the IDE? For instance, you might need an add-in that inserts canned code and modules into a user's local application. Or, perhaps you'd like to make your life easier and create automatic code generators that insert useful functions into a module.
Fortunately, Visual Basic provides an object model, called the Microsoft Visual Basic 6.0 Extensibility library (VBIDE), that you can program and manipulate via code. In this article, we'll explain some of the VBIDE's basic objects. Then, in the article "Save development time with code generating add-ins," we'll build a code generator that will make life a little easier for you by automatically inserting some commonly used functions into your projects.
VBIDE object model basics
In the VBIDE object model, the VBE object contains the collection of projects. In turn, each project holds various components--forms, modules, class modules and references. Each of these components has an associated code module. As you'd expect, the VBProjects collection contains each VBProject; the VBComponents collection contains each VBComponent; and the CodeModule object represents each component's code module. Each component has a CodeModule property that lets you access its underlying CodeModule object, like so:
Set vbCode = objVBComp.CodeModule
where the objVBComp variable represents a VBComponent. Finally, the VBE top-level object also contains a VBForm object, which lets you manipulate forms, controls and designers. Of course, this is by no means an all-inclusive representation of the VBIDE object model, but it will give you a good grounding. Next, let's take a look at some useful commands.
Working with lines of code
In a VBE CodeModule, VB manipulates entire lines of code, rather than individual keywords. The Lines property returns an entire code line or block of lines. This property takes the startline and count arguments. The startline parameter indicates the first code line you want to return (code lines start at 1), while count specifies the number of lines to return. So, the VB statement
myString = vbCode.Lines(3,5)
would set the myString variable equal to five lines of code in the vbCode object variable, starting with line number three. Of course, if the CodeModule doesn't contain code, the Lines property generates an error. With this in mind, you can use the CountOfLines property to determine the number of code lines in the CodeModule, as in
iCount = vbCode.CountOfLines
|Warning: When you use any of the CodeModule's code manipulation properties or methods, keep in mind that this object includes all lines in its count, such as procedure and event declarations as well as carriage returns. So, if a standard module contained
then the CountOfLines property would return six four code lines and two carriage returns.
Inserting and deleting code lines
Often you'll need a way to insert and delete code lines from a component, and the VBIDE uses two methods to do so: InsertLines and DeleteLines. As their first argument, both of these methods take a Long argument that indicates which line you want to manipulate. As its second argument, the InsertLines method takes the string of code that you want to insert. For instance, to place a comment in the general declarations section of a component, you'd use
vbCode.InsertLines 1, "'Hello, world!"
To delete this line, you'd add
To remove an entire code block, use
vbCode.DeleteLines 1, 5
which would delete lines one through five.
Finding specific code strings
Once your add-in accesses a code module, it can use the Find method to locate a specific string. This method returns a True value if the search is successful, and takes the following syntax:
object.Find(Target, StartLine, StartCol, _ EndLine, EndCol [, WholeWord] _ [,MatchCase] [,PatternSearch])
Here, object represents any CodeModule, which is the only object on which you can execute this method. Indicate the text or pattern you want to find in the Target argument. Both StartLine and StartCol serve two purposes. When you call the Find method, these arguments indicate the line number and column number within that line where you want to begin the search. If VB finds code matching the Target argument, it changes StartLine to the line number where it found the match, and StartCol to the column number in the code line where the match begins. Similarly, VB changes EndLine and EndCol to the last line and last column of the match.
The next three optional boolean arguments are the same as those in the IDE's Replace dialog box. When you set WholeWord to True, VB searches for whole words only. To indicate that VB should match the case of your search string with potential matches, use True for the MatchCase argument. Lastly, a True value in PatternSearch indicates that the search string contains pattern-matching characters, such as *, ?, or [ and ].
Finally, be aware that this method doesn't execute recursively. That is, it only finds the first instance of the specified search string. If you want to search the entire CodeModule, you'll want to set up your own loop. We'll show you one way to do so in a moment.
Replacing the code now that you've found it
Once your procedure finds a specific string, the VBIDE gives you the option to replace it with the ReplaceLine method. Use this command
where object represents a CodeModule object. The line argument indicates the line number that you want to replace, and code is the string of code you want to insert. In most cases, to replace a specific keyword within a statement, you'll need to parse out the string you don't want and concatenate the string you do. You can use the altered arguments from the Find method to help you do so.
An example add-in
At this point, let's take a look at a simple add-in that uses each of the objects, properties and methods we've discussed. To do so, launch Visual Basic. In the New Project dialog box, select Addin to create this project. When you do, Visual Basic sets up a barebones add-in project, which includes a designer and form. In the designer, choose Visual Basic 6.0 as the Application Version, and Command Line/Startup as the Initial Load Behavior option. We'll use the code as is. So for now, in the Project Explorer window, double-click on the frmAddIn icon to open this form in design view. Next, drop a command button onto the form, and then open the form's Code window. As you can see, Visual Basic has already supplied some stock code that creates an instance of the VBE object in the VBInstance variable. For our example, all we need do is add some code to the command button's Click() event.
What exactly is a VBComponent, anyway?
To begin, let's see what types of objects the VBE considers to be VBComponents. To do so, in Command1's Click() event, enter the following code:
Dim vbcom As VBComponent For Each vbcom In VBInstance _ .ActiveVBProject.VBComponents MsgBox vbcom.Name Next vbcom Set vbcom = Nothing End Sub
Now, press [F5] to run the add-in. At this point, we'll need to create a separate project in which to run the add-in. To do so, launch a new instance of Visual Basic and create a standard project. In addition to the default form, add one class and one standard module, as well as a property page and a UserControl. Next, select Add-Ins | My Addin from the menu bar. When you do, Visual Basic should display the form from your add-in project. Click the Command button, and Visual Basic loops through all the components in the current project and displays their names.
Working with lines
Now, let's add code that will insert a comment into every component. First, however, in the test project add the procedure in Listing A to the default form's Load() event. Because we're going to alter the add-in, we'll need to reconnect to the updated version. The simplest way to do so is to save the test project and then close this particular Visual Basic IDE instance. Next, switch to the add-in project, and click the End button to shut down the add-in. Open frmAddIn's Code window and update the Click() event as shown in Listing B. As you can see, the procedure will insert the comment "Hello, World!" in those components that contain code. It also displays the second code line in a message box.
Listing A: Dummy code to illustrate CodeModule properties and methods
Private Sub Form_Load() Dim dummy1 As String Dim dummy2 As Integer Dim dummy3 As Boolean dummy1 = "Test code" dummy2 = 500 dummy3 = False End Sub
Listing B: The add-in's updated Click() event procedure
Private Sub Command1_Click() Dim vbcom As VBComponent Dim vbCode As CodeModule Dim sCode As String Dim lCount As Long For Each vbcom In VBInstance.ActiveVBProject _ .VBComponents MsgBox vbcom.Name sCode = "" Set vbCode = vbcom.CodeModule With vbCode lCount = .CountOfLines If lCount Then .InsertLines 1, "'Hello, world!" sCode = .Lines(2, 1) MsgBox sCode End If End With Next vbcom Set vbCode = Nothing End Sub
To test the modifications, press [F5] to execute the add-in, and then launch a new instance of Visual Basic. When prompted, select the Recent tab and open the test project. Select Add-Ins | My AddIn from the menu bar. When you do, Visual Basic displays the names of each VBComponent, inserts a comment into the Form1's general declarations section, and displays the form's second line of code, which should be the Load() event's opening declaration.
An iterative find-and-replace procedure
As our last example, let's create a simple find-and-replace procedure that iterates through an entire module and replaces every matching search string, not just the first one. To do so, follow the same steps we outlined earlier to shut down the test project and return to the add-in project. Next, in frmAddIn's code module, enter the FindAndReplace sub procedure shown in Listing C. This procedure takes as its first argument the string you want to find, the string you want to insert as its second argument, and the CodeModule you want to search as its third argument. Of course, to make the procedure more robust, you could also include parameters to set the Find() method's other arguments, such as MatchCase and PatternSearch. Finally, to call the new procedure, in Command1's Click() event add the following statement to the bottom of the If lCount Then code block:
FindAndReplace "Dim", "Public", vbCode
We'll use this procedure to give the variables in the test project a public scope. Figure A shows the test project's final code after running the add-in.
Listing C: The FindAndReplace sub procedure
Private Sub FindAndReplace(sToFind As String, _ sToReplace As String, objToSearch As CodeModule) Dim sCode As String Dim lCount As Long Dim lStartCol As Long Dim lStartLine As Long Dim lEndCol As Long Dim bFound As Boolean Dim sBeginLine As String Dim sEndLine As String sCode = "" lStartLine = 1 lStartCol = 1 With objToSearch lCount = .CountOfLines If lCount Then Do 'execute at least one search bFound = .Find(sToFind, lStartLine, lStartCol, _ lCount, lEndCol, True, False, False) If bFound Then 'Replace search string with replacement string sCode = .Lines(lStartLine, 1) sBeginLine = Left(sCode, lStartCol - 1) sEndLine = Mid(sCode, lEndCol) .ReplaceLine Line:=lStartLine, _ String:=sBeginLine & sToReplace & sEndLine lStartLine = lStartLine + 1 End If Loop While bFound End If End With End Sub
Figure A: We used an iterative find-and-replace procedure to replace all Dim keywords with Public.
On to bigger and better add-ins
Now that you've gained an understanding of the VBE object model's fundamentals, you're ready to move on to more advanced uses. In "Save development time with code generating add-ins," Douglas Allen explains how to use these new tools to build a bigger and better code generator.
Copyright © 2000 Element K Content LLC. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Element K Content LLC is prohibited. Element K is a service mark of Element K LLC.