I have a working Outlook macro which exports the task list of the current user to an Excel spreadsheet, but I want to change it to use late binding for ease of distribution (ie I don't have to explain to other users about setting a library reference etc.)
I followed the example Convert Early Binding VBA to Late Binding VBA : Excel to Outlook Contacts to set my Excel variables as objects.
Below is a comparison of how i declared the variables pre/post binding change:
'Late binding variables and their early binding equivilants
Dim objExcel As Object 'Dim objExcel As New Excel.Application
Dim exWB As Object 'Dim exWb As Excel.Workbook
Dim sht As Object 'Dim sht As Excel.Worksheet
Dim Range As Object 'Dim Range As Excel.Range
Dim r As Object 'Dim r As Range
Dim cell As Object 'Dim cell As Range
'set application
Set objExcel = CreateObject("Excel.Application")
I am now getting a runtime 1004 error in the following section of my code:
With objExcel.ActiveSheet
Set r = .Range(.Cells(2, col), .Cells(.Rows.Count, col).End(xlUp)) 'runtime 1004 error here after late binding modification
End With
For Each cell In r
s = cell.Text
If Len(Trim(s)) > 0 Then
iloc = InStr(1, s, sChar, vbTextCompare)
If iloc > 1 Then
s1 = Left(s, iloc - 1)
cell.Value = s1
Else
If iloc <> 0 Then
cell.ClearContents
End If
End If
End If
Next cell
y = y + 1
stat_string = ""
End If
Next x
'Autofit all column widths
For Each sht In objExcel.ActiveWorkbook.Worksheets
sht.Columns("A").EntireColumn.AutoFit
sht.Columns("B").EntireColumn.AutoFit
sht.Columns("C").EntireColumn.AutoFit
sht.Columns("D").EntireColumn.AutoFit
sht.Columns("E").EntireColumn.AutoFit
sht.Columns("F").EntireColumn.AutoFit
Next sht
exWB.Save
exWB.Close
Set exWB = Nothing
'this kills the excel program from the task manager so the code will not double up on opening the application
'sKillExcel = "TASKKILL /F /IM Excel.exe"
'Shell sKillExcel, vbHide
objExcel.Application.Quit
I have included the rest of the code after the error line so, if there are further run-time problems, they might be picked up by the incredible people on SO.
I'm assuming that the methodology for declaring my "Range" is incorrect, but I am not really sure why, and therefore unsure on how to fix it.
Any body out there with a suggestion?
Thanks!
xlUp is an Excel constant that is defined in the Excel library. If you have removed the reference, then xlUp will be an undeclared variable.
If you have Option Explicit set, then you should find that when compiling.
Related
I have an access form with a button to send a record set to excel.
It works 70% of the time but for some reason I get an error "Runtime error '1004' Method 'Rows' of object '_Global' Failed".
Dim xlApp As Excel.Application
Dim xlwb As Excel.Workbook
Dim xlws As Excel.Worksheet
Dim xlrng As Excel.Range
rst.open [Select Query]
Loop through record set and copy values
i = 2
Do Until rst.EOF
dblTotHr = rst!Hours
i = 2
Do Until rst.EOF
dblTotHr = rst!Hours
xlws.Range("a" & i).Value = rst!A
xlws.Range("b" & i).Value = rst!B
xlws.Range("c" & i).Value = rst!C
i = i + 1
rst.MoveNext
Loop
Code that fails (sometimes):
lrow = xlws.Cells(Rows.Count, 1).End(xlUp).Row
Clean up:
xlApp.Visible = True
Set xlApp = Nothing
Set xlwb = Nothing
Set xlws = Nothing
Set xlrng = Nothing
Set rst = Nothing
Set rst1 = Nothing
Since this code works sometimes and not others with no pattern, I am confused on where to try and start looking for answers.
Any help is much appreciated!!
The fix is
lrow = xlws.Cells(xlws.Rows.Count, 1).End(xlUp).Row
Otherwise you cannot be sure Rows refers to the sheet xlws. Interesting that it sometimes resp. quite often works.
If you use Rows in a VBA code within Excel it refers to the ActiveSheet unless you add an explicit reference. This can even cause issues in Excel as the ActiveSheet can be a diagramm.
To automate Microsoft Excel, you establish an object variable that usually refers to the Excel Application object or the Excel Workbook object. Other object variables can then be set to refer to a Worksheet, a Range, or other objects in the Microsoft Excel object model. When you write code to use an Excel object, method, or property, you should always precede the call with the appropriate object variable. If you do not, Visual Basic establishes its own reference to Excel. This reference might cause problems when you try to run the automation code multiple times. Note that even if the line of code begins with the object variable, a call may be made to an Excel object, method, or property in the middle of the line of code that is not preceded with an object variable.
Further reading
I am new to VBA and macros.
I got the repeated task of copy data from Excel and paste it in a particular location in the word document.
For example, my excel sheet has the data like this:
Col1
Col2
ID_1
I'm_One
ID_2
I'm_Two
ID_3
I'm_Three
Now i'm looking for a Word macro
Get text in Word table with cell position 3
Find the same text in Excel Col1
Get the value of Col2 from Excel
Paste the value of Col2 in word table with cell position 10
Repeat the same process for another table in Word document
[Update]
I have tried with multiple code snippets by google search but unable to construct the working macro.
Sub pull_from_Excel2()
'ref: https://www.macworld.com/article/211753/excelwordvisualbasic.html
Dim Month As String
ID_Range = "A2:A6" 'Select this as range like "A2:A16"
Offset_to_fetch = 1 'Select this to fetch comments etc. value starts with
Set xlSheet = GetObject("D:\Excel.xlsx")
'Snippets:
'Debug.Print VarType(xlSheet.Worksheets("Sheet1").Range("A3:A5").Value)
'8204
Dim Cell As Range, rng As Range
Debug.Print VarType(xlSheet.Worksheets("Sheet1").Range(ID_Range).Value2)
Set rng = xlSheet.Worksheets(1).Range(ID_Range)
For Each Cell In rng
Debug.Print Cell.Text
Next Cell
End Sub
I used this url to construct my skeleton code: https://www.macworld.com/article/211753/excelwordvisualbasic.html
When i try to get the values from the range of cells in excel, i got the following error for the code.
Set rng = xlSheet.Worksheets(1).Range(ID_Range).Value2
The above line gives "Object required" error when running.
Set rng = xlSheet.Worksheets(1).Range(ID_Range)
The above line gives "Type Mismatch" error when running.
Notes: For this error, I tried to use for each loop as this is array but the error is showing before executing the for loop.
Kindly assist.
I recommend to use Option Explicit and declare all your varibales properly. This way it is less likely that you end up with unseen errors.
To activate it for all new codes that you add in the future, you can activate it directly in Excel and Word. This is a good practice and will protect you from doing it wrong by notifying you of not declared variables:
In the VBA editor go to Tools › Options › Require Variable Declaration.
This will add Option Explicit to new modules only. In existing modules Option Explicit needs to be added manually as first line.
Further I highly recommend to name your variables according what they contain because otherwise it gets very confusing. You named your variable xlSheet but you load a workbook into it and not a worksheet.
The next issue is that your code is in Word and if you declare rng As Range then this is of type Word.Range and not Excel.Range and those are diffetent types so that is why you get a "Type Mismatch" error.
To solve this you either go in Word VBA to Extras › Refereces … and set a reference to the Excel library so you can declare your variable Dim xlRng As Excel.Range or if you don't set a reference you declare it as Object or Variant like in below example:
' This code is in Word!
Option Explicit
Public Sub pull_from_Excel2()
'declare constants
Const ID_Range As Sting = "A2:A6" 'Select this as range like "A2:A16"
Const Offset_to_fetch As Long = 1 'Select this to fetch comments etc. value starts with
Dim xlWorkbook As Object
Set xlWorkbook = GetObject("D:\Excel.xlsx") 'This expects the Excel to be already open! If not open you need to use CreateObject("Excel.Application")
Dim xlRng As Object
Set xlRng = xlWorkbook.Worksheets(1).Range(ID_Range)
Dim xlCell As Object
For Each xlCell In xlRng
Debug.Print xlCell.Text
Next xlCell
End Sub
Note if your workbook Set xlWorkbook = GetObject("D:\Excel.xlsx") is not open in Excel you need to use CreateObject("Excel.Application") and open it.
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
Dim xlWorkbook As Object
Set xlWorkbook = xlApp.Workbooks.Open(FileName:="D:\Excel.xlsx") 'will open the workbook
xlApp.Visible = True 'make it false to open Excel invisible in the background
'your code here …
'in the end close workbook and Excel (espaciall if you had it invisible!)
xlWorkbook.Close SaveChanges:=False
xlApp.Quit 'close Excel
Option Explicit
Sub UpdateTables()
Const XLSX = "D:\Excel.xlsx"
Dim xlApp, wb, ws
Dim rngSearch, rngFound
Dim iLastRow As Long, n As Integer
' open spreadsheet
'Set xlApp = New Excel.Application
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = True
Set wb = xlApp.Workbooks.Open(XLSX, 1, 1)
Set ws = wb.Sheets(1)
iLastRow = ws.Cells(ws.Rows.Count, "A").End(-4162).Row 'xlUp
Set rngSearch = ws.Range("A2:A" & iLastRow)
' update tables
Dim doc As Document, tbl As Table, s As String
Set doc = ThisDocument
For Each tbl In doc.Tables
s = tbl.Cell(1, 1).Range.Text
s = Left(s, Len(s) - 2)
Set rngFound = rngSearch.Find(s, LookIn:=-4163, LookAt:=1) ' xlValues, xlWhole
If rngFound Is Nothing Then
MsgBox "'" & s & "' not found in table " & tbl.Title, vbExclamation
Else
tbl.Range.Cells(3).Range.Text = rngFound.Offset(0, 1)
n = n + 1
End If
Next
wb.Close False
xlApp.Quit
MsgBox n & " tables updated", vbInformation
End Sub
I am writing a macro in CATIA v5 using VBA. The program is suppose to take points from a geometric set and transfer them into an excel file. I have successfully gotten the excel document open, a header created, but then I receive "Run-time error '438': Object doesn't support this property or method.
I have tried searching around and it seems like the section of code is trying to interact with something outside of its domain, but I cannot figure out how. Below is a sample of my code. The line that contains "***" to the left is the line that is being pointed out in the debugger.
Dim xls As Object
Dim wkbks As Object
Dim wkbk As Object
Dim wksheets As Object
Dim sheet As Object
Dim fs, f, f1, fc, s
Dim coords(2) As Integer
Dim PartDoc
Sub CATMain()
CATIA.ActiveDocument.Selection.Search "CATGmoSearch.Point,all"
'Function Calls
AppStart
CATIAtoXLS
'wksheet.Application.ActiveWorkbook.SaveAs (ExcelFolder & Left(CATIA.ActiveDocument.Name,Len(CATIA.ActiveDocument.Name)-8)&".xls")
'wksheet.Application.ActiveWorkbook.Close
End Sub
Private Sub AppStart()
Err.Clear
On Error Resume Next
Set xls = GetObject(, "Excel.Application")
If Err.Number <> 0 Then
Err.Clear
Set xls = CreateObject("Excel.Application")
End If
xls.Application.Visible = True
Set wkbks = xls.Application.Workbooks
Set wkbk = wkbks.Add
Set wksheets = wkbk.Worksheets(1)
Set sheet = wkbk.Sheets(1)
sheet.Cells(1, "A") = "X-Cord"
sheet.Cells(1, "B") = "Y-Cord"
sheet.Cells(1, "C") = "Z-Cord"
End Sub
Private Sub CATIAtoXLS()
For i = 1 To CATIA.ActiveDocument.Selection.Count
Set Selection = CATIA.ActiveDocument.Selection ***
Set Element = Selection.Item(i)
'Transfer data to xls
Point.GetCoordinates (coords)
sheet.Cells(i + 1, "A") = coords(0)
sheet.Cells(i + 1, "B") = coords(1)
sheet.Cells(i + 1, "C") = coords(2)
Next i
End Sub
Your first issue is that in any method in CATIA VBA which passes an array as an argument, must be called on a object declared variant (explicitly or by default).
So you it should look like this:
Dim px as Variant
Set px = CATIA.ActiveDocument.Selection.Item(i).Value
Call Point.GetCoordinates(coords)
The second problem is that in VBA if you use a subroutine with parentheses, you must use the Call keyword:
Call Point.GetCoordinates (coords)
Otherwise, you can skip the parentheses and the keyword:
Point.GetCoordinates coords
I created code that will copy the RecordSet to Excel and I want a macro in the Excel file to run. The code works perfectly until it hits the code to run the macro. I must not be calling the application correctly but can't figure it out!
Private Sub Command233_Click()
Dim objXLS As Object
Dim wks As Object
Dim rsc As Recordset
Dim idx As Long
Set rsc = Me.RecordsetClone
If Me.RecordsetClone.RecordCount = 0 Then
MsgBox ("No Records To Export")
Else
rsc.MoveLast
rsc.MoveFirst
Set objXLS = CreateObject("Excel.Application")
objXLS.Workbooks.Open FileName:="C:\Comps Macro.xlsm", ReadOnly:=True
Set wks = objXLS.Worksheets(1)
For idx = 0 To rsc.Fields.Count - 1
wks.Cells(1, idx + 1).Value = rsc.Fields(idx).Name
Next
wks.Range(wks.Cells(1, 1), wks.Cells(1, rsc.Fields.Count)).Font.Bold = True
wks.Range("A2").CopyFromRecordset rsc, rsc.RecordCount, rsc.Fields.Count
objXLS.Visible = True
objXLS.Run ("Format")
End If
Set objXLS = Nothing
End Sub
The runtime error I am receiving is:
Run-Time Error '-2147417851 (80010105)':
Method 'Run' of object '_Application' failed
You have to reference the Sub or Function correctly.
Your Sub named Format is defined at Workbook- or Sheet- level?
If defined in a Sheet module (for example Sheet1):
objXLS.Run ("Sheet1.Format")
If at Workbook level:
objXLS.Run ("ThisWorkbook.Format")
Hope this helps
Ok, so I have an Excel-file with data. This data comes from a query that has been manually copied from an Access database. Since this has to be done every day we want to make it automatically.
I already have VBA code inside the Access database that opens the query and writes it away into the Excel-file on the right sheet.
However, it works when I put a static range for the insert so it actually just overwrites the range I say:
Dim rst As DAO.Recordset
Dim ApXL As Object
Dim xlWBk As Object
Dim xlWSh As Object
Set rst = CurrentDb.OpenRecordset("Query name")
Set ApXL = CreateObject("Excel.Application")
ApXL.Application.ScreenUpdating = False
ApXL.Visible = True
Set xlWBk = ApXL.Workbooks.Open("C:\blabla.xlsm", True, False)
Set xlWSh = xlWBk.Worksheets(1)
xlWSh.Activate
xlWSh.range("A1341").CopyFromRecordset rst
xlWBk.Save
xlWBk.Close False
ApXL.Quit
rst.Close
Set rst = Nothing
Notice the xlWSh.range("A1341").CopyFromRecordset rst.
It just pastes the query from this row because I know this is the first empty row.
I already tried lots of other codes but I always get errors:
TheLastRow = ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row
=> Error 424: Object required
Dim MyRange As range
Dim lngLastRow As Long
Set MyRange = xlWSh.range(strColum & "1")
lngLastRow = xlWSh.Cells(65536, MyRange.Column).End(xlUp).Row
=> Compilation-error on Dim MyRange As range: user-defined type not defined
Dim MyRange As Object
Dim lngLastRow As Long
Set MyRange = xlWSh.range(strColum & "1")
lngLastRow = xlWSh.Cells(65536, MyRange.Column).End(xlUp).Row
=> Error 1004: Application-defined or object-defined error
With xlWBk.Sheets("Sheetname")
lastrow = .range("A" & .Rows.Count).End(xlUp).Row
=> Error 1004: Application-defined or object-defined error
End With
With xlWSh
lastrow = .Cells.Find(What:="*", After:=.range("A1"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
=> Error 9: Subscript out of range
End With
So I have no idea anymore what to do.
The only other option is by reading the entire sheet into the Access database as a List or Array or Table and then do a .Count or something but inserting into lastRow+1 or firstEmptyRow should be quicker, doable and much easier to program.
Thanks in advance!
The problem is that Access doesn't know anything about Excel constants, such as xlUp, xlByRows and so on (until you add reference to excel library).
There are to ways for you:
1) Go to TOOLS->REFERENCES and add reference to Microsoft Excel 1x.0 Object Library (version may vary)
2) change all excel constants to their values (e.g. change SearchOrder:=xlByRows to SearchOrder:=1 and so on):
xlUp equals to -4162
xlByRows eqals to 1
xlPrevious eqals to 2
xlCellTypeLastCell equals to 11
Here is link with values of excel constants: xlConstants (or another way to determine constants values - is to use this line in EXCEL VBA : MsgBox xlCellTypeLastCell)