ExcelAsyncUtil Rx Issue

Jul 30, 2014 at 4:40 PM
Edited Jul 30, 2014 at 4:51 PM
hi, when I try the following in an [ExcelFunction] I receive an error:
return RxExcel.Observe("ReturnPrice", null,
                        () => Observable.Timer(TimeSpan.FromSeconds(1)));
Error message: "ExcelAsyncUtil has not been initialized. This is an unexpected error."

Even when I call the Initialize method (which is deprecated) I receive the same message. Checking the source code it looks as though SynchronizationManager.IsInstalled is false although beyond that i'm not sure. Can someone advise the best way to hook into an observable stream and display the data in Excel?

Also using version 0.32.5236.31783 of Excel DNA and Rx v1.0.10621 for 4.0.

Many thanks
Coordinator
Jul 30, 2014 at 7:57 PM
Hi Philip,

My first guess is that you are using mismatched versions of ExcelDna.Integration and ExcelDna.xll. Is it possible that you updated the reference to ExcelDna.Integration, but still have the old .xll version being copied to your output directory?

If it's not that, write back and I'll have a closer look.

-Govert
Jul 31, 2014 at 8:38 AM
Thanks for the reply Govert. Im using the latest package with the stock ExcelDna.xll on a Windows 7 64 bit machine using Excel 2007 in 32 bit, maybe this is the issue? At the top of my DNA file I have:
<DnaLibrary RuntimeVersion="v4.0" Language="VB" Name="ExcelDna.RTD">
And then call a dll which is compiled in 32bit.
Jul 31, 2014 at 1:49 PM
FYI I also get the same on another PC using with the same setup with a fresh version on Excel DNA and Rx and receive the same error. Right now i'm only trying to make Observable.Timer() work.
Coordinator
Jul 31, 2014 at 3:38 PM
Hi Philip,

It worked fine in my tests, so I'll put together an example for you to check, and post back here.

-Govert
Coordinator
Jul 31, 2014 at 10:40 PM
Hi Philip,

Could you try the following steps:
  • Create a new C# Class Library project.
  • Open the NuGet Package Manager Console.
  • Enter: Install-Package Excel-DNA
  • Enter: Install-Package Rx-Main
  • Add a new file (maybe called ObservableRtdUtil.cs) to the project, with the following code:
using System;

namespace ExcelDna.Integration
{
    public static class ObservableRtdUtil
    {
        public static object Observe<T>(string callerFunctionName, object callerParameters, Func<IObservable<T>> observableSource)
        {
            return ExcelAsyncUtil.Observe(callerFunctionName, callerParameters, () => new ExcelObservable<T>(observableSource()));
        }

        // An IExcelObservable that wraps an IObservable
        class ExcelObservable<T> : IExcelObservable
        {
            readonly IObservable<T> _observable;

            public ExcelObservable(IObservable<T> observable)
            {
                _observable = observable;
            }

            public IDisposable Subscribe(IExcelObserver excelObserver)
            {
                var observer = new AnonymousObserver<T>(value => excelObserver.OnNext(value), excelObserver.OnError, excelObserver.OnCompleted);
                return _observable.Subscribe(observer);
            }
        }

        // An IObserver that forwards the inputs to given methods.
        class AnonymousObserver<T> : IObserver<T>
        {
            readonly Action<T> _onNext;
            readonly Action<Exception> _onError;
            readonly Action _onCompleted;

            public AnonymousObserver(Action<T> onNext, Action<Exception> onError, Action onCompleted)
            {
                if (onNext == null)
                {
                    throw new ArgumentNullException("onNext");
                }
                if (onError == null)
                {
                    throw new ArgumentNullException("onError");
                }
                if (onCompleted == null)
                {
                    throw new ArgumentNullException("onCompleted");
                }
                _onNext = onNext;
                _onError = onError;
                _onCompleted = onCompleted;
            }

            public void OnNext(T value)
            {
                _onNext(value);
            }

            public void OnError(Exception error)
            {
                _onError(error);
            }

            public void OnCompleted()
            {
                _onCompleted();
            }
        }
    }
}
  • Replace the code in Class1.cs with:
using System;
using System.Reactive.Linq;
using ExcelDna.Integration;

public class TestFunctions
{
    public static object ReturnPrice()
    {
        return ObservableRtdUtil.Observe("ReturnPrice", null,
                    () => Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)));
    }
}
  • Press F5 to build and load in Excel.
  • Enter =ReturnPrice() into the sheet.
This works on my machine.

-Govert
Aug 1, 2014 at 8:23 AM
many thanks Govert, problem solved. It was due to the Rx version I was using... interestingly I have a folder called C:\Program Files (x86)\Microsoft Reactive Extensions SDK\v1.0.10621\ and for the above to work need to be using v2 dll's which are in C:\Program Files (x86)\Microsoft SDKs\Reactive Extensions\v2.0.
Aug 1, 2014 at 1:26 PM
Edited Aug 1, 2014 at 1:28 PM
-- removed
Aug 1, 2014 at 4:37 PM
looking further into this, setting Copy Local = true on the ExcelDna.Integration.dll should replicate my issue. Although I now know the problem and cause is this expected behavior?
Coordinator
Aug 1, 2014 at 5:36 PM
Hi Philip,

With 'Copy Local=true' you get a copy of ExcelDna.Integration.dll in the output directory. This is never required (there is already a copy of the library embedded in the ExcelDna.xll file, which is copied there and renamed).

If the version of ExcelDna.Integration.dll in the output directory does not match the version embedded in the .xll file (as you would get if you update only ExcelDna.Integration.dll and not the .xll files too) then there are problems. The Excel-DNA loading gets confused between the types, leading to a variety of problems.

I've tried in recent versions to make the problem scenario fail immediately when mismatched versions are detected, but I have not been able to detect that consistently. Dues to quirks of .NET and Excel-DNA, is really hard to ignore the file when it is present.

As you found, just making sure that ExcelDna.Integration.dll is never present in the output directory when you run the add-in avoid all such issues. The NuGet package always configures that reference to 'Copy Local = false'.

-Govert