Excel 2007 UDF: как добавить описание функции, помощь аргумента?

Описание

Я пишу пару UDF Excel в COM-серверах. Я хотел бы получить стандартную справку (диалоговое окно "Вставить функцию "), которую вы получаете при нажатии клавиши fx. Да, я вижу мой COM-сервер в раскрывающемся списке Категория, но

  • Я также вижу Equals, GetHashCode, GetType и ToString (которые довольно нежелательно выставлять пользователю Excel),
  • При выборе моего COM-сервера открывается диалоговое окно * Function Arguments * [1] без информации об аргументах и ​​описания функции.

Вот хромота, которую я получаю:

http://www.iwebthereforeiam.com/files/Insert%20function%20dialog.gif

http://www.iwebthereforeiam.com/files/Function%20Arguments%20dialog.gif

Вопрос

Существуют ли атрибуты.NET, которые я мог бы добавить в методы, чтобы передать это в Excel?

  • Могу ли я предоставить описание функции?
  • Могу ли я предоставить описание параметров?
  • Могу ли я предоставить название категории для своих функций, чтобы получить что-то лучше, чем просто ProgID?

(Я вижу, что это выглядит к сожалению легко сделать в ExcelDNA, но я не собираюсь идти по этому пути. Эмуляция кода Говерта [пользовательские атрибуты, какой-то загрузчик и т. Д.] Выглядит так, как будто это будет довольно сложно.)


Дополнительный фон

Если вы раньше не работали с серверами Excel + COM, вот несколько полезных ресурсов, которые помогут вам освоиться:

Предыдущие вопросы Stackru:
Как установить и зарегистрировать COM-сервер для Excel, написанный на VB.NET, в списке серверов автоматизации?
Как добавить COM-выставленный проект.NET в диалог ссылок VB6 (или VBA)?

Другие источники:
Написание пользовательских функций для Excel в.NET
Сборка и развертывание сборки.NET COM
Написание пользовательских функций листа Excel в C#


Редактировать 2009-10-20 14:10

Я пробовал звонить Application.MacroOptions в Sub New(),

  1. Нет Sub New()
    Приемлемо: функция указана в категории ProgID.
  2. Shared Sub New()
    Неприемлемо: ошибка во время сборки.
    Не удается зарегистрировать сборку "...\Foo.dll".
    Исключение было брошено целью вызова.
  3. Sub New()
    Недопустимо: категория не указана в диалоговом окне "Вставка функции".

Я подозреваю, что это проблема как для MacroOptions, так и для более сложного маршрута, рекомендованного Чарльзом.


Редактировать 2009-10-20 14:55

С другой стороны, рекомендация Майка о создании интерфейса для реализации убила надоедливые дополнительные методы, которые были выставлены.


Изменить 2009-10-20 15:00

Эта статья Microsoft начала 2007 года (по ссылке Майка) кажется довольно полным ответом на эту тему:

Автоматизированные надстройки и мастер функций

Каждая надстройка автоматизации имеет свою собственную категорию в мастере функций Excel. Имя категории - это ProgID для надстройки; Вы не можете указать другое имя категории для функций надстроек автоматизации. Кроме того, в мастере функций невозможно указать описания функций, описания аргументов или справку для функций надстроек автоматизации.


1 Да, ошибка StackOverFlow. Похоже, вы не можете выделить курсивом строку в явном HTML-списке ul?

2 ответа

Решение

Некоторые из них легко исправить, другие части довольно сложно. Все это выполнимо, хотя, если вы готовы потратить время.

Вы написали:

Я также вижу Equals, GetHashCode, GetType и ToString (которые нежелательно выставлять пользователю Excel)

Да, согласился, это определенно нежелательно, но это можно предотвратить. Это происходит потому, что ваш класс наследуется от "System.Object", как и все классы.NET, и ваш интерфейс по умолчанию, доступный для COM, включает эти члены. Это происходит, например, если вы используете ClassInterfaceAttribute, используя параметр ClassInterfaceType.AutoDual.

Например, в C#:

[ClassInterface(ClassInterfaceType.AutoDual)]

В VB.NET:

<ClassInterface(ClassInterfaceType.AutoDual)>

Однако следует избегать использования ClassInterfaceType.AutoDual, чтобы предотвратить раскрытие элементов, унаследованных от "System.Object" (а также для предотвращения потенциальных проблем с версиями в будущем). Вместо этого определите свой собственный интерфейс, реализуйте интерфейс в своем классе, а затем пометьте свой класс атрибутом "ClassInterface" со значением "ClassInterfaceType.None".

Например, используя C#:

[ComVisible(true)]
[Guid("5B88B8D0-8AF1-4741-A645-3D362A31BD37")]
public interface IClassName
{
    double AddTwo(double x, double y);
}

[ComVisible(true)]
[Guid("010B0245-55BB-4485-ABAF-46DF4356DB7B")]
[ProgId("ProjectName.ClassName")]
[ComDefaultInterface(typeof(IClassName))]
[ClassInterface(ClassInterfaceType.None)]
public class ClassName : IClassName
{
    public double AddTwo(double x, double y)
    {
        return x + y;
    }
}

Использование VB.NET:

<ComVisible(True)> _
<Guid("5B88B8D0-8AF1-4741-A645-3D362A31BD37")> _
Public Interface IClassName
    Function AddTwo(ByVal x As Double, ByVal y As Double) As Double
End Interface

<ComVisible(True)> _
<Guid("010B0245-55BB-4485-ABAF-46DF4356DB7B")> _
<ProgId("ProjectName.ClassName")> _
<ComDefaultInterface(GetType(IClassName))> _
<ClassInterface(ClassInterfaceType.None)> _
Public Class ClassName
    Implements IClassName

    Public Function AddTwo(ByVal x As Double, ByVal y As Double) As Double _
        Implements IClassName.AddTwo
        Return x + y
    End Function
End Class

При использовании ClassInterfaceAtribute со значением ClassInterfaceType.None унаследованные члены System.Object исключаются, поскольку интерфейс класса не сделан видимым для COM. Вместо этого только реализованный интерфейс (в данном примере "IClassName") экспортируется в COM.

Выше также используется 'ComDefaultInterfaceAttribute'. Это не очень важно и ничего не делает, если вы реализуете только один интерфейс - как в этом примере - но это хорошая идея, если вы добавляете интерфейс позже, например, IDTExtensibility2.

Подробнее об этом см.:

(1) Надстройки управляемой автоматизации от Andrew Whitechapel.

(2) Написание пользовательских функций листа Excel в C# по Габхан Берри.

Хорошо, теперь самое сложное. Вы написали:

Выбор моего COM-сервера вызывает диалоговое окно Function Arguments [1] без информации об аргументах и ​​описания функции.

Могу ли я предоставить описание функции?

Могу ли я предоставить описание параметров?

Могу ли я предоставить название категории для своих функций, чтобы получить что-то лучше, чем просто ProgID?

Самый простой подход - использовать метод Application.MacroOptions. Этот метод позволяет вам предоставить описание функции и указать, в какой категории вы хотите, чтобы она отображалась. Этот подход, к сожалению, не позволяет вам указывать какую-либо информацию для параметров функций, но методы, которые позволяют вам это делать, очень сложны, о которых я расскажу позже. [Исправление: метод Application.MacroOptions работает только для пользовательских функций, созданных с помощью VBA, и не может использоваться для надстроек автоматизации. Продолжайте читать для более сложных подходов, чтобы обработать регистрацию содержимого UDFs в надстройках автоматизации - Майк Розенблюм 2009.10.20]

Обратите внимание, что в файлах справки для Excel 2003 и файлах справки для Excel 2007 указано, что для аргумента категории можно указать строку, чтобы указать произвольное имя категории по вашему выбору. Однако помните, что файлы справки для Excel 2002 этого не делают. Я не знаю, является ли это упущением в файлах справки Excel 2002, или это новая возможность в Excel 2003. Я предполагаю последнее, но вам придется проверить, чтобы быть уверенным.

Единственный способ получить информацию о параметрах в мастере функций - использовать довольно сложную технику, включающую метод Excel.Application.ExecuteExcel4Macro. Будьте осторожны: многие Excel MVP боролись с этим подходом и не смогли получить надежный результат. Совсем недавно, однако, похоже, что Ян Карел Питерс (JKP) разработал его и опубликовал подробности здесь: Регистрация определяемой пользователем функции в Excel.

Просматривая эту статью, вы увидите, что она не для слабонервных. Частично проблема заключается в том, что он написал его для VBA / VB 6.0, и поэтому весь этот код должен быть переведен на VB.NET или C#. Однако ключевой командой является метод "Excel.Application.ExecuteExcel4Macro", который доступен для.NET, поэтому все должно работать нормально.

Однако на практике я предпочитаю использовать подход "Excel.Application.MacroOptions", потому что он прост и надежен. Он не предоставляет информацию о параметрах, но у меня еще не было острой необходимости мотивировать меня использовать подход "ExecuteExcel4Macro".

Так что, удачи в этом, но я бы посоветовал использовать "Макроопции", если вам не платят по часам.;-)

- Майк

Продолжение ответов Хью

Я попытался вызвать Application.MacroOptions в Sub New ().

No Sub New () Полуприемлемый: функция указана в категории ProgID.

Shared Sub New () Недопустимо: ошибка во время сборки. Не удается зарегистрировать сборку "...\Foo.dll". Исключение было брошено целью вызова.

Sub New () Недопустимо: категория не указана в диалоговом окне "Вставка функции". Я подозреваю, что это проблема как для MacroOptions, так и для более сложного маршрута, рекомендованного Чарльзом.

Вы не можете использовать общие (то есть "статические") классы или конструкторы при представлении ваших классов COM, потому что COM не знает об этой концепции и поэтому не может скомпилировать - как вы узнали! Возможно, вы сможете применить COMVisibleAttribute со значением "False" к общему конструктору, чтобы хотя бы позволить ему скомпилироваться. Но это не поможет вам в этом случае в любом случае...

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

Проблема в том, что надстройки автоматизации загружаются по требованию. То есть, их там нет, пока Excel не попытается получить доступ к первой функции листа из вашей надстройки автоматизации. Есть две проблемы, связанные с этим:

(1) Если вы поместите свой регистрационный код в конструктор для своего класса, то, по определению, информация вашего мастера функций не может существовать, пока функция не будет вызвана в первый раз.

(2) Ваш конструктор может выполняться, когда Excel не готов принимать команды автоматизации. Например, надстройка автоматизации обычно загружается по требованию, когда пользователь начинает вводить имя одной из пользовательских функций (UDF), определенных в надстройке автоматизации. В результате ячейка находится в режиме редактирования при первой загрузке надстройки автоматизации. Если у вас есть код автоматизации в вашем конструкторе в режиме редактирования, многие команды не будут выполнены. Я не знаю, есть ли у этого проблемы методы "Excel.Application.MacroOptions" или "Excel.Application.Excel4Macro", но многие команды будут задыхаться при попытке выполнить, когда ячейка находится в режиме редактирования. И если надстройка автоматизации загружается впервые, потому что она вызывается во время работы мастера функций, я понятия не имею, могут ли эти методы работать правильно.

Нет простого решения, если вы хотите, чтобы надстройка автоматизации была полностью автономной без какой-либо другой поддержки. Однако вы можете создать управляемую надстройку COM, которая будет регистрировать вашу надстройку автоматизации с помощью "Excel.Application.MacroOptions" или "Excel.Application.Excel4Macro" при запуске Excel. Управляемый класс надстройки COM может находиться в той же сборке, что и ваша надстройка автоматизации, поэтому вам по-прежнему нужна только одна сборка.

Кстати, вы можете даже использовать рабочую книгу VBA или надстройку.XLA, чтобы сделать то же самое - использовать событие Workbook.Open в VBA для вызова регистрационного кода. Вам просто нужно что-то, чтобы позвонить регистрационный код при запуске Excel. Преимущество использования VBA в этом случае заключается в том, что вы можете использовать код из статьи " Регистрация определенной пользователем функции" в статье Яна Карела Питерса "как есть", без необходимости переводить ее в.NET.

С другой стороны, рекомендация Майка о создании интерфейса для реализации убила надоедливые дополнительные методы, которые были выставлены.

лол, я рада что-то сработало!

Эта статья Microsoft начала 2007 года (по ссылке Майка) кажется довольно полным ответом на эту тему:

Автоматизированные надстройки и мастер функций

Каждая надстройка автоматизации имеет свою собственную категорию в мастере функций Excel. Имя категории - это ProgID для надстройки; Вы не можете указать другое имя категории для функций надстроек автоматизации. Кроме того, в мастере функций невозможно указать описания функций, описания аргументов или справку для функций надстроек автоматизации.

Это ограничение только для подхода "Excel.Application.MacroOptions". (Мои извинения, я забыл об этом ограничении метода "Excel.Application.MacroOptions" в отношении надстроек автоматизации, когда писал свой оригинальный ответ выше.) Более сложное "Excel.Application. Подход ExecuteExcel4Macro', однако, абсолютно работает для надстроек автоматизации. Он также должен работать для надстроек автоматизации.NET ("управляемых"), поскольку Excel не знает, загружает ли он надстройку автоматизации COM, созданную с помощью VB 6.0/C++, или надстройку управляемой автоматизации COM, созданную с помощью VB.NET/C#. Механика абсолютно одинакова со стороны COM, потому что Excel не знает, что такое.NET или что.NET вообще существует.

Тем не менее, подход "Excel.Application.Excel4Macro" определенно будет много работы...

Вы можете использовать одну из систем.Net Excel, такую ​​как ExcelDNA или ADDIN Express, или попытаться адаптировать одно из решений VBA/VB6: посмотрите FunCustomise Лорана Лонгра http://xcell05.free.fr/english/index.html или статья Яна Карела Питерса по адресу http://www.jkp-ads.com/Articles/RegisterUDF00.asp которой используется функция, перегрузившая хак.

Другие вопросы по тегам