Excel VBA call function with variable name - excel

I'm trying to call a function with a variable name that is generated at run time based upon a combo box value. This is straightforward in most languages but I can't seem to figure it out in Excel VBA, I suspect this is because I don't really understand how the compiler works. I've found several posts that are close but don't quite seem to do the trick. The code below is wrong but should give an idea of what I want.
Thanks
Sub main()
'run formatting macros for each institution on format button click
Dim fn As String
Dim x As Boolean
'create format function name from CB value
fn = "format_" & CBinst.Value
'run function that returns bool
x = Eval(fn)
...
End Sub

CallByName is what you'll need to accomplish the task.
example:
Code in Sheet1
Option Explicit
Public Function Sum(ByVal x As Integer, ByVal y As Integer) As Long
Sum = x + y
End Function
Code is Module1 (bas module)
Option Explicit
Sub testSum()
Dim methodToCall As String
methodToCall = "Sum"
MsgBox CallByName(Sheet1, methodToCall, VbMethod, 1, 2)
End Sub
Running the method testSum calls the method Sum using the name of the method given in a string variable, passing 2 parameters (1 and 2). The return value of the call to function is returned as output of CallByName.

You should write a function that accepts the CB value as a parameter and then uses a select case to call the appropriate formatting function.
Something similar to this
Function SelectFormatting(Name as String) As Boolean
Select Case CBinst.Value
Case "Text1":
SelectFormatting = Text1FormattingFunction()
Case "Text2":
.
.
.
End Select
End Function

The above will work but not with a large number of names
Use Application.Run(MacroName, Parameters)
You have to may sure that there is a macro but it is better than the above as there is no select statement.

With respect to my answer above you might also find this useful to check whether the macro exists
'=================================================================================
'- CHECK IF A MODULE & SUBROUTINE EXISTS
'- VBA constant : vbext_pk_Proc = All procedures other than property procedures.
'- An error is generated if the Module or Sub() does not exist - so we trap them.
'---------------------------------------------------------------------------------
'- VB Editor : Tools/References - add reference TO ......
'- .... "Microsoft Visual Basic For Applications Extensibility"
'----------------------------------------------------------------------------------
'- Brian Baulsom October 2007
'==================================================================================
Sub MacroExists()
Dim MyModule As Object
Dim MyModuleName As String
Dim MySub As String
Dim MyLine As Long
'---------------------------------------------------------------------------
'- test data
MyModuleName = "TestModule"
MySub = "Number2"
'----------------------------------------------------------------------------
On Error Resume Next
'- MODULE
Set MyModule = ActiveWorkbook.VBProject.vbComponents(MyModuleName).CodeModule
If Err.Number <> 0 Then
MsgBox ("Module : " & MyModuleName & vbCr & "does not exist.")
Exit Sub
End If
'-----------------------------------------------------------------------------
'- SUBROUTINE
'- find first line of subroutine (or error)
MyLine = MyModule.ProcStartLine(MySub, vbext_pk_Proc)
If Err.Number <> 0 Then
MsgBox ("Module exists : " & MyModuleName & vbCr _
& "Sub " & MySub & "( ) : does not exist.")
Else
MsgBox ("Module : " & MyModuleName & vbCr _
& "Subroutine : " & MySub & vbCr _
& "Line Number : " & MyLine)
End If
End Sub
'-----------------------------------------------------------------------------------

Related

Find Immediate Windows localized name in Excel-VBA

Is there a way in VBA-Excel to find how is named the Immediate window in a localized version of Microsoft Office Excel, not English ?
For example, I use an Italian version of Excel, and here Immediate window is called "Immediata", other, for example Dutch here, called it "Direct"
and so on...
I'm trying to modify a function finded in the page linked above, but I wish to release a version able to work in any localized version of MsO Excel.
Thanks in advance for the answer.
The name of the Immediate Window is available in the Window object with the type vbext_wt_Immediate. This type is only available with the correct imports, but all it says is vbext_wt_Immediate = 5. Instead of creating a reference to this, it can be declared and used like this:
Const VBEXT_WT_IMMEDIATE = 5
Function ImmediateLabel() As String
Dim win As Object
For Each win In Application.VBE.Windows
If win.Type = VBEXT_WT_IMMEDIATE Then
ImmediateLabel = win.Caption
End If
Next
End Function
Sub Test()
Debug.Print ImmediateLabel
End Sub
'++++++++++++++++++++++++++++++++++++++++++++++
'+ Function to find the name of the localized +
'+ version of the Immediate windows. +
'++++++++++++++++++++++++++++++++++++++++++++++
Public Function LocalizedImmediateWin() As String
' String pass to the MsgBox.
Dim strMsg As String
' This Integer'll contain the total number of the VBE Windows.
Dim intNumWin As Integer
' This Integer is used as counter in the For...Next loop.
Dim intLoop As Integer
' Count the number of all the windows (show or hidden) in the VBE.
intNumWin = Application.VBE.Windows.Count
' Loop for all the windows find, starting from 1.
For intLoop = 1 To intNumWin
' If the Type of the Windows we're examine is an Immediate Windows then
If Application.VBE.Windows.Item(intLoop).Type = vbext_wt_Immediate Then
' Build the MsgBox.
strMsg = MsgBox("In this localized version of " & Chr(13) & Chr(10) & "Microsoft Office Excel, " & Chr(13) & Chr(10) & "Immediate windows is called:" & Chr(13) & Chr(10) & Chr(13) & Chr(10) & Application.VBE.Windows.Item(intLoop).Caption & "", vbCritical, "Localized Immediate")
' Pass the value as result of the Function.
LocalizedImmediateWin = Application.VBE.Windows.Item(intLoop).Caption
Exit For
End If
' Next windows to examine.
Next intLoop
' End of the function.
End Function
' Simple way to try.
Sub Try()
MsgBox LocalizedImmediateWin
End Sub

deactivate/comment out makros in a lot of excel files

i do have several hundred of excel files. Every excel file contains a makro in the "workbooks_open" method. I want to open all these files, comment out the code, save and close the file.
a loop through all files with open/close is not a problem, but with the changing of the vba code i have no idea.
many thanks in advance!
Sub test()
Dim Path as string = "C:\123\"
Dim cDir As String
cDir = Dir(Path & "*.xlsx")
Do While cDir <> ""
Application.DisplayAlerts = False
'### open
Workbooks.Open Filename:=Path & cDir
'### here i want to deactivate/comment out the makro in the workbook_open method
'### save
ActiveWorkbook.Save
ActiveWorkbook.Saved = True
'### close
ActiveWorkbook.Close False
cDir = Dir
Loop
End Sub
To access the code of a workbook using code, you need to allow access to the VBE via code - see https://stackoverflow.com/a/11680865/7599798 how to do so.
You access all the coding stuff of a workbook using its VBProject-Property.
If you want to use the Types and Constants of the Project, add a reference to Microsoft Visual Basic for Applications Extensibility
The VBProject contains a collection of Components VBComponents, this is the list you see in the VBE in the project window, it contains all modules, classes and forms.
The Workbook-Module has the Name ThisWorkbook and it's type = 100 (use vbext_ct_Document if you have added the mentioned reference)
To access the code of a module, use the property CodeModule of the component.
The lines of code can be fetched using the lines-property of CodeModule, you need to pass two parameters (startrow and numbers of rows).
The lines-property is read only, if you want to change code, you can use the methods InsertLines, DeleteLines and ReplaceLines
Have a look to the next routine to see how it could look like. It will simply replace the Workbook_Open()-routine with Workbook_Open_BACKUP() so it will no longer fire when the workbook is opened.
Sub RemoveOnOpen(wb As Workbook)
Dim i As Long
With wb.VBProject
For i = 1 to .VBComponents.Count
' Debug.Print .VBComponents(i).Type, .VBComponents(i).Name
If .VBComponents(i).Type = vbext_ct_Document And .VBComponents(i).Name = "ThisWorkbook" Then
Dim row As Long
For row = 1 To .VBComponents(i).CodeModule.CountOfLines
Dim module As CodeModule, line As String
Set module = .VBComponents(i).CodeModule
line = Trim(module.Lines(row, 1))
If Left(line, 27) = "Private Sub Workbook_Open()" Then
module.ReplaceLine row, Replace(line, "Workbook_Open()", "Workbook_Open_BACKUP()")
End If
Next
End If
Next i
End With
End Sub
Update: As T.M. noted, the name of the Workbook module may be different if used in a different language environment, you should check this.
I also added a Trim-statement when checking the code line for the Sub.
Please, use the next Sub. It should be called by the code iterating between all workbooks to be changed:
Sub ComSpecSub(wb As Workbook, moduleName As String, strLine As String)
Dim objThisWb As VBComponent, CodeM As CodeModule, i As Long, j As Long
Set objThisWb = wb.VBProject.VBComponents("ThisWorkbook")
Set CodeM = objThisWb.CodeModule
If CodeM.Find(strLine, 1, 1, CodeM.CountOfLines, 1, False) = True Then
For i = 1 To CodeM.CountOfLines
If InStr(CodeM.lines(i, 1), strLine) > 0 Then
If left(CodeM.lines(i, 1), 1) = "'" Then Exit Sub 'already commented...
'if running the code again
Do While i + j <= CodeM.CountOfLines
CodeM.ReplaceLine i + j, "'" & CodeM.lines(i + j, 1)
If InStr(CodeM.lines(i + j, 1), "End Sub") > 0 Then Exit Do
j = j + 1
Loop
End If
Next i
End If
End Sub
The above code needs a reference to 'Microsoft Visual Basic for Applications Extensibility'
It should be called from your code as:
ComSpecSub ActiveWorkbook, "ThisWorkbook", "Private Sub Workbook_Open()"
ActiveWorkbook.Close True
If adding the required reference looks problematic, please firstly run the next code, which will add it automatically:
Sub addExtenssibilityReference()
'Add a reference to 'Microsoft Visual Basic for Applications Extensibilty 5.3':
ThisWorkbook.VBProject.References.AddFromGuid _
GUID:="{0002E157-0000-0000-C000-000000000046}", _
Major:=5, Minor:=3
End Sub
Language independant & no loops
In addition to the valid answers of #FunThomas (following his renaming idea) and #FaneDuru I demonstrate an approach with two benefits:
the component ThisWorkbook can be found independantly from regional language settings via wb.VBProject.VBComponents(wb.CodeName),
as workbooks can be referenced not only by their name string which may differ for other languages than English,
but also via a workbook's wb.CodeName property (similar for sheets);
the effective procedure start row can be found in one go via
.ProcBodyLine(srchProcName, 0), where the zero input defines a sub or function procedure kind (other than Get|Let|Set props);
Further hints:
Needs a library reference to Microsoft Visual Basic for Applications Extensibility 5.3 (c.f. also #FaneDuru's progamatical approach).
Generally replacing a code line by another should consider possible line breaks ( _) resulting in two or several lines, too; due to the brevity of the procedure I don't assume a line break before "Workbook_Open" (like e.g. `Private Sub _".
Sub BackUp(wb as WorkBook, Optional ByVal srchProcName As String = "Workbook_Open")
'Purp: change a given procedures name in ThisWorkbook (e.g. "Workbook_Open") by adding "_BACKUP"
'0) Define backup name string
Dim backupName As String: backupName = srchProcName & "_BACKUP"
'1) Access ThisWorkbook directly by its CodeName (independant from regional language settings)!
Dim myComp As VBIDE.VBComponent
Set myComp = wb.VBProject.VBComponents(wb.CodeName)
'Debug.Print "** Code(Name): " & wb.CodeName & " (Local Name: " & myComp.Name & ")"
'2) Search directly for the effective start row of srchProcName (e.g. "Workbook_Open")
Dim effectiveRow As Long
With myComp.CodeModule ' the component's code module
On Error Resume Next
effectiveRow = .ProcBodyLine(srchProcName, 0) ' find effective row of search procedure
Select Case Err.Number
Case 0
Dim newContent As String
newContent = Replace(Trim(.Lines(effectiveRow, 1)), srchProcName, backupName)
.ReplaceLine effectiveRow, newContent
Debug.Print "** " & wb.Name & vbNewLine & "" _
; " Changed procedure '" & srchProcName & "' in row " & effectiveRow & _
" to " & backupName
Case 35
Debug.Print "** " & wb.Name & vbNewLine & _
" Error " & Err.Number & " " & Err.Description & vbNewLine & _
" Procedure '" & srchProcName & "' doesn't exist!" & vbNewLine & _
" (Possibly already 'backupped')": Err.Clear
Case Else
Debug.Print "** " & wb.Name & vbNewLine & _
" Error " & Err.Number & " " & Err.Description: Err.Clear
End Select
End With
End Sub
Example output in VB Editor's immeditate window
Inserting Backup ActiveWorkbook or a pre-set Backup wb in your code should suffice to rename existing "Workbook_Open" procedures by a "_BACKUP" suffix.
** ExampleWorkbook147.xlsm
Changed procedure 'Workbook_Open' in row 8 to Workbook_Open_BACKUP
In reply of #T.M comment and nice answer:
The next solution uses Find, which besides returning True when the searched string has been found, it modifies the StartLine parameter, if used as a variable. Then, since the question also involves commenting all the procedure lines, not only changing the declaration line, it will do it, without iteration, too:
Sub findProcThisWb(Optional wb As Workbook, Optional strLine As String = "Workbook_Open")
Dim thisWBCodeM As CodeModule, foundLine As Long, ProcExists As Boolean, arrPr
Dim procName As String, strCodeLine As String, strProcedure As String, strComProc As String
If wb Is Nothing Then Set wb = ThisWorkbook
Set thisWBCodeM = wb.VBProject.VBComponents(wb.CodeName).CodeModule
foundLine = 1 'initialize the line where from Find starts searching
Dim noLines As Long 'it will keep the found procedure number of lines
With thisWBCodeM
' ProcExists = .Find(strLine, foundLine, .CountOfLines, 1, -1, False, False) ' OP
ProcExists = .Find(strLine, foundLine, 1, .CountOfLines, -1, False, False) ' << Edit/2022-01-24 corr. argument order
Debug.Print foundLine: ' the line of the found procedure, if it has been found!
If ProcExists Then
strCodeLine = .lines(foundLine, 1) 'return the whole line
Debug.Print strCodeLine 'the whole line where the searched string has been found
procName = .ProcOfLine(foundLine, vbext_pk_Proc): Debug.Print "Proc name = " & procName
noLines = .ProcCountLines(procName, vbext_pk_Proc): Debug.Print "Number of procedure lines = " & noLines
strProcedure = .lines(foundLine, noLines): Debug.Print "The whole procedure:" & vbLf & strProcedure
arrPr = Split(strProcedure, vbLf)
strComProc = "'" & Join(arrPr, vbLf & "'"): Debug.Print "The whole commented procedure:" & vbLf; strComProc
'Delete the actual procedure lines:
.DeleteLines foundLine, noLines - 1 ' Edit 2022-01-24: -1
'Add the commented procedure code (from string, but not in the same place, after the declaration lines):
.AddFromString strComProc
End If
End With
End Sub

Create a VBA version of dictionaries with 2 values per key

I am trying to make my excel macro dynamic. The excel macro essentially looks at only 2 columns, one which contains the name and the other contains the numeric part. I have my macro working perfectly, the only problem is that it is hard coded when I created the program. In my code, I hard coded the name in column 2 and the numeric part in column 3. However, that is not the case in real life. The name and numeric data could appear in column 1 and 5, for example. I've been manually rearranging the data in the columns so that it fits into what hard coded. However, I want to make this process dynamic and less manual work for the user.
There are 5 different versions of spreadsheets this macro will be used on and in each spreadsheet, the name and number columns are different. I am looking to make a user form box of some sort, where the user selects "Vendor XYZ" and since Vendor XYZ always sends their data sheets the same way I know that Vendor XYZ's name column is 2 and number is 4. So I was thinking that the dictionary would be something in the form of {Vendor XYZ: 2,4} (where the first number is the name column and the second number is the numeric columnnumber...I know the syntax is wrong)
I think my work around this would be to hard code the different vendors and then use if statements ( I haven't tried it yet)
I will have a user input/dropdown box of 5 different vendors. Then something like
If userinput="A"
then namecol=2 and numcol=1
If userinput="B"
then namecol="3" and numcol="4"
I don't know if that would even work. The problem with that is that the number of vendors is small now, but will be scaling up and I can't do that if we have 100 or 1000 vendors.
Any ideas?
Depending on how your initial dataset is retrieved, you can use something like this:
Public Function GetHeaderIndices(ByVal InputData As Variant) As Scripting.Dictionary
If IsEmpty(InputData) Then Exit Function
Dim HeaderIndices As Scripting.Dictionary
Set HeaderIndices = New Scripting.Dictionary
HeaderIndices.CompareMode = TextCompare
Dim i As Long
For i = LBound(InputData, 2) To UBound(InputData, 2)
If Not HeaderIndices.Exists(Trim(InputData(LBound(InputData, 1), i))) Then _
HeaderIndices.Add Trim(InputData(LBound(InputData, 1), i)), i
Next
Set GetHeaderIndices = HeaderIndices
End Function
This Function takes an array as an input and gives the user a dictionary with the indices of the headers from the input.
If you are smart (and I say this because too many users just don't use tables) you will have your data in a table, and you will have named that table. If you did, you could do something like this:
Sub DoSomething()
Dim MyData as Variant
MyData = ThisWorkbook.Worksheets("MyDataSheet").ListObjects("MyTableName").Range.Value
End Sub
So, if you data looked like this:
Foo Baz Bar
1 Car Apple
3 Van Orange
2 Truck Banana
The function would give you a dictionary like:
Keys Items
Foo 1
Baz 2
Bar 3
Then your subroutines could do something like this:
Sub DoEverything()
Dim MyData as Variant
MyData = ThisWorkbook.Worksheets("MyDataSheet").ListObjects("MyTableName").Range.Value
DoSomething(MyData)
End Sub
Sub DoSomething(ByRef MyData as Variant)
Dim HeaderIndices as Scripting.Dictionary
Set HeaderIndices = GetHeaderIndices(MyData)
Dim i as Long
' Loop through all the rows after the header row.
For i = LBound(MyData, 1) + 1 to Ubound(MyData, 1)
If MyData(i, HeaderIndices("Baz")) = "Truck" Then
?MyData(i, HeaderIndices("Foo"))
?MyData(i, HeaderIndices("Baz"))
?MyData(i, HeaderIndices("Bar"))
End If
Next
End Sub
This does require a reference to Scripting.Runtime so if you don't want to add a reference you will need to change any reference to As Scripting.Dictionary to As Object and any New Scripting.Dictionary to CreateObject("Scripting.Dictionary").
Alternatively, I use the following code module to take care of adding references programmatically for all my users:
Public Sub PrepareReferences()
If CheckForAccess Then
RemoveBrokenReferences
AddReferencebyGUID "{420B2830-E718-11CF-893D-00A0C9054228}"
End If
End Sub
Public Sub AddReferencebyGUID(ByVal ReferenceGUID As String)
Dim Reference As Variant
Dim i As Long
' Set to continue in case of error
On Error Resume Next
' Add the reference
ThisWorkbook.VBProject.References.AddFromGuid _
GUID:=ReferenceGUID, Major:=1, Minor:=0
' If an error was encountered, inform the user
Select Case Err.Number
Case 32813
' Reference already in use. No action necessary
Case vbNullString
' Reference added without issue
Case Else
' An unknown error was encountered, so alert the user
MsgBox "A problem was encountered trying to" & vbNewLine _
& "add or remove a reference in this file" & vbNewLine & "Please check the " _
& "references in your VBA project!", vbCritical + vbOKOnly, "Error!"
End Select
On Error GoTo 0
End Sub
Private Sub RemoveBrokenReferences()
' Reference is a Variant here since it requires an external reference.
' It isnt possible to ensure that the external reference is checked when this process runs.
Dim Reference As Variant
Dim i As Long
For i = ThisWorkbook.VBProject.References.Count To 1 Step -1
Set Reference = ThisWorkbook.VBProject.References.Item(i)
If Reference.IsBroken Then
ThisWorkbook.VBProject.References.Remove Reference
End If
Next i
End Sub
Public Function CheckForAccess() As Boolean
' Checks to ensure access to the Object Model is set
Dim VBP As Variant
If Val(Application.Version) >= 10 Then
On Error Resume Next
Set VBP = ThisWorkbook.VBProject
If Err.Number <> 0 Then
MsgBox "Please pay attention to this message." _
& vbCrLf & vbCrLf & "Your security settings do not allow this procedure to run." _
& vbCrLf & vbCrLf & "To change your security setting:" _
& vbCrLf & vbCrLf & " 1. Select File - Options - Trust Center - Trust Center Settings - Macro Settings." & vbCrLf _
& " 2. Place a checkmark next to 'Trust access to the VBA project object model.'" _
& vbCrLf & "Once you have completed this process, please save and reopen the workbook." _
& vbCrLf & "Please reach out for assistance with this process.", _
vbCritical
CheckForAccess = False
Err.Clear
Exit Function
End If
End If
CheckForAccess = True
End Function
And I have the following command in each Workbook_Open event (less than ideal, but only good solution I have so far)
Private Sub Workbook_Open()
PrepareReferences
End Sub

VBA macro which writes a new macro from string on the fly

Is it possible to create Excel VBA macro from a string variable?
Suppose we have FirstMacro:
Sub FirstMacro()
Dim MyString
MyString = "Sub SecondMacro()" & Chr(13) & Chr(10) & "MsgBox " & Chr(34) & "Hello" & Chr(34) & Chr(13) & Chr(10) & "End Sub"
Debug.Print MyString
'Here be code that magicly creates SecondMacro
End Sub
Running the macro, I want to create SecondMacro which is stored in VBA string variable. The second macro can be created either below in the same module or in a new module.
So the second macro from string looks like this:
Sub SecondMacro()
MsgBox "Hello"
End Sub
Sure is possible. It should be noted that you can't add/delete from the module you're running code in.
This will append the code at the end of the module. If you can avoid this though you should, I only use it for adding code to buttons that I've added programatically.
With Workbooks(ThisWorkbook.Name).VBProject.VBComponents("MyModuleHere").CodeModule
.InsertLines .CountOfLines + 1, "Sub... End Sub"
End With
So to add to the "MyModuleHere" code module (assuming you have a module named that), drop this in:
Sub addcode()
Dim subtext As String
subtext = "Sub PrintStuff" & vbCrLf & "msgbox ""Hello World""" & vbCrLf & "End Sub"
With Workbooks(ThisWorkbook.Name).VBProject.VBComponents("MyModuleHere").CodeModule
.InsertLines .CountOfLines + 1, subtext
End With
End Sub
As usual, CPearson adds some really useful insight:
http://www.cpearson.com/excel/vbe.aspx
With regard to removing code, which I think you're hinting at in your comment, I use the below function to find a sub name, and remove it (this assumes that I will know the length of the sub):
Function ClearModule(strShapeName As String)
Dim start As Long
Dim Lines As Long
Dim i As Variant, a As Variant
With Workbooks(ThisWorkbook.Name).VBProject.VBComponents("MyModuleHere").CodeModule
For i = .CountOfLines To 1 Step -1
If Left(.Lines(i, 1), 8 + Len(strShapeName)) = "Sub " & strShapeName & "_Cli" Then
.DeleteLines i, 6
End If
Next
End With
End Function
Here you have more or less all variations which, hopefully, will solve your problem. To test this code copy all of it in a normal code module (by default "Module1") Rename it as "Remin" and write "FirstMacro" in cell A1 of the worksheet you activate, a number in cell A2. Then run the first of the following procedures directly from the VBE window.
Sub SelectMacroToRun()
' 04 Apr 2017
Dim MacroName As String
Dim Arg1 As String
Dim Outcome As Long
With ActiveSheet
MacroName = .Cells(1, 1).Value
Arg1 = .Cells(2, 1).Value
End With
On Error Resume Next
Outcome = Application.Run(ActiveSheet.name & "." & MacroName, Arg1)
If Err Then
MsgBox "The macro """ & MacroName & """ wasn't found", _
vbInformation, "Error message"
Else
If Outcome <> xlNone Then MsgBox "Outcome = " & Outcome
End If
End Sub
Private Function FirstMacro(Optional ByVal Dummy As String) As Long
MsgBox "First Macro"
FirstMacro = xlNone
End Function
Private Function SecondMacro(Arg1 As Long) As Long
MsgBox "Second Macro" & vbCr & _
"Argument is " & Arg1
SecondMacro = Arg1 * 111
End Function
The code will run the FirstMacro, reading the name from the worksheet. Change that name to "SecondMacro" to call the second macro instead. The second macro requires an argument, the first only accepts it and does nothing with it. You don't need to pass any argument, but this code shows how to pass (as many as you want, comma separated) and it also shows how to ignore it - the argument is passed to a dummy variable in the FirstMacro, and the function also returns nothing.
Application.Run "Remin" & MacroName, Arg1
Would just run the macro (it could be a sub). Omit the argument if you don't want to pass an argument. "Remin" is the name of the code sheet where the called macro resides. This name could be extended to include the name of another workbook. However, if the called macro isn't in the same module as the caller it can't be Private.

How to convert string to Workbook name in VBA

Sub openwb()
Dim x260path As String
x260path = "E:\sarath\PTMetrics\20131002\D8 L538-L550 16MY\D8 L538-L550_16MY_Powertrain Metrics_" & Format(Date, "YYYYMMDD") - 1
Workbooks("x260path").Activate
ActiveWorkbook.SaveAs ["E:\sarath\PTMetrics\20131002\D8 L538-L550 16MY\D8 L538-L550_16MY_Powertrain Metrics_" & Format(Date, "YYYYMMDD")]
Debug.Print x260path
End Sub
Here, when i execute, an error says "subscript out of Range". And it appears on 4th line.when i use 'workbook' to declare 'x260path' instead of string, It shows another error saying "Object variable or with block variable not set" on line 3. Can u help?Why is this happening?
In VBA the equivalent function to =Today() is Date() (*or Date)
x260path = CONCATENATE("..." & Date)
Alternatively, use Now() function ( that includes a time stamp as well though )
x260path = CONCATENATE("..." & Now)
debug.print Date
02/10/2013
and
debug.print Now
02/10/2013 08:39:20
some of the spreadsheet functions are available to use with the WorksheetFunction class. For example
Sub Main()
Dim sum As Double
sum = WorksheetFunction.sum(10, 20)
MsgBox sum
End Sub
Note: when you type the sum = WorksheetFunction. as soon as you type in the . you should get the VBA's Intelli-sense help. It is a list of all available functions you can use with the WorksheetFunction class.
In your case the =Concatenate function is equivalent to & operator in VBA. Therefore the easiest way would be to join two string using the &
x260path = "C:\..." & date
If a function you are trying to use doesn't exist in the Intelli-sense you can create your own UDF or you can do some online research on how the function works and how to overwrite it.

Resources