Integration.RegisterMethods

289 views
Skip to first unread message

Peer

unread,
Jan 27, 2009, 4:11:25 AM1/27/09
to ExcelDna
I am trying to register additional methods as UDF's via
Integration.RegisterMethods().
The idea is to generate methods at runtime and then register them for
use in Excel.

This is my method signature: "public static string MyFunc(string)" as
defined by this code:

MethodBuilder method = typeBuilder.DefineMethod(S_DYNAMIC_FUNC_1,
MethodAttributes.Public |
MethodAttributes.Static |
MethodAttributes.NewSlot,
typeof(string), new Type[] { typeof(string) });

Afterwards, I am getting the method info for my dynamically generated
method and calling Inergration.RegisterMethods()

MethodInfo methodInfo = dynaType.GetMethod(S_DYNAMIC_FUNC_1);
List<MethodInfo> methodInfos = new List<MethodInfo>();
methodInfos.Add(methodInfo);
Integration.RegisterMethods(methodInfos);

The registeration call completes without exception but the UDF is not
available in Excel. I suspect that ExcelDNA requires some other method
attribues or makes class/assembly assumptions.

Has anybody done something similar? Or have any ideas on what the
method signature needs to be

Peer

unread,
Jan 27, 2009, 4:28:04 AM1/27/09
to ExcelDna
A similar example of why I would want to use Integration.Register is
to have a "plugin" type architecture.

For example, I want to create FunctionLoader.xll which allows users to
select different plugin dll's and use them from Excel.
I don't want to slow down excel startup time, so don't want
multiple .xll files nor do I want the plugin's to be ExcelDNA aware.
They will just expose public static methods and the FunctionLoader.xll
will use ExcelDNA to make them available.

PS: This is not what I am actually trying to do. I am trying to
embedded interactive IronPython scripting into Excel via ExcelDNA
(which is brilliant).

Govert van Drimmelen

unread,
Jan 27, 2009, 6:43:30 AM1/27/09
to ExcelDna
Hi Peer,

Does the DynamicMethodSample in the distribution work OK for you?

Your signature should be fine; what is the actual name of your
function? - weird names might not be accepted by Excel. No attributes
are needed for a method to be registered.

I'd be happy to debug a small sample where something goes wrong.

-----

I am currently reworking the marshaling and extensibility in ExcelDna
- I want to make it easier to replace or wrap methods to add
functionality, and also to generate methods and export them, as you
describe. So any suggestions you have in terms of making this kind of
extensibility easier would be most welcome.

There is some existing support towards the kind of FunctionLoader you
write of in the second message:
In recent versions the add-ins are loaded in separate AppDomains. This
means that unloading an ExcelDna add-in releases all the associated
resources. Loading and unloading .xll add-ins is very light-weight,
once the CLR is started up. And when you re-open an add-in, the .dna
files is processed again and add-ins are (re)loaded accordingly.
ExcelDna is also designed to make an add-in manager quite easy to
build in, should you not want to go through the .dna file to set up
your add-ins. Also, .dna files can be chained (and ExternalLibrary can
be a .dna file). It is already so that user plug-ins need not be
ExcelDna aware.

Support for IronPython would be very exciting.

Regards,
Govert

Peer

unread,
Jan 27, 2009, 7:22:38 AM1/27/09
to ExcelDna
Hi Govert,

Thanks for the swift reply.

I will definitely have a look at the DynamicMethodSample that you
mentioned.

I am currently using version 0.16. But am very keen to move over to a
newer version that supports multiple app domains as I think that is an
excellent idea. In particular it will help improve stability of the
Excel session when someone writes ill-behaving code. Which is of
particular concern when allowing excel end-users to write IronPython
code.

Peer

unread,
Jan 27, 2009, 8:39:37 AM1/27/09
to ExcelDna
I tested the DynamicMethodSample.dna using 0.18 and it works fine.

But the .dna file exhibits the same problem as my code base.

When I register a dynamic method from AutoOpen() then it works. But if
I do it from else where (via a button etc) then the registeration
seems to fail. No exception just returns #NAME from Excel.

I have created this dna file which gives an example in action.
Although it is a little different because it is trying to create a new
function from within an existing function which is probably accounting
for the failure.


<DnaLibrary Name="ExcelDna Test Dynamic Method" Language="C#">
<!--
This example shows how to dynamically create a method and register
it.
-->

<![CDATA[
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using ExcelDna.Integration;
public class Test : IExcelAddIn
{
public void AutoOpen()
{
Create("MyMulti");
}

private static void Create(string funcName)
{
DynamicMethod dynaMethod = new DynamicMethod(funcName,
typeof(double),
new Type[] {typeof(double), typeof(double)},
typeof(Test));

ILGenerator il = dynaMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Mul);
il.Emit(OpCodes.Ret);
// Method will be completed when CreateDelegate is called during
registration.

// Registration takes a list of methods - the registration
// creates a new assembly and a type every time it is called.
List<MethodInfo> methods = new List<MethodInfo>();
methods.Add(dynaMethod);

Integration.RegisterMethods(methods);
}

public void AutoClose()
{
}

public static string CreateUDF()
{
try
{
Create("runtimeFunc");
}
catch(Exception ex)
{
return ex.ToString();
}
return "created runTimeFunc";
}
}
]]>
</DnaLibrary>

Govert van Drimmelen

unread,
Jan 28, 2009, 11:16:33 AM1/28/09
to ExcelDna
Hi Peer,

You're right - the Register call must be in a command rather than a
function, then everything seems to work OK.
I post a .dna file that you can try below.

On AppDomains and reliability:
Even though ExcelDna now loads add-ins into different AppDomains,
errors like StackOverflow and OutOfMemory will still bring down the
whole Excel process. I have not yet been able to change the CLR
setting that makes these errors take down the AppDomain only, and they
cannot be caught or handled otherwise. I have experimented with the
CLR hosting interfaces, but my call to
ICLRPolicyManager->SetActionOnFailure(FAIL_StackOverflow,
eRudeUnloadAppDomain);
always fails (asif the runtime has already started, but I don't think
it has).

To make a reliable add-in architecture for Excel that users cannot
take down with their scripts will need more work on this issue, so if
anyone is an expert on CLR hosting, or knows an expert who can help,
please let me know. In any even, the settings will have to be set by
the first add-in to load the CLR, so VSTO and the other CLR add-in
frameworks and COM shims (or Excel itself) will need to cooperate to
really get this right.

Also, I'd be interested to know whether ManagedXll is able to contain
StackOverflowExceptions.

Regards,
Govert


<DnaLibrary Name="ExcelDna Dynamic Method Test" Language="C#">
<![CDATA[
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using ExcelDna.Integration;

public class Test
{
[ExcelCommand(MenuText="Add the 'MyMultiply'
function")]
public static void AddMyMultiply()
{
DynamicMethod mult = new DynamicMethod("MyMultiply",
typeof(double),
new Type[] {typeof(double), typeof(double)},
typeof(Test));
ILGenerator il = mult.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Mul);
il.Emit(OpCodes.Ret);
// Method will be 'completed' when CreateDelegate is called during
registration.

// Registration takes a list of methods - the registration
// creates a new assembly and delegate types every time it is
called.
List<MethodInfo> methods = new List<MethodInfo>();
methods.Add(mult);

Integration.RegisterMethods(methods);
}
}
]]>
</DnaLibrary>

Peer

unread,
Jan 30, 2009, 2:20:29 AM1/30/09
to ExcelDna
Thanks Govert that solved my problem with Intergration.RegisterMethods
().

I am now creating a mini-IDE for the interactive python scripts to
control Excel. As such, I want to call Intergration.RegisterMethods()
from a button OnClick event. But it still fails for me.

My work around was simple: The OnClick event calls
Excel.Application.Run("ExcelCommandRegister") which in turn calls
Intergration.RegisterMethods() in the same way as your above .dna
example.

private void m_buttonRegister_Click(object sender, EventArgs e)
{
Excel.Application.Run("Register", Type.Missing x30 )
}

Thanks to ExcelDNA and your assistance with the dynamic method
registration my proof of concept project to embedded interactive
IronPython scripting into Excel has worked out well.

I definitely need to solve the StackOverflow and OutOfMemory
exceptions. I will try playing with the CLR hosting interfaces and if
find any solutions I will post back onto this thread.

Once I have made my tool more robust I will investigate making it
available for download.
> ...
>
> read more »

Peer

unread,
Jan 30, 2009, 2:20:29 AM1/30/09
to ExcelDna
Thanks Govert that solved my problem with Intergration.RegisterMethods
().

I am now creating a mini-IDE for the interactive python scripts to
control Excel. As such, I want to call Intergration.RegisterMethods()
from a button OnClick event. But it still fails for me.

My work around was simple: The OnClick event calls
Excel.Application.Run("ExcelCommandRegister") which in turn calls
Intergration.RegisterMethods() in the same way as your above .dna
example.

private void m_buttonRegister_Click(object sender, EventArgs e)
{
Excel.Application.Run("Register", Type.Missing x30 )
}

Thanks to ExcelDNA and your assistance with the dynamic method
registration my proof of concept project to embedded interactive
IronPython scripting into Excel has worked out well.

I definitely need to solve the StackOverflow and OutOfMemory
exceptions. I will try playing with the CLR hosting interfaces and if
find any solutions I will post back onto this thread.

Once I have made my tool more robust I will investigate making it
available for download.

> ...
>
> read more »

Govert van Drimmelen

unread,
Jan 30, 2009, 5:52:36 AM1/30/09
to exce...@googlegroups.com
Hi Peer,

My attempt at dealing with the StackOverflow issue was to put the TryConfigClr function (which I paste below) just before the call to CorBindToRuntimeEx around line 265 of ExcelDnaLoader.cpp. If this worked, there would still be a few things to sort out regarding loading the AppDomain, but I don't expect problems with these parts.

So our problem is that the call to
hr = pCLRControl->GetCLRManager(IID_ICLRPolicyManager, (PVOID*)&pCLRPolicyManager);
always fails with HOST_E_INVALIDOPERATION. In the Rotor code (where I expect the hosting part to be the same) in file clr\src\vm\CorHost.cpp, line 3516, it seems the only way this can happen is if the g_fEEStarted flag is set. In the debugger I can see that the CLR is only loaded when CorBindToRuntimeEx is called, and I don't call ->Start(). So maybe Excel or the VSTO add-in are interfering somehow.

This might need a bit of patience, or some CLR hosting expertise to sort out. I have some ideas on how to approach this, and although fascinating, it is not a high priority for me. In any event, one would not easily be able to change these settings if another add-in started the runtime.

Another way to make the add-ins robust is to host them out-of-process. This would be easy, but pretty much defeats the purpose, and there are other products that do this already.

Regards,
Govert

void TryConfigClr(pfnCorBindToRuntimeEx CorBindToRuntimeEx )
{
// If the CLR has not yet been loaded, it will be possible to configure some settings
// that improve the robustness of the runtime.
// For now we just try to configure stack overflow to unload the appdomain, not the
// whole Excel process.

//
// HRESULT hr = E_FAIL;
// CComPtr<ICLRRuntimeHost> pHost;
// hr = CorBindToRuntimeEx(L"v2.0.50727", L"wks", NULL, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pHost);
// if (FAILED(hr))
// {
// // Just ignore and not try to set robust handling
// // - typically we expect HOST_E_INVALIDOPERATION
// // which indicated that the CLR has already started.
//#if _DEBUG
// DebugBreak();
//#endif
// return;
// }
//
// // Set up error handling for the runtime
// CComPtr<ICLRControl> pCLRControl;
// hr = pHost->GetCLRControl(&pCLRControl);
// if (FAILED(hr))
// {
// // Just ignore and not try to set robust handling
// // - typically we expect HOST_E_INVALIDOPERATION
// // which indicated that the CLR has already started.
//#if _DEBUG
// DebugBreak();
//#endif
// return;
// }
//
// ICLRGCManager *ppObject;
// hr = pCLRControl->GetCLRManager(IID_ICLRGCManager, (VOID **) &ppObject);
//
// ICLRPolicyManager* pCLRPolicyManager = NULL;
// hr = pCLRControl->GetCLRManager(IID_ICLRPolicyManager, (PVOID*)&pCLRPolicyManager);
// if (FAILED(hr))
// {
// if (hr == HOST_E_INVALIDOPERATION)
// {
//#if _DEBUG
// DebugBreak();
//#endif
// }
// else
// {
//#if _DEBUG
// DebugBreak();
//#endif
// }
// return;
// }
// hr = pCLRPolicyManager->SetActionOnFailure(FAIL_StackOverflow, eRudeUnloadAppDomain);
// if (FAILED(hr))
// {
// // Unexpected error
//#if _DEBUG
// DebugBreak();
//#endif
// return;
// }
}

-----Original Message-----
From: exce...@googlegroups.com [mailto:exce...@googlegroups.com] On Behalf Of Peer
Sent: 30 January 2009 10:01
To: ExcelDna
Subject: [ExcelDna] Re: Integration.RegisterMethods


Thanks Govert that solved my problem with Intergration.RegisterMethods
().

I am now creating a mini-IDE for the interactive python scripts to
control Excel. As such, I want to call Intergration.RegisterMethods()
from a button OnClick event. But it still fails for me.

My work around was simple: The OnClick event calls
Excel.Application.Run("ExcelCommandRegister") which in turn calls
Intergration.RegisterMethods() in the same way as your above .dna
example.

private void m_buttonRegister_Click(object sender, EventArgs e)
{
Excel.Application.Run("Register", Type.Missing x30 )
}

Thanks to ExcelDNA and your assistance with the dynamic method
registration my proof of concept project to embedded interactive
IronPython scripting into Excel has worked out well.

I definitely need to solve the StackOverflow and OutOfMemory
exceptions. I will try playing with the CLR hosting interfaces and if
find any solutions I will post back onto this thread.

Once I have made my tool more robust I will investigate making it
available for download.

> ...
>
> read more »




Reply all
Reply to author
Forward
0 new messages