Hi Govert,
After walking through the ExcelDna code (have got a nice pretty
diagram if you want it) we decided to use a dynamic assembly.
One question though, would it be simple to modify ExcelDna to do the
equivelent of raising a OnRegisteringFunction event out to the
assembly being registered? This could give the opportunity to change
the FunctionAttributes and ArgumentAttributes through EventArgs.
FYI, our code solution:
Imports System
Imports System.Collections.Generic
Imports System.Reflection
Imports System.Reflection.Emit
Imports ExcelDna.Integration
Public Class Test
Implements IExcelAddIn
Public Sub AutoClose() Implements
Integration.IExcelAddIn.AutoClose
End Sub
Public Sub AutoOpen() Implements Integration.IExcelAddIn.AutoOpen
Dim methods As New Generic.List(Of MethodInfo)
methods.Add(CreateMethod())
Integration.Integration.RegisterMethods(methods)
End Sub
Private Shared Function CreateMethod() As MethodInfo
Dim className As String = "Class1"
Dim asssemblyName As New AssemblyName
asssemblyName.Name = "Assembly1"
asssemblyName.Version = New Version(1, 0, 0, 0)
Dim assemblyBuilder As AssemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(asssemblyName,
AssemblyBuilderAccess.RunAndSave)
Dim moduleBuilder As ModuleBuilder =
assemblyBuilder.DefineDynamicModule(asssemblyName.Name & ".dll",
asssemblyName.Name & ".dll")
Dim typeBuilder As TypeBuilder = moduleBuilder.DefineType
(className, TypeAttributes.Class Or TypeAttributes.Public)
'Build the function name
Dim functionName As String = "Function1"
'Build the method attributes
Dim attributes As MethodAttributes = MethodAttributes.Static
Or MethodAttributes.Public
'Build the return type
Dim retType As Type = GetType(Integer)
'Build the signature
Dim signature As New Generic.List(Of Type)
signature.Add(GetType(String))
'Build the method
Dim methodBuilder As MethodBuilder = typeBuilder.DefineMethod
(functionName, attributes, retType, signature.ToArray)
Dim paramBuilder As ParameterBuilder =
methodBuilder.DefineParameter(1, ParameterAttributes.In, "param1")
'Generate the actual IL code
With methodBuilder.GetILGenerator
.Emit(OpCodes.Ldarg_0) 'Place the first parameter from
Excel onto the stack
.Emit(OpCodes.Call, GetType(ExcelDna.Core).GetMethod
("InternalMethod", New Type() {GetType(String)})) 'Call InternalMethod
.Emit(OpCodes.Ret) 'Return
End With
'Define the attributes to be applied to the new method.
'This will break if the implementation of
ExcelFunctionAttribute changes
With GetType(ExcelFunctionAttribute)
Dim constructor As ConstructorInfo = .GetConstructor(New
Type() {})
Dim namedFields As FieldInfo() = New FieldInfo() {.GetField
("Name"), .GetField("Description"), .GetField("Category")}
Dim fieldValues As Object() = New Object()
{"NiceFunctionName", "Nice long descrtipion with lots of text", "Nice
Category"}
Dim attributeBuilder As New CustomAttributeBuilder
(constructor, New Object() {}, namedFields, fieldValues)
methodBuilder.SetCustomAttribute(attributeBuilder)
End With
'Define the attributes to be applied to the new parameters.
With GetType(ExcelArgumentAttribute)
Dim constructor As ConstructorInfo = .GetConstructor(New
Type() {})
Dim namedFields As FieldInfo() = New FieldInfo() {.GetField
("Name"), .GetField("Description")}
Dim fieldValues As Object() = New Object()
{"NiceParameterName", "Nice long descrtipion with lots of text"}
Dim attributeBuilder As New CustomAttributeBuilder
(constructor, New Object() {}, namedFields, fieldValues)
paramBuilder.SetCustomAttribute(attributeBuilder)
End With
'Commit the class
Dim classType As Type = typeBuilder.CreateType()
'Return the methodinfo to the calling code
Return classType.GetMethod(functionName, signature.ToArray)
End Function
End Class
Public Class Core
Public Shared Function InternalMethod(ByVal param1 As String) As
Integer
Return param1.Length
End Function
End Class
Thanks for your feedback,
Simon.
> > Thanks, Simon- Hide quoted text -
>
> - Show quoted text -