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
Related
Trying to use an Excel-macro that will automatically save the workbook once certain cells are filled in. The macro will check when changes are made to specific cells, then use variable data to save the workbook through a folder system organized by year and quarter, while giving the Workbook a name based on the Current date and a cell number. The macro will also check to see if the network path (it being on a server) is connected, and if not, exit the sub. I am getting a compile error "Expected: end of statement" at
Set mTitle = Year(Now)," & . & ", Month(Now), " &.& ", Day(Now), " & - & ", ActiveWorkbooks.Sheets("Control").Cells(1, "C")
I want to save the workbook with the following format: Year.Month.Day - CellValue, but it looks like VBA doesn't like periods. How can I solve this? Full code below.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim cYear As String
Dim Quarter As String
Dim fdObj As Object
Dim mTitle As String
Dim sCheck
Application.ScreenUpdating = False
Set cYear = Year(Now)
Set Quarter = (Month(Now) + 2) \ 3
Set fdObj = CreateObject("Scripting.FileSystemObject")
sCheck = "S:\Estimating Data\Estimates\test.txt"
Set mTitle = Year(Now)," & . & ", Month(Now), " &.& ", Day(Now), " &.& ", ActiveWorkbooks.Sheets("Control").Cells(1, "C")
If Intersect(Target, Range("C1:C5")) Is Nothing Then
Exit Sub
Else
If WorksheetFunction.CountA(Range("C1:C5")) = 0 Then
Exit Sub
Else
Shell ("Net View \\S:\ > " & vsFileName)
If FileLen(vsFileName) = 0 Then
Exit Sub
Else
If fdObj.FolderExists("S:\Estimating Data\Estimates\" & cYear & "\""Q" & Quarter & ".*xlsm") Then
ActiveWorkbook.SaveAs Filename:="S:\Estimating Data\Estimates\" & cYear & "\""Q" & Quarter & "\" & mTitle & ".*xlsm"
Else
fdObj.CreateFolder ("S:\Estimating Data\Estimates\" & cYear & "\""Q" & Quarter & ".*xlsm")
End If
End If
End If
End If
End Sub
I need help copying data from a closed workbooks (without opening them) into a column in the master workbook using VBA. I keep getting the error:
Run-time Error 424: object required
Here is my code:
Set x = Workbooks.Open("C:\Users\DD\Desktop\EMS")
x.Sheets("PO Report").Range("Y3:Y500").Copy
y.Activate
Sheets("Sheet1").Range("Q2").PasteSpecial
Application.CutCopyMode = False
x.Close
Thanks for the help in advance!
this is the problem - you are not specifying the filename of the excel file
Set x = Workbooks.Open("C:\Users\DD\Desktop\EMS")
you cannot read data out of a closed file... it has to be open
you also need to Dim your x object
Dim x as object
I altered the code posted here. Insert the following code in your "Sheet1" sheet module:
Option Explicit
Sub GetDataDemo()
Dim FilePath$
Dim i As Long
Const FileName$ = "EMS.xlsx"
Const SheetName$ = "PO Report"
FilePath = "C:\Users\DD\Desktop\"
DoEvents
Application.ScreenUpdating = False
If Dir(FilePath & FileName) = Empty Then
MsgBox "The file " & FileName & " was not found", , "File Doesn't Exist"
Exit Sub
End If
For i = 3 To 500
Range("Q" & i - 1) = GetData(FilePath, FileName, SheetName, Range("Y" & i))
Next i
ActiveWindow.DisplayZeros = False
End Sub
Private Function GetData(Path, File, Sheet, Rng)
Dim Data$
Data = "'" & Path & "[" & File & "]" & Sheet & "'!" & Rng.Address(, , xlR1C1)
GetData = ExecuteExcel4Macro(Data)
End Function
I have a function which is Boolean, and returns whether is the cell OK for creating a New Folder based on its value or its not (if it posses following chars:<,>,|,\,*,?)
But from some weird reason, it returns always false, either is a cell OK or not.
So, I have a sub which creates a loop for all rows and creates some .txt files and puts it in auto-generated folders.
Here is my code:
Sub CreateTxtSrb()
Dim iRow As Long
Dim iFile As Integer
Dim sPath As String
Dim sFile As String
Dim iEnd As Range
'iEnd = Cells(Rows.Count, "B").End(xlUp).Row
For iRow = 1 To Cells(Rows.Count, "B").End(xlUp).Row
iFile = FreeFile
With Rows(iRow)
If IsValidFolderName(.Range("B2").Value) = False Or IsValidFolderName(.Range("D2").Value) = False Or IsValidFolderName(.Range("F2").Value) = False Then
MsgBox ("Check columns B,D or F, it cannot contains chars: <,>,?,|,\,/,*,. or a space at the end")
Exit Sub
Else
strShort = IIf(InStr(.Range("E2").Value, vbCrLf), Left(.Range("E2").Value, InStr(.Range("E2").Value, vbCrLf) - 2), .Range("E2").Value)
sPath = "E:\" & .Range("B2").Value & "\"
If Len(Dir(sPath, vbDirectory)) = 0 Then MkDir sPath
sFile = .Range("D2").Value & ".txt"
Open sPath & sFile For Output As #iFile
Print #iFile, .Range("E2").Value
Close #iFile
End If
End With
Next iRow
End Sub
Function IsValidFolderName(ByVal sFolderName As String) As Boolean
'http://msdn.microsoft.com/en- us/library/windows/desktop/aa365247(v=vs.85).aspx#file_and_directory_names
'http://msdn.microsoft.com/en-us/library/ie/ms974570.aspx
On Error GoTo Error_Handler
Dim oRegEx As Object
'Check to see if any illegal characters have been used
Set oRegEx = CreateObject("vbscript.regexp")
oRegEx.Pattern = "[<>:""/\\\|\?\*]"
IsValidFolderName = Not oRegEx.test(sFolderName)
'Ensure the folder name does end with a . or a blank space
If Right(sFolderName, 1) = "." Then IsValidFolderName = False
If Right(sFolderName, 1) = " " Then IsValidFolderName = False
Error_Handler_Exit:
On Error Resume Next
Set oRegEx = Nothing
Exit Function
Error_Handler:
MsgBox ("test")
' MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
' "Error Number: " & Err.Number & vbCrLf & vbCrLf & _
' "Error Source: IsInvalidFolderName" & vbCrLf & _
' "Error Description: " & Err.Description, _
' vbCritical, "An Error has Occurred!"
Resume Error_Handler_Exit
End Function
How can I make it return true if need be?
You don't need the external reference you can simply:
hasInvalidChars = sFolderName like "*[<>|\/:*?""]*"
I added " and : which are also illegal.
(In your example you have HTML entities (E.g. <) - these have no meaning in your RegEx string and are interpreted as 4 characters in the class)
That's a mess. Use a separate function
Public Function IsInvalid(ByVal name As String) As Boolean
Dim regex As Object
Set regex = VBA.CreateObject("VBScript.RegExp")
regex.Pattern = "[\\/:\*\?""<>\|]" 'the disallowed characters
IsInvalid = (regex.Execute(name).Count > 0)
End Function
instead, and call it when appropriate.
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.
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.