Thanks for responding, Govert.
I have made some progress on this. I was able to expose my own assembly, edna1.dll, to dynamically-compiled
code. By by this, i mean a new source module that is added at some point AFTER initialization (not in an autoOpen callback,
for example). I had to do doing the following in my .dna file:
<ExternalLibrary Path="edna1.dll" LoadFromBytes="false" Pack="false" />
i was unable to get this to work with either Pack="true" or LoadFromBytes="true". I can't remember the exact symptoms
now, but I believe that I could not resolve the assembly if I packed it, and I had multiple loadings if i set LoadFromBytes.
Unfortunately, this was not enough to allow me to reference items from ExcelDna.Integration.dll. I was able to make my code
work by placing a copy of ExcelDna.Integration.dll in my addin directory. I know that's not what I am supposed to do, but otherwise
I cannot resolve the assembly. I looked at the source code for exceldna and did see that ExcelDna.Integration is handled
specially by the assembly resolution mechanism -- but I am not familiar enough with the overall architecture to figure out why
this isn't sufficient.
Perhaps its related to my CompilerOptions settings, since all of that runs in a separate process for the c# compiler
and doesn't see your custom resolver? If so, is this also the problem with edna1.dll and in indeed any "packed" assembly?
I'm not sure if having this copy of ExcelDna.Integration.dll will cause other problems later. I am comfortable guaranteeing that
it is exactly the same version as the one contained inside the main dll; I am just worried that there are some global structures
that will be duplicated by doing this.
Below are the relevant portions off my working F# code. Here, when the "Compiler 2" menu item is selected, the F# function compiles a string containing
c# code and then ExcelIntegration.RegisterMethods successfully adds a new menu item called "Dynamic!" This new menu item executes the c# code,
which references f# module MyFunctions (the same module that contains all the code below). This new menu item
correctly executes MyFunctions.dolog (not included in the source here), which writes to a global log window (thus proving it has linked to the
right edna1.dll assembly and not a new copy).
I greatly prefer having everything packed into a single file. Perhaps you can explain why this doesn't work, and if it is or is not possible.
Can you point out any problems that can occur with using a copy of ExcelDna.Integration.dll?
Thank you for looking at this!
Herb
CODE SNIPPET FOLLOWS:
let wuggascript3 = """
using System;
using ExcelDna.Integration;
namespace wugga {
public class wuggaclass {
[ExcelCommand(MenuName="My AddIn", MenuText="Dynamic!")]
public static void Main() {
Console.WriteLine("hello");
MyFunctions.dolog("oh boy");
}
}
}
"""
[<ExcelCommand(MenuName="My AddIn", MenuText="Compiler 2")>]
let cpdemo2 () =
let compile snippet =
use provider = new CSharpCodeProvider()
let options = CompilerParameters(GenerateInMemory=true)
options.ReferencedAssemblies.Add("edna1.dll") |> ignore
options.ReferencedAssemblies.Add("ExcelDna.Integration.dll") |> ignore
let ea=System.Reflection.Assembly.GetExecutingAssembly()
options.CompilerOptions <- @" /lib:C:\Data\exceldna\edna1\edna1\bin\Debug"
provider.CompileAssemblyFromSource(options, snippet)
let cr = [|wuggascript3|] |> compile
if cr.Errors.Count>0 then
for er in cr.Errors do
dolog (sprintf "%d:%d %s" er.Line er.Column er.ErrorText)
else
dolog ("successfully compiled: "+cr.CompiledAssembly.FullName)
let asm = cr.CompiledAssembly
let types = asm.GetTypes()
let methods = new List<MethodInfo>()
for ty in types do
for info in ty.GetMethods(BindingFlags.Public ||| BindingFlags.Static) do
for attr in info.GetCustomAttributes(false) do
let attribty = attr.GetType()
if (attribty.FullName = "ExcelDna.Integration.ExcelFunctionAttribute" ||
attribty.FullName = "ExcelDna.Integration.ExcelCommandAttribute") then methods.Add(info)
ExcelIntegration.RegisterMethods(methods)