Getting object undefined runtime error in uno service callfunction to offset function

Hi, just converting from Excel to Calc, so if this question is simple, I apologize. Also new to forum, I’m still learning how to use the forum also. But I’m stuck.

Trying to call the offset function through a uno service callfunction in a UDF, but keep getting an object undefined runtime error. Strange thing is, I have very similar code in other functions that work as expected.

Things I’ve tried:

  1. Copied and then modified working code from working routines.
  2. Turned on Option Explicit as recommended on several pages. And defined everything.
  3. Added watches on all the objects involved and added a breakpoint to the line with the error so I could check the objects were initialized.
  4. Added some simple debugging code just before the error line and verified I could access the objects. (If that messed things up, realize the line was erroring before they were added.)
  5. Have tried using set in the lines were each object is defined. No change. Also not used in the working functions.
  6. Have tried defining (dim) the objects both as objects and variants with no change to the error behavior.

Here is the code:

'*************************************************************************************************************
Function GetYearRow(Yr as double, optional sRangeName as string) as integer
dim oFuncAccess as object
dim oRanges as object
Dim oNamedRange As Object
dim oRange as variant 

oRanges = ThisComponent.NamedRanges
if ismissing(sRangeName) then sRangeName = "TaxYears"
oRange = oRanges.getByName(sRangeName).getReferredCells().getdataarray()
oFuncAccess = createUnoService("com.sun.star.sheet.FunctionAccess")
GetYearRow=oFuncAccess.CallFunction("MATCH",array(Yr,oRange,0))
'The above call works.
end function
'*************************************************************************************************************
Function GetTaxTableColumn(rw as integer, Status as string, TaxIncome as double) as integer
'=IF(F8="MFJ",MATCH(M8,OFFSET(MFJTIThresholds ,N8,0,1)),MATCH(M8,OFFSET(SingleTIThresholds,N8,0,1)))   Formula that works in calc that I'm trying to mimic here.
dim oFuncAccess as object
dim oRanges as object
dim oRange as variant
dim sRangeName as string
dim YearsTIThresholds as variant
oRanges = ThisComponent.NamedRanges
if Status="MFJ" then sRangeName="MFJTIThresholds" else sRangename="SingleTIThresholds"
oRange=oRanges.getByName(sRangeName).getReferredCells().getdataarray()
oFuncAccess = createUnoService("com.sun.star.sheet.FunctionAccess")
YearsTIThresholds=oFuncAccess.CallFunction("OFFSET",array(oRange,rw,0,1))
'The above call works.  
GetTaxTableColumn=oFuncAccess.CallFunction("MATCH",array(TaxIncome,YearsTIThresholds))
'The above call works.
end function
'*************************************************************************************************************
Option explicit
Function Taxes(TaxableIncome as Double,Status as String, Year as Integer) as Double
dim oFuncAccess as object
dim oRanges as object
dim oRange as variant
dim Yrw as variant
dim MargRate as double
dim sRangeName as string
dim TaxColumn as integer
dim test as double
YRw=GetYearRow(Year)
TaxColumn=GetTaxTableColumn(YRw, Status, TaxableIncome)
'=OFFSET(MFJMarginalRates,N8,O8-1,1,1) Formula that works in calc that I'm trying to mimic here.
oRanges = ThisComponent.NamedRanges
oRange=oRanges.getByName("MFJMarginalRates").getReferredCells().getdataarray()
oFuncAccess = createUnoService("com.sun.star.sheet.FunctionAccess")
'Next few lines are debugging code to assess which object is not defined.  Both appear to be defined.
     test=oRange(0)(0) 
     'Above is testing if oRange is initialized.  Note I'm able to access values in oRange and it appears as an object in the watch window so it appears initialized to me.
     test = oFuncAccess.CallFunction( "PI",array()) 
      'returns value of pi so looks like oFuncAccess is defined, and it appears as an object in the watch window also.
'back to code that initially had error.
'Next code line generates object not initialized runtime error.  I see only 2 objects involved, oRange and oFuncAccess, both of which seem to be initialized.
'Note the next line (and object initialization) is nearly identical in structure to code in GetTaxTableColuimn above which works.
'Have tried using set on where the two objects are defined, no change, and not required in working GetTaxTableColumn function.
'Have tried defining both objects as objects (as they are in the other function) and as variants, no change.
MargRate = oFuncAccess.CallFunction("OFFSET",array(oRange,YRw,TaxColumn-1))
'The above call generates a runtime object not defined error.
'=IF(F8="MFJ",OFFSET(MFJTIThresholds,N8,O8-1,1,1),OFFSET(SingleTIThresholds,N8,O8-1,1,1))  Formula that works in calc that I'm trying to mimic here.
if Status="MFJ" then sRangeName="MFJTIThresholds" else sRangeName="SingleTIThresholds"
oRange=oRanges.getByName(sRangeName).getReferredCells().getdataarray()
Threshold=oFuncAccess.CallFunction("OFFSET",array(oRange,YRw, TaxColumn-1,1,1))
'=IF(F8="MFJ",OFFSET(MFJTaxAtThreshold ,N8,O8-1,1,1),OFFSET(SingleTaxAtThreshold ,N8,O8-1,1,1))  Formula that works in calc that I'm trying to mimic here.
if Status="MFJ" then sRangeName="MFJTaxAtThreshold" else sRangeName="SingleTaxAtThreshold"
oRange=oRanges.getByName(sRangeName).getReferredCells().getdataarray()
Threshold=oFuncAccess.CallFunction("OFFSET",array(oRange,YRw, TaxColumn-1,1,1))
Taxes=Threshold+MargRate*(TaxableIncome-Threshold)
End Function
'*************************************************************************************************************

The line where the error occurs is:

MargRate = oFuncAccess.CallFunction("OFFSET",array(oRange,YRw,TaxColumn-1))

in the last function. Also tried it with the two optional parameters (,1,1).
To me this appears to use two objects, oFuncAccess and oRange.

Wanted to include screenshots of the watch window FYI, but can’t figure out how to. (Newbie problems)
With the function at a breakpoint at the error generating line (before the error) the watch window shows:
oFuncAccess is showing as type com.sun.star.sheet.FunctionAccess. It also contains several items whose values seem reasonable.
oRange is showing as a Object(0 to 40). Each item is a variant(0 to 6) and each item in that is a variant/double as expected.

In the code I’ve added debugging lines just before the call where I access one of the values in oRange and call another function from oFuncAccess (“PI”), which returns the expected value.
So both objects involved in the call seem initialized to me.

I’m stuck, I can’t see what I’m doing wrong or different from the working functions. Any help the forum can provide would be greatly appreciated.
Thansk

It seems as if you don’t understand how “offset” works?
The first argument of “offset” is passed to the function by Calc as a “cell object”.

Otherwise, I see your “UDFs” as nothing more than an unnecessarily complicated replica of:

=INDEX( whole_range ; MATCH( …the_row…); MATCH(…the_column…)

Some background:
I’ve been using Excel since the mid 90’s (before that it was symphony and 123). It’s true I stopped routinely using index and match when xlookup came out so I admit I’m a little rusty. If I had to do this job in Excel I’d use a combination of xlookup, filter, and let. I downloaded linux and libre office less than a week ago and am trying to learn. (I said I was a newbie.)

I also implemented this in calc with functions (several of the formulas I used are in comments in the above code. I copied the formula and then recreated the functionality in the UDF below the comment). It was relatively simple to do in calc and calculates correctly, so the general functions to use and logic are correct. But, it took 6 columns with intermediate values. For my application all these helper columns are not desirable. I know I could just hide or use group/outline to de-emphasize the helper columns, but I just don’t like that solution. In Excel I’d just use a let function to encapsulate all the helper values internally in the function, but that functionality does not appear to be available in calc. So, a UDF seems like the best solution to me. Besides I like to learn new things and this is my first attempt at a calc UDF.

So in my view this is a necessary complication of your(and my) “calc” functions approach.

On your cell object comment. First I assume you are referring to Libre Office Basic not Calc. Yes it occurred to me that the function might want an object containing cell references, not values. In fact this was the first thing I tried: ThisComponent.NamedRanges.getByName(sRangeName).getReferredCells()
as the first parameter in the call. It failed and after looking around on line that evolved into what I’m using now: ThisComponent.NamedRanges.getByName(sRangeName).getReferredCells().getdataarray() which seems to work in the first two functions.

If this is the problem, then why does:

dim oFuncAccess as object
dim oRange as variant
...
oRange=ThisComponent.NamedRanges.getByName(sRangeName).getReferredCells().getdataarray()
oFuncAccess = createUnoService("com.sun.star.sheet.FunctionAccess")
YearsTIThresholds=oFuncAccess.CallFunction("OFFSET",array(oRange,rw,0,1))

work in the second function, while:

dim oFuncAccess as object
dim oRange as variant
...
oRanges = ThisComponent.NamedRanges
oRange=ThisComponent.NamedRanges.getByName("MFJMarginalRates").getReferredCells().getdataarray()
oFuncAccess = createUnoService("com.sun.star.sheet.FunctionAccess")
MargRate = oFuncAccess.CallFunction("OFFSET",array(oRange,YRw,TaxColumn-1))

generates the object undefined error?

If the problem is that offset wants addresses in the first parameter, it seems like both functions would have the error. (as they both are initialized with the .getdataarray()) But I did try it without the .getdataarray() initially and this generated errors also (in both functions). These errors went away in the function that is working after .getdataarray() was added, but remain in the last function.

at least since LO-version 25.2 any of them is available!

Interesting, I downloaded Libre Office late last week using software manager and it was 24.2.7.2. And that’s still what is showing in software manager under system package, but 25.2.4.3 is showing up under flatpack in software manager. Will install new version and try again. Thanks for the tip.

Still would like to know why the udf generated errors though.

Welcome @chippedlens !

One of many possible reasons is a bug in the code, another possible reason is a bug in the data… And there are also errors in the user profile, illogical settings of system parameters and many other different reasons. It is difficult to answer your question unambiguously - you know much more about your project than we do - you see both a spreadsheet with data and the full code, and we see only code fragments and do not even guess what data it should work with. You will get a comprehensive answer or useful tips much faster if you give us more complete information.

1 Like

I totally agree this is probably an bug in the code, I just can’t seem to find it. Note, that although I did put code fragments in the responses, the original question contained the entire code as I realize if it is a bug the entire code may be required to find it.

As for problems with the data: The error is an object undefined error and there are only two objects used in the line that generates the error.

  1. oFuncAccess - object referring to a Uno function access. As the calls that define the object are identical, and one works while the other generates the error, I doubt this is the object with the issue. In any case the watch window shows apparently valid data for the object in both functions (working and not working).

  2. oRange - As this object refers to the data in my spreadsheet I suspect it is the problem object (many more places to make a mistake). But when I add oRange to the watch window the data looks correct in both cases ( function that works GetTaxTableColumn) and the one that generates the error (Taxes function). In both cases the watch window shows oRange as object(0 to 40) which contains variants(0 to 6) which contain the expected numerical values as variant/double.

So all the objects look good to me. Is it possible the root cause here is not an undefined object but something else that is just generating that error by mistake?

I understand the request for more complete information. So here is some.
For the function that works(GetTaxTableColumn), oRange is defined by (Here I’m calling with Status=“MFJ”):

oRanges = ThisComponent.NamedRanges
if Status=“MFJ” then sRangeName=“MFJTIThresholds” else sRangename=“SingleTIThresholds”
oRange=oRanges.getByName(sRangeName).getReferredCells().getdataarray()

The name MFJTIThresholds refers to $‘Tax laws’.$R$4:$X$44 and oRange in the watch window contains the correct data.

For the function that does not work (Taxes) oRange is defined by:
oRanges = ThisComponent.NamedRanges
oRange=oRanges.getByName(“MFJMarginalRates”).getReferredCells().getdataarray()

The name MFJMarginalRates refers to $‘Tax laws’.$K$4:$Q$44 and oRange in the watch window contains the correct data.

I suppose I could try and figure out how to upload the spreadsheet, but it would require stripping a lot of personal data out and I think I’ve given enough data here so the spreadsheet is not needed.

On the user profile/system parameters settings, two points.
First, I don’t see how an issue here could impact only one of the two functions in the same module. One exception to this is that the failing function is defined with option explicit while the working function is not (although I’m not sure the scope of this setting). Option explicit was suggested online to try and track down this error, so I tried it. The error predates the option, but I’ve changed so many things trying to fix this it’s probably worth removing the option to see if it changes anything. Hopefully it prevented any typos in variable names.

Second, Yikes! I’m new to Linux and Libre Office and this basic implementation. But, having some random system or user profile setting change the programming language behavior at the object level does not seem ideal. If, for example I install software that changes some system parameter, all my code breaks. Not ideal. Can you give examples of what types of settings might impact basic code and why one would want that flexibility?

Have implemented the calculations in a big LET function to eliminate the helper columns and it is working correctly. So, thanks for the tip on the new (25.2.4.3) version of office.

May be, may be… I expected approximately this reaction from you.
To be honest, I immediately saw the mistake, it’s simple, @karolus was trying to tell you about it.

I asked for a sample of the data because I was interested in this point:

I just don’t understand how this could work, I was hoping it was some unexpected effect related to defining a named range and the data in it. What can I do, I still believe in miracles.

As for possible sources of errors - don’t worry: here, on this resource, completely incomprehensible problems have been described more than once, which after careful study turned out to be, for example, a buggy clipboard manager or the absence of a printer driver (what I called system settings in my comment), or a long-known error recorded in Bugzilla. So I simply stated in general, without reference to your specific problem - errors can be different.

Thanks for the reply.

I originally used just getreferredcells, but was getting errors. Saw an example with getdataarray online and tried that and it just worked (well 2/3 of the time). But I agree it probably shouldn’t. The input to the first two functions (that work) is also an object(0 to 40) of variant(0 to 6) of variant/double. So it is in fact operating on an (object) array of data, not the reference. I think there are easier ways to do this without offset. In fact I ended up just writing a large let function that encapsulated all the intermediate values and did the did the whole calculation in a single cell.

=LET(comment0, “Calculates taxes owed from taxableincome, filing status, and year.”,
comment1, “Inputs first.”,
TaxableIncome,M8,
Status,F8,
Year,B8,
comment2, “Now do the preliminary calculations.”,
YearRow,MATCH(Year,TaxYears,0),
TIColumn,IF(Status=“MFJ”,MATCH(TaxableIncome,OFFSET(MFJTIThresholds ,YearRow,0,1)),MATCH(TaxableIncome,OFFSET(SingleTIThresholds,YearRow,0,1))),
MargRate,OFFSET(MFJMarginalRates,YearRow,TIColumn-1,1,1),
Threshold,IF(Status=“MFJ”,OFFSET(MFJTIThresholds,YearRow,TIColumn-1,1,1),OFFSET(SingleTIThresholds,YearRow,TIColumn-1,1,1)),
TaxAtThreshold, IF(Status=“MFJ”,OFFSET(MFJTaxAtThreshold ,YearRow,TIColumn-1,1,1),OFFSET(SingleTaxAtThreshold ,YearRow,TIColumn-1,1,1)),
comment3, “Finally calculate taxes owed.”,
TaxAtThreshold+(TaxableIncome-Threshold)*MargRate)

About sharing the sheet, the sheet contains much personal financial information that I don’t want to have online. (Names, ages, income, pensions, social security, etc.) Thought about deleting that and sharing, but I’m new enough at this that I don’t trust that when I delete something it is not recoverable. Not that I don’t trust you, I just don’t trust everyone that might get access online.