ExcelDNA динамическая регистрация UDF во время выполнения - PullRequest
0 голосов
/ 25 августа 2018

Моя цель - динамически создать и зарегистрировать пользовательскую функцию Excel во время выполнения в надстройке ExcelDNA.

Вот пример , предоставленный автором ExcelDNA, который подчеркивает, как вы можете скомпилировать UDF из простой строки кода C #.

Как видите, этот код выполняется путем вызова RegisterMyClass из метода AutoOpen AddIn; и все работает отлично.

Однако, если вы переместите метод RegisterMyClass в (например) метод действия кнопки ленты, регистрация динамического UDF не будет работать и приведет к следующей ошибке:

Registration [Error] xlfRegister call failed for function or command: 'MyDynamicAdd'

На самом деле, кажется, что любые вызовы ExcelIntegration.RegisterMethods терпят неудачу в приведенном выше сообщении об ошибке - если они не вызываются из метода AutoOpen.

Мой вопрос:

Как я могу динамически зарегистрировать новый UDF во время выполнения и вызвать его нажатием на кнопку ленты?

Ссылочный код Gist для полноты:

<DnaLibrary Name="ExcelDna Test Dynamic Method" Language="C#">
<Reference Name="System.Windows.Forms" />
    <![CDATA[
    using System;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.IO;
    using System.Reflection;
    using System.Windows.Forms;
    using Microsoft.CSharp;
    using ExcelDna.Integration;

    public class Test : IExcelAddIn
    {
        // Just to test that we are loaded.
        public static double MyAdd(double d1, double d2)
        {
            return d1 + d2;
        }

        public void AutoOpen()
        {
            RegisterMyClass();
        }

        public void AutoClose()
        {
        }

        private void RegisterMyClass()
        {
            string code = 
                @"
                public class Script 
                { 
                    public static double MyDynamicAdd(double d1, double d2)
                    {
                        return d1 + d2;
                    }
                }";

        CompilerParameters cp = new CompilerParameters();
        cp.GenerateExecutable = false;
        cp.GenerateInMemory = true;
        cp.TreatWarningsAsErrors = false;
        cp.ReferencedAssemblies.Add("System.dll"); //, "System.Windows.Forms.dll", "ExcelDna.Integration.dll" );
        CSharpCodeProvider provider = new CSharpCodeProvider();
        CompilerResults cr = provider.CompileAssemblyFromSource(cp, new string[] { code });
        if (!cr.Errors.HasErrors)
        {
            Assembly asm = cr.CompiledAssembly;
            Type[] types = asm.GetTypes();
            List<MethodInfo> methods = new List<MethodInfo>();

            // Get list of MethodInfo's from assembly for each method with ExcelFunction attribute
            foreach (Type type in types)
            {
                foreach (MethodInfo info in type.GetMethods(BindingFlags.Public | BindingFlags.Static))
                {
                    methods.Add(info);
                }
            }
            Integration.RegisterMethods(methods);
        }
        else
        {
            MessageBox.Show("Errors during compile!");
        }
    }
    }
]]>
</DnaLibrary>

1 Ответ

0 голосов
/ 25 августа 2018

Ваш код для регистрации функции должен быть в контексте, где доступен C API.Он не будет работать в обратном вызове ленты или любом другом обработчике событий COM.

Один из вариантов переключения в контекст макроса, где доступен API C, - это вызвать помощник ExcelAsyncUtil.QueueAsMacro и запустить регистрационный кодв делегате вы проходите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...