Tawm
Tawm

Reputation: 545

VBA: Passing a Function as an Argument

I'm trying to pass a function (2 functions, actually) as arguments for a Sub with the line:

Call OpenPulledReports(GetFilePaths(), GetFileNames())

I'm not sure if I need the () at the end of the names, but I'm getting an Argument not optional error.


Here are those two functions:

Function GetFilePaths(ByRef GetDateItems) As String

Dim fp As String

Dim cy2c As String
cy2c = GetDateItems(currentYear2char)

fp.PartMasterFilePath = "path1" & cy2c & "\" & currentMonth & "\"
fp.SupplierMasterFilePath = "path 2" & cy2c & "\" & currentMonth & "\"

GetFilePaths = fp

End Function

Function GetFileNames(ByRef GetDateItems) As String

Dim f As String
Dim cd As String

cd = GetDateItems.currentDate

f.FargoPlant = "part master for SM - blah1 - " & cd & ".xls"
f.Logistics = "part master for SM - blah2 - " & cd & ".xls"
f.PES = "part master for SM - blah3 - " & cd & ".xls"
f.Torreon = "part master for SM - blah4 - " & cd & ".xls"
f.FargoSM = "Supplier Master - blah5 - " & cd & ".xls"
f.TorreonSM = "Supplier Master - blah6 - " & cd & ".xls"

GetFileNames = f

End Function

And I suppose I'll include GetDateItems() since it's referenced by both of those functions:

Function GetDateItems() As String

Dim d As String

d.currentMonth = Format(Date, "mmmm") 'July
d.currentDate = Format(Date, "mm-dd-yy") '06-09-15
d.currentYear2char = Format(Date, "yy") '15
d.currentYear4char = Format(Date, "yyyy") '2015
d.currentFiscalMonth = Format(DateAdd("m", 1, Date), "mm") '08
d.wsDate = currentFiscalMonth & currentYear4char '082015

GetDateItems = d

End Function

I was originally just using ByRef to every DateItem, FilePath, and FileName item but decided to put them into their own functions to clean my code up.

Thank you very much for your time.

EDIT:

@Brad I'm trying to use an Object now instead of a String.

I'm now getting an "Object variable or With block variable not set" Run-time error on the line d.currentMonth = ...

Function GetDateItems() As String

Dim d As Object

d.currentMonth = Format(Date, "mmmm") 'July
d.currentDate = Format(Date, "mm-dd-yy") '06-09-15
d.currentYear2char = Format(Date, "yy") '15
d.currentYear4char = Format(Date, "yyyy") '2015
d.currentFiscalMonth = Format(DateAdd("m", 1, Date), "mm") '08
d.wsDate = currentFiscalMonth & currentYear4char '082015

GetDateItems = d

End Function

Based on this: http://www.cpearson.com/excel/Classes.aspx , I feel like I'm doing it wrong, but I'm not sure how to do it correctly.

Upvotes: 3

Views: 12227

Answers (3)

PYC
PYC

Reputation: 21

THERE ARE 2 WAYS TO CALL DYNAMICALLY A FUNCTION IN VBA

Here a complete example that you can try


I would like to call dynamically one or another function in my procedure depending on some situations ...

To simulate it, here 2 different functions which I will decide at last minute (so at runtime) which to call

Common code to both examples

        Function My_Function_number_1(varTheData As String) As String
            Debug.Print "Calling  My function n°1 with parameter  = (" & varTheData & ")"
            My_Function_number_1 = "I return value = 1"
        End Function

        Function My_Function_number_2(varTheData As String) As String
            Debug.Print "Calling  My function n°2 (" & varTheData & ")"
            My_Function_number_2 = "I return value = 2"
        End Function
        
There are 2 way to do it .. 

FIRST MANNER : CALLING DIRECTLY THE FUNCTION WITH THERE PARAMETERS

        Sub Another_Sub_in_which_I_will_pass_the_return_of_the_function_called(ByRef xfunc As Variant)
            Dim RetFromFunction As Variant
            Debug.Print "Another_Sub_in_which_I_will_pass_the_return_of_the_function_called get this datas -> [" & xfunc & "]"
            RetFromFunction = xfunc
            Debug.Print "La fonction appelee dynamiquement a renvoyé ceci : " & RetFromFunction
        End Sub

        Sub My_program_I()
           Dim SomeData As String
           SomeData = "this is the data I want to work in my functions"
           Debug.Print "My_program_I"
           Debug.Print ""
           Debug.Print "Call n°1 -------------------------------------------------------------"
           Call Another_Sub_in_which_I_will_pass_the_return_of_the_function_called(My_Function_number_1(SomeData))
           Debug.Print ""
           Debug.Print "Call n°2 -------------------------------------------------------------"
           Call Another_Sub_in_which_I_will_pass_the_return_of_the_function_called(My_Function_number_2(SomeData))
           Debug.Print ""
        End Sub

Result in debug window

My_program_I
Call n°1 -------------------------------------------------------------
Calling  My function n°1 with parameter  = (this is the data I want to work in my functions)
Another_Sub_in_which_I_will_pass_the_return_of_the_function_called get this datas -> [I return value = 1]
La fonction appelee dynamiquement a renvoyé ceci : I return value = 1
Call n°2 -------------------------------------------------------------
Calling  My function n°2 (this is the data I want to work in my functions)
Another_Sub_in_which_I_will_pass_the_return_of_the_function_called get this datas -> [I return value = 2]
La fonction appelee dynamiquement a renvoyé ceci : I return value = 2

SECOND MANNER : CALLING INDIRECTLY THE FUNCTION INSIDE THE OTHER SUB WHICH WILL TAKE IN CHARGE TO PASS SOME PARAMETERS

        Sub Another_Sub_in_Which_I_just_pass_the_function_to_call_and_which_will_take_care_to_call_it_with_some_parameters(varNameofFunction2Execute As String)
            Dim SomeData As Variant
            SomeData = "some datas to pass to the function"
            Debug.Print ("I will call the function : " & varNameofFunction2Execute & " with the paramters (" & SomeData & ")")
            result = Application.Run(varNameofFunction2Execute, SomeData)
            Debug.Print ("this is the retust I obtained = [" & result & "]")
        End Sub

        Sub My_program_II()
            Debug.Print "My_program_II"
            Debug.Print ""
            Debug.Print "Call n°1 -------------------------------------------------------------"
            Call Another_Sub_in_Which_I_just_pass_the_function_to_call_and_which_will_take_care_to_call_it_with_some_parameters("My_Function_number_1")
            Debug.Print ""
            Debug.Print "Call n°1 -------------------------------------------------------------"
            Call Another_Sub_in_Which_I_just_pass_the_function_to_call_and_which_will_take_care_to_call_it_with_some_parameters("My_Function_number_2")
            Debug.Print ""
        End Sub

Result in debug window

My_program_II
Call n°1 -------------------------------------------------------------
I will call the function : My_Function_number_1 with the paramters (some datas to pass to the function)
Calling  My function n°1 with parameter  = (some datas to pass to the function)
this is the retust I obtained = [I return value = 1]
Call n°1 -------------------------------------------------------------
I will call the function : My_Function_number_2 with the paramters (some datas to pass to the function)
Calling  My function n°2 (some datas to pass to the function)
this is the retust I obtained = [I return value = 2]

Upvotes: 1

Richard Braxton
Richard Braxton

Reputation: 165

I am not certain this is a good way to code but if you want to pass values in this manner then you should be using User Defined Types. Below is a module which provides functionality similar to you have described.

If you run this:

call OpenPulledReports(GetFilePaths(GetDateItems()), GetFileNames(GetDateItems()))

You will get this (in the debug window):

path 218\April\part master for SM - blah4 - 04-23-18.xls

Option Compare Database

Type TDateItems
    currentMonth As String
    currentDate As String
    currentYear2Char As String
    currentYear4Char As String
    currentFiscalMonth As String
    wsDate As String
End Type

Type TFiles
    FargoPlant As String
    Logistics As String
    PES As String
    Torreon As String
    FargoSM As String
    TorreonSM As String
End Type

Type TFilePaths
    PartMasterFilePath As String
    SupplierMasterFilePath As String
End Type

Sub OpenPulledReports(ByRef GFP As TFilePaths, ByRef GFN As TFiles)
    ' do things with strings
    Debug.Print GFP.SupplierMasterFilePath & GFN.Torreon
End Function

Function GetFilePaths(ByRef GDI As TDateItems) As TFilePaths
    Dim fp As TFilePaths
    Dim cy2c As String
    cy2c = GDI.currentYear2Char
    fp.PartMasterFilePath = "path1" & cy2c & "\" & GDI.currentMonth & "\"
    fp.SupplierMasterFilePath = "path 2" & cy2c & "\" & GDI.currentMonth & "\"
    GetFilePaths = fp
End Function

Function GetFileNames(ByRef GDI As TDateItems) As TFiles
    Dim f As TFiles
    Dim cd As String
    cd = GDI.currentDate
    f.FargoPlant = "part master for SM - blah1 - " & cd & ".xls"
    f.Logistics = "part master for SM - blah2 - " & cd & ".xls"
    f.PES = "part master for SM - blah3 - " & cd & ".xls"
    f.Torreon = "part master for SM - blah4 - " & cd & ".xls"
    f.FargoSM = "Supplier Master - blah5 - " & cd & ".xls"
    f.TorreonSM = "Supplier Master - blah6 - " & cd & ".xls"
    GetFileNames = f
End Function

Function GetDateItems() As TDateItems
    Dim d As TDateItems
    d.currentMonth = Format(Date, "mmmm") 'July
    d.currentDate = Format(Date, "mm-dd-yy") '06-09-15
    d.currentYear2Char = Format(Date, "yy") '15
    d.currentYear4Char = Format(Date, "yyyy") '2015
    d.currentFiscalMonth = Format(DateAdd("m", 1, Date), "mm") '08
    d.wsDate = currentFiscalMonth & currentYear4Char '082015
    GetDateItems = d
End Function

Upvotes: 1

mumfy
mumfy

Reputation: 154

You can't actually pass functions in VBA unfortunately and OpenPulledReports() thinks it is getting passed 2 values.
So you calling OpenPulledReports(GetFilePaths(), GetFileNames()) thinks it is getting the output from the GetFilePaths() and GetFileNames() which are then getting errors since you are not passing them the proper inputs.

Upvotes: 0

Related Questions