MS Access Compile Error opening excel application [duplicate] - vba

This question already has answers here:
How to fix Compile Error: User-defined type not defined when using Excel VBA from Outlook?
(2 answers)
Closed 5 days ago.
I am trying to write a simple onclick button to open an excel file that already exists on my desktop
what i dont understand is I am using the same Dim as many other examples I have seen. but I am getting a Compile Error "User defined type not defined" and it pulls up the code showing blue highlights Dim excelapp As Excel.Application but Yellow highlight on Private Sub line. Where am i going wrong. is the failure actually further down the code? I ma running Access 365 and Should i be using a different syntax to reference Excel?
Private Sub cmdcopyfieldsonly_Click()
Dim excelapp As Excel.Application
Dim wbTarget As Excel.Workbooks
Dim qdfquerytest As QueryDef
Dim rsquerytest As Recordset
Set qdfquerytest = CurrentDb.QueryDefs("OpenComplaintsQuery")
Set rsquerytest = qdfquerytest.OpenRecordset()
Set excelapp = CreateObject("Excel.Application")
excelapp.Visible = True
Set wbTarget = Excel.Workbooks.Open("C:\Desktop\copytest.xlsx")
wbTarget.worksheets("Sheet1").Range("B8").Value = rsquerytest(2).Value
End Sub

It's a matter of early vs late binding, which are mixed in your code.
Early Binding.
Early binding requires a hard reference of the type e.g. Excel, so VBA has information about the type during compilation. You can then declare the variable by its type and also have intellisense while typing.
Dim app As Excel.Application
Set app = New Excel.Application
The drawback is when changing office versions as the code still references the old version - the reference will need to be updated.
Late Binding
Late binding does not require a hard reference since the variable is declared using the base type of Object and gets resolved at runtime. No issues when changing office version but you lose intellisense.
Dim app As Object
Set app = CreateObject("Excel.Application")
In you case, this is absolutely valid when using late binding:
With CreateObject("Excel.Application")
With .Workbooks.Open("C:\Desktop\copytest.xlsx")
.Worksheets("Sheet1").Range("B8").Value = rsquerytest(2).Value
End With
End With

Related

Open Word Document Run-time error '424': Object required

I have a set of functions in an Access database where I am generating Word documents based on a fixed template in a folder.
I am doing this with the function shown below. For easier maintenance, I would like to be able to define the Word-template paths as public constants in the begining of my module. And therefore, I have been trying to create the adjusted function below.
Original function:
Function MyFunc(rs as DAO.Recordset)
Dim objWord As Object
Dim objDoc As Object
...
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Open("C:\test_template.docx")
...
End Function
Adjusted function:
Public Const ReminderOneTemplate As Variant = "C:\test_template.docx"
...
Function MyFunc(rs as DAO.Recordset)
Dim objWord As Object
Dim objDoc As Object
...
Set objWord = CreateObject("Word.Application")
for the Word.Documents.Open method in the next, subsequent line of code I have tried this:
Set objDoc = objWord.Documents.Open(ReminderOneTemplate)
...
End Function
and
Set objDoc = objWord.Documents.Open(Chr(34) & ReminderOneTemplate & Chr(34))
...
End Function
But the function keeps returning Run-time error '424' Object required when I use a constant as input to the Word.Documents.Open method.
Can anyone explain why this is the case and what I am doing wrong. Is it not possible to pass a Constant to the Word.Open method?
Thanks.
I refactored your function, using the following sub procedure to test the basic code of creating a Word instance, and then opening an existing document using a constant for the document name.
I used Office 2007 to test the code, and everything worked fine. I don't see anything wrong with your code, what version of Access and Word are you using? Notice that I added some code to test whether the objWord variable is actually assigned a value by the call to CreateObject. I would suggest 2 things to help try to resolve the problem you are having:
1. use a String for the filename. I know the documentation for the Open method of the Documents collection says that the filename argument is a Variant, but the code does seem to work better if it is a String.
2. Make sure you set the instance of Word to be visible, otherwise you clutter up your system with invisible instances of Word (which will not be listed in Task Manager) and the only way to get rid of them is to restart the computer. If the Word instance is visible, you can switch to it and see if Word is displaying any error messages.
You may notice that the Word document my code opens is a macro-enabled .docm file. I did this because I tested whether a document with an Open event-handler that caused a runtime error would show the error message in the code in Access, but it does not.
When I first ran the code with the constant declared as a Variant, I did get an error, but not the Object required error that is giving you a problem. I then noticed that when I re-opened the Word document in Word, that I got an error message from Word that "the last time this document was opened it caused a serious error, are you sure you want to continue to open the document?" I would suggest you make sure that you can open your Word document in Word without errors or problems. I also suggest you add code similar to what I have in the example below to ensure that the objWord variable is indeed being initialized by the CreateObject method -- if CreatObject is failing to create an instance of Word, then objWord will still be Nothing, and might then produce an object required runtime error. (problems in the Registry can make CreateObject fail.)
I'm really sorry, but I have no idea why you are getting the error you are getting. I think if you redeclare the constant as a String, and ensure that you make the Word instance visible, that your code will work! The only problem I had when testing was that the document failed to open until I added the code to make the Word instance visible. But I did not get the same error that you are trying to overcome.
I have develop a library of Access VBA code for exactly this type of task -- using code in Access to create instances of Word, Excel, and to open documents and worksheets. If you think looking at a code library designed to provide easily called procedures and functions for inter-operability among MS Office applications, you can download it from here: [http://www.didjiman.com/business/vbademo/libMSOffice.htm] The code in the library has been tested to work in all versions of MS Office from 2003 though 2016, and is released to the public under the Gnu public license. The code is in a zip archive that contains an Access .accdb file with all the code, and a PDF document discussing the functions and procedures, and how to use them, along with complete code listings.
Public Const ReminderOneTemplate As String = "C:\users\matthew\documents\temp\test document1.docm"
Sub testWord_DocOpen()
Dim objWord As Object
Dim objDoc As Object
Set objWord = CreateObject("Word.Application")
objWord.Visible = True 'make the Word application window visible
objWord.Application.WindowState = 1 'maximize the Word application window
If (objWord Is Nothing) Then
Debug.Print "Word object NOT initialized."
End If
Set objDoc = objWord.Documents.Open(ReminderOneTemplate)
End Sub

How do I set the default save format in PowerPoint?

Microsoft, in their infinite wisdom, decided that the default file format for Office 2010 applications should be the format that was 13 years old (Office 97-2002) at the time of release.
The newer formats (2007 and newer) save the data in compressed XML files which are much smaller, and also allow for many additional features. Our corporate IT department hasn't or can't set a group policy to force users to default to saving in the new format, so I'm writing a macro to adjust the settings for everyone in our department.
I can do this in Excel and Word very simply by executing the following VBA code (I'm running it from an Excel workbook):
Public Sub SetExcelSave()
Dim myExcel As Excel.Application
Set myExcel = New Excel.Application
Excel.DefaultSaveFormat = xlOpenXMLWorkbook
Excel.Quit
Set Excel = Nothing
End Sub
Public Sub SetWordSave()
Dim myWord As Word.Application
Set myWord = New Word.Application
Word.DefaultSaveFormat = wdFormatDocumentDefault
Word.Quit
Set Word = Nothing
End Sub
However, I haven't been able to find the appropriate setting to adjust in PowerPoint. Does anyone know where that property is or what it's called?
This code will not compile cleanly, giving an error on the PPT.DefaultSaveFormat line:
Public Sub SetPowerPointSave()
Dim PPT As PowerPoint.Application
Set PPT = New PowerPoint.Application
PPT.DefaultSaveFormat = ppSaveAsOpenXMLPresentation
PPT.Quit
Set PPT = Nothing
End Sub
I've rummaged around in the Office Application Object documentation for PowerPoint, but I'm just not finding what I'm after. It's highly likely that I just don't know what I'm looking for and have simply overlooked it.
Does anyone know what property I'm supposed to set to be able to programmatically change this?
The default save format for PPT 2007 and later is the new XML format (PPTX rather than PPT and so on). If the user (or IT staff via policies) have overridden this in the File | Save | Save files in this format: then the default becomes whatever they've selected, for whatever reason.
App-wide defaults like this typically aren't exposed via the object model; they're stored in the registry. In this case, in
HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\PowerPoint\Options
DefaultFormat DWORD=27 for PPTX
Substitute the correct version for 14.0 above; 12.0 for PPT 2007, 14.0 for 2010, and so on (no 13.0).
If you can write the value you want to the registry when PPT isn't running, you can reset the defaults. If you write to the reg while PPT's running, it won't affect the current instance of PPT, and your changes will be overwritten when PPT quits.

Why doesn't code work in VB.net, but works in VBA; GetObject

VBA code works great:
Sub testVBA()
Dim wb As Object ' Lotus123.Document
Set wb = GetObject("S:\Temp\T\0375D.WK3", "Lotus123.Workbook")
End Sub
VB.net code fails:
Sub TestVBNet()
Dim wb As Object ' Lotus123.Document
wb = GetObject("S:\Temp\T\0375D.WK3", "Lotus123.Workbook")
End Sub
In VB.net I get a FileNotFoundException: "File name or class name not found during Automation operation."
As I can run it from VBA that means the file exists and that the class name exists. So why doesn't it work and how can I fix it in VB.net.
EDIT: I guess I'm not sure how to start diagnosing this: Obviously the class exists on my computer but somehow VB.net doesn't manage to find it. Maybe VB.net uses a different method to activate the class. Maybe a registry entry is missing. I am glad for any suggestions.
Edit 2: I also tried using CreateObject and got this error: "Cannot create ActiveX component." Not unexpected.
For some reason VB.net cannot find the class name "Lotus123.Workbook" so I tried getting the file without the class name and it works fine in XP.
Dim wb As Object ' Lotus123.Document
wb = GetObject("S:\Temp\T\0375D.WK3")
EDIT: In Win8 64bit the above doesn't work; just hangs.
The code below works in XP 32 bit as well as in Win8 64 bit. I checked with process monitor what is happening under the hood. CreateObject checks for the CLSID in the registry using the given object. Then it looks up the necessary info using the CLSID.
Public Shared Function GetLotusWB(ByVal sFile As String) As Object
'HKCU takes precedence if exists
'HKCU\Software\Classes\Lotus123.Workbook\CLSID
'HKCU\Software\Classes\CLSID\{29130007-2EED-1069-BF5D-00DD011186B7}
'normally this is used because Lotus123 doesn't create HKCU entries
'HKCR\Lotus123.Workbook\CLSID = {29130007-2EED-1069-BF5D-00DD011186B7}
'HKCR\CLSID\{29130007-2EED-1069-BF5D-00DD011186B7}\InprocHandler32 = ole32.dll
'HKCR\CLSID\{29130007-2EED-1069-BF5D-00DD011186B7}\LocalServer32 = C:\Lotus\123\123w.exe
'using object as that sometimes works better
Dim LotusObj As Object = CreateObject("Lotus123.Workbook")
'get application
'need a reference to Lotus 123 else declare as Object
Dim LotusApp As Lotus123.Application = LotusObj.Application
'FAILS: LotusApp.Visible = True
'open file; also works fine As Lotus123.Document
Dim ldoc As Object = LotusApp.OpenDocument(sFile)
'visible and activate (must declare as Object else gives exception)
Dim appObject As Object = ldoc.Application
appObject.Visible = True
ldoc.Activate()
Return ldoc
End Function
This works great because it creates the "Lotus123.Workbook" which is used to get the application object.
Load the file into an Excel workbook. It should be able to convert the lotus123 workbook on the fly.
First of all, check to make sure your inclusions (I think under Tools menu, includes or references or something like that) include the library that references Lotus123.Document. Chances are it's in the "Microsoft Excel 14.0 Object Library" or similar.
I've heard it said that VB is not VBA!

how to make vba-word work in vba-excel?

the following two lines
Dim curTasks As Tasks
Set curTasks = Application.Tasks
get the list of all current tasks and work like charm in vba-word but not in vba-excel.
is there a way to port it into vba-excel?
As I said in comments, the Excel object in VBA doesn't have the concept of tasks. You can do the below though in an Excel Module (although I'm still not sure why you would do it):
Dim curTasks As Tasks
Dim wrd As Word.Application
Set wrd = CreateObject("Word.Application")
Set curTasks = wrd.Tasks
NOTE: you have to add a reference to Microsoft Word Object Library to get this to work

Advice on Debugging Machine-Specific Excel VBA Issue

I have an Excel workbook with dependencies on code in other other Excel workbooks (these dependent .xls's are VB-level references, i.e. via the Tools->References dialog box in the VBA editor), and some dependencies on dll's such as:
Microsoft Scripting Runtime
Microsoft Forms 2.0 Object Library
This sheet has worked for about 2 years on around 20 machines running Windows XP and Office XP. Recently we have taken delivery of 3 new machines (same OS, same office version) which refuse to run this sheet. When the sheet opens, it throws a 'Compile Error', and the session hangs.
If I open the sheet on a 'bad' machine, hold down the left shift key to stop macro's from running, and then go to VBA Editor->Debug->Complie VBAProject, it compiles fine. I am then able to save the sheet and open it normally on a 'bad' machine. However this new version of the sheet refuses to run on a 'good' machine!!
I think there must be some sort of version mismatch between certain dll's on the 'good' and 'bad' machines. How do I establish what is causing the issue? Are there any tools available for comparing versions of com components?
Two suggestions
1) First open the file with macros disabled. And then check VBA Editor | Tools | References. Check for any missing references and then let us know what are they. We will take it from there.
2) For references like "Microsoft Scripting Runtime Object Library" I never use Early Binding. Early Binding is the major cause for these kind of errors. Just FYI: Early Binding is creating references beforehand via VBA Editor | Tools | References. I would recommend changing your code to Late Binding. Here are 2 examples of the same code using "Microsoft Scripting Runtime Object Library" with Early Binding and Late Binding
EARLY BINDING EXAMPLE
'~~> Set Reference to "Microsoft Scripting Runtime Object Library"
Sub EBExample()
Dim FSO As Scripting.FileSystemObject
Dim SourceFolder As Scripting.Folder
Dim FileItem As Scripting.File
Set FSO = New Scripting.FileSystemObject
Set SourceFolder = FSO.GetFolder(SourceFolderName)
For Each FileItem In SourceFolder.Files
'~~> You code
Next FileItem
End Sub
LATE BINDING EXAMPLE
'~~> This doesn't need a reference
Sub LBExample()
Dim FSO As Object, SourceFolder As Object, FileItem As Object
Set FSO = CreateObject("Scripting.FileSystemObject")
Set SourceFolder = FSO.GetFolder(SourceFolderName)
For Each FileItem In SourceFolder.Files
'~~> You code
Next FileItem
End Sub
As for me I use early binding to take advantage of Intellisense but then convert it to late binding to avoid version-specific code before distributing the code. That ways the code always works. :)
IMP NOTE: Late Binding fails in scenarios where the destination machine doesn't have the relevant dll registered.
RECOMMENDED LINK:
Topic: Using early binding and late binding in Automation
Link: http://support.microsoft.com/kb/245115
Hope this helps
Sid
The easiest way I've found to compare references on two different machines is to run a little macro on each pc to show me all the details.
Make sure Excel is set to trust access to the VBA project object model and run the below code on the two versions of your macro.
Sub GetReferences()
Dim r As Object
For Each r In ActiveWorkbook.VBProject.References
Debug.Print r.Name, r.Description, r.FullPath
Next r
End Sub