Академический Документы
Профессиональный Документы
Культура Документы
aspx
Microsoft Excel
Training
Beginners to
Advanced
Courses 應用
EXCEL於商業及
財務分析
www.welkin.com.hk
Programming The VBA Editor
This page describes how to write code that modifies or reads
other VBA code.
Introduction
You can write code in VBA that reads or modifies other VBA projects, modules, or procedures. This is
called extensibility because extends the editor -- you can used VBA code to create new VBA code. You
can use these features to write custom procedures that create, change, or delete VBA modules and
code procedures.
In order to use the code on this page in your projects, you must change two settings.
First, you need to set an reference to the VBA Extensibililty library. The library contains the
definitions of the objects that make up the VBProject. In the VBA editor, go the the Tools menu
and choose References. In that dialog, scroll down to and check the entry for Microsoft Visual
Basic For Applications Extensibility 5.3. If you do not set this reference, you will receive a
User-defined type not defined compiler error.
Next, you need to enable programmatic access to the VBA Project. In Excel 2003 and earlier,
go the Tools menu (in Excel, not in the VBA editor), choose Macros and then the Security item.
In that dialog, click on the Trusted Publishers tab and check the Trust access to the Visual Basic
Project setting.
In Excel 2007, click the Developer item on the main Ribbon and then click the Macro Security
item in the Code panel. In that dialog, choose Macro Settings and check the Trust access to the
VBA project object model.
The VBA Project that you are going to change with these procedures must be unlocked. There is no
programmatic way to unlock a VBA project (other than using SendKeys). If the project is locked, you
must manually unlock. Otherwise, the procedures will not work.
For information about using creating custom menu items in the Visual Basic Editor, see Menus In The
VBA Editor.
1 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
VBIDE
The VBIDE is the object library that defines all the objects and values that make up VBProject and the
Visual Basic Editor. You must reference this library to use the VBA Extensibility objects. To add this
reference, open the VBA editor, open your VBProject in the editor, and go to the Tools menu. There,
choose References . In the References dialog, scroll down to Microsoft Visual Basic for Applications
Extensibility 5.3 and check that item in the list. You can add the reference programmatically with code
like:
ThisWorkbook.VBProject.References.AddFromGuid _
GUID:="{0002E157-0000-0000-C000-000000000046}", _
Major:=5, Minor:=3
VBE
The VBE refers to the Visual Basic Editor, which includes all the windows and projects that make up
the editor.
VBProject
A VBProject contains all the code modules and components of a single workbook. One workbook
has exactly one VBProject. The VBProject is made up of 1 or more VBComponent objects.
VBComponent
A VBComponent is one object within the VBProject. A VBComponent is a code module, a
UserForm, a class module, one of the Sheet modules, or the ThisWorkbook module (together, the
Sheet modules and the ThisWorkbook module are called Document Type modules.. A VBComponent
is of one of the following types, identified by the Type property. The following constants are used to
identify the Type. The numeric value of each constant is shown in parentheses.
vbext_ct_ClassModule (2): A class module to create your own objects. See Class Modules
for details about classes and objects.
vbext_ct_Document (100): One of the Sheet modules or the ThisWorkbook module.
vbext_ct_MSForm (3): A UserForm. The visual component of a UserForm in the VBA Editor is
called a designer.
vbext_ct_StdModule (1): A regular code module. Most of the procedures on this page will
work with these types of components.
CodeModule
A CodeModule is the VBA source code of a VBComponent. You use the CodeModule object to
access the code associated with a VBComponent. A VBComponent has exactly one CodeModule.
CodePane
A CodePane is an open editing window of a CodeModule.
2 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
' or
Set VBComp = VBProj.VBComponents("Module1")
'''''''''''''''''''''''''''''''''''''''''''
Set CodeMod = ActiveWorkbook.VBProject.VBComponents("Module1").CodeModule
' or
Set CodeMod = VBComp.CodeModule
In the code and descriptions on this page, the term Procedure means a Sub, Function, Property
Get, Property Let, or Property Set procedure. The Extensibility library defines four procedures
types, identified by the following constants. The numeric value of each constant is shown within
parentheses.
The rest of this page describes various procedures that modify the various objects of a VBProject.
You can test whether the editor in in sync with code like the following.
You can force synchronization with code like the following. This will set the ActiveVBProject to the
project associated with the ActiveCodePane.
Sub SyncVBAEditor()
'=======================================================================
' SyncVBAEditor
' This syncs the editor with respect to the ActiveVBProject and the
' VBProject containing the ActiveCodePane. This makes the project
' that conrains the ActiveCodePane the ActiveVBProject.
'=======================================================================
With Application.VBE
If Not .ActiveCodePane Is Nothing Then
Set .ActiveVBProject = .ActiveCodePane.CodeModule.Parent.Collection.Parent
End If
End With
End Sub
Sub AddModuleToProject()
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
3 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
Sub AddProcedureToModule()
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Dim CodeMod As VBIDE.CodeModule
Dim LineNum As Long
Const DQUOTE = """" ' one " character
With CodeMod
LineNum = .CountOfLines + 1
.InsertLines LineNum, "Public Sub SayHello()"
LineNum = LineNum + 1
.InsertLines LineNum, " MsgBox " & DQUOTE & "Hello World" & DQUOTE
LineNum = LineNum + 1
.InsertLines LineNum, "End Sub"
End With
End Sub
ModuleName is the name of the module you want to copy from one project to another.
FromVBProject is the VBProject that contains the module to be copied. This is the source
VBProject.
ToVBProject is the VBProject in to which the module is to be copied. This is the destination
VBProject.
The function returns True if successful or False is an error occurs. The function will return False if
any of the following are true:
FromVBProject is nothing.
ToVBProject is nothing.
ModuleName is blank.
FromVBProject is locked.
ToVBProject is locked.
ModuleName does not exist in FromVBProject.
ModuleName exists in ToVBProject and OverwriteExisting is False.
4 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
'''''''''''''''''''''''''''''''''''''''''''''
' Do some housekeeping validation.
'''''''''''''''''''''''''''''''''''''''''''''
If FromVBProject Is Nothing Then
CopyModule = False
Exit Function
End If
''''''''''''''''''''''''''''''''''''''''''''''''''''
' FName is the name of the temporary file to be
' used in the Export/Import code.
''''''''''''''''''''''''''''''''''''''''''''''''''''
5 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
''''''''''''''''''''''''''''''''''''''''''''''''''''
' Do the Export and Import operation using FName
' and then Kill FName.
''''''''''''''''''''''''''''''''''''''''''''''''''''
FromVBProject.VBComponents(ModuleName).Export Filename:=FName
'''''''''''''''''''''''''''''''''''''
' Extract the module name from the
' export file name.
'''''''''''''''''''''''''''''''''''''
SlashPos = InStrRev(FName, "\")
ExtPos = InStrRev(FName, ".")
CompName = Mid(FName, SlashPos + 1, ExtPos - SlashPos - 1)
''''''''''''''''''''''''''''''''''''''''''''''
' Document modules (SheetX and ThisWorkbook)
' cannot be removed. So, if we are working with
' a document object, delete all code in that
' component and add the lines of FName
' back in to the module.
''''''''''''''''''''''''''''''''''''''''''''''
Set VBComp = Nothing
Set VBComp = ToVBProject.VBComponents(CompName)
6 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
End If
Kill FName
CopyModule = True
End Function
Sub CreateEventProcedure()
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Dim CodeMod As VBIDE.CodeModule
Dim LineNum As Long
Const DQUOTE = """" ' one " character
With CodeMod
LineNum = .CreateEventProc("Open", "Workbook")
LineNum = LineNum + 1
.InsertLines LineNum, " MsgBox " & DQUOTE & "Hello World" & DQUOTE
End With
End Sub
Sub DeleteModule()
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Sub DeleteProcedureFromModule()
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Dim CodeMod As VBIDE.CodeModule
Dim StartLine As Long
Dim NumLines As Long
Dim ProcName As String
ProcName = "DeleteThisProc"
With CodeMod
7 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
Sub DeleteAllVBACode()
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Dim CodeMod As VBIDE.CodeModule
Application.VBE.MainWindow.Visible = False
This will hide the VBE window, but you may still see it flicker. To prevent this, you must use the
LockWindowUpdate Windows API function.
Sub EliminateScreenFlicker()
Dim VBEHwnd As Long
Application.VBE.MainWindow.Visible = False
VBEHwnd = FindWindow("wndclass_desked_gsk", _
Application.VBE.MainWindow.Caption)
If VBEHwnd Then
LockWindowUpdate VBEHwnd
End If
'''''''''''''''''''''''''
' your code here
'''''''''''''''''''''''''
Application.VBE.MainWindow.Visible = False
ErrH:
LockWindowUpdate 0&
End Sub
8 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
VBComp.Export FileName:=FName
ExportVBComponent = True
End Function
End Function
9 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
Sub ListModules()
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Dim WS As Worksheet
Dim Rng As Range
Sub ListProcedures()
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Dim CodeMod As VBIDE.CodeModule
Dim LineNum As Long
Dim NumLines As Long
Dim WS As Worksheet
Dim Rng As Range
Dim ProcName As String
Dim ProcKind As VBIDE.vbext_ProcKind
Set WS = ActiveWorkbook.Worksheets("Sheet1")
Set Rng = WS.Range("A1")
With CodeMod
LineNum = .CountOfDeclarationLines + 1
Do Until LineNum >= .CountOfLines
ProcName = .ProcOfLine(LineNum, ProcKind)
Rng.Value = ProcName
Rng(1, 2).Value = ProcKindString(ProcKind)
LineNum = .ProcStartLine(ProcName, ProcKind) + _
.ProcCountLines(ProcName, ProcKind) + 1
Set Rng = Rng(2, 1)
Loop
End With
End Sub
10 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
Case vbext_pk_Get
ProcKindString = "Property Get"
Case vbext_pk_Let
ProcKindString = "Property Let"
Case vbext_pk_Set
ProcKindString = "Property Set"
Case vbext_pk_Proc
ProcKindString = "Sub Or Function"
Case Else
ProcKindString = "Unknown Type: " & CStr(ProcKind)
End Select
End Function
FirstLine = .Lines(PInfo.ProcBodyLine, 1)
If StrComp(Left(FirstLine, Len("Public")), "Public", vbBinaryCompare) = 0 Then
PInfo.ProcScope = ScopePublic
ElseIf StrComp(Left(FirstLine, Len("Private")), "Private", vbBinaryCompare) = 0 Then
PInfo.ProcScope = ScopePrivate
ElseIf StrComp(Left(FirstLine, Len("Friend")), "Friend", vbBinaryCompare) = 0 Then
PInfo.ProcScope = ScopeFriend
Else
PInfo.ProcScope = ScopeDefault
End If
PInfo.ProcDeclaration = GetProcedureDeclaration(CodeMod, ProcName, ProcKind, LineSplitKe
11 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
End With
End If
ProcedureInfo = PInfo
End Function
End Function
You can call the ProcedureInfo function using code like the following:
Sub ShowProcedureInfo()
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Dim CodeMod As VBIDE.CodeModule
Dim CompName As String
Dim ProcName As String
Dim ProcKind As VBIDE.vbext_ProcKind
Dim PInfo As ProcInfo
CompName = "modVBECode"
ProcName = "ProcedureInfo"
ProcKind = vbext_pk_Proc
12 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
Sub SearchCodeModule()
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Dim CodeMod As VBIDE.CodeModule
Dim FindWhat As String
Dim SL As Long ' start line
Dim EL As Long ' end line
Dim SC As Long ' start column
Dim EC As Long ' end column
Dim Found As Boolean
FindWhat = "findthis"
With CodeMod
SL = 1
EL = .CountOfLines
SC = 1
EC = 255
Found = .Find(target:=FindWhat, StartLine:=SL, StartColumn:=SC, _
EndLine:=EL, EndColumn:=EC, _
wholeword:=True, MatchCase:=False, patternsearch:=False)
Do Until Found = False
Debug.Print "Found at: Line: " & CStr(SL) & " Column: " & CStr(SC)
EL = .CountOfLines
SC = EC + 1
EC = 255
Found = .Find(target:=FindWhat, StartLine:=SL, StartColumn:=SC, _
EndLine:=EL, EndColumn:=EC, _
wholeword:=True, MatchCase:=False, patternsearch:=False)
Loop
End With
End Sub
13 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' This returns True or False indicating whether a VBComponent named
' VBCompName exists in the VBProject referenced by VBProj. If VBProj
' is omitted, the VBProject of the ActiveWorkbook is used.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim VBP As VBIDE.VBProject
If VBProj Is Nothing Then
Set VBP = ActiveWorkbook.VBProject
Else
Set VBP = VBProj
End If
On Error Resume Next
VBComponentExists = CBool(Len(VBP.VBComponents(VBCompName).Name))
End Function
With VBComp.CodeModule
For N = 1 To .CountOfLines
S = .Lines(N, 1)
If Trim(S) = vbNullString Then
' blank line, skip it
ElseIf Left(Trim(S), 1) = "'" Then
' comment line, skip it
Else
LineCount = LineCount + 1
End If
Next N
End With
TotalCodeLinesInVBComponent = LineCount
End Function
14 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
TotalLinesInProject = LineCount
End Function
With VBComp.CodeModule
For N = 1 To .CountOfLines
S = .Lines(N, 1)
If Trim(S) = vbNullString Then
' blank line, skip it
ElseIf Left(Trim(S), 1) = "'" Then
' comment line, skip it
Else
LineCount = LineCount + 1
End If
Next N
End With
TotalCodeLinesInVBComponent = LineCount
End Function
15 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
TotalCodeLinesInProject = LineCount
End Function
Dim WB As Workbook
Dim AI As AddIn
Dim VBP As VBIDE.VBProject
End Function
16 of 17 05/02/2011 8:51 PM
Programming In The VBA Editor http://www.cpearson.com/excel/vbe.aspx
Submit bug information or errors on the Bug And Error Report Page.
Ready
Excel file migration Move or rename groups of Microsoft Excel files without breaking links! www.LinkFixerPlus.com
Learn Investment Banking Build Financial Models in Excel Step-by-Step Self Study & Classes www.WallStreetPrep.com
Notes-Office Integration Integrate Notes, Word & Excel Reports, quotes, mail merge, export www.integra4notes.com/export
17 of 17 05/02/2011 8:51 PM