ExcelAsyncFunc registration error

582 views
Skip to first unread message

ateene

unread,
Jan 29, 2018, 1:36:05 PM1/29/18
to Excel-DNA
I'm trying to understand the options for using  .NET 4.5 async functions.


        // .NET 4.5 function with async/await
        // Change the Example project's target runtime and uncomment
        [ExcelAsyncFunction]
        public static async Task<string> dnaDelayedTaskHello(string name, int msDelay)
        {
            await Task.Delay(msDelay);
            return "Hello " + name;
        }

I'm getting the following registration error

Registration [Error] Method not registered due to unsupported signature: 'Func`3.Invoke' : DnaMarshalException - Unknown Data Type: System.Threading.Tasks.Task`1[System.String]

What am I missing?

Govert van Drimmelen

unread,
Jan 29, 2018, 2:43:39 PM1/29/18
to exce...@googlegroups.com
I think you need to check that ExplicitRegistration='true' is set in your .dna file, as in the sample.

-Govert
--
You received this message because you are subscribed to the Google Groups "Excel-DNA" group.
To unsubscribe from this group and stop receiving emails from it, send an email to exceldna+u...@googlegroups.com.
To post to this group, send email to exce...@googlegroups.com.
Visit this group at https://groups.google.com/group/exceldna.
For more options, visit https://groups.google.com/d/optout.

ateene

unread,
Jan 29, 2018, 3:00:09 PM1/29/18
to Excel-DNA
I have the ExplicitRegistration= true set. 

I'm not sure why but I had to add .ProcessAsyncRegistrations(nativeAsyncIfAvailable: false) to the ExcelRegistration.GetExcelFunctions() in AutoOpen to get it to work
                           

Govert van Drimmelen

unread,
Jan 30, 2018, 3:43:56 AM1/30/18
to exce...@googlegroups.com

Yes, that’s right.

 

Glad you got it working.

 

-Govert

--

ateene

unread,
Jan 31, 2018, 11:03:00 AM1/31/18
to Excel-DNA
I really like the Async Registration setup for using async functions, but there a few things I don't understand about the ExcelRegistration. It appears that the order of the ExcelRegistion statement needs to be different for registering RTD or Native async functions.

case #1
======
Here is my example that works for registering RTD async functions and what I think the wrapped functions look like. In this case all three async functions work as expected with the dnaDelayedTaskHello working as RTD based async function, and the postAsyncReturnConfig works for both the dnaDelayedTaskHello and dnaRtdWrapped functions, returning #GETTING_DATA while processing.

using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
using ExcelDna.Integration;
using ExcelDna.Registration;
using ExcelDna.Registration.Utils;
using ExcelDna.IntelliSense;

namespace ExcelDnaRegistration
{
    public class AddIn : IExcelAddIn
    {
        public void AutoOpen()
        {
            // Register Funtion settings
            var postAsyncReturnConfig = GetPostAsyncReturnConversionConfig();
            ExcelRegistration.GetExcelFunctions()
                .ProcessAsyncRegistrations(nativeAsyncIfAvailable: false)
                .ProcessParameterConversions(postAsyncReturnConfig)
                .RegisterFunctions();

            // Intellinse Sense
            IntelliSenseServer.Register();
        }
        
        public void AutoClose()
        {
        }
        
        static ParameterConversionConfiguration GetPostAsyncReturnConversionConfig()
        {
            // This conversion replaces the default #N/A return value of async functions with the #GETTING_DATA value.
            var rval = ExcelError.ExcelErrorGettingData;
            return new ParameterConversionConfiguration()
                .AddReturnConversion((type, customAttributes) => type != typeof(object) ? null : ((Expression<Func<object, object>>)
                                                ((object returnValue) => returnValue.Equals(ExcelError.ExcelErrorNA) ? rval : returnValue)));
        }
    }

    public class Functions
    {
        // .NET 4.5 function with async/await
        [ExcelAsyncFunction(Description = "Excel Dna Async Test")]
        public static async Task<string> dnaDelayedTaskHello(
            [ExcelArgument(Name = "name")] string name,
            [ExcelArgument(Name = "delay(ms)")] int msDelay)
        {
            await Task.Delay(msDelay);
            return $"Hello {name}";
        }

        // This is what I think the generated RTD based Task wrappers looks like.
        [ExcelFunction]
        public static object dnaRtdWrapper(string name, int msDelay)
        {
            return AsyncTaskUtil.RunTask("dnaExplicitWrap", new object[] { name, msDelay }, () => dnaDelayedTaskHello(name, msDelay));
        }

        // This is what I think the generated Native based async wrapper looks like
        [ExcelFunction]
        public static void dnaNativeWrapper(string name, int msDelay, ExcelAsyncHandle asyncHandle)
        {
            NativeAsyncTaskUtil.RunTask(() => dnaDelayedTaskHello(name, msDelay), asyncHandle);
        }
    }
}

case #2
======
When I make the following change for registering Native async functions 

ExcelRegistration.GetExcelFunctions()
                .ProcessAsyncRegistrations(nativeAsyncIfAvailable: true)
                .ProcessParameterConversions(postAsyncReturnConfig)
                .RegisterFunctions();

I get a System.ArgumentOutOfRangeException error for the ExcelRegistraion statement

case #3
======
I can fix this by changing the order of statement to the following, then all three async functions work as expected. The dnaDelayedTaskHello works as Native async function 

    ExcelRegistration.GetExcelFunctions()
                .ProcessParameterConversions(postAsyncReturnConfig)
                .ProcessAsyncRegistrations(nativeAsyncIfAvailable: true)
                .RegisterFunctions();

case #4
======
When I switch back to the nativeAsyncIfAvable back to false keeping the same order

ExcelRegistration.GetExcelFunctions()
                .ProcessParameterConversions(postAsyncReturnConfig)
                .ProcessAsyncRegistrations(nativeAsyncIfAvailable: false)
                .RegisterFunctions();

All three async function work, however the postAsyncReturnConfig does not work for the dnaDelayTaskHello function (it still returns the #N/A while processing), whereas the dnaRtdWrapper does return the #GETTIN_DATA while processing.


So It looks like I have to case #1 for registering RTD async functions and case #3 for registering Native async functions. 

Govert van Drimmelen

unread,
Feb 1, 2018, 9:56:51 AM2/1/18
to Excel-DNA
This is an interesting quirk, and I think I understand how it happens.
The native async functions in Excel are quite special - their signatures look something like this:

public void MyFunction(string param1, ExcelAsyncHandle asyncHandle) {...}

Then the 'return value' is set on the asyncHandle when the function completes.

The problem is that the return value conversion is not aware of this special signature at all, so gives an error.

Can I ask that you add your post and details as a new issue in the Registrations project: https://github.com/Excel-DNA/Registration/issues

I'm not sure how quickly I'll be able to pay attention to the problem, but that way it won't be forgotten as an issue (at least an issue with the samples).

For now as a workaround I suggest you decide on the two different registration pipelines according to your preference for native asyc or not, as you show in your post.

-Govert
Reply all
Reply to author
Forward
0 new messages