The first change we need to make to the add-in function is to add a new argument. This will contain the sequence number discussed in Communication between worker thread and RTD. When a calculation completes, the sequence number changes and, since it is an argument to the function AvgOptValue, the function is refreshed by Excel.
Use the XLL+ Function Wizard to add a new argument to AvgOptValue:

The new argument is of type Long and is named RtdSeqNum.
The next step is to change the add-in functions body, so that calls are passed to a worker thread, instead of being immediately calculated.
The original function looked as shown below:
extern "C" __declspec( dllexport )
LPXLOPER AvgOptValue(BOOL Put, double Spot, double Vol, double
Loan, double Discount, double DivYield, long ValueDate, long
Maturity, const COper* AvgInDates, const COper* AvgOutDates,
long Iterations)
{
...
//}}XLP_SRC
// Call the library function
double dResult = 0.0;
char achErr[256];
int calc_ok = eval_avg_opt(Put ? 1 : 0, Spot, Vol, Loan, Discount, DivYield,
ValueDate, Maturity, vecAvgInDates.size(), &vecAvgInDates[0],
vecAvgOutDates.size(), &vecAvgOutDates[0], Iterations,
&dResult, achErr, sizeof(achErr));
// Put the result or an error string in xloResult
if (calc_ok)
xloResult = dResult;
else
xloResult.Format("#ERROR: %s", achErr);
return xloResult.Ret();
}
The new logic should work as follows:
This logic is implemented as shown below:
extern "C" __declspec( dllexport )
LPXLOPER AvgOptValue(BOOL Put, double Spot, double Vol, double
Loan, double Discount, double DivYield, long ValueDate, long
Maturity, const COper* AvgInDates, const COper* AvgOutDates,
long Iterations, long RtdSeqNum)
{
...
//}}XLP_SRC
AvgOptData* argsIn = new AvgOptData(
Put, Spot, Vol, Loan, Discount, DivYield,
ValueDate, Maturity, vecAvgInDates,
vecAvgOutDates, Iterations);
AvgOptData* argsOld = ::XllGetTypedApp()->m_cacheAvgOpt.Find(argsIn);
if (argsOld != 0)
{
delete argsIn;
if (argsOld->done)
xloResult = argsOld->result;
else
xloResult = "#WAIT!";
return xloResult.Ret();
}
XllGetTypedApp()->m_cacheAvgOpt.Add(argsIn);
if (!::XllGetTypedApp()->m_threadManager.StartThread(
AvgOptValue_threadfn, argsIn))
return CXlOper::RetError(xlerrNull);
xloResult = "#WAIT!";
return xloResult.Ret();
}
Note that the old call to eval_avg_opt() is replaced with a call to ThreadManager::StartThread(), passing the address of our worker thread function and the AvgOptData object that it will use.