vba run other excel files macros - vba

I have following code:
Sub MacroRunner()
Dim Nomefile As String, Nomefolder As String
Nomefolder = ActiveWorkbook.Path
Nomefile = Dir(Nomefolder & "\*.xlsb")
Workbooks.Open (Nomefolder & "\" & Nomefile)
ActiveWorkbook.Worksheets(2).Select
Application.Run "Nomefile!listaIdprodotto" '<-------- "nomefile" variable not returned
Application.DisplayAlerts = False
ActiveWindow.Close
End Sub
The issue is in line marked by a left arrow; Excel doesn't return variable value making itself unable to find asked Macro to be executed.
Thanks for any help.

You should refer a bit differently (in case that Nomefile.xlsb is the file):
Application.Run "'Nomefile.xlsb'!listaIdprodotto"
Or even (in case that Nomefile is a variable):
Application.Run "'" & Nomefile & "'!listaIdprodotto"
Source

It would be better to be more specific about what files and sheets you want to act on.
Nomefolder = ActiveWorkbook.Path
This isn't necessarily the workbook containing the code. If you create a new workbook immediately before running the code then this will equal an empty string - it's whichever workbook is currently on top (active).
Nomefile = Dir(Nomefolder & "\*.xlsb")
This will return the first file in the folder that has an xlsb extension. If todays file wasn't created it will return the previous file and run yesterdays update again.
If it's a file that's generated each day then look for the file name with the correct date.
ActiveWorkbook.Worksheets(2).Select
Again - same problem with ActiveWorkbook. This is also looking at the second sheet in the tab order which may not be the sheet you're after if someone moved it. Reference the sheet by name (which could still be changed). It would be better to reference by sheet CodeName which can't be changed by the user, but that opens a different kettle of worms as the sheet you're referencing isn't in the workbook containing the code.
Application.Run "Nomefile!listaIdprodotto"
As you've enclosed Nomefile within the double quotes it's not seeing it as a variable but as a file called Nomefile. To see it as a variable it needs to be written as Application.Run Nomefile & "!listaIdprodotto". If the file name contains spaces then it needs to be written as Vityata has written: Application.Run "'" & Nomefile & "'!listaIdprodotto". This encloses the file name in single quotes.
I'd rewrite the code as:
Public Sub Test()
Dim Nomefile As String, Nomefolder As String
Dim wrkBk As Workbook
'Nomefolder = ActiveWorkbook.Path
Nomefolder = ThisWorkbook.Path
'Nomefile = Dir(Nomefolder & "\*.xlsb")
Nomefile = Nomefolder & "\WorkbookWithCode.xlsb"
'Open the workbook, run the code and close the workbook.
Set wrkBk = Workbooks.Open(Nomefile)
Application.Run "'" & wrkBk.Name & "'!listaIdprodotto"
wrkBk.Close
End Sub
The main difference here is that I set the whole workbook to a variable - Set wrkBk = ..... From there on I can always reference the correct workbook and don't have to worry whether it's Active or not.

Related

Option Explicit and Macros in a function [duplicate]

This question already has answers here:
running excel macro from another workbook
(4 answers)
Closed 5 years ago.
I have the following code:
Option Explicit
Public Function LastWeekOfMonth() As Boolean
'finds the current date
Dim CurrentDate As Date
CurrentDate = CDate(ActiveSheet.Cells(FIRST_DATA_ROW, 1))
'find filepath and filename
Dim filepath As String
Dim filename As String
filepath = "C:\target\file\path\here\"
filename = Cells(3, 4) & ".m_d.xlsm"
MsgBox (filepath & filename)
'if it is the last week of the month, write a monthly report, and return true to continue with the face to face paperwork
If (31 - Day(CurrentDate)) <= 7 Then
'write a monthly report
Dim app As New Excel.Application
Dim wsheet As New Worksheet
Dim book As Excel.Workbook
app.Visible = False 'Visible is False by default, so this isn't necessary
Set book = app.Workbooks.Open(filepath & filename)
Set wsheet = book.Worksheets("Monthly")
'Application.Run ("WriteMonthly")
app.book.wsheet.Run ("WriteMonthly")
book.Close SaveChanges:=True
app.Quit
Set app = Nothing
LastWeekOfMonth = True
'if it is not, simply continue with the face to face paperwork
Else
LastWeekOfMonth = False
End If
End Function
WriteMonthly is a macro that is currently contained in the target spreadsheet. Documentation online says that macros can be run through application.run(macro name, arg1,arg2,arg3, ...)
I want to pull information from the current spreadsheet to call up a specific spreadsheet and run a macro on that spreadsheet, with the code for that macro being on that spreadsheet, and eventually any data that is generated to be stored on that spreadsheet.
This is part of a form which looks at if the last days of the month have been reached; if they have, write a specific "monthly" report.
The problem is this:
app.book.wsheet.Run ("WriteMonthly")
doesn't work and neither does:
Application.run("!WriteMonthly")
The syntax is Application.Run "'WbkName'!ProcedureName"
However because the procedure you are calling resides in an Object Module (a worksheet in this case) the syntax has to include the name of the object as well, such as this: Application.Run "'WbkName'!ObjectName.ProcedureName"
Application.Run "'" & filename & "'!ObjectName.WriteMonthly"
Replace ObjectName with the name of the VbModule of the worksheet Monthly.
Try: Application.Run "'" & filename & "'!" & wsheet.CodeName & ".WriteMonthly"
Also ensure that procedure WriteMonthly is not declared as Private in the `Monthly' Module

How can I export a closed workbook sheet to a .CSV file?

I am currently working on a set of vba functions that should allow the user to export several sheets from a xls or xlsx file and export them all to different file formats depending on the name of the sheets. It's a very specific procedure using older files.
Some of the sheets in the chosen file should be treated as raw data, and I want to export them as a .CSV file without making any change in the data. If it helps, I don't even need to "see" the data to make IFs or other logical treatments.
I already have a function to get data from a specific cell in a specific sheet from the closed file, but I can't figure out how to get all the data from the sheet without iterating through all the billions of cells that are mostly empty just to check if there is data in the Cell(23785;GP).
Here is the function I already have, which might help understanding the expected behavior.
Private Function GetInfoFromClosedFile(ByVal wbPath As String, _
ByVal WBName As String, wsName As String, cellRef As String) As Variant
Dim arg As String
GetInfoFromClosedFile = ""
If Right(wbPath, 1) <> "\" Then wbPath = wbPath & "\"
If Dir(wbPath & "\" & WBName) = "" Then Exit Function
arg = "'" & wbPath & "[" & WBName & "]" & wsName & "'!" & Range(cellRef).Address(True, True, xlR1C1)
On Error Resume Next
GetInfoFromClosedFile = ExecuteExcel4Macro(arg)
End Function
It is necessary that the other workbook is still closed at the end, and that no changes whatsoever are made to the current one. At the very least, all changes made should be undone so that after choosing the file, the user will only see my confirmation messages and the newly created files on his computer, with no visible difference in his Excel. Since this will be used by people who are neither programmers nor very tech savvy, so any messing up with their current workbook that they could be using for something at the same time will earn us some complaints.
This Sub takes a file string and the sheet name as arguments to create a .CSV file with the extension .csv appended to its previous name, sheet name and extension.
Private Sub export_file_to_csv(src_path, sheet_name)
Application.DisplayAlerts = False
Set src_workbook = Workbooks.Open(src_path, , True)
src_workbook.Sheets(sheet_name).Activate
dst_path = src_path & " - " & sheet_name & ".csv"
src_workbook.SaveAs Filename:=dst_path, FileFormat:=xlCSV
src_workbook.Close
Application.DisplayAlerts = True
End Sub
You can then call it as many times as needed in another sub.
Sub main_sub()
export_file_to_csv "C:\Users\username\Desktop\maps.xlsx", "Europe"
export_file_to_csv "C:\Users\username\Desktop\maps.xlsx", "Asia"
export_file_to_csv "C:\Users\username\Documents\budget.xls", "Sheet1"
End Sub
Just put this code in another workbook, edit the paths and sheet names of the files that will be exported to CSV and run the main_sub, which should appear on the macro menu. The original files will be kept untouched, as they were open read-only.
Hope it helps!

Loop to run macros from other workbooks

I would greatly appreciate your help with a macro that I am trying to create.
I have a pathway that looks as follows: K:\XXX\XXX\XXX\Module 1
Module 1 is a folder that contains a bunch of xlsm files named with a number (i.e. 100.xlsm, 110.xlsm, and so forth)
I would like to create a loop that:
Runs the macro in workbook 100.xlsm;
Saves the 100.xlsm (NOT "save as") when the macro is done running;
Closes the saved xlsm, moves on to the next file (i.e.
110.xlsm), and repeats the same steps.
Before running the loop, I would like to create a statement that stores the names of those xlsm files.
The macro below may give you an idea of what I am after. There are indeed several errors.
Sub update()
Dim path As String path = "K:\XXX\XXX\XXX\Module 1"
Dim list() As Integer
List=(100, 110, 137, 140)
For Each n As Integer In list
Application.Run (path & "\" &n.xslm!refresh)
Save WORKBOOK
Close WORKBOOK
Next
End Sub
I think something like the code below will achieve what you are wanting to do.
Note that the code first opens the workbook whose macro you want to run.
You can then run the macro in that opened workbook from your original workbook with the Application.Run() command, e.g.
Application.Run("book1.xlsm!mymacro"), or
result = Application.Run("book1.xlsm!mymacro", "Hello", 20)
The second example calls a macro that requires a string paramater and an integer parameter.
The fuller example below opens some specific workbooks called 100.xlsm, 110.xlsm, etc and then runs a macro in each of them called SayHelloMessage.
I hope this helps.
Sub RunMacrosInOtherWorkbooks()
Dim wbpath As String 'path where the workbooks containing the macros you want to run are saved
Dim wbnames() As String 'array containing names of workbooks whose macros you want to run
Dim wbTarget As Workbook 'current workbook who macro is being run
Dim macroname As String 'name of macro being run
wbpath = "C:\Test"
wbnames() = Split("100.xlsm,110.xlsm,137.xlsm,140.xlsm", ",") 'Just one way of creating the list of workbooks.
macroname = "SayHelloMessage"
Dim i As Integer
Dim result As Variant
For i = 0 To UBound(wbnames)
Set wbTarget = Workbooks.Open(wbpath & "\" & wbnames(i))
result = Application.Run(wbTarget.Name & "!" & macroname)
' result = Application.Run(wbTarget.Name & "!" & macroname, 76) 'calling a subroutine or function with an argument. You need something to catch a return code
wbTarget.Save
wbTarget.Close
Next
End Sub

Auto generated save excel file name VBA Macro?

Auto generated excel file name VBA Macro?
Hi all i want auto generated excel file name in macro
my code is below here
Sub Sheet_SaveAs()
Dim wb As Workbook
Sheets("Sheet1").Copy
Set wb = ActiveWorkbook
With wb
.SaveAs ThisWorkbook.Path & "\autogenrate.xlsx"
'.Close False
End With
End Sub
my code is working fine but when i save next time then asking do you want replace it but i want auto generate name
The simplest fix is to change to a unique name each time. The easiest way to do this might be to use a date-time string
Sub Sheet_SaveAs()
Dim wb As Workbook
Sheets("Sheet1").Copy
Set wb = ActiveWorkbook
With wb
.SaveAs ThisWorkbook.Path & "\" & _
Format(Now, "yyyymmdd") & _
Replace(Format(Now, "Long Time"), ":", "") & _
".xlsx"
.Close False
End With
End Sub
The date and tie part are seperate to allow you to use seconds and therefore your limit is 1 save per second. If you need more frequent saves you would have to include a millisecond counter too. The good thing about this method is that it keeps your backups in sequential order in the folder.
You can read more about formatting dates etc. here - https://msdn.microsoft.com/en-us/library/office/gg251755.aspx

Excel UDF: retrieving value from arbitrary, closed, external workbook

I am looking for a way to return the value from an arbitrary workbook (the workbook will also not be open at the time of running the UDF), defined based on calculations in the UDF.
Pseudo code:
Start by calling =someFunc(currentCell) in any cell
Function someFunc(adr As Range)
region_eval = "C" & Range(adr).Row ' where column C contains string entries, all of which have a corresponding sub-dir (see fileReference).
networkLocation = ActiveWorkbook.Path
networkPath = networkLocation & "\Locations\"
fileReference = networkPath & region_eval & "\ProductList.xlsx"
Workbook.Open fileReference readonly
Perform index/match call against some sheet in this workbook
someFunc = returned value
Close workbook and end function
This is the desired behavior.
The logic to return the desired values is OK, I have tried it in a simpler formula, and in a UDF that relies on the file being opened manually:
INDEX(locationlist_$A$5000, MATCH(masterlist_A1, locationlist_$B$5000))
I have, after hours of hair-pulling, discovered that this functionality is not directly available in a UDF designed to work on workbooks that aren't opened manually, and that this is intended from Microsoft's side. But I have also discovered that there is a possible workaround!
Ref:
1. https://stackoverflow.com/a/27844592/4604845
2. http://numbermonger.com/2012/02/11/excel-pull-function-creating-dynamic-links-to-closed-workbooks/
These solutions require hardcoded file paths, which defeats the purpose for my intended usage.
Is there anyone who has insight about how to achieve what is achieved in any of the two above links, but with an arbitrary filepath (as in, contained in a cell neighbouring the cell where the UDF is being called from)?
Note: I tried doing the heavy lifting in a sub, and just call the sub as the first line in the UDF, set the result as a global var, and set the UDF return value to the same var after the sub finished, but either I crashed and burned pretty heavily or Excel saw through my trick and denied it.
EDIT:
Here's the sub/func combo.
Option Explicit
Public networkLocation As String, networkPath As String, fileReference As String, c_formula As String
Public sheet_src As Worksheet, sheet As Worksheet, wb_src As Workbook, wb As Workbook
Public region_eval As String, sheetName_src As String, sheetName As String, regionPath As String, fileName As String
Sub findProductStatus(adr As Range)
networkLocation = ActiveWorkbook.Path
networkPath = networkLocation & "\Locations\"
sheetName_src = "Sheet1"
sheetName = "Sheet1"
Set wb_src = ThisWorkbook
Set sheet_src = wb_src.Sheets(sheetName_src)
region_eval = Range("I" & adr.Row)
regionPath = networkPath & region_eval
'fileReference = regionPath & "\ProductList.xlsx"
fileName = "ProductList.xlsx"
ChDir regionPath
Workbooks.Open fileName:=fileName, ReadOnly:=True
'Set wb = Workbooks.Open(fileName:=ThisWorkbook.Path & "\Locations\Test\ProductList.xlsx", ReadOnly:=True)
Set wb = Workbooks("ProductList.xlsx")
Set sheet = wb.Sheets(sheetName)
c_formula = Application.WorksheetFunction.Index(sheet.Range("$K$2:$K$5000"), Application.WorksheetFunction.Match(sheet_src.Range("A" & adr.Row), sheet.Range("$A$2:$A$5000"), 0))
End Sub
Function getProductStatus(adr As Range) As String
Call findCourseStatus(adr)
getCourseStatus = c_formula
wb.Close
End Function
I haven't tested the sub/func combo against an open file, but when all of the code was inside the Function and the file in question was opened manually, it worked flawlessly. Stepping through the code and using Debug.Print, I see that even though "Workbooks.Open ..." goes through without any discernible error, the workbook doesn't actually get opened, and thus, when we try to use the workbook object to set the sheet, the function/sub terminates.
This can be achieved with a combination of a UDF() and an Event macro.
To retrieve data from a closed workbook, we need four things:
the path
the filename
the sheetname
the cell address
The only thing the UDF will do is to display these items in a very specific format:
Public Function someFunc() As String
Dim wbPath As String, wbName As String
Dim wsName As String, CellRef As String
Dim Ret As String
wbPath = "C:\TestFolder\"
wbName = "ABC.xls"
wsName = "xxx"
CellRef = "B9"
someFunc = "'" & wbPath & "[" & wbName & "]" & _
wsName & "'!" & Range(CellRef).Address(True, True, -4150)
End Function
Take note of the position of the single quotes.
We then use a Calculate event macro to detect the UDF's execution and retrieve the data:
Private Sub Worksheet_Calculate()
Dim r1 As Range, r2 As Range
Set r1 = Range("C3")
Set r2 = Range("C4")
r2.Value = ExecuteExcel4Macro(r1.Value)
End Sub
The Calculate macro needs to know where the UDF is returning the string (C3) and it also needs to know where to put the retrieved data (C4).