Hey Govert,
Many thanks for pointing me in the right direction. Through bits of research, trial and error, your recommendation of stuffing stuff into a static cache of some sort is going to be the way forward for me.
My concern about the order of initialisation was unfounded, having
read that the UDF wrapper is always called for a cell containing an RTD function, and my experiments have shown that it has a reliable lifecycle on saving/loading a spreadsheet & cell content clearing. So I shall construct my static cache in the UDF function for later access in the RTD server implementation. I did note that in order to get the RTD server to produce a reliable value into a cell, I could not mark the UDF wrapper as IsThreadSafe=true. I was also hoping to avoid the IsMacroType=true and IsVolatile=true for performance reasons.
I also ran into a small problem where a UDF function executing GetValue() on an ExcelReference argument containing another UDF was throwing an xlReturnUncalced, because the first UDF was being called before it's dependent reference had been called to calculate (verified using some breakpoints). I believe this is
due to the issue you describe of a UDF having to be executed in order to "discover hidden dependencies". I followed
your advice you also gave for that issue and ran a XlCall.TryExcel to see whether such a call would be successful, and if not, I terminate the UDF early using a handled exception (into a global exception handler). The UDF actually then executes again in the expected order after the dependent UDF has calculated and GetValue() succeeds on the second pass through, very strange, but it works! This was important because although the functions worked fine with IsMacroType=true or IsThreadSafe=false, I actually need them to be IsMacroType=false and IsThreadSafe=true ... I hope I don't head crashing into another unexpected behaviour, but I believe I've connected enough dots together now to get around these issues!
Many thanks
Tom