Error when getting data from closed excel workbooks with a dynamic range - vba

I’m getting an error 1004 with my code which takes data from closed workbooks in a list. The code functions as it should and retrieves the values without an issue, however it still brings up the error message. I’m probably missing something very obvious so I’d appreciate any help anyone can provide. Below is my code:
Sub ExecMacro4Excel()
Dim path As String
Dim workbookName As String
Dim worksheetName As String
Dim cell As String
Dim returnedValue As String
Dim lRow, x As Integer
Dim wbName As String
On Error GoTo PROC_ERR
lRow = Sheets("Raw Data").Range("C" & Rows.Count).End(xlUp).Row
path = Sheets("Front").Range("B4").Value
worksheetName = "Template"
cell = "J2"
x = 1
Do
x = x + 1
workbookName = Sheets("Raw Data").Range("C" & x).Value
returnedValue = "'" & path & "[" & workbookName & "]" & _
worksheetName & "'!" & Range(cell).Address(True, True, -4150)
Sheets("Raw Data").Range("I" & x) = ExecuteExcel4Macro(returnedValue)
Loop Until x = lRow
PROC_ERR:
MsgBox "Error: (" & Err.Number & ") " & Err.Description, vbCritical
End Sub
To further clarify, below shows the location where the data is the 1row variable is located and where the data will be put:
http://i.imgur.com/1UcuTd8.png
In addition here is the spreadsheet where the original data is kept and is the same for all of the files:
http://i.imgur.com/j40FD3z.png
And finally, this is the error box reads: "error 1004: A formula in this worksheet contains one or more invalid references. Verify your formulas contain a valid path, workbook, range name and cell reference".

Not sure why you want to use xlR1C1 for the range address, you might have just missed the = at the beginning of returnedValue. You can do it more simpler (assuming path will not change):
Sub ExecMacro4Excel()
Const worksheetName = "Template"
Const cell = "$J$2"
Dim path As String
Dim workbookName As String
'Dim worksheetName As String
'Dim cell As String
Dim returnedValue As String
Dim lRow, x As Integer
Dim wbName As String
On Error GoTo PROC_ERR
path = Sheets("Front").Range("B4").Value
If Right(path, 1) <> Application.PathSeparator Then path = path & Application.PathSeparator
lRow = Sheets("Raw Data").Range("C" & Rows.Count).End(xlUp).Row
For x = 2 To lRow
workbookName = Sheets("Raw Data").Range("C" & x).Value
returnedValue = "='" & path & "[" & workbookName & "]" & _
worksheetName & "'!" & Range(cell).Address
Sheets("Raw Data").Range("I" & x).Formula = returnedValue
Next
PROC_ERR:
MsgBox "Error: (" & Err.Number & ") " & Err.Description, vbCritical
End Sub

I managed to solve this issue myself. The problem was that the list of file names was copied from another list and pasted in. The way I coded it the area selected wasn't done by finding the last row and copying only that section, instead it copied a finite number of cells, which included the data AND blank cells. So as the files were accessed the code worked fine, but when it came to the one following which had a blank cell it caused an error to occur.

Related

How to get the sheet name using GetOpenFilename in VLOOKUP

I am using this code down below to use a VLOOKUP in another file that you select using the GetOpenFilename. I want shtName to be the name of the sheet in the file that you select, but whenever I step through it, it is always the name of the sheet that I am working in and putting the VLOOKUP in.
I have shtName in my VLOOKUP and it doesn't show anything when I step through it. X shows the filename and path, but shtName right after shows nothing. But my VLOOKUP ends up working anyway and it puts the sheet in the formula.
Why is that? I want to be able to do it myself and so I know I get the sheet name from the file you are selecting.
Dim iRet As Integer
Dim strPrompt As String
Dim strTitle As String
' Promt
strPrompt = "Please select the last Kronos Full File before the dates of this HCM Report." & vbCrLf & _
"This will be used to find the Old Position, Org Unit, and Old Cost Center." & vbCrLf & _
"For example, if the date of this report is 7-28-17 thru 8-25-17, the closest Kronos Full File you would want to use is 7-27-17."
' Dialog's Title
strTitle = "Last Kronos Full File for Old Positions"
'Display MessageBox
iRet = MsgBox(strPrompt, vbOK, strTitle)
Dim LR As Long
Dim X As String
Dim lNewBracketLocation As Long
X = Application.GetOpenFilename( _
FileFilter:="Excel Files (*.xls*),*.xls*", _
Title:="Choose the Kronos Full File.", MultiSelect:=False)
MsgBox "You selected " & X
'Find the last instance in the string of the path separator "\"
lNewBracketLocation = InStrRev(X, Application.PathSeparator)
'Edit the string to suit the VLOOKUP formula - insert "["
X = Left$(X, lNewBracketLocation) & "[" & Right$(X, Len(X) - lNewBracketLocation)
shtName = ActiveWorkbook.Worksheets(1).name
LR = Range("E" & Rows.Count).End(xlUp).Row
Range("T2").Formula = "=VLOOKUP($E2,'" & X & "]shtName'!$B$1:$AP$99999,15,0)"
Stop
Range("T2").AutoFill Destination:=Range("T2:T" & Range("E" & Rows.Count).End(xlUp).Row)
Stop
Range("T2:T" & Range("E" & Rows.Count).End(xlUp).Row).Select
Stop
Range("U2").Formula = "=VLOOKUP($E2,'" & X & "]shtName'!$B$1:$AP$99999,41,0)"
Range("U2").AutoFill Destination:=Range("U2:U" & Range("E" & Rows.Count).End(xlUp).Row)
Range("U2:U" & Range("E" & Rows.Count).End(xlUp).Row).Select
Range("V2").Formula = "=VLOOKUP($E2,'" & X & "]shtName'!$B$1:$AP$99999,18,0)"
Range("V2").AutoFill Destination:=Range("V2:V" & Range("E" & Rows.Count).End(xlUp).Row)
Range("V2:V" & Range("E" & Rows.Count).End(xlUp).Row).Select
Cells.Select
Cells.EntireColumn.AutoFit
Something like the following should give you the worksheets name out of a file
Dim wbk As Workbook
Set wbk = Workbooks.Open(Filename:="YOUR_FILE_PATH", ReadOnly:=True)
Dim shtName As String
shtName = wbk.Worksheets(1).Name
wbk.Close
Note: We can open the workbook in read only mode if we don't plan to change anything.
Additionally I recommend (for a good code following good practices):
Always specify a worksheet.
Eg for every Range("") like Worksheets("YourSheetName").Range("")
Or use With statements:
With Worksheets("YourSheetName")
.Range("A1").Value = 5 'recognize the starting full stop referring to the with statement
End With
Same for every Rows, Columns, Cells, etc.
Avoid using .Select, .Activate and Selection. at all.
(there are many tutorials out there in the Internet how to avoid them).
Use Option Explicit and declare all your variables before use.
(avoids many issues, especially typos).

Run-time error 438: Object doesn't support this property or method (VBA)

This is driving me absolutely insane.
I'm new to VBA and I compiled code line by line, adding more and more verifying it all worked within the same workbook using F8. The last bit I have to add is just opening a separate workbook, and now it's giving me errors each time. Here's my code:
Sub MasterXfer()
Dim mystring As String, wbName As String, dt As String, sdt As String, ldt As String
Dim wb1 As Workbook, wb2 As Workbook, mypath As String
wbNam = "Productivity "
dt = Sheet1.Range("B1").Value
sdt = Format(CStr(dt), "m.d.yy") & ".xlsx"
ldt = Format(CStr(dt), "yyyy") & "\" & Format(CStr(dt), "mm") & "_" & MonthName(Month(dt)) & "_" & Year(dt)
mypath = "S:\" & ldt & "\" & wbNam & sdt
Set wb1 = ThisWorkbook
Set wb2 = Workbooks.Open(mypath) 'HERE'S WHERE IT ERRORS OUT
With wb1
lastrow = Worksheets(1).Range("A" & Rows.Count).End(xlUp).Row
For x = 2 To lastrow Step 16
mystring = .Range("A" & x)
Stepping through this, it works fine. Then I get to the Set wb2 = Workbooks.Open line, and it successfully opens the target workbook, however immediately upon opening it the code stops and the error in question comes up.
If anyone at all can tell me what mistake I'm making I will name my firstborn after you.
Your error if caused by this line mystring = .Range("A" & x). Workbook does not have a Range method. You need to change it to wb1.Worksheets(1).
You should also test if the file exists before opening it.
I included an alternate method of creating your file string using the backslash to escape characters in the Format functions Format parameter.
Sub MasterXfer()
Dim wb2 As Workbook
Dim mypath As String
mypath = Format(Sheet1.Range("B1").Value, "\S:\\YYYY\\MM_MMMM_YYYY\\Pro\du\ctivit\y MM.DD.YY.xl\sx")
If Len(Dir(mypath)) = 0 Then
MsgBox "File not found" & vbCrLf & mypath
Stop
Exit Sub
End If
Set wb2 = Workbooks.Open(mypath)
With ThisWorkbook.Worksheets(1)
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
For x = 2 To LastRow Step 16
mystring = .Range("A" & x)
Next
End With
End Sub

Checking If A Sheet Exists In An External Closed Workbook

I want to test whether certain sheets in the current workbook exist in another closed workbook and return a message saying which sheet/s are causing errors.
I prefer not to open/close the workbook so I'm trying to change the formula in a random cell to link to the workbook of filepath (fp) to test whether the sheet exists.
I've tested this with a dummy sheet that I know doesn't exist in the other workbook and it works but when I have more than one sheet that causes errors I get an "Application-defined or object-defined error". On the second iteration I believe the way the error handling is written causes the crash but I don't exactly understand how that works.
The code I've got is:
Sub SheetTest(ByVal fp As String)
Dim i, errcount As Integer
Dim errshts As String
For i = 2 To Sheets.Count
On Error GoTo NoSheet
Sheets(1).Range("A50").Formula = "='" & fp & Sheets(i).Name & "'!A1"
GoTo NoError
NoSheet:
errshts = errshts & "'" & Sheets(i).Name & "', "
errcount = errcount + 1
NoError:
Next i
Sheets(1).Range("A50").ClearContents
If Not errshts = "" Then
If errcount = 1 Then
MsgBox "Sheet " & Left(errshts, Len(errshts) - 2) & " does not exist in the Output file. Please check the sheet name or select another Output file."
Else
MsgBox "Sheets " & Left(errshts, Len(errshts) - 2) & " do not exist in the Output file. Please check each sheet's name or select another Output file."
End If
End
End If
End Sub
Hopefully you guys can help me out here, thanks!
Here's a slightly different approach:
Sub Tester()
Dim s As Worksheet
For Each s In ThisWorkbook.Worksheets
Debug.Print s.Name, HasSheet("C:\Users\blah\Desktop\", "temp.xlsm", s.Name)
Next s
End Sub
Function HasSheet(fPath As String, fName As String, sheetName As String)
Dim f As String
f = "'" & fPath & "[" & fName & "]" & sheetName & "'!R1C1"
HasSheet = Not IsError(Application.ExecuteExcel4Macro(f))
End Function
Just an update for Tim's Function for error Handling:
VBA:
Function HasSheet(fPath As String, fName As String, sheetName As String)
On Error Resume Next
Dim f As String
f = "'" & fPath & "[" & fName & "]" & sheetName & "'!R1C1"
HasSheet = Not IsError(Application.ExecuteExcel4Macro(f))
If Err.Number <> 0 Then
HasSheet = False
End If
On Error GoTo 0
End Function
Sub Tester()
MsgBox (Not IsError(Application.ExecuteExcel4Macro("'C:\temp[temp.xlsm]Sheetxyz'!R1C1")))
End Sub

Excel VBA UDF Executes in Immediate Window, Fails on Worksheet

UDF "NAV()" is designed to find the correct report on a network drive based on the first argument (always a date), then loop through all worksheets to find a piece of data with the same row as second argument and same column as third argument (second and third can be text or numbers).
Works reliably in the immediate window. Always returns #VALUE! when used on worksheet, e.g. =NAV(D7,D8,D9) or =NAV(2/19/2016,"Net Asset Value","221-I").
In general it looks like one could get this behaviour if trying to alter other cells in a UDF, but my functions don't do that. Also, I believe all range references specify which workbook and worksheet, so I don't think that is the problem either. I'm not sure where to look next.
Function also attempts to email me a report through Outlook when it fails to find what the user is looking for. I don't know if that is relevant.
Again, what is perplexing is that this code seems to work fine in the immediate window, but only gives #VALUE! when used on a worksheet.
Where else can I look in my code below to determine what would cause NAV() to function correctly in the immediate window, but always yield #VALUE! when used on a worksheet?
Option Explicit
Function NAV(ByVal NAVDate As Date, ByVal matchRow As Variant, ByVal matchColumn As Variant) As Variant
'Application.ScreenUpdating = False
Application.Volatile True
NAV = FindItemOnWorksheet(NAVDate, matchRow, matchColumn)
'Application.ScreenUpdating = True
End Function
Function FindItemOnWorksheet(ByVal NAVDate As Date, ByVal ItemSpecies As Variant, ByVal ItemGenus As Variant) As Variant
' Finds Item by opening NAV workbook with correct date, activating correct worksheet, and searching for correct row and column
Dim startingRange As Range
Dim ws As Worksheet
Dim wb As Workbook
Dim theDate As Date
Dim theItemSpecies As String
Dim theItemGenus As String
theDate = NAVDate
theItemSpecies = ItemSpecies
theItemGenus = ItemGenus
Set wb = GetWB(NAVDate)
'Loop through ws
Dim WS_Count As Integer
Dim i As Integer
WS_Count = wb.Worksheets.Count
For i = 1 To WS_Count
Set ws = wb.Worksheets(i)
Set startingRange = ws.Range("A1:Z100")
Dim theRow As Range
Dim theColumn As Range
Set theRow = startingRange.Cells.Find(theItemSpecies, SearchDirection:=xlPrevious, lookat:=xlWhole)
If Not (theRow Is Nothing) Then
Set theColumn = startingRange.Cells.Find(theItemGenus, SearchDirection:=xlPrevious, lookat:=xlWhole)
If Not (theColumn Is Nothing) Then
FindItemOnWorksheet = ws.Cells(theRow.Row, theColumn.Column).Value
wb.Close
Exit Function
End If
End If
Next i
'Loop if no hit on either row or column Find()
'following executes only if no match found
MsgBox "No Match Found. Make sure you are entering arguments--" & vbNewLine & _
" The Date of NAV, " & vbNewLine & _
" the entry found in the right row of NAV workbooks (e.g. 'Net Asset Value'), " & vbNewLine & _
" the right column (e.g. 'Fund')." & vbNewLine & _
" This function will only find exact matches." & vbNewLine & vbNewLine & _
"Now emailing developer to ask for a fix."
Dim OutApp As Object
Dim OutMail As Object
Dim strbody As String
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
strbody = "User attempted" & _
"=FindItemOnWorksheet( " & theDate & ", " & theItemSpecies & ", " & theItemGenus & " )" & vbNewLine & _
"theDate type " & TypeName(theDate) & vbNewLine & _
"theItemSpecies type " & TypeName(theItemSpecies) & vbNewLine & _
"theItemGenus type " & TypeName(theItemGenus)
On Error Resume Next
With OutMail
.To = <Address Removed>
.CC = ""
.BCC = ""
.Subject = "FindItemOnWorksheet Error"
.Body = strbody
'.Attachments.Add ("C:\file.xlsx")
.Send
End With
On Error GoTo 0
Set OutMail = Nothing
Set OutApp = Nothing
FindItemOnWorksheet = "Error"
'wb.Close
Exit Function
End Function
Function GetWB(ByVal NAVDate As Date) As Workbook
'Open requested workbook, return to parent procedure
Dim wbPath As String
Dim wbYear As String
Dim wbMonth As String
Dim wbWeek As String
Dim wbFile As String
Dim wbString As String
Dim wb As Workbook
Dim BackADay As Boolean
Dim OriginalNAVDateRequested As Date
OriginalNAVDateRequested = NAVDate
BackADay = True
'Loop through possible file tree structures and dates to find the closest NAV in the past to the date requested.
Do While BackADay = True
'Don't go back to a previous week if cannot find current NAV
If OriginalNAVDateRequested - NAVDate > 4 Then
BackADay = False
End If
wbPath = <Network Path Removed>
wbYear = CStr(Year(NAVDate)) & "\"
wbMonth = MonthName(Month(NAVDate)) & " " & wbYear
wbWeek = DateFormat(NAVDate) & "\"
wbFile = Dir(wbPath & wbYear & wbMonth & wbWeek & "*Valuation Package*.xlsx")
'Pricings with distributions have differing tree structure
If wbFile = "" Then
wbWeek = wbWeek & "POST Distribution " & wbWeek
wbFile = Dir(wbPath & wbYear & wbMonth & wbWeek & "*Valuation Package*.xlsx")
If wbFile = "" Then
NAVDate = NAVDate - 1
Else: BackADay = False
End If
Else: BackADay = False
End If
Loop
wbString = wbPath & wbYear & wbMonth & wbWeek & wbFile
Set wb = Workbooks.Open(wbString, UpdateLinks:=False, ReadOnly:=True)
Set GetWB = wb
End Function
Function DateFormat(ByVal X As Date) As String
'Appends leading zeroes if needed to achieve form "00" for any two digit integer, and converts to string
Dim MM As String
Dim DD As String
Dim YYYY As String
If Month(X) < 10 Then
MM = "0" & CStr(Month(X))
Else
MM = CStr(Month(X))
End If
If Day(X) < 10 Then
DD = "0" & CStr(Day(X))
Else
DD = CStr(Day(X))
End If
YYYY = CStr(Year(X))
DateFormat = MM & "." & DD & "." & YYYY
End Function
You can Open Workbooks within a Worksheet_Change Event.
For demonstration, if a change in Sheet1!A2, Excel will try open the workbook name with that cell value, then Output the status to Sheet1!A4.
Put below in a Module:
Option Explicit
Function TryOpenWB(ByVal oItem As Variant) As Variant
Dim sOut As String
Dim oWB As Workbook
On Error Resume Next
Set oWB = Workbooks.Open(CStr(oItem))
If oWB Is Nothing Then
sOut = "Cannot open """ & CStr(oItem) & """"
Else
sOut = "Opened """ & CStr(oItem) & """ successfully."
'oWB.Close
End If
TryOpenWB = sOut
End Function
Then below in Worksheet Module (I used Sheet1 for demonstration):
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = Range("A2").Address Then
Application.EnableEvents = False
Range("A4").Value = TryOpenWB(Target)
Application.EnableEvents = True
End If
End Sub
So this idea is to open the Workbook only if some cell address is matched.

Read a value from a cell without opening the Workbook [duplicate]

I found this bit of code and thought it might be good to use if I just need to pull one value from a closed sheet.
strInfoCell = "'" & strPath & "[" & strFile & "]Sheet1'!R3C3"
myvalue = ExecuteExcel4Macro(strInfoCell)
When I run this code I get a value for strinfocell of
'C:\Users\my.name\Desktop[QOS DGL stuff.xlsx]Sheet1'!R3C3
But when I run the code a dialogue pops up, showing desktop files with "QOS DGL suff" showing.
What's causing this, why is it not just pulling back the data as expected?
I know the path and file name are right, because if I copy them from the debug output and paste them in to start>>run then the correct sheet opens.
I know that Sheet1 (named: ACL), does have a value in cells(3,3)
It depends on how you use it. The open file dialog box is being showed to you because the "strPath" doesn't have a "" in the end ;)
Try this code.
Option Explicit
Sub Sample()
Dim wbPath As String, wbName As String
Dim wsName As String, cellRef As String
Dim Ret As String
'wbPath = "C:\Documents and Settings\Siddharth Rout\Desktop\"
wbPath = "C:\Users\my.name\Desktop\"
wbName = "QOS DGL stuff.xls"
wsName = "ACL"
cellRef = "C3"
Ret = "'" & wbPath & "[" & wbName & "]" & _
wsName & "'!" & Range(cellRef).Address(True, True, -4150)
MsgBox ExecuteExcel4Macro(Ret)
End Sub
Similar application, but no hard coded paths as in the examples above. This function copies the value from another closed workbook, similar to the =INDIRECT() function, but not as sophisticated. This only returns the value...not a reference..so it cannot be used with further functions which require references (i.e.: VLOOKUP()). Paste this code into a new VBA module:
'Requires filename, sheetname as first argument and cell reference as second argument
'Usage: type in an excel cell -> =getvalue(A1,B1)
'Example of A1 -> C:\TEMP\[FILE1.XLS]SHEET1'
'Example of B1 -> B3
'This will fetch contents of cell (B3) located in (sheet1) of (c:\temp\file1.xls)
'Create a module and paste the code into the module (e.g. Module1, Module2)
Public xlapp As Object
Public Function getvalue(ByVal filename As String, ref As String) As Variant
' Retrieves a value from a closed workbook
Dim arg As String
Dim path As String
Dim file As String
filename = Trim(filename)
path = Mid(filename, 1, InStrRev(filename, "\"))
file = Mid(filename, InStr(1, filename, "[") + 1, InStr(1, filename, "]") - InStr(1, filename, "[") - 1)
If Dir(path & file) = "" Then
getvalue = "File Not Found"
Exit Function
End If
If xlapp Is Nothing Then
'Object must be created only once and not at each function call
Set xlapp = CreateObject("Excel.application")
End If
' Create the argument
arg = "'" & filename & "'!" & Range(ref).Range("A1").Address(, , xlR1C1)
'Execute an XLM macro
getvalue = xlapp.ExecuteExcel4Macro(arg)
End Function
Code above
strInfoCell = "'" & strPath & "[" & strFile & "]Sheet1'!R3C3"
myvalue = ExecuteExcel4Macro(strInfoCell)
Should read
strInfoCell = "'" & strPath & "[" & strFile & "]" & "Sheet1'!R3C3"
myvalue = ExecuteExcel4Macro(strInfoCell)
It is missing " & "
No need for a function
Cheers
Neil
Data = "'" & GetDirectory & "[" & GetFileName & "]" & Sheet & "'!" & Range(Address).Range("A1").Address(, , xlR1C1)
Address = "$C$3"
GetDirectory = "C:\Users\my.name\Desktop\"
GetFileName = "QOS DGL stuff.xlsx"
Sheet = "ACL"