 |

Date: Jun 30 1999
From: James Skipper
To: ron@oreilly.com
Subject: VBIDE and Add-Ins
I just purchased the O'Reilly book
Developing Visual
Basic Add-ins by Steven Roman.
It is great and has given me a great headstart on
my current project. However, everytime I try to invoke one of the
CodeModule methods, I get a runtime error 35, Sub or Function not
defined.
Here is a code snippet:
Dim vbp As VBProject
Dim w As Window
Dim vbc As VBComponent
Dim vbcm As CodeModule
Dim vbm As Member
Set vbp = VBInstance.ActiveVBProject
For Each vbc In vbp.VBComponents
frmAddIn.List1.AddItem vbc.Name
Set vbcm = vbp.VBComponents _(vbc.Name).CodeModule
For Each vbm In vbcm.Members
LineNumber = vbcm.ProcBodyLine _
(vbm.Name,vbm.Type)
Next
Next
Hi James,
I'd have to say that the Visual Basic's displaying the "Sub or
Function not defined" error message in this case is a worthy
candidate for inclusion in our book, Developing Windows Error
Messages. The problem with your call to the ProcBodyLine property
(which syntactically appears to be a method rather than a property)
is not that the procedure or function is not defined, but rather
that one of the arguments that you've supplied is incorrect.
Your code snippet iterates the components (that is, the objects
listed in the Project Explorer) in a project, and then iterates each
member of the code module belonging to a particular component. For
each member, you call the ProcBodyLine procedure to retrieve the
line number on which the member begins. To do this, you pass two
arguments to the code module's ProcBodyLine property: the name of
the member whose line number is to be retrieved, and the member's
type. This code looks like it should work, except, of course, that
it doesn't; instead, that pesky error message appears.
To see what's wrong with the code, let's begin by taking a closer
look at a code module's Members collection. According to the
documentation, the collection consists of Member objects, each of
which represents a module-level property, method, and or event
contained within that code module. Each member object, however, has
a Type property, which (again according tot he documentation)
returns one of the following members of the vbext_MemberType
enumeration: (click
here for code example)
This suggests that the documentation for the Members collection is
not wholly accurate, and that the collection contains module-level
variables and constants as well as procedures.
Modifying your code
fragment to display the objects of the Members collection confirms
this, as Figure 1 shows.

Figure 1
Now let's look a bit more closely at the ProcBodyLine property of
the CodeModule object, which returns the starting line number of a
procedure. It takes two parameters -- the name of the procedure, and
the procedure's type. This latter parameter, though, seems
unnecessary; you would think that the procedure name should be
sufficient to identify the procedure. However, this isn't accurate;
within a single code module, multiple property procedures can have
the same name. Hence, the ProcBodyLine's type argument requires one
of the following members of the vbext_ProcKind enumeration (and not
of the vbext_MemberType enumeration):
(click here for code
example)
In other words, in your original code snippet, supplying vbm.Type as
an argument to ProcBodyLine raises the "Sub or Function not defined"
error. Instead, the following variation of your code snippet
correctly retrieves the starting line number of functions,
procedures, and properties:
(click here for
code example)
Getting the line number of functions, procedures, and event handlers
is easy enough, since each of these members has a type property
whose value is vbext_mt_Method. There is, however, a complication in
getting the line number for a particular property procedure: there
is just one Member object in the Members collection for each set of
property procedures. Presumably, the Member object's CodeLocation
property returns the line number of the first of the possible set of
property procedures, but its values appear to be inaccurate.
Instead, the code adopts the admittedly kludgy expedient of using
the CodeModule object's ProcBodyLine property to retrieve the
starting line number of each of the three possible types of property
procedures However, if the relevant property is not present, a
runtime error is generated. The code snippet relies on the On Error
Resume Next statement to insure that this does not interrupt program
execution.
I hope that this helps you with your project, and I'm glad that
you're enjoying
Developing Visual
Basic Add-ins.
-- Ron
Return to: Ron's VB Forum

|
 |