Hi Govert,
Thanks for giving me some insight. However I'm still struggling to
make it work and the error is same. My code is below:
public static class MyFunction
{
public static object ProcessAndWrite(string data)
{
Debug.WriteLine(Thread.CurrentThread.GetApartmentState());
return XlCall.Excel(XlCall.xlUDF, "MyWorkerMacro", data);
}
}
public class ToolkitTest
{
public static string _data;
public static object MyWorkerMacro(string data)
{
_data = data;
AsyncRunMacro("ProcessData");
return _data;
}
public static void ProcessData()
{
XlCall.Excel(XlCall.xlcEcho, false);
Debug.WriteLine(Thread.CurrentThread.GetApartmentState());
XL.Application app =
(XL.Application)ExcelDnaUtil.Application;
Debug.WriteLine(app.Version);
try
{
XL.Worksheet wks = app.ThisWorkbook.ActiveSheet;
if (wks != null)
{
XL.Range rng = wks.get_Range("H1");
rng.Value2 = string.Format("It worked {0}.",
_data);
}
}
catch (Exception exception)
{
Debug.WriteLine(exception.StackTrace);
}
finally
{
XlCall.Excel(XlCall.xlcEcho, true);
}
}
private static readonly TimeSpan BackoffTime =
TimeSpan.FromSeconds(1);
static void AsyncRunMacro(string macroName)
{
// Do this on a new thread....
Thread newThread = new Thread(delegate()
{
while (true)
{
try
{
RunMacro(macroName);
break;
}
catch (COMException cex)
{
if (IsRetry(cex))
{
Thread.Sleep(BackoffTime);
continue;
}
// TODO: Handle unexpected error
return;
}
catch (Exception ex)
{
// TODO: Handle unexpected error
return;
}
}
});
newThread.Start();
}
static void RunMacro(string macroName)
{
XL.Application xlApp =
(XL.Application)ExcelDnaUtil.Application;
try
{
//xlApp.GetType().InvokeMember("Run",
BindingFlags.InvokeMethod, null, xlApp, new object[] { macroName });
xlApp.Run(macroName);
}
catch (TargetInvocationException tie)
{
throw tie.InnerException;
}
finally
{
Marshal.ReleaseComObject(xlApp);
}
}
const uint RPC_E_SERVERCALL_RETRYLATER = 0x8001010A;
const uint VBA_E_IGNORE = 0x800AC472;
static bool IsRetry(COMException e)
{
uint errorCode = (uint)e.ErrorCode;
switch (errorCode)
{
case RPC_E_SERVERCALL_RETRYLATER:
case VBA_E_IGNORE:
return true;
default:
return false;
}
}
}
The call to
XL.Worksheet wks = app.ThisWorkbook.ActiveSheet;
is causing the same exception now. Also can you pls explain why we are
calling the code below:
Marshal.ReleaseComObject(xlApp);
The .xll is hosted in the Excel Application so I a bit lost as to why
we need to release/destroy the host application.
Thanks so much,
Norman
On Mar 11, 1:01 am, Govert van Drimmelen <
gov...@icon.co.za> wrote:
> Hi Norman,
>
> Setting other cells from a function breaks Excel's calculation model,
> so Excel tries really hard to prevent this.
> Scarily, yours is a common request. I'd advise against it, but you can
> do this in Excel-DNA as well as any other tool.
>
> From Excel-DNA you could hook the same event you did in VB, or you can
> start a separate thread to do the update.
> A more robust design might be something like this:
> 1. Keep a list of pending work items in a static variable.
> 2. Create a macro "MyWorkerMacro" that processes all the pending work
> items. This will run in the macro context, so will be able to change
> cells etc.
> 3. In your function, append to the work item list, and call
> AsyncRunMacro("MyWorkerMacro"), where AsyncRunMacro can look something
> like the code I paste below.
>
> The code comes from the Resize example I posted here:
http://excel-dna.net/2011/01/30/resizing-excel-udf-result-arrays/.
>
> Please report back any problems you run into.
>
> Regards,
> Govert
>
> // Most of this from the newsgroup thread:
> //
http://groups.google.com/group/exceldna/browse_thread/thread/a72c9b9f...
> > > Norman- Hide quoted text -
>
> - Show quoted text -