VBA Dim Object error - excel

If I Run
Sub test()
Dim Template_Excel_Instance As excel.application
Set Template_Excel_Instance = CreateObject("excel.application")
End Sub
my code breaks with an error "Automation Error, Library not registered"
If I run
Sub test()
Dim Template_Excel_Instance As object
Set Template_Excel_Instance = CreateObject("excel.application")
End Sub
It runs fine. Is there any way to fix this? Reason I ask is that this issue only affects one PC, despite having the same references as all other PCs. The first error is not coming up anywhere else

Does that PC have a different version of Excel?
The problem is with As Excel.Application. If you don't have the appropriate reference defined, then the VBA compiler will not recognise the type. Yes, VBA does have a compilation step. If you do have the reference defined, then this is sensitive to the application version (just the major part of the application version I think), so is therefore inherently non-portable.
In your latter example, you are using late binding, so only COM object registration is required, not any specific library to be added to your project. For portability, this is the way to go.

Firstly, have you tried repairing the install?
Secondly, is there a reason you are instantiating a second instance of Excel?
Thirdly, let's get a grip on what is happening, please run this code and report back.
Option Explicit
Sub TestWhatVersionDoesCreateObjectReturn()
Dim obj As Object
Set obj = CreateObject("Excel.Application")
Debug.Print obj.Version
End Sub
Sub TestWhatOtherVersionsAreCreatable()
Dim lLoop As Long
For lLoop = 7 To 16
Dim obj As Object
Set obj = Nothing
On Error Resume Next '///set break on unhadnled errors
Set obj = CreateObject("Excel.Application." & CStr(lLoop))
On Error GoTo 0
If Not obj Is Nothing Then Debug.Print obj.Version
Next
End Sub
Also, look for multiple installations of Excel. The code at this blog page will read your registry and write the results to an Excel worksheet. You say you have repaired the install but there might be other Excel installations interfering. The code in that blog will highlight multiple Excel installs.
Ok, from your feedback you say all the Excel libraries version return 14, implying no multi version installs. Hmmm, we ought to consider that actually the library that error is complaining about isn't Excel but a dependency.
Other possible leads
Social MSDN - automation error. Library not registered - solved by cleaning registry of legacy "Microsoft.Office.Interop.Excel" keys

Related

Can't create Scripting.Dictionary or MSXML.DOMDocument60 in VBA since Windows Update KB4586781

Some VBA code no longer works for me, when creating COM objects from standard libraries such as Microsoft Scripting Runtime or Microsoft Xml, v6.0. I get an error on the line of instantiation, the error is code
80004021(-2147467231) and error description is Automation error The operation attempted is not supported. But I can create C# code with interop references to these libraries perfectly fine. I had an Windows 10 update KB4586781 two days ago.
The code fails in both Excel VBA and Word VBA. Anyone else with similar issues?
Sub TestCreate_Scripting_Dictionary()
'* THIS CODE FAILS !!!!
Dim lateBound As Object
Set lateBound = VBA.CreateObject("Scripting.Dictionary") '<=== FAILS 80004021
' ... Automation error The operation attempted is not supported.
'* Tools->References->Microsoft Scripting Runtime
Dim dict As Scripting.Dictionary
Set dict = New Scripting.Dictionary '<=== FAILS 80004021
' ... Automation error The operation attempted is not supported.
End Sub
Sub TestCreate_MSXML2_DOMDocument60()
'* THIS CODE FAILS !!!!
'* Tools->References->Microsoft Xml, v6.0
Dim xml As MSXML2.DOMDocument60
Set xml = New MSXML2.DOMDocument60 '<=== FAILS 80004021
' ... Automation error The operation attempted is not supported.
End Sub
UPDATE: I was meaning to reinstall but it went away without any intervention. Odd.

Workbook Subroutines cannot be called directly by name anymore from VB6

I have a vb6 program that calls Macros from an Excel file.
Until recently it worked fine (for years), but now it throws an error.
We get a runtime 438 "Object doesn't support this property or method" error.
As an example you can use this simple vb6 program:
Set App = CreateObject("Excel.Application")
Set wrkbook = App.Workbooks.Open(fileName)
App.visible = True
wrkbook.Test
The above code doesn't work anymore.
Instead, if we replace the last line with this:
wrkbook.Application.Run "ThisWorkbook.Test"
it works.
The Excel reference used for this, was "Microsoft Excel 16.0 Object Library"
This has been tested against Excel 2010, 2013, Excel365 with the same results.
Also security settings are all set off in Excel.
Before changing my entire codebase and use Application.Run, I would know why this is happening.
Also using Application.Run has also some downsides, like calling both private & public subs and exceptions thrown are not propagated back to vb6.
Are there other considerations for using Application.Run?
Did Microsoft changed something lately (Scurity update), or am I doing something wrong?
I found the problem, thanks to #UuDdLrLrSs comment.
Problem was the use of early binding.
All Excel objects should use late binding.
More specific, the workbook should be declared as object:
Dim wrkbook As Object 'New Excel.Workbook
Otherwise it cannot recognize/find your Macro method.

How to auto check the 'Microsoft ActiveX Data Objects x.x Library' from the Tools --> References?

We share our Excel Macro - MS Access project with our client.
They don't know to select the 'Microsoft ActiveX Data Objects x.x Library' from the Tools --> References.
Any code to automatically update MS ADO library settings?
Note: In Office we are using MS 2010. I think the client's office is using Micorsoft XP.
I suggest above to use late binding, but you could do something like this (my code exactly as used in PPT 2010, should be easy enough to adapt to Access but I do not ever use access).
You may need to change the ADODBReference constant for use in XP. Or you could add another constant and a logic check to see what Application.Version and load from the appropriate destination path.
Public Const ADODBReference As String = "C:\Program Files (x86)\Common Files\System\ado\msado15.dll"
Sub PPT_AddRefToADODBLibrary()
'Adds a programmatic reference to ADODB library if one doesn't already exist
'ADODBReference is a public const refers to Microsoft ActiveX Data Objects 6.0 Library
If Not PPT_RefExists(ADODBReference, "Microsoft ActiveX Data Objects 6.0 Library") Then
Application.VBE.ActiveVBProject.References.AddFromFile _
ADODBReference
Else:
'Already installed
End If
End Sub
The sub above calls on this custom function, which first iterates the active References
Function PPT_RefExists(refPath As String, refDescrip As String) As Boolean
'Returns true/false if a specified reference exists, based on LIKE comparison
' to reference.description.
Dim ref As Variant
Dim bExists As Boolean
'Assume the reference doesn't exist
bExists = False
For Each ref In Application.VBE.ActiveVBProject.References
If ref.Description Like refDescrip Then
PPT_RefExists = True
Exit Function
End If
Next
PPT_RefExists = bExists
End Function
Trying to simply turn it on with a code like this:
Application.VBE.ActiveVBProject.References.AddFromFile "C:\Program Files (x86)\Common Files\System\ado\msado15.dll"
you may come across three problems: it is already installed, earlier version is installed, the file path is invalid. So my logic is as follows:
Code loops through all refs and checks if ref to Microsoft ActiveX Data Objects 6.0 Library is installed.
If not installed, then it tries to install it with error handling.
If failure will occur, it means that either earlier version i.e. Microsoft ActiveX Data Objects 2.8 is installed (could be checked while looping) or the file path is invalid.
Code:
Sub AddReferenceMicrosoftActiveXDataObjectsLibrary()
Const MyRefPath As String = "C:\Program Files (x86)\Common Files\System\ado\msado15.dll"
Dim ref As Variant
Dim IsInstalled As Boolean: IsInstalled = False
For Each ref In Application.VBE.ActiveVBProject.References
Debug.Print ref.FullPath
If ref.FullPath = MyRefPath Then IsInstalled = True
Next
If IsInstalled = False Then
On Error GoTo err:
Application.VBE.ActiveVBProject.References.AddFromFile MyRefPath
On Error GoTo 0
Debug.Print "Just installed"
Exit Sub
Else
Debug.Print "Already installed"
End If
Exit Sub
err:
MsgBox "Probably earlier version of Microsoft ActiveX Data Objects is already installed or other error occurred"
End Sub
I think late binding is the only way.
I made an Excel-based application for my office, and every time i prepare new version there is about 10% of users I have to visit to add references.
I found out, that since these computers have different Windows versions, for some dll's there is no version which would exist on each computer.
This makes adding references from code more difficult and I do not want to use late binding.
Thats a pity - most of the dll's functionality I use is compatible among all versions.

Cannot add DLL reference with AddFromFile

I am trying to use a COM visible .NET DLL from Excel VBA. I have been successful when registering the DLL using regasm and then manually adding a reference to it via the Tools -> References menu item in the VBA Developer window.
However, I am now trying to register the DLL without using the regasm command so that the Excel file can be used on any computer without registering the DLL. So far this is what I've tried:
Dim JART_Instance As Object
Sub Initialize()
Dim RefPath As String, X As Byte
Const RefName = "JART xxx"
RefPath = Application.ActiveWorkbook.Path & "\JART\JART.dll"
With ActiveWorkbook.VBProject.References
For X = 1 To .Count
If .Item(X).Description Like RefName Then
.Remove .Item(X)
End If
Next
.AddFromFile (RefPath)
End With
End Sub
Sub PostInitialize()
Set JART_Instance = New JART.MainJobControl
End Sub
I have added a reference to "Microsoft Visual Basic for Applications Extensibility 5.3". When I run the above code I get "Run-time error '48': Error in loading DLL". I have loaded this DLL a couple times using regasm. Do I need to do something like change the GUID's used in the project and retry. I've seen code examples where this is supposed to work.
If I reference the tlb file instead of the .dll I do not get the DLL loading error. Instead I get an error whenever I try to use the JART_Instance variable saying that the reference has not been set. Even though PostInitialize gets called directly after Initialize and there is no evidence that any of the code threw an error or failed to run. If I try to put a "Stop" command in the PostInitialize function it tells me that it "Cannot enter break-mode at this time".
Any ideas, thanks.
Excel-DNA has a helper function that does this for Com Addins written on that platform.
It appears to:
load the addin
register it with CoRegisterClassObject
add it's progid to the registry
add it to the registry key HKCU\Software\Microsoft\Office\Excel\Addins
call Application.ComAddins.Update in Excel
remove all the previous registry entries
Unregister the object with CoRevokeClassObject
It would appear that once Excel has loaded the addon, it doesn't unload when the registry entries are removed and CoRevokeClassObject is called. It stays loaded until Excel closes and releases it.
So, it's doable but not easy.
Okay so I've resorted to doing a shell command to register the DLL with regasm. Here is my code:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Dim strWinCmd As String
Dim retVal As Double
strWinCmd = "cmd.exe %SystemRoot%\Microsoft.NET\Framework\v2.0.50727\regasm.exe /u /codebase /tlb .\JART\JART.dll"
retVal = Shell(strWinCmd, vbHide)
End Sub
Private Sub Workbook_Open()
Dim strWinCmd As String
Dim retVal As Double
strWinCmd = "cmd.exe /c %SystemRoot%\Microsoft.NET\Framework\v2.0.50727\regasm.exe /codebase /tlb """ & Application.ActiveWorkbook.Path & "\JART\JART.dll"""
Call Shell(strWinCmd, vbNormalFocus)
Call Button_Handlers.Sleep(1500)
Call Button_Handlers.Initialize
End Sub
For reference the Button_Handlers.Sleep just calls the system sleep method and Button_Handlers.Initialize does this:
Sub Initialize()
'This JART.MainJobControl is the main class in the JART DLL
Set JART_Instance = New JART.MainJobControl
'Use JART_Instance
End Sub
So basically I'm trying to register the DLL at start-up and un-register it on close. My problem is that when I open this file on a new PC I get an error in Button_Handlers.Initialize. It tells me that I'm trying to use an undefined class (JART.MainJobControl), as if the DLL wasn't referenced. If I try to reopen the file everything works fine???
The way I'm doing this is manually adding the reference to the DLL on a machine that already has it registered with regasm. I then save this excel file and transport it to a machine that hasn't had the DLL registered and try to open it and run it. I think that since the reference is already added to the excel file, alls the code has to do is register it with regasm. Does anyone know why this wouldn't work? Am I not sleeping long enough. I may post this as a separate question.

Excel VBA Compile Error

We have an excel spread sheet which we use and it works for most machines but bombs out with 'Compile Error in Hidden Module - General' on others, and the reason appears to be due to missing References.
We check that Macros is enabled but still doesn't help.
Since we protect this excel spread sheet with a password, we don't want to be giving this password out to our users to check the References, and wondered if anyone had any idea how I can add VBA code to check whether the References required for the excel spread sheet is there and if not then bring up a message box to advise the user.
The References we use are as follows:
Visual Basic For Applications
Microsoft Excel 11.0 Object Library
Microsoft Forms 2.0 Object Library
Microsoft Windows Common Controls 5.0 (SP2)
Alternatively, if anyone has any other suggestions on how to go about this problem, that would be great.
The only reference you have listed that could possibly be missing is the common controls. The rest are default in every version of Excel. The Forms one is only if you have a userform or explicitly set it, but that's not your problem. Common Controls is your problem. It doesn't ship with Office anymore. If you have Visual Studio or VB6 you probably have it. Or an old version of Office like XP Developer Edition.
Anyway, you can check for the existence of the OCX file in the System folder. I don't think it's required to be in that folder, but I've never seen it anywhere else.
It's been quite a while since I've seen a reference to 5.0, so I included how to find 6.0 in the code below. Check to make sure you know what version you're using.
In a standard module:
Private Declare Function GetSystemDirectory Lib "kernel32" Alias "GetSystemDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
Public Function HasCommonControl() As Boolean
Dim sFolder As String
Dim lReturn As Long
Const lSIZE As Long = 255
Const sDLLNAME As String = "COMCTL32.OCX" 'For windows common control 5.0
'Const sDLLNAME As String = "MSCOMCTL.OCX" 'For windows common control 6.0
sFolder = Space(lSIZE)
lReturn = GetSystemDirectory(sFolder, lSIZE)
sFolder = Left$(sFolder, lReturn)
HasCommonControl = Len(Dir(sFolder & Application.PathSeparator & sDLLNAME)) > 0
End Function
Having said all that, why are you using common controls? If it's for a treeview on a userform, then check out this all-vba treeview
http://www.jkp-ads.com/articles/treeview.asp
Since jkp wrote that, I haven't used common controls. So few normal-people PCs have it installed that it's just a pain.
Depending on a reference to a specific Excel or other component version is one possible problem. Switching to late binding would solve that problem, so long as you're careful not to use any commands/objects/methods/properties that are supported in one version and not another.
Following up on RowanC's link (good choice), you can add a reference to Excel, for example and write your code like so:
Dim xlWks as Excel.Worksheet
'Dim xlWks as Object
Once everything's debugged, remove the Excel reference and change the declarations to:
'Dim xlWks as Excel.Worksheet
Dim xlWks as Object
That gives you the benefit of intellisense while coding/debugging but removes the dependency on a specific version of Excel later.
Might be mistaken, but IIRC the Common Controls component is part of Visual Basic, not Office, so unless you distribute it and register it along with your app, it might not be present on some systems.
To try late binding, which doesn't need the references setup (although it may have a performance hit, and it will mean that autocomplete doesn't work in your code) instead of calling excel in the following way:
Dim oExcel As Excel.Application
Set oExcel = CreateObject("Excel.Application")
try calling it this way, and drop the reference to the excel object model.
Dim oExcel As Object
Set oExcel = CreateObject("Excel.Application")

Resources