Проблемы с созданием пользовательской функции C # .NET - PullRequest
0 голосов
/ 19 февраля 2019

Я изучаю возможность создания надстройки автоматизации для Excel в качестве альтернативы Excel ДНК.Ссылка на статью Адама Тиби (http://www.adamtibi.net/07-2012/using-c-sharp-net-user-defined-functions-udf-in-excel),) Мне удалось заставить библиотеку классов работать с некоторыми проблемами. Самая большая проблема заключается в том, что формула работает, но не отображается в списке формул Excel. Кроме того, яхотел бы иметь intellisense для параметров UDF, а также хотел бы знать, есть ли какой-нибудь способ получения ссылок на ячейки, из которых была отправлена ​​формула.

С точки зрения настройки я выбрал«Сделать сборку COM видимой» и «Зарегистрироваться для взаимодействия COM».

По кодам у меня есть следующие классы.

using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;

namespace AutoExcel
{
    public abstract class UdfBase
    {
        [ComRegisterFunction]
        public static void ComRegisterFunction(Type type)
        {
            Registry.ClassesRoot.CreateSubKey(
                GetClsIdSubKeyName(type, "Programmable"));

            // Solves an intermittent issue where Excel
            // reports that it cannot find mscoree.dll
            // Register the full path to mscoree.dll.
            var key = Registry.ClassesRoot.OpenSubKey(GetClsIdSubKeyName(type, "InprocServer32"), true);
            if (key == null)
            {
                return;
            }
            key.SetValue("", $"{Environment.SystemDirectory}\\mscoree.dll", RegistryValueKind.String);
        }

        [ComUnregisterFunction]
        public static void ComUnregisterFunction(Type type)
        {
            // Adds the "Programmable" registry key under CLSID
            Registry.ClassesRoot.DeleteSubKey(GetClsIdSubKeyName(type, "Programmable"));
        }

        private static string GetClsIdSubKeyName(Type type, String subKeyName)
        {
            return $"CLSID\\{{{type.GUID.ToString().ToUpper()}}}\\{subKeyName}";
        }

        // Hiding these methods from Excel
        [ComVisible(false)]
        public override string ToString()
        {
            return base.ToString();
        }

        [ComVisible(false)]
        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        [ComVisible(false)]
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
}

и

using System.Runtime.InteropServices;

namespace AVstoAddIn
{
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [Guid("3CA06A95-F1A6-4C36-9E56-501BDC7AFDCF")]
    public class UdfTest : UdfBase
    {
        public double AddNumbers(double a, double b)
        {
            return a + b;
        }

        public double SubtractNumbers(double a, double b)
        {
            return a - b;
        }
    }
}

Когда я пытаюсь взять надстройку Excel VSTO и применить те же методы, я могу заставить ее собрать все то же самое, кроме выбора «Зарегистрироваться для взаимодействия COM».

Моя среда разработки - Windows 10, Excelдля Office 365, 64-разрядная версия Visual Studio Professional 2017 версии 15.9.7. Моя надстройка Excel должна будет поддерживать 2010, 2013, 2016 2019 и Office 365.

Я хотел бы, чтобы функция появилась в списке функций, а также создала категорию, в которой она должна отображаться, но не знаю как.

Любая помощь будет принята с благодарностью.

Edit 1

Я понял, как определить диапазон, из которого вызывается UDF.Интересно, что приложение не сохраняется даже при попытке сохранить его в статическом классе / переменной / свойстве.Я устанавливал приложение в ThisAddIn.cs в методе ThisAddIn_Startup, но приложение было пустым, когда я пытался получить к нему доступ в методе COM Automation.

using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;

namespace AVstoAddIn
{
     public static class ExcelApplication
     {
        static Excel.Application application;

        public static Excel.Application XlApplication
        {
           get => application ?? (Excel.Application) Marshal.GetActiveObject("Excel.Application");
           set { application = Globals.ThisAddIn.Application ?? (Excel.Application) Marshal.GetActiveObject("Excel.Application"); }
        }
     }
}

В упомянутом выше классе COM Automationссылки могут быть найдены следующим образом:

public class UdfTest : UdfBase
{
    public double AddNumbers(double a, double b)
    {
        Excel.Application excelApp = ExcelApplication.XlApplication;
        Excel.Range target = (Excel.Range)excelApp.get_Caller(Type.Missing);
        string cellAddress = target.get_Address(Missing.Value, Missing.Value, Excel.XlReferenceStyle.xlA1, Missing.Value, Missing.Value);

        return a + b;
    }
}

На данный момент у меня следующие вопросы: 1. Как заставить UDF показывать, когда пользователь начинает печатать.2. Как заставить intellisense работать с параметрами UDF.3. Как сохранить приложение.

...