I've written a program that runs and messages Skype with information when if finishes. I need to add a reference for Skype4COM.dll in order to send a message through Skype. We have a dozen or so computers on a network and a shared file server (among other things). All of the other computers need to be able to run this program. I was hoping to avoid setting up the reference by hand. I had planned on putting the reference in a shared location, and adding it programmatically when the program ran.
I can't seem to figure out how to add a reference programmatically to Excel 2007 using VBA. I know how to do it manually: Open VBE --> Tools --> References --> browse --_> File Location and Name. But that's not very useful for my purposes. I know there are ways to do it in Access Vb.net and code similar to this kept popping up, but I'm not sure I understand it, or if it's relevant:
ThisWorkbook.VBProject.References.AddFromGuid _
GUID:="{0002E157-0000-0000-C000-000000000046}", _
Major:=5, Minor:=3
So far, in the solutions presented, in order to add the reference programmatically I will need to add a reference by hand and change the Trust Center - which is more than just adding the reference. Though I guess if I follow through with the solutions proposed I will be able to add future references programmatically. Which probably makes it worth the effort.
Any further thoughts would be great.
Ommit
There are two ways to add references via VBA to your projects
1) Using GUID
2) Directly referencing the dll.
Let me cover both.
But first these are 3 things you need to take care of
a) Macros should be enabled
b) In Security settings, ensure that "Trust Access To Visual Basic Project" is checked
c) You have manually set a reference to `Microsoft Visual Basic for Applications Extensibility" object
Way 1 (Using GUID)
I usually avoid this way as I have to search for the GUID in the registry... which I hate LOL. More on GUID here.
Topic: Add a VBA Reference Library via code
Link: http://www.vbaexpress.com/kb/getarticle.php?kb_id=267
'Credits: Ken Puls
Sub AddReference()
'Macro purpose: To add a reference to the project using the GUID for the
'reference library
Dim strGUID As String, theRef As Variant, i As Long
'Update the GUID you need below.
strGUID = "{00020905-0000-0000-C000-000000000046}"
'Set to continue in case of error
On Error Resume Next
'Remove any missing references
For i = ThisWorkbook.VBProject.References.Count To 1 Step -1
Set theRef = ThisWorkbook.VBProject.References.Item(i)
If theRef.isbroken = True Then
ThisWorkbook.VBProject.References.Remove theRef
End If
Next i
'Clear any errors so that error trapping for GUID additions can be evaluated
Err.Clear
'Add the reference
ThisWorkbook.VBProject.References.AddFromGuid _
GUID:=strGUID, Major:=1, Minor:=0
'If an error was encountered, inform the user
Select Case Err.Number
Case Is = 32813
'Reference already in use. No action necessary
Case Is = vbNullString
'Reference added without issue
Case Else
'An unknown error was encountered, so alert the user
MsgBox "A problem was encountered trying to" & vbNewLine _
& "add or remove a reference in this file" & vbNewLine & "Please check the " _
& "references in your VBA project!", vbCritical + vbOKOnly, "Error!"
End Select
On Error GoTo 0
End Sub
Way 2 (Directly referencing the dll)
This code adds a reference to Microsoft VBScript Regular Expressions 5.5
Option Explicit
Sub AddReference()
Dim VBAEditor As VBIDE.VBE
Dim vbProj As VBIDE.VBProject
Dim chkRef As VBIDE.Reference
Dim BoolExists As Boolean
Set VBAEditor = Application.VBE
Set vbProj = ActiveWorkbook.VBProject
'~~> Check if "Microsoft VBScript Regular Expressions 5.5" is already added
For Each chkRef In vbProj.References
If chkRef.Name = "VBScript_RegExp_55" Then
BoolExists = True
GoTo CleanUp
End If
Next
vbProj.References.AddFromFile "C:\WINDOWS\system32\vbscript.dll\3"
CleanUp:
If BoolExists = True Then
MsgBox "Reference already exists"
Else
MsgBox "Reference Added Successfully"
End If
Set vbProj = Nothing
Set VBAEditor = Nothing
End Sub
Note: I have not added Error Handling. It is recommended that in your actual code, do use it :)
EDIT Beaten by mischab1 :)
There are two ways to add references using VBA. .AddFromGuid(Guid, Major, Minor) and .AddFromFile(Filename). Which one is best depends on what you are trying to add a reference to. I almost always use .AddFromFile because the things I am referencing are other Excel VBA Projects and they aren't in the Windows Registry.
The example code you are showing will add a reference to the workbook the code is in. I generally don't see any point in doing that because 90% of the time, before you can add the reference, the code has already failed to compile because the reference is missing. (And if it didn't fail-to-compile, you are probably using late binding and you don't need to add a reference.)
If you are having problems getting the code to run, there are two possible issues.
In order to easily use the VBE's object model, you need to add a reference to Microsoft Visual Basic for Application Extensibility. (VBIDE)
In order to run Excel VBA code that changes anything in a VBProject, you need to Trust access to the VBA Project Object Model. (In Excel 2010, it is located in the Trust Center - Macro Settings.)
Aside from that, if you can be a little more clear on what your question is or what you are trying to do that isn't working, I could give a more specific answer.
Browsing the registry for guids or using paths, which method is best. If browsing the registry is no longer necessary, won't it be the better way to use guids?
Office is not always installed in the same directory. The installation path can be manually altered. Also the version number is a part of the path.
I could have never predicted that Microsoft would ever add '(x86)' to 'Program Files' before the introduction of 64 bits processors.
If possible I would try to avoid using a path.
The code below is derived from Siddharth Rout's answer, with an additional function to list all the references that are used in the active workbook.
What if I open my workbook in a later version of Excel? Will the workbook still work without adapting the VBA code?
I have already checked that the guids for office 2003 and 2010 are identical. Let's hope that Microsoft doesn't change guids in future versions.
The arguments 0,0 (from .AddFromGuid) should use the latest version of a reference (which I have not been able to test).
What are your thoughts? Of course we cannot predict the future but what can we do to make our code version proof?
Sub AddReferences(wbk As Workbook)
' Run DebugPrintExistingRefs in the immediate pane, to show guids of existing references
AddRef wbk, "{00025E01-0000-0000-C000-000000000046}", "DAO"
AddRef wbk, "{00020905-0000-0000-C000-000000000046}", "Word"
AddRef wbk, "{91493440-5A91-11CF-8700-00AA0060263B}", "PowerPoint"
End Sub
Sub AddRef(wbk As Workbook, sGuid As String, sRefName As String)
Dim i As Integer
On Error GoTo EH
With wbk.VBProject.References
For i = 1 To .Count
If .Item(i).Name = sRefName Then
Exit For
End If
Next i
If i > .Count Then
.AddFromGuid sGuid, 0, 0 ' 0,0 should pick the latest version installed on the computer
End If
End With
EX: Exit Sub
EH: MsgBox "Error in 'AddRef'" & vbCrLf & vbCrLf & err.Description
Resume EX
Resume ' debug code
End Sub
Public Sub DebugPrintExistingRefs()
Dim i As Integer
With Application.ThisWorkbook.VBProject.References
For i = 1 To .Count
Debug.Print " AddRef wbk, """ & .Item(i).GUID & """, """ & .Item(i).Name & """"
Next i
End With
End Sub
The code above does not need the reference to the "Microsoft Visual Basic for Applications Extensibility" object anymore.
Here is how to get the Guid's programmatically! You can then use these guids/filepaths with an above answer to add the reference!
Reference: http://www.vbaexpress.com/kb/getarticle.php?kb_id=278
Sub ListReferencePaths()
'Lists path and GUID (Globally Unique Identifier) for each referenced library.
'Select a reference in Tools > References, then run this code to get GUID etc.
Dim rw As Long, ref
With ThisWorkbook.Sheets(1)
.Cells.Clear
rw = 1
.Range("A" & rw & ":D" & rw) = Array("Reference","Version","GUID","Path")
For Each ref In ThisWorkbook.VBProject.References
rw = rw + 1
.Range("A" & rw & ":D" & rw) = Array(ref.Description, _
"v." & ref.Major & "." & ref.Minor, ref.GUID, ref.FullPath)
Next ref
.Range("A:D").Columns.AutoFit
End With
End Sub
Here is the same code but printing to the terminal if you don't want to dedicate a worksheet to the output.
Sub ListReferencePaths()
'Macro purpose: To determine full path and Globally Unique Identifier (GUID)
'to each referenced library. Select the reference in the Tools\References
'window, then run this code to get the information on the reference's library
On Error Resume Next
Dim i As Long
Debug.Print "Reference name" & " | " & "Full path to reference" & " | " & "Reference GUID"
For i = 1 To ThisWorkbook.VBProject.References.Count
With ThisWorkbook.VBProject.References(i)
Debug.Print .Name & " | " & .FullPath & " | " & .GUID
End With
Next i
On Error GoTo 0
End Sub
Related
May I ask how to get to know right GUID of 'Accessibility(System32\oleacc.dll)' for every Access version?
I'd like to get VBA library for 'Accessibility(System32\oleacc.dll)' automatically, depends on the client Access version, using like script as follows.
< Set Excel library depends on Client Access Version >
Sub Set_RefExcel()
On Error GoTo Err_Set_RefExcel
Dim Ref As Reference
Dim AccVer As String
Dim strExcel As String
'Once Unset Any Excel Reference
Call Unset_RefExcel
'Check Access Vertion
AccVer = GetAccessVersion 'Get Access Version my Formular
Select Case AccVer
Case "16.0"
strExcel = "{00020813-0000-0000-C000-000000000046}"
Case "15.0" 'Access2013
strExcel = "{00020813-0000-0000-C000-000000000046}"
Case "14.0" 'Access2010
strExcel = "{00020813-0000-0000-C000-000000000046}"
Case Else
End Select
'Set Reference
Set Ref = References.AddFromGuid(strExcel, 1, 3)
Set Ref = Nothing
Exit Sub
Err_Set_RefExcel:
If Err.Number = 32813 Then
Resume Next
Else
MsgBox Err.Number & " : " & Err.Description
Exit Sub
End If
The reason why I'd like to this is, would like to compact and repair database by VBA, when detect the mdb file getting close to its limit size, 2GB. We need oleacc.dll to use Quick Access ToolBars like following script sample.
http://www.ka-net.org/office/of06.html#CompactAndRepairDatabase
(sorry, it's in all Japanese)
Any advice would be so helpful.
Regards,
You don't need the GUID to add the reference if it has a fixed location on disk independent of the version.
Since it's always in a fixed path from your Windows directory, you can use that:
References.AddFromFile Environ("WINDIR") & "\System32\oleacc.dll"
Thanks to all of usuful advice, revised my script.
Now we can automatically make it compact and repair, when would expand.
Just FYI:
-- Script for Set Accessibility Reference.
Sub Set_AccessibilityReference()
Dim Ref As Reference
'To Avoid 32183 Error, Once Remove Accessibility Reference if already referred
For Each Ref In References
If Ref.Name = "Accessibility" Then
Application.References.Remove Ref
End If
Next Ref
'Accessibility Reference Add
References.AddFromFile Environ("WINDIR") & "\System32\oleacc.dll"
End Sub
-- Set reference before call procedure for Compact and Repair Database
Sub Chk_Optimization(ByVal ChkSizeByte As Long)
On Error Resume Next
Dim strFileName As String
Dim CurrentSizeByte As Long
'Set Reference
Set_AccessibilityReference
'Get Current File Size
strFileName = Application.CurrentDb.Name
CurrentSizeByte = FileLen(strFileName)
'File Size Check
If CurrentSizeByte > ChkSizeByte Then
'Call Procedure for Auto Compact And Repair Database
Exec_CompactAndRepairDatabase
End If
End Sub
-- Before extract and export reports, if file exceeds 0.5 GB, then Compact and Repair
Chk_NeedOptimization 536870912
Again, I really appreciate Erik von Asmuth and Foxfire And Burns And Burns.
Further advice would be grateful.
If anyone notice any issue, please let me know.
Best Regards,
I have this simple VBA code below, and I don't know why is not working.
Sub Run()
test = "MsgBox" & """" & "Job Done!" & """"
Application.Run test
End Sub
What I want to do is to put the VBA Command into a variable as text and run it as a command. In this case, I want to run like MsgBox "Job Done!" and print just:
Job Done!
You may be tempted by adding your own string "Executer":
Sub StringExecute(s As String)
Dim vbComp As Object
Set vbComp = ThisWorkbook.VBProject.VBComponents.Add(1)
vbComp.CodeModule.AddFromString "Sub foo()" & vbCrLf & s & vbCrLf & "End Sub"
Application.Run vbComp.name & ".foo"
ThisWorkbook.VBProject.VBComponents.Remove vbComp
End Sub
Sub Testing()
StringExecute "MsgBox" & """" & "Job Done!" & """"
End Sub
Short answer is, you cannot do that (You should not do that) but ... read the following to find out why and see a work around!
As you know you are writing your code in a compiler. What you want to do is running human-legible line of text as a command which is not possible. While you run the program all of it is compiled to machine language. When you pass that line of text to it, it cannot recognize it as a command and you will end up getting an error. What you can do is passing arguments to it:
Sub Run()
test = "Job Done"
MsgBox(test)
End Sub
You can also run an executable which can be written as a text file within a macro and then runs within the same Sub (extension needs to be taken care of).
If you cannot change the variable (i.e. test) then you need to take another approach towards it. I would suggest something like extracting the argument which can be passed to the function and use that. Something like below;
Sub Run()
test = "MsgBox" & """" & "Job Done!" & """"
extest = Right(test, Len(test) - 7)
MsgBox (extest)
End Sub
I believe there was a same question on SO but I couldn't find it. I will included it as a reference if found it.
P.S. These two posts may help to find an answer:
Access VBA - Evaluate function with string arguments
Excel VBA - How to run a string as a line of code
ANOTHER SOLUTION
This needs to trust the VB project. Quoting from ExcelForum and referencing to Programmatic Access To Visual Basic Project Is Not Trusted - Excel
Quote:
Place your Macro-Enabled Workbook in a folder which you can designate
as macro friendly.
Then open the workbook.
Click on the Office Button -> Excel Options ->
Trust Center -> Trust Center Setting -> Trusted Locations.
Then you add your folder (where you have your Excel Macro-Enabled Workbook) as
a trusted location.
Also you need to do this:
File -> Options -> Trust Center -> Trust Center Setting -> Macro Setting ->
Check the box beside "Trust access to the VBA project object model"
Close and re-open your workbook.
Those who use your macro should go through the same steps.
Unquote.
Then you can use this which I got from VBA - Execute string as command in Excel (This is not tested)
Sub test()
Set VBComp = ThisWorkbook.VBProject.VBComponents.Add(vbext_ct_StdModule)
VBComp.Name = "NewModule"
Set VBCodeMod = ThisWorkbook.VBProject.VBComponents("NewModule").CodeModule
Dim test As String
test = "MsgBox " & """" & "Job Done!" & """"
With VBCodeMod
LineNum = .CountOfLines + 1
.InsertLines LineNum, _
"Sub MyNewProcedure()" & Chr(13) & test & Chr(13) & "End Sub"
End With
'run the new module
Application.Run "MyNewProcedure"
UserForm1.Show
'Delete the created module
ThisWorkbook.VBProject.VBComponents.Remove VBComp
End Sub
#A.S.H answer does the thing that last solution intends to implement. I am including it here for the sake of completeness. You can refer to the original answer and up-vote it.
Public Sub StringExecute(s As String)
Dim vbComp As Object
Set vbComp = ThisWorkbook.VBProject.VBComponents.Add(1)
vbComp.CodeModule.AddFromString "Sub foo" & vbCrLf & s & vbCrLf & "End Sub"
Application.Run vbComp.name & ".foo"
ThisWorkbook.VBProject.VBComponents.Remove vbComp
End Sub
Sub Testing()
StringExecute "MsgBox" & """" & "Job Done!" & """"
End Sub
If you need a solution which doesn't require special permissions, and has significantly more power than hard coding code, I maintain a library, stdLambda from stdVBA, for this kind of thing:
'Ensure module name is "mainModule"
Public Sub Main()
Call stdLambda.bindGlobal("msgbox", stdCallback.CreateFromModule("mainModule","msgbox"))
x = stdLambda.Create("msgbox(""hello world"")").Run()
End Sub
Public Function msgbox(ByVal sMessage as string) as long
msgbox = VBA.msgbox(sMessage)
End Function
stdLambda syntax is vba-like but is a fully embedded programming language in its own right. See the documentation for more details.
I was up against a similar variation: the macro name was in a 'control specification' worksheet table. A custom ribbon was added with an 'onAction' parameter in the ribbon XML. The 'tag' Name was returned in the Ribbon call back macro that was then used to lookup the macro Name to run based on the XML tag name. Makes sense so far!!!! I already had the handling subs in an existing Code Module=[m0_RibbonCallBack]. In the [m0_RibbonCallBack] module I wanted to run the sub name=[mResetToCellA2] when I clicked the ribbon button with tagName=[Reset2CellA2]. In the 'control specification' worksheet table I did a vLookUp() on the tagname=[Reset2CellA2] and returned the string value from column 3 (onAction) ="mResetToCellA2". Now I need to run the macro string (macroName) name on the VBA side!!!
I wound up solving the challenge with this simple line:
Application.Run "m0_RibbonCallBack." & macroName
Cheers!
RESOLVED: I've accepted an answer below from Siddharth. I greatly appreciate everyone's help and I am amazed at the swift responses. I always learn something new when coming to this community for help, you guys are awesome.
Thanks for taking a moment to look at my message. I've put together a script (thanks in no small part to the great help here on SO) that takes an excel workbook and imports each worksheet to a separate table in an Access 2007 database. The script used to work fine on my PC but since a recent recovery from a hardware failure I haven't been able to get the script to run. To top it off, my client is getting different error messages than my own.
A large part of the issue has to do with my object references, when I have the Microsoft Excel 14 Object Library added as a reference from the tools menu, all works fine. However, the client has a different version of Office on their systems and wishes this app to be distributed to others who may have other versions of office installed. I've tried to implement some form of late binding, but I may not be approaching this correctly. Code is below:
edit: current code updated again, related to the accepted post from Siddharth below
Private Sub Command101_Click()
On Error GoTo Err_Command101_Click
' Set up excel object
Dim excelApp As Object
Set excelApp = CreateObject("Excel.Application")
' Set up workbook object
Dim excelbook As Object
' Set up file selection objects with parameters
Dim fileSelection As Object
Dim intNoOfSheets As Integer, intCounter As Integer
Dim strFilePath As String, strLastDataColumn As String
Dim strLastDataRow As String, strLastDataCell As String
' Prompt user with file open dialog
Set fileSelection = Application.FileDialog(1)
fileSelection.AllowMultiSelect = False
fileSelection.Show
' Get the selected file path
strFilePath = fileSelection.SelectedItems.Item(1)
' Open the workbook using the file path
Set excelbook = excelApp.Workbooks.Open(strFilePath)
' Get the number of worksheets
intNoOfSheets = excelbook.Worksheets.Count
' Set up object for current sheet name
Dim CurrSheetName As String
' Disable errors
DoCmd.SetWarnings False
' Loop through each sheet, adding data to the named table that matches the sheet
For intCounter = 1 To intNoOfSheets
excelbook.Worksheets(intCounter).Activate
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel12, _
excelbook.Worksheets(intCounter).Name, strFilePath, True, _
excelbook.Worksheets(intCounter).Name & "!" & _
Replace(excelbook.Worksheets(intCounter).UsedRange.Address, "$", "")
Next
' Close Excel objects
excelbook.Close
excelApp.Quit
Set excelApp = Nothing
' Confirmation message
MsgBox "Data import Complete!", vbOKOnly, ""
DoCmd.SetWarnings True
Err_Command101_Click:
MsgBox Err.Description
End Sub
The failure seems to occur for the client on the line Set excelbook = excelApp.Workbooks.Add with this message:
My question is somewhat twofold:
a) Have I implemented late binding properly? and
b) How can I resolve this error while making sure to keep the script independent of a specific Office release?
Thanks for any help you can provide!
I believe the error is in this line
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel12, ActiveSheet.Name, _
strFilePath, True, _
excelbook.Worksheets(intCounter).Name & "!" & _
Replace(excelbook.Worksheets(intCounter).UsedRange.Address, "$", "")
ActiveSheet.Name <+++++ This is causing the error.
Change that to excelbook.Worksheets(intCounter).Name
In Latebinding the code will not understand what Activesheet is
FOLLOWUP
You are getting a compile error because you did not add " _" at the end of the first line in DoCmd.TransferSpreadsheet
Copy the below code and paste it as it is in your code.
DoCmd.TransferSpreadsheet acImport, acSpreadsheetTypeExcel12, _
excelbook.Worksheets(intCounter).Name, _
strFilePath, True, _
excelbook.Worksheets(intCounter).Name & "!" & _
Replace(excelbook.Worksheets(intCounter).UsedRange.Address, "$", "")
The Workbooks.Add method creates a new workbook. I don't understand why you're using that. Seems so me you want the user to select an existing workbook and open that, so you should use Workbooks.Open instead.
As to whether you have implemented late binding correctly, make sure your code module includes Option Explicit in its Declarations section (see Gord's answer for useful details), and then run Debug->Compile from the VB Editor's main menu. That effort will alert you to anything in your code (objects, properties, methods, constants) for which you need further work to make them compatible with late binding.
This is a big red flag:
DoCmd.SetWarnings False
Turning SetWarnings off can suppress error information which you need to help understand why your code isn't doing what you want. If you feel you must turn off SetWarnings in your production code, at least leave it on during development and debugging.
I'll add this just for reference... In the VBA IDE Window choose Tools > Options... and ensure that the "Require Variable Declaration" box has a check mark in it:
Then, check all of your existing modules to make sure that the very first two lines are
Option Compare Database
Option Explicit
The Option Explicit statement will be added to any new Modules that you create, but you'll need to add it yourself for any existing Modules.
I've written a program that runs and messages Skype with information when if finishes. I need to add a reference for Skype4COM.dll in order to send a message through Skype. We have a dozen or so computers on a network and a shared file server (among other things). All of the other computers need to be able to run this program. I was hoping to avoid setting up the reference by hand. I had planned on putting the reference in a shared location, and adding it programmatically when the program ran.
I can't seem to figure out how to add a reference programmatically to Excel 2007 using VBA. I know how to do it manually: Open VBE --> Tools --> References --> browse --_> File Location and Name. But that's not very useful for my purposes. I know there are ways to do it in Access Vb.net and code similar to this kept popping up, but I'm not sure I understand it, or if it's relevant:
ThisWorkbook.VBProject.References.AddFromGuid _
GUID:="{0002E157-0000-0000-C000-000000000046}", _
Major:=5, Minor:=3
So far, in the solutions presented, in order to add the reference programmatically I will need to add a reference by hand and change the Trust Center - which is more than just adding the reference. Though I guess if I follow through with the solutions proposed I will be able to add future references programmatically. Which probably makes it worth the effort.
Any further thoughts would be great.
Ommit
There are two ways to add references via VBA to your projects
1) Using GUID
2) Directly referencing the dll.
Let me cover both.
But first these are 3 things you need to take care of
a) Macros should be enabled
b) In Security settings, ensure that "Trust Access To Visual Basic Project" is checked
c) You have manually set a reference to `Microsoft Visual Basic for Applications Extensibility" object
Way 1 (Using GUID)
I usually avoid this way as I have to search for the GUID in the registry... which I hate LOL. More on GUID here.
Topic: Add a VBA Reference Library via code
Link: http://www.vbaexpress.com/kb/getarticle.php?kb_id=267
'Credits: Ken Puls
Sub AddReference()
'Macro purpose: To add a reference to the project using the GUID for the
'reference library
Dim strGUID As String, theRef As Variant, i As Long
'Update the GUID you need below.
strGUID = "{00020905-0000-0000-C000-000000000046}"
'Set to continue in case of error
On Error Resume Next
'Remove any missing references
For i = ThisWorkbook.VBProject.References.Count To 1 Step -1
Set theRef = ThisWorkbook.VBProject.References.Item(i)
If theRef.isbroken = True Then
ThisWorkbook.VBProject.References.Remove theRef
End If
Next i
'Clear any errors so that error trapping for GUID additions can be evaluated
Err.Clear
'Add the reference
ThisWorkbook.VBProject.References.AddFromGuid _
GUID:=strGUID, Major:=1, Minor:=0
'If an error was encountered, inform the user
Select Case Err.Number
Case Is = 32813
'Reference already in use. No action necessary
Case Is = vbNullString
'Reference added without issue
Case Else
'An unknown error was encountered, so alert the user
MsgBox "A problem was encountered trying to" & vbNewLine _
& "add or remove a reference in this file" & vbNewLine & "Please check the " _
& "references in your VBA project!", vbCritical + vbOKOnly, "Error!"
End Select
On Error GoTo 0
End Sub
Way 2 (Directly referencing the dll)
This code adds a reference to Microsoft VBScript Regular Expressions 5.5
Option Explicit
Sub AddReference()
Dim VBAEditor As VBIDE.VBE
Dim vbProj As VBIDE.VBProject
Dim chkRef As VBIDE.Reference
Dim BoolExists As Boolean
Set VBAEditor = Application.VBE
Set vbProj = ActiveWorkbook.VBProject
'~~> Check if "Microsoft VBScript Regular Expressions 5.5" is already added
For Each chkRef In vbProj.References
If chkRef.Name = "VBScript_RegExp_55" Then
BoolExists = True
GoTo CleanUp
End If
Next
vbProj.References.AddFromFile "C:\WINDOWS\system32\vbscript.dll\3"
CleanUp:
If BoolExists = True Then
MsgBox "Reference already exists"
Else
MsgBox "Reference Added Successfully"
End If
Set vbProj = Nothing
Set VBAEditor = Nothing
End Sub
Note: I have not added Error Handling. It is recommended that in your actual code, do use it :)
EDIT Beaten by mischab1 :)
There are two ways to add references using VBA. .AddFromGuid(Guid, Major, Minor) and .AddFromFile(Filename). Which one is best depends on what you are trying to add a reference to. I almost always use .AddFromFile because the things I am referencing are other Excel VBA Projects and they aren't in the Windows Registry.
The example code you are showing will add a reference to the workbook the code is in. I generally don't see any point in doing that because 90% of the time, before you can add the reference, the code has already failed to compile because the reference is missing. (And if it didn't fail-to-compile, you are probably using late binding and you don't need to add a reference.)
If you are having problems getting the code to run, there are two possible issues.
In order to easily use the VBE's object model, you need to add a reference to Microsoft Visual Basic for Application Extensibility. (VBIDE)
In order to run Excel VBA code that changes anything in a VBProject, you need to Trust access to the VBA Project Object Model. (In Excel 2010, it is located in the Trust Center - Macro Settings.)
Aside from that, if you can be a little more clear on what your question is or what you are trying to do that isn't working, I could give a more specific answer.
Browsing the registry for guids or using paths, which method is best. If browsing the registry is no longer necessary, won't it be the better way to use guids?
Office is not always installed in the same directory. The installation path can be manually altered. Also the version number is a part of the path.
I could have never predicted that Microsoft would ever add '(x86)' to 'Program Files' before the introduction of 64 bits processors.
If possible I would try to avoid using a path.
The code below is derived from Siddharth Rout's answer, with an additional function to list all the references that are used in the active workbook.
What if I open my workbook in a later version of Excel? Will the workbook still work without adapting the VBA code?
I have already checked that the guids for office 2003 and 2010 are identical. Let's hope that Microsoft doesn't change guids in future versions.
The arguments 0,0 (from .AddFromGuid) should use the latest version of a reference (which I have not been able to test).
What are your thoughts? Of course we cannot predict the future but what can we do to make our code version proof?
Sub AddReferences(wbk As Workbook)
' Run DebugPrintExistingRefs in the immediate pane, to show guids of existing references
AddRef wbk, "{00025E01-0000-0000-C000-000000000046}", "DAO"
AddRef wbk, "{00020905-0000-0000-C000-000000000046}", "Word"
AddRef wbk, "{91493440-5A91-11CF-8700-00AA0060263B}", "PowerPoint"
End Sub
Sub AddRef(wbk As Workbook, sGuid As String, sRefName As String)
Dim i As Integer
On Error GoTo EH
With wbk.VBProject.References
For i = 1 To .Count
If .Item(i).Name = sRefName Then
Exit For
End If
Next i
If i > .Count Then
.AddFromGuid sGuid, 0, 0 ' 0,0 should pick the latest version installed on the computer
End If
End With
EX: Exit Sub
EH: MsgBox "Error in 'AddRef'" & vbCrLf & vbCrLf & err.Description
Resume EX
Resume ' debug code
End Sub
Public Sub DebugPrintExistingRefs()
Dim i As Integer
With Application.ThisWorkbook.VBProject.References
For i = 1 To .Count
Debug.Print " AddRef wbk, """ & .Item(i).GUID & """, """ & .Item(i).Name & """"
Next i
End With
End Sub
The code above does not need the reference to the "Microsoft Visual Basic for Applications Extensibility" object anymore.
Here is how to get the Guid's programmatically! You can then use these guids/filepaths with an above answer to add the reference!
Reference: http://www.vbaexpress.com/kb/getarticle.php?kb_id=278
Sub ListReferencePaths()
'Lists path and GUID (Globally Unique Identifier) for each referenced library.
'Select a reference in Tools > References, then run this code to get GUID etc.
Dim rw As Long, ref
With ThisWorkbook.Sheets(1)
.Cells.Clear
rw = 1
.Range("A" & rw & ":D" & rw) = Array("Reference","Version","GUID","Path")
For Each ref In ThisWorkbook.VBProject.References
rw = rw + 1
.Range("A" & rw & ":D" & rw) = Array(ref.Description, _
"v." & ref.Major & "." & ref.Minor, ref.GUID, ref.FullPath)
Next ref
.Range("A:D").Columns.AutoFit
End With
End Sub
Here is the same code but printing to the terminal if you don't want to dedicate a worksheet to the output.
Sub ListReferencePaths()
'Macro purpose: To determine full path and Globally Unique Identifier (GUID)
'to each referenced library. Select the reference in the Tools\References
'window, then run this code to get the information on the reference's library
On Error Resume Next
Dim i As Long
Debug.Print "Reference name" & " | " & "Full path to reference" & " | " & "Reference GUID"
For i = 1 To ThisWorkbook.VBProject.References.Count
With ThisWorkbook.VBProject.References(i)
Debug.Print .Name & " | " & .FullPath & " | " & .GUID
End With
Next i
On Error GoTo 0
End Sub
In VBA Help for the RefersTo Property, they give this example of listing all the Names in a Wkb (fleshed out so you can run it as is)
Sub showNames()'from VBA Help for "RefersTo"
Dim newSheet As Worksheet
Set newSheet = Worksheets.Add
Dim i As Long, nm As Name
i = 1
For Each nm In ActiveWorkbook.Names
newSheet.Cells(i, 1).Value = nm.Name
newSheet.Cells(i, 2).Value = "'" & nm.RefersTo
i = i + 1
Next
newSheet.Columns("A:B").AutoFit
End Sub
When I run that on my current project, it turns up many Names that I thought were long gone. But here they are still hanging around and referring to places that no longer exist. I think this is what's slowing up my system and I'd love to get rid of those Names, but they don't show up in the Define Name window so where do I find them?
edit: Meant to mention that the Links item is greyed out for this Wbk.
Update
option 1
A manual method to delete corrupt names using R1C1 (I can recall JKP stating on another forum he had code to do this but he wasn't prepared to provide it for free)
Select Tools, Options and click the General tab.
Click the check box next to "R1C1 Reference Style", so that you change the current setting.
Press OK.
Excel will prompt you to change the name of any name (in all open workbooks!) that contains illegal characters.
Select Insert, name, define to delete the newly renamed names.
Set the R1C1 Reference style back the way you prefer using Tools, Options, General.
option 2
Chris Neilsen posted this at Any chance to delete programatically corrupt ranged names (with spaces) in Excel (2007/2010)
But, here's a possible alternative: SaveAs your workbook as a .xlsm
You should get a dialog complaining about invalid names, with a option
to rename and a Ok to All button. Once saved, close and reopen the
file, Save As an .xls and you should be good to go
Initial Post
Download Name Manager which is the stand out addin by Jan Karel Pieterse and Charles Williams for managing names
It will handle Names that
now error out as the ranges have been deleted (your issue),
link to other Workbooks,
are now corrupt
Plus it will convert global names to local sheet names, and vice versa and so on
- Updated Answer -
Since you know the names of the invalid ranges but can't see them in the Name Manager, you can try to delete them manually from the VBA Immediate window. The name you gave GrPix!patternListRange indicates a worksheet name so you should be able to delete it by typing
ActiveWorkbook.Names("GrPix!patternListRange").Delete
or
Sheets("GrPix").Names("patternListRange").Delete
in the Immediate Window
Original Answer
Have you tried deleting the invalid names via code? i.e.
For Each nm In ActiveWorkbook.Names
If InStr(nm.RefersTo, "OldFileName.xls") > 0 Then
nm.Delete
End If
Next nm
Here are two more solutions that may work for others searching on this topic, but these still don't fix my own particular Workbook.
I'm still looking.
This is from Aaron Blood and shows the R1C1 method mentioned by brettdj:
Sub RemoveDemonLinks()
Dim wbBook As Workbook
Dim nName As Name
Dim i As Long
Set wbBook = ActiveWorkbook
i = 0
If wbBook.Names.Count > 0 Then
With Application
.ReferenceStyle = xlR1C1
.ReferenceStyle = xlA1
End With
For Each nName In wbBook.Name
If InStr(nName.RefersTo, "#REF!") > 0 Then nName.Delete
i = i + 1
Next nName
If i > 0 Then MsgBox i & " corrupted names was deleted from " & wbBook.Name
End If
End Sub
This is from MS Help
' Module to remove all hidden names on active workbook
Sub Remove_Hidden_Names()
' Dimension variables.
Dim xName As Variant
Dim Result As Variant
Dim Vis As Variant
' Loop once for each name in the workbook.
For Each xName In ActiveWorkbook.Names
'If a name is not visible (it is hidden)...
If xName.Visible = True Then
Vis = "Visible"
Else
Vis = "Hidden"
End If
' ...ask whether or not to delete the name.
Result = MsgBox(prompt:="Delete " & Vis & " Name " & _
Chr(10) & xName.Name & "?" & Chr(10) & _
"Which refers to: " & Chr(10) & xName.RefersTo, _
Buttons:=vbYesNo)
' If the result is true, then delete the name.
If Result = vbYes Then xName.Delete
' Loop to the next name.
Next xName
End Sub