I've been attempting to add a reference to a specific DLL, and after several attempts I've found a bit of code that actually works. However when I attempt it with the DLL that is supposed to work in Excel, it gives me an error and refuses to load.
I've tested this code with a few DLLs that came with Excel/Windows, and I've had no issues.. Was wondering if perhaps there is some 'install' process I need to go through with new DLLs or something of that sort.
Runtime-error '48'
Error in loading DLL
Code:
Sub AddReference()
Dim VBAEditor As VBIDE.VBE
Dim vbProj As VBIDE.VBProject
Dim chkRef As 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\HIDDEN.dll"
CleanUp:
If BoolExists = True Then
MsgBox "Reference already exists"
Else
MsgBox "Reference Added Successfully"
End If
Set vbProj = Nothing
Set VBAEditor = Nothing
End Sub
Usually this kind of problems are related to conflicting bit versions of Office and the DLL you are loading.
Try to load the correct version of the DLL.
Related
Can I delete an Outlook VBA Module?
I have tried the below code:
Dim vbMod As Object
Set vbMod = Application.VBE.ActiveVBProject.VBComponents
vbMod.Remove VBComponent:=vbMod.Item("Module2")
But getting an error:
438 Error, Object doesn't support this property or method
Can this be done with Outlook VBA and are there any References to be included?
Try this.
You will need to add a reference to Microsoft Visual Basic for Applications Extensibility 5.3.
Public Sub DeleteModule(ByVal ModuleName As String)
On Error GoTo Trap
Dim VBAEditor As VBIDE.VBE
Dim objProject As VBIDE.VBProject
Dim objComponent As VBIDE.VBComponent
Set VBAEditor = Application.VBE
Set objProject = VBAEditor.ActiveVBProject
For Each objComponent In objProject.VBComponents
If objComponent.Name = ModuleName Then
objComponent.Collection.Remove objComponent
End If
Next
Leave:
On Error GoTo 0
Exit Sub
Trap:
MsgBox Err.Description, vbCritical
Resume Leave
End Sub
To test it:
Sub Test()
DeleteModule "ModuleName"
End Sub
The answer to your answer is no, we can't delete or even access programmatically the VBIDE; it is correct that you can add reference to Microsoft Visual Basic for Applications Extensibility 5.3, but to no avail.
If you try this at Word or Excel, this is the output:
But, when you try this at Outlook, VBE is not exposed:
Here is a confirmation. Maybe in older Outlook versions, less safer, you could do that, but at least since Outlook 2002, it is not possible.
I'm trying to open an excel document when a user clicks a button. There are multiple buttons that open the same document but I want it to change the worksheet if the document is already opened and not another instance of the document
Public objExcel As Object
Sub Main()
Set objExcel = CreateObject("Excel.Application")
End Sub
Public Sub QE1_Click()
Call Main
If objExcel Is Nothing Then
objExcel.Visible = True
objExcel.Workbooks.Open "H:\My Documents\Flowchart to Word\Quality and Environmental management system flowchart.xlsm"
objExcel.Worksheets("Project enquiry").Activate
Else
objExcel.Worksheets("Project enquiry").Activate
End If
End Sub
Public Sub QE2_Click()
Call Main
If objExcel Is Nothing Then
objExcel.Visible = True
objExcel.Workbooks.Open "H:\My Documents\Flowchart to Word\Quality and Environmental management system flowchart.xlsm"
objExcel.Worksheets("Order and project release").Activate
Else
objExcel.Worksheets("Order and project release").Activate
End If
End Sub
Running the code gives me the error: Application-defined or object-defined error
Can anyone point out what's causing the error?
This code here:
Set objExcel = CreateObject("Excel.Application")
Is creating a new Excel Application. Then this one here:
objExcel.Worksheets("Project enquiry").Activate
already assumes that the new application is having a worksheet called Project enquiry, which cannot be true. Thus, you are getting the 1004 error. Refine your business logic and it should work.
In general, try to delete this condition If objExcel Is Nothing Then because objExcel will never be Nothing, you are calling Main which assigns object to it. Then the code may work.
A little upgardes to get your code to work more efficiently:
Option Explicit
Public objExcel As Object
Sub Main()
' don't need to open another instance of Excel, can use the same instance
On Error Resume Next
Set objExcel = GetObject(, "Excel.Application") ' check if there is an open instance of Excel running
On Error GoTo 0
If objExcel Is Nothing Then
Set objExcel = CreateObject("Excel.Application")
End If
End Sub
'==================================================================
Public Sub QE1_Click()
Dim wb As Workbook
Dim sht As Worksheet
If objExcel Is Nothing Then
Main ' call sub that initializes an Excel application object
End If
objExcel.Visible = True
Set wb = objExcel.Workbooks.Open("H:\My Documents\Flowchart to Word\Quality and Environmental management system flowchart.xlsm")
On Error Resume Next
Set sht = wb.Worksheets("Project enquiry")
On Error GoTo 0
If sht Is Nothing Then ' sheet doesn't exist >> raise an error
MsgBox "Workbook doesn't have a sheet named 'Project enquiry'", vbCritical, "Sheet critical error"
Else ' sheet object created successfully
sht.Activate ' <-- NOT SURE why you need to use Activate ?
End If
End Sub
Note: same modifications should be applied to Sub QE2_Click().
If you want to control an Office application from within a different one - Excel from within Word, for example, you first need to decide whether you want to write your code using Intellisense and what's called "early-binding" or whether you want to use "late-binding", which does not have Intellisense but has the advantage that you don't need to rely on a link to the other (Excel) VBA code library.
In order to use early-binding you must go to Tools/References in the VBA editor and activate the checkbox next to the entry for the other application (Excel). Only then can you use something like Dim wb As Workbook.
If you don't want to use early-binding, then you must declare things as Dim wb as Object, same as you've done for the Excel.Application.
In order have code decide whether it needs to use an running instance of the other application (Excel) or start a new instance, use the method GetObject. This can be used to pick up any running instance, or to check for a specific file.
Set ojbExcel = GetObject(,"Excel.Application")
vs
Set objExcel = GetObject("H:\My Documents\Flowchart to Word\Quality and Environmental management system flowchart.xlsm")
If what you're looking for with GetObject isn't currently available, you'll get an error which you can check and subsequently use CreateObject in order to start the application.
Option Explicit
Public objExcel As Object
Sub Main()
''' Try to re-use an existing instance
' If that instance does not exist, an error will be generated
' So temporarily turn off error messages
On Error Resume Next
' check if there is an open instance of Excel running
Set objExcel = GetObject(, "Excel.Application")
' Turn error messages back on
On Error GoTo 0
If objExcel Is Nothing Then
Set objExcel = CreateObject("Excel.Application")
End If
End Sub
Note that you should usually not turn off error-messaging - you need a really good reason to do so and you should turn it on again as soon as possible.
If all your buttons are essentially the same - in the two procedures you show everything is the same except the Else step - then you can cut down on the duplicate code. (That will also make maintenance simpler if you don't have to make changes in all the procedures).
Also, since the Else action is the same as the last action in the If you can simply put that after End If.
Private Sub ActivateWorksheet(wsName as String)
If objExcel Is Nothing Then
objExcel.Visible = True
objExcel.Workbooks.Open "H:\My Documents\Flowchart to Word\Quality and Environmental management system flowchart.xlsm"
End If
objExcel.Worksheets(wsName).Activate
End Sub
Public Sub QE1_Click()
Call Main
ActivateWorksheet "Project enquiry"
End Sub
Public Sub QE2_Click()
Call Main
ActivateWorksheet "Order and project release"
End Sub
this is an example sub to programatically install a type library for API. Why is the error handling routine failing? I attempted to follow the try...except...finally strategy I am familiar with from Python.
Sub CopyViewLayout():
'TRY:
On Error GoTo addReference
Dim App As femap.model
'COMPILE ERROR: USER TYPE NOT DEFINED
ResumeSub:
Dim App As femap.model
Set App = GetObject(, "femap.model")
Dim rc As Variant
Dim feView As femap.View
Set feView = App.feView
rc = feView.Get(0)
Exit Sub
'EXCEPT:
addReference:
Dim vbaEditor As VBIDE.VBE
Dim vbProj As VBIDE.VBProject
Dim checkRef As VBIDE.Reference
Dim filepath As String
Set vbaEditor = Application.VBE
Set vbProj = ActiveWorkbook.VBProject
filepath = "C:\apps\FEMAPv11\"
On Error GoTo Failure
vbProj.References.AddFromFile (filepath & "femap.tlb")
Set vbProj = Nothing
Set vbaEditor = Nothing
GoTo ResumeSub
'FINALLY
Failure:
MsgBox ("couldn't find type library, exiting sub")
End Sub
EDIT
I broke out this section from main because Error handling is just ridiculous in VBA... A better approach for me was to implement a finite-state-machine using Booleans.
answer
Sub refcheck()
Dim i As Long
Dim FEMAP_GUID As String
FEMAP_GUID = "{08F336B3-E668-11D4-9441-001083FFF11C}"
With ActiveWorkbook.VBProject.references
For i = 1 To .Count
If .Item(i).GUID = FEMAP_GUID Then
Exit For
Else
'note: filepath is determined using Dir() elsewhere...
.AddFromFile (filepath & "femap.tlb")
Exit For
End If
Next
End With
End Sub
Error handling only handles runtime errors; not compile time errors. Use
Dim App as Object
And make sure you only Dim App once in your code.
By using As Object, you can late bind any object to it. You lose Intellisense while youre coding thought.
Like Dick mentioned, use Late Binding but that alone is not enough. You will have to use it with proper Error Handling.
For example
Dim App As Object
On Error Resume Next
Set App = GetObject(, "femap.model")
On Error GoTo 0
If App Is Nothing Then
MsgBox "Please check if femap is installed"
Exit Sub
End If
'
'~~> Rest of the code
'
If you are sure that it is installed then you are getting the error because the relevant library is not referenced. For that I would recommend having a look at How to add a reference programmatically
I would however still suggest that you take the Late Binding route.
I have created a VB add-in for excel with the below code. However, when I open a new excel workbook and attempt to add the reference to the newly created dll, I get an error: "Can't add a reference to the specified path." I am using Excel 2010 on a 32 bit machine. The add-in was created with Visual Studio 2010.
Public Class Utils
'!Deletes old reference and adds new reference. Must be used when switching to new machine.
Function addReference() As Boolean
If Dir("C:\refname.dll") <> "" Then
Dim ref
For Each ref In Application.ActiveWorkbook.VBProject.VBE.ActiveVBProject.References
If ref.name = "refname" Then
Application.ActiveWorkbook.VBProject.VBE.ActiveVBProject.References.Remove(ref)
End If
Next
Application.ActiveWorkbook.VBProject.VBE.ActiveVBProject.References.AddFromFile("C:\refname.dll")
addReference = True
Else
addReference = False
End If
End Function
End Class
You can try this:
Option Explicit
Sub AddReference()
Dim VBAEditor As VBIDE.VBE
Dim vbProj As VBIDE.VBProject
Dim chkRef As Reference
Dim BoolExists As Boolean
Set VBAEditor = Application.VBE
Set vbProj = ActiveWorkbook.VBProject
'~~> Check if reference is already added
For Each ref In vbProj.References
If ref.Name = "refname" Then
BoolExists = True
GoTo CleanUp
End If
Next
vbProj.References.AddFromFile "C:\WINDOWS\system32\refname.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
I got this code from: How to add a reference programmatically
I apologize in advance for the newbie question -- most of my VBA experience is in Excel, or Word to Excel. In this case, I am going from Excel to Word. I am trying to capture some data off of some Word forms and store it in an Excel file.
Right now, my code works for the first document in the folder, but after that, it hoses up with an automation error "the server threw an exception" (goo!)
Here is my code:
Dim objWordApp As Object
strCurFileName = Dir(strFilePath)
Set objWordApp = CreateObject("word.application")
objWordApp.Visible = True
Do While strCurFileName <> ""
objWordApp.documents.Open strFilePath & strCurFileName
objWordApp.activedocument.Unprotect password:="testcode"
{EXCEL PROCESSING HERE}
strCurFileName = Dir
objWordApp.activedocument.Close 0
Loop
objWordApp.Quit
Set objWordApp = Nothing
I notice that the code works fine if I quit the app and set the object = nothing within the loop. But the way it is now, it bombs-out on the second file in the folder on the "objWordApp.documents.Open strFilePath & strCurFileName" line.
Can I open and close Word documents in a loop without having to create the object over and over? It's really slow when I do it that way.
Thanks for the help -- I like your way much better. Unfortunately, I get the same result. The program dies the second time through the loop on the line that reads:
Set objWordDoc = objWordApp.Documents.Open(objFile.Path)
The error that I get is:
Run-time Error -2147417851 (80010105)
Automation Error
The server threw an exception.
I tried your code on regular word docs (not the ones I'm processing) and it worked fine. The docs I'm running have form fields and macros -- not sure if that makes a difference. I have set the macro security in Word to both "low" and "very high" to make sure the other macros don't interfere.
I just can't figure it out why it works for the first doc and then not the next. I even cloned the first doc but it made no difference.
Still no luck, though. The only thing I can get to work is if I completely wipe the objects and re-create them every time I want to open a file.
Set objFolder = FSO.GetFolder(strFilePath)
For Each objFile In objFolder.Files
Set objWordApp = CreateObject("word.application")
objWordApp.Visible = True
If Right(objFile.Name, 4) = ".doc" Then
Set objWordDoc = objWordApp.documents.Open(Filename:=objFile.Path, ConfirmConversions:=False, _
ReadOnly:=True, AddToRecentFiles:=False, PasswordDocument:="", _
PasswordTemplate:="", Revert:=False, WritePasswordDocument:="", _
WritePasswordTemplate:="", Format:=wdOpenFormatAuto)
[Process DOC]
objWordDoc.Close 0, 1
End If
Set objWordDoc = Nothing
objWordApp.Quit
Set objWordApp = Nothing
Next
I'm not sure why that works and why it won't work the other way. If I have to go this route, I can -- it just seems really slow and inefficient. Is this a bad idea?
I changed the Dir to a FileSystemObject (go to Tools\References and add Microsoft Scripting Runtime) and I was able to successfully open multiple files. If you are having problems, please describe the error you see in the debugger. Also, if you need to recurse into subdirectories, you will need to refactor this.
Private mobjWordApp As Word.Application
Sub Test()
ProcessDirectory "PathName"
End Sub
Property Get WordApp() As Word.Application
If mobjWordApp Is Nothing Then
Set mobjWordApp = CreateObject("Word.Application")
mobjWordApp.Visible = True
End If
Set WordApp = mobjWordApp
End Property
Sub CloseWordApp()
If Not (mobjWordApp Is Nothing) Then
On Error Resume Next
mobjWordApp.Quit
Set mobjWordApp = Nothing
End If
End Sub
Function GetWordDocument(FileName As String) As Word.Document
On Error Resume Next
Set GetWordDocument = WordApp.Documents.Open(FileName)
If Err.Number = &H80010105 Then
CloseWordApp
On Error GoTo 0
Set GetWordDocument = WordApp.Documents.Open(FileName)
End If
End Function
Sub ProcessDirectory(PathName As String)
Dim fso As New FileSystemObject
Dim objFile As File
Dim objFolder As Folder
Dim objWordDoc As Object
On Error Goto Err_Handler
Set objFolder = fso.GetFolder(PathName)
For Each objFile In objFolder.Files
If StrComp(Right(objFile.Name, 4), ".doc", vbTextCompare) = 0 Then
Set objWordDoc = GetWordDocument(objFile.Path)
' objWordDoc.Unprotect Password:="testcode" ' Need to check if it has Password?
ProcessDocument objWordDoc
objWordDoc.Close 0, 1
Set objWordDoc = Nothing
End If
Next
Exit_Handler:
CloseWordApp
Exit Sub
Err_Handler:
MsgBox "Error " & Err.Number & ": " & Err.Description
Resume Exit_Handler
'Resume Next ' or as above
End Sub
Sub ProcessDocument(objWordDoc As Document)
'{EXCEL PROCESSING HERE}'
End Sub
EDIT: I've added some error handling and a little refactoring although there is quite a bit more refactoring that could be done.
There must be something special about the documents you are opening. You might try using different parameters for opening the documents, such as:
Set objWordDoc = objWordApp.Documents.Open( _
FileName:=objFile.Path, ReadOnly:=True)
You may need to add Microsoft Word as a Reference, and if you do that then start using the Word constants (wdDoNotSaveChanges, etc.). Check out the help on Documents.Open and test different parameters.
Also, use the "Set Next Statement" from the Context Menu during debugging and maybe skip the first document and open the second document directly and see if there are issues.
EDIT: I've changed the code to close and reopen Word if you get the automation error you described. You may have to adjust the error numbers, or simply close Word on any error (If Err.Number <> 0 Then ...).
Again, something must be special about your documents (macros, protection, etc.) because this code works on the test cases I have tried. Have you tried manually opening the documents in Word in the same order as the script, updating information similar to your process script, and then closing the documents to see if Word does anything strange?
Closing the Word.Application won't hurt anything, but it will obviously significantly slower.