UDF gets executed twice for a single call

JenniferMurphy

Well-known Member
Joined
Jul 23, 2011
Messages
2,676
Office Version
  1. 365
Platform
  1. Windows
I am working on a UDF that may be more complicated than I can handle. (sigh)

The UDF is called just once from a single cell in the only sheet in the only open workbook. I have break point (F9) set at the top of this section of code:

Code:
  . . .
Dim iCol As Long
Dim RBestI As Variant
Dim RBestIAddr As String  

  . . .
For iCol = RngColBeg To RngColEnd
 . . .
  RBestI = pRtgsBest(1, iCol)
  RBestIAddr = pRtgsBest(1, iCol).Address
  . . .
Next i
  . . .

RngColBeg & RngColEnd are global variables (type Long) calculated by a subroutine.

pRtgsBest is a range passed to the UDF from Excel.

As I step through the code, after executing the two statements inside the loop, the watch window shows that the value of RBestI is "Empty". But the cell that it is supposed to be getting its value from, (E10), contains "900".

I get these results from the Immediate window:

Code:
?rbesti

?pRtgsBest(1, iCol)
 900 
?rbestiaddr
$E$10

How can RBestI be empty when it was just set to the value in E10 (pRtgsBest(1, iCol)) which is 900 according to the Immediate window?

So, then I press F5 to resume execution. I am immediately brought back to the same break point, but this time, RBestI contains 900.

Can anyone suggest why this UDF is getting executed twice. I've checked and it is not calling itself, as far as I can tell. And why is the value in RBestI wrong the first time and right the second?

I'd appreciate any suggestions for things to try.

I'd post the code somewhere, but it is hundreds of lines.

Thanks
 

Excel Facts

Round to nearest half hour?
Use =MROUND(A2,"0:30") to round to nearest half hour. Use =CEILING(A2,"0:30") to round to next half hour.
If I was faced with this problem i would check that the indexing into prtgsbest is correct the first time through.
check what the start index for prtgsbest so check what range that is looking at, and check what value is in Rngcolbeg.
It looks to me as thought your index is starting with the wrong value.
 
Upvote 0
If I was faced with this problem i would check that the indexing into prtgsbest is correct the first time through.
check what the start index for prtgsbest so check what range that is looking at, and check what value is in Rngcolbeg.
It looks to me as thought your index is starting with the wrong value.

OK, I'll look into the indexing. But first, why is the UDF getting executed twice? It is only called once. I've tracked the calling workbook name, worksheet name, and cell address and they are the same on both iterations.
 
Upvote 0
You have not given us very much to work on :smile:

A deliberately-created double-trigger

UDF to sum a range which fires once - message box appears once
Code:
Function MySum(aRange As Range) As Double
    MsgBox 1
    MySum = WorksheetFunction.Sum(aRange)
End Function

With a minor modification and a very simple Worksheet_Change event the message box appears twice
Code:
Function MySum(aRange As Range) As Double
    [COLOR=#ff0000]Application.Volatile[/COLOR]
    MsgBox 1
    MySum = WorksheetFunction.Sum(aRange)
End Function
[COLOR=#006400][I]and (in sheet module) .....[/I][/COLOR]
Private Sub Worksheet_Change(ByVal Target As Range)
    Application.Calculate
End Sub
Excel 2016 (Windows) 32 bit
[Table="width:, class:head"][tr=bgcolor:#E0E0F0][th] [/th][th]
A
[/th][th]
B
[/th][/tr]
[tr=bgcolor:#FFFFFF][td=bgcolor:#E0E0F0]
1
[/td][td]
1​
[/td][td][/td][/tr]

[tr=bgcolor:#FFFFFF][td=bgcolor:#E0E0F0]
2
[/td][td]
2​
[/td][td][/td][/tr]

[tr=bgcolor:#FFFFFF][td=bgcolor:#E0E0F0]
3
[/td][td]
3​
[/td][td][/td][/tr]

[tr=bgcolor:#FFFFFF][td=bgcolor:#E0E0F0]
4
[/td][td]
4​
[/td][td][/td][/tr]

[tr=bgcolor:#FFFFFF][td=bgcolor:#E0E0F0]
5
[/td][td]
5​
[/td][td][/td][/tr]

[tr=bgcolor:#FFFFFF][td=bgcolor:#E0E0F0]
6
[/td][td]
15
[/td][td] =mysum(A1:A5)[/td][/tr]
[/table]
[Table="width:, class:grid"][tr][td]Sheet: Sheet1[/td][/tr][/table]
 
Last edited:
Upvote 0
You have not given us very much to work on :smile:

Yes, I know. But as I said, the UDF is quite lengthy, so I am struggling with which parts to post.

I'm working on a response with more information, but to reply to two of you points:
  1. There are no Application.Volatile statements.
  2. There are no workbook or worksheet modules. All of the code is in a separate module in one of my add-ins.
 
Upvote 0
I thought I figured out why my UDF is getting called twice and that it might also explain why the data values are different. There is a reference that could be termed circular. I got it to fail once, but now I cannot repeat it.

Here's a sample table. The application calculates a weighted rating for various products on several features. The UDF is passed 6 ranges. In this table, the calls are in cells D12-D14. The formulas are shown in I12-I14. The ranges defined as follows: Ratings (=Test!$D12:$H12), RtgsBest (=Test!$D$7:$H$7), RtgsWrst (=Test!$D$8:$H$8), RtgTypes (=Test!$D$9:$H$9), RtgReq (=Test!$D$10:$H$10), and RtgWts (=Test!$D$11:$H$11). All but Ratings are absolute in both the rows and columns. Ratings is absolute in the columns, but the rows adjust to match the calling cell row.

[TABLE="class: grid, width: 800"]
<tbody>[TR]
[TD="align: center"]R/C
[/TD]
[TD="align: center"]C[/TD]
[TD="align: center"]D[/TD]
[TD="align: center"]E[/TD]
[TD="align: center"]F[/TD]
[TD="align: center"]G[/TD]
[TD="align: center"]H[/TD]
[TD="align: center"]I
[/TD]
[/TR]
[TR]
[TD="align: center"]3[/TD]
[TD][/TD]
[TD="align: right"]Features[/TD]
[TD="align: center"]Price[/TD]
[TD="align: center"]Wt[/TD]
[TD="align: center"]Hgt[/TD]
[TD="align: center"]End[/TD]
[TD="align: center"]Comments
[/TD]
[/TR]
[TR]
[TD="align: center"]4[/TD]
[TD][/TD]
[TD="align: right"]Max Values[/TD]
[TD]$400[/TD]
[TD="align: center"]260[/TD]
[TD="align: center"]80[/TD]
[TD]End[/TD]
[TD]E4: =MAX(OFFSET(Header E:E,1,0):OFFSET(Footer E:E,-1,0))[/TD]
[/TR]
[TR]
[TD="align: center"]5[/TD]
[TD][/TD]
[TD="align: right"]Min Values[/TD]
[TD]$236[/TD]
[TD="align: center"]110[/TD]
[TD="align: center"]59[/TD]
[TD]End[/TD]
[TD]E5: =MIN(OFFSET(Header E:E,1,0):OFFSET(Footer E:E,-1,0))[/TD]
[/TR]
[TR]
[TD="align: center"]6[/TD]
[TD][/TD]
[TD="align: right"]Ave Values[/TD]
[TD]$295[/TD]
[TD="align: center"]167[/TD]
[TD="align: center"]67[/TD]
[TD]End[/TD]
[TD]E6: =AVERAGE(OFFSET(Header E:E,1,0):OFFSET(Footer E:E,-1,0))[/TD]
[/TR]
[TR]
[TD="align: center"]7[/TD]
[TD][/TD]
[TD="align: right"]Best Values[/TD]
[TD]$200[/TD]
[TD="align: center"]100[/TD]
[TD="align: center"]80[/TD]
[TD]End[/TD]
[TD]The best (top rated) values for each feature[/TD]
[/TR]
[TR]
[TD="align: center"]8
[/TD]
[TD][/TD]
[TD="align: right"]Worst Values[/TD]
[TD]$400[/TD]
[TD="align: center"]300[/TD]
[TD="align: center"]59[/TD]
[TD]End[/TD]
[TD]The worst (bottom rated) values for each feature[/TD]
[/TR]
[TR]
[TD="align: center"]9[/TD]
[TD][/TD]
[TD="align: right"]Scale Types[/TD]
[TD]Num[/TD]
[TD="align: center"]Num[/TD]
[TD="align: center"]Num[/TD]
[TD]End[/TD]
[TD]Specifies the type of feature
[/TD]
[/TR]
[TR]
[TD="align: center"]10[/TD]
[TD][/TD]
[TD="align: right"]Opt/Req Flags[/TD]
[TD]Opt[/TD]
[TD="align: center"]Req[/TD]
[TD="align: center"]Opt[/TD]
[TD]End[/TD]
[TD]Specifies if the feature is required or optional
[/TD]
[/TR]
[TR]
[TD="align: center"]11[/TD]
[TD][/TD]
[TD="align: right"]Weights[/TD]
[TD="align: center"]6[/TD]
[TD="align: center"]2[/TD]
[TD="align: center"]8[/TD]
[TD]End[/TD]
[TD]Specifies the relative weight for each feature
[/TD]
[/TR]
[TR]
[TD="align: center"]12[/TD]
[TD]Prod 1[/TD]
[TD="align: center"]45.89[/TD]
[TD]$250[/TD]
[TD="align: center"]130[/TD]
[TD="align: center"]62[/TD]
[TD]End[/TD]
[TD]D12: =wtdrtg(Ratings,RtgsBest,RtgsWrst,RtgTypes,RtgReq,RtgWts)[/TD]
[/TR]
[TR]
[TD="align: center"]13[/TD]
[TD]Prod 2[/TD]
[TD="align: center"]42.63[/TD]
[TD]$236[/TD]
[TD="align: center"]110[/TD]
[TD="align: center"]59[/TD]
[TD]End[/TD]
[TD]D13: =wtdrtg(Ratings,RtgsBest,RtgsWrst,RtgTypes,RtgReq,RtgWts)[/TD]
[/TR]
[TR]
[TD="align: center"]14[/TD]
[TD]Prod 3[/TD]
[TD="align: center"]52.50[/TD]
[TD]$400[/TD]
[TD="align: center"]260[/TD]
[TD="align: center"]80[/TD]
[TD]End[/TD]
[TD]D14: =wtdrtg(Ratings,RtgsBest,RtgsWrst,RtgTypes,RtgReq,RtgWts)[/TD]
[/TR]
[TR]
[TD="align: center"]15
[/TD]
[TD="align: center"]Ftr[/TD]
[TD="align: center"]Ftr[/TD]
[TD="align: center"]Ftr[/TD]
[TD="align: center"]Ftr[/TD]
[TD="align: center"]Ftr[/TD]
[TD="align: center"]Ftr[/TD]
[TD][/TD]
[/TR]
</tbody>[/TABLE]

The data columns are E:G. In this example there are just 3 features to be rated, Price, Wt, & Hgt. But the ranges include columns D & H, the column just before the first data column and the one just after the last data column. This allows me to add columns without having to redefine the ranges. They dynamically redefine themselves. So the UDF has to start indexing at "2" and stop at N-1, where N is the number of columns in the extended ranges.

The table as shown above works without any problems. The UDF is not called twice from each cell and all of the values match.

The problem arises when I change the contents of any of the Best or Worst cells from a literal value to a formula. Consider E7. This is the best (highest rated) value for the Price feature. Products that cost $200 or less will get the highest rating. Products that cost $400 or more will get the lowest rating. Products that cost somewhere in between will get a prorated rating.

As long as these are literal values, everything is fine.

Now consider rows 4 & 5. Row 4, as can be seen from the formula I4-I5, is the maximum value for all of the products. Similarly, row 5 in the minimum. Header is defined as "=Test!$11:$11" and Footer as "=Test!$15:$15". These serve the same purpose of allowing me to add products without having to adjust the formulas for max, min, and average. The maximum of $250, $236, & 400 is $400 and the minimum in $236.

Now suppose I want to dynamically adjust the Best/Worst values to be the same as the Max/Min values (or the Min/Max values if lower is better than higher, as in this case with Price). If I add a new product that costs more than $400 or less than $200, I want the ranges to automatically adjust. I could replace the $200 in E7 with "=MinValue", where MinValue is defined as "=Test!$5:$5". The first time I did that, the UDF was called 4 times. I believe the first time the value the UDF saw for E7 was empty or null. The next three times, it was not. I say "I believe", because I didn't pay close attention thinking I could reproduce the condition. But now I have changed to a literal and back to an expression ad I can't get it to fail.

My theory was that since MinValue based on all of the ratings but the one associated with the calling cell was also passed as part of the Ratings range, it resulted in a circular reference. But now that is not happening.

I've had enough for tonight. I'm going to bed. I'll try again in the morning.
 
Upvote 0

Forum statistics

Threads
1,223,231
Messages
6,170,884
Members
452,364
Latest member
springate

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top