Excel VBA Load worksheet in Function
Asked Answered
W

2

3

I am trying to write a function to find the first line of an external worksheet. I can do this with a sub, but it is not working as a function. can it be done.

Currently I am using

Function GetLine(fileName As String) As Boolean
  GetLine = 0 
  Dim loadBook As Workbook
  If loadBook = Application.Workbooks.Open(fileName) Then
    GetLine = True
  Else
    GetLine = False
  End If
end function

I am getting a return of #value. I think this is because of an error in loading the workbook.

Please advice and thank you.

Warthman answered 22/4, 2014 at 17:43 Comment(1)
So - why not use a Sub rather than complex UDF workarounds? :)Podvin
C
6

That's right, execution of user-defined functions has certain limitations. There is few tricks to do what you want within UDF and not to violate an order.

1. Get another instance of Excel.Application via late binding, open workbook with it, perform all the necessary calculations by referring to the instance. It's critical to refer exactly to the created instance, so that some nested With ... End With statements or additional syntax e. g. before .Cells(), .Sheets() may seem unusual. There is an UDF example how to obtain the first line on the sheet from the closed file:

Function GetFirstRowLbind(FileName, SheetName) ' UDF function that calculates value, works with certain limitations
    On Error Resume Next
    With CreateObject("Excel.Application") ' late binding
        .Workbooks.Open (FileName)
        GetFirstRowLbind = .Sheets(SheetName).UsedRange.Row
        .Quit
    End With
End Function

OERN used only to skip errors like missing file and others so that .Quit statement be surely executed to prevent memory leakage, otherwise launched excel processes will stay in memory after each sheet recalc and UDF call.

2. Implement some UDF extending by scheduling to another procedure the actions that should be done after the UDF completion, with execution based on the sheet recalc event. This way more complex and hard to debug, but more flexible and it gives opportunity to do much more "within" UDF, like changing neighbour cells, or even any accessible data in the whole application. Example with scheduling:

Place code to one of the module of VBAProject:

Public Tasks, Permit, Transfer

Function GetFirstRowSched(FileName, SheetName) ' UDF function, schedules filling this UDF cell with a value after all UDFs to be completed
    If IsEmpty(Tasks) Then TasksInit
    If Permit Then Tasks.Add Application.Caller, Array(FileName, SheetName) ' pack arguments to array, the dictionary key is actually this cell object
    GetFirstRowSched = Transfer
End Function

Sub TasksInit() ' function for initial setting values
    Set Tasks = CreateObject("Scripting.Dictionary")
    Transfer = ""
    Permit = True
End Sub

Function GetFirstRowConv(FileName, SheetName) ' function that actually calculates the value, runs without UDF limitations like an usual function
    With Application.Workbooks.Open(FileName)
        GetFirstRowConv = .Sheets(SheetName).UsedRange.Row
        .Close
    End With
End Function


Place code to ThisWorkbook section of Microsoft Excel Objects in VBAProject:

Private Sub Workbook_SheetCalculate(ByVal Sh As Object) ' sheets recalc event that perform all scheduled calls, puts data to each of UDFs cells
    Dim Task, TempFormula
    If IsEmpty(Tasks) Then TasksInit
    Application.EnableEvents = False
    Permit = False
    For Each Task In Tasks ' cycle trough all stored cell objects
        TempFormula = Task.FormulaR1C1
        Transfer = GetFirstRowConv(Tasks(Task)(0), Tasks(Task)(1)) ' unpack arguments from array to perform calculations
        Task.FormulaR1C1 = TempFormula
        Tasks.Remove Task
    Next
    Application.EnableEvents = True
    Transfer = ""
    Permit = True
End Sub
Carven answered 22/4, 2014 at 23:49 Comment(1)
O
0

If the UDF is being called from a cell, it can only return a value to that cell. It cannot open another workbook

Oliviaolivie answered 22/4, 2014 at 18:2 Comment(5)
I only want it to return a value to the cell. The value happens to be in a different workbook. I also have been able to make a UDF that in the function sets for example range("A1").value = 2Warthman
Please review my answer................trying to open a workbook in this kind of UDF WILL NOT WORK.Andrew
@Riggs1985, there are few methods how to bypass standard limitations within UDF :) I've posted examples.Carven
@Riggs1985, BTW if you want just to put the value from another workbook to the cell try to use conventional external linking instead of UDF, type this formula into the cell: ='C:\Test\Ref\[Source.xls]Sheet1'!R1C1Carven
@Gary'sStudent see #8521232Podvin

© 2022 - 2024 — McMap. All rights reserved.