Как установить и зарегистрировать COM-сервер для Excel, написанный на VB.NET, в списке серверов автоматизации? - PullRequest
11 голосов
/ 02 октября 2009

Версия

Excel 2007, Windows Vista, VB.NET, Visual Studio 2008 с .NET 3.5 sp2, установочный пакет MSI.

Что я пытаюсь сделать

У меня есть Excel UDF, который написан на VB.NET. Он отображается как COM-сервер, потому что вы не можете напрямую создавать пользовательские функции Excel на языках .NET. Установка - настоящая боль, потому что ни одна из установок установки, кажется, не делает это правильно; Ни один из них не дает вам инсталляционного пакета, который помещает COM-сервер на клиентский компьютер с зарегистрированным сервером, зарегистрированной библиотекой типов и компонентом, видимым в списке серверов автоматизации Excel 2007.

Что я пробовал

Вот параметры установки для библиотек типов с их дефектами, очевидными во время компиляции и во время установки:

vsdrfComSelfReg

  • нет предупреждений во время компиляции проекта установки
  • Модуль xxx.tlb не смог зарегистрироваться. HRESULT -2147024703
  • ProgID и GUID компонента задаются в реестре, но компонент не отображается в списке серверов автоматизации

vsdrfDoNotregister

  • нет предупреждений во время компиляции
  • установка работает, но, конечно, TLB не зарегистрирован

vsdrfCOM

  • Предупреждение во время компиляции: ПРЕДУПРЕЖДЕНИЕ: невозможно создать регистрационную информацию для файла с именем 'xxx.tlb'
  • библиотека типов не зарегистрирована при установке

Правильная настройка должна быть vsdrfCOM, как объяснено здесь :

Q. Может кто-нибудь, пожалуйста, скажите, что делает vsdrfCOM означает в проекте установки Visual Studio? Это доступно, когда я проверить свойство "Регистрация" среди свойства добавленных файлов в настройках проект.

A. Это означает, что Visual Studio будет извлекать регистрационные данные COM при сборке время и положить его в файл MSI (в основном таблица реестра MSI-файла, но и таблица классов). Итак, когда вы установить его ваш код не нужно самостоятельно зарегистрироваться, потому что файл получает скопировать на диск и в реестр записи создаются. Это также будет создать регистрацию библиотеки типов добавление записи в TypeLib MSI таблица.

Многие трудности кажутся специфичными для Vista. В частности, использование утилиты REGCAP для создания файла .REG из файла .TLB не работает в Vista. Если бы не это, возможно , этот совет был бы полезен . Вместо этого он генерирует пустые файлы .REG, когда он вообще работает.

Я испробовал все советы в этом сообщении StackOverflow . Этот пост имеет довольно хорошее описание технической проблемы:

Записи в диалоге Ссылки коробка пришла из HKCR \ TypeLib ключ реестра, а не из HKCR \ CLSID. Если ваша сборка не отображается в Диалог ссылок, но скомпилированные DLL все еще можно использовать вашу сборку COM, это означает, что классы и интерфейсы были правильно зарегистрирован для вашего сборка, но это библиотека типов сам не был.

Вопрос

У кого-нибудь есть идеи, как заставить установку зарегистрировать компонент и библиотеку типов? У меня нет доступа к машине с Windows XP.


Уточнение, почему это отстой

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

Это не совсем так в Excel.

  • Пользователь открывает рабочий лист и пытается сослаться на UDF. Не найден, потому что DLL не загружена. FAIL
  • Пользователь переходит в раздел Домашняя страница | Параметры Excel | Надстройки | Надстройки Excel + Go, и COM-сервер не отображается в диалоговом окне «Надстройки». FAIL
  • Затем пользователь нажимает серверы автоматизации, чтобы получить список доступных серверов автоматизации. DLL там нет. FAIL
  • Пользователь возвращается в диалоговое окно «Надстройки» и выбирает «Обзор», переходит в каталог установки и выбирает либо DLL («XXX не является допустимой надстройкой»), либо библиотеку типов («Выбранный вами файл делает не содержат новый сервер автоматизации или у вас недостаточно прав ... »). FAIL

Насколько я могу судить, пользователь должен запустить regasm.exe из командной строки, чтобы сделать сервер Excel UDF / COM доступным. Что бы вы посоветовали людям запускать regasm из командной строки для установки надстройки в Excel?


Редактировать 2009-10-04

Замечания и указания Майка ниже потрясающие. Главное, чего я не знал, это то, что в программе установки есть встроенный редактор реестра для добавления ключей реестра . Да, и что установочная функция с атрибутом ComRegisterFunctionAttribute не была вызвана установщиком Microsoft . У меня уже были инструкции по написанию функций установщика из цитируемых им источников.

1 Ответ

29 голосов
/ 02 октября 2009

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

Существуют источники, которые описывают, как использовать RegAsm, но нет, как правильно использовать проект установки для регистрации надстройки автоматизации, которая немного отличается от вашей стандартной надстройки COM.

К счастью, я смог ее решить. Вот что я узнал:

Если вы прочитаете некоторые статьи о том, как создать и зарегистрировать надстройку C # для автоматизации, вы увидите, что вам нужно добавить раздел реестра с именем Programmable в HKEY\_CLASSES\_ROOT\CLSID\\{GUID}, где {GUID} - это GUID вашего COM-видимого класса.

Обычно это делается путем добавления пары методов, помеченных ComRegisterFunctionAttribute и ComUnregisterFunctionAttribute . Хороший пример этого можно найти в статье Написание пользовательских функций листа Excel в C # Габханом Берри:

// C#:

[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type) {
  Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type));
}

[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type) {
  Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type), false);
}

private static string GetSubKeyName(Type type) {
  string s = @"CLSID\{" + type.GUID.ToString().ToUpper() + @"}\Programmable";
  return s;
}

В переводе на VB.NET это работает:

'VB.NET:

<ComRegisterFunctionAttribute()> _
Public Shared Sub RegisterFunction(ByVal type As Type)
    Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type))
End Sub

<ComUnregisterFunctionAttribute()> _
Public Shared Sub UnregisterFunction(ByVal type As Type)
    Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type), false)
End Sub

Private Shared Function GetSubKeyName(ByVal type As Type) As String
    Dim s As String = ("CLSID\{" _
                + (type.GUID.ToString.ToUpper + "}\Programmable"))
    Return s
End Function

Метод, отмеченный ComRegisterFunctionAttribute, автоматически вызывается RegAsm при регистрации сборки для этого класса. Метод, отмеченный ComUnregisterFunctionAttribute, автоматически вызывается RegAsm, когда сборка для этого класса не регистрируется с помощью переключателя /u.

Проблема в том, что ComRegisterFunctionAttribute и ComUnregisterFunctionAttribute полностью игнорируются при установке через проект установки Visual Studio.

Поначалу это кажется удивительным, поскольку проект установки Visual Studio запускает RegAsm с использованием переключателя /regfile, чтобы сгенерировать файл .REG, содержащий все необходимые ключи реестра. Именно этот файл .REG затем используется, после чего на клиентском сайте запускается пакет .MSI.

С Сборка и развертывание .NET COM Assembly Автор Phil Wilson:

Как Visual Studio работает Регистрация класса COM записи? Что ж, если вы настроили Fusion Log Средство просмотра (Fuslogvw.exe в .NET 2.0 SDK) для записи загрузки сборки, запустить это после сборки вашей установки и вы заметите, что Regasm.exe на самом деле работает во время сборки вашей установки проект. Тем не менее, он не выполняет любая регистрация. Что происходит то Visual Studio запускает Regasm с /regfile опция для создания файла .reg содержащий записи реестра требуется, чтобы получить информацию для Шаг 1, и этот файл .reg внутренне импортированные в настройку проект. Так что если вы хотите увидеть, что регистрация классов записи Visual Studio создаст в настройке MSI, Вы можете запустить Regasm самостоятельно с /regfile опция

После запуска RegAsm сам, используя переключатель /regfile, я заметил, что переключатель Programmable был , а не . Затем я включил ведение журнала в мои методы, отмеченные ComRegisterFunctionAttribute и ComUnregisterFunctionAttribute, и обнаружил, что они оба вызываются при запуске RegAsm без переключателя /regfile, но не вызываются при запуске с /regfile и не вызываются при запуске через пакет .MSI, созданный проектом установки Visual Studio.

Файлы справки для Regasm.exe подтверждают это (выделение добавлено):

Вы можете использовать опцию /regfile для создать файл .reg, который содержит записи реестра вместо того, чтобы сделать изменения непосредственно в реестре. Вы можно обновить реестр на компьютере импортировав файл .reg с Инструмент редактора реестра (Regedit.exe). Обратите внимание, что файл .reg не содержит обновлений реестра, которые могут быть сделан пользовательским регистром функции.

Решение, таким образом, заключается в добавлении ключа Programmable самостоятельно. Это можно сделать следующим образом:

  1. В проекте установки откройте редактор реестра. Создайте новый ключ с именем CLSID в HKEY_CLASSES_ROOT, щелкнув правой кнопкой мыши папку HKEY_CLASSES_ROOT, выбрав «Новый», а затем «Ключ».
  2. Под ключом CLSID добавьте новый ключ с именем GUID, включая фигурные скобки.
  3. Под новым ключом GUID, который вы добавили, добавьте ключ с именем Programmable. Вам не нужно указывать какое-либо значение в этом ключе; тем не менее, нам нужно заставить его быть созданным. Поэтому щелкните правой кнопкой мыши на ключе Programmable и выберите «Окно свойств». Затем измените свойство AlwaysCreate на True.

После того, как вы это сделали, вам больше не нужны методы, отмеченные с помощью ComRegisterFunctionAttribute и ComUnregisterFunctionAttribute, но я все равно оставляю их в тех случаях, когда вы выполняете вызов через RegAsm, а не через проект установки.

На данный момент вы готовы к развертыванию. Создайте свое решение, а затем щелкните правой кнопкой мыши по вашему проекту установки и выберите «Build» Затем можно использовать созданные файлы Setup.exe и MSI для развертывания на клиентском компьютере.

Однако следует учитывать и то, что при добавлении надстройки автоматизации через диалоговое окно надстроек Excel будет отображаться сообщение об ошибке, в котором говорится, что «Mscoree.dll не найден, хотите удалить добавление». -в?" или что-то очень похожее. Это сообщение об ошибке можно игнорировать, и ваша надстройка будет работать независимо от того, что вы ответите, но это может вызвать тревогу у клиента, устанавливающего вашу надстройку.

Эта ситуация и объяснение того, как ее решить, хорошо описаны в статье Написание пользовательских функций для Excel в .NET Эриком Картером.

Проблема в том, что значением по умолчанию для клавиши InprocServer32 является просто mscorree.dll, что достаточно для .NET, чтобы найти его, но заставляет Excel жаловаться. Решение состоит в том, чтобы убедиться, что значение по умолчанию для ключа InprocServer32 включает полный путь к системному каталогу. Например, в 32-битных окнах он должен читать C:\Windows\system32\mscoree.dll. Однако этот путь должен меняться в зависимости от системы, в которой он установлен. Так что этот путь не должен быть жестко закодирован.

Эрик Картер справляется с этим, изменяя методы, отмеченные ComRegisterFunctionAttribute и ComUnregisterFunctionAttribute, следующим образом:

// C#: 

[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{

  Registry.ClassesRoot.CreateSubKey(
    GetSubKeyName(type, "Programmable"));
  RegistryKey key = Registry.ClassesRoot.OpenSubKey(
    GetSubKeyName(type, "InprocServer32"), true);
  key.SetValue("",
    System.Environment.SystemDirectory + @"\mscoree.dll",
    RegistryValueKind.String);
}

[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{

  Registry.ClassesRoot.DeleteSubKey(
    GetSubKeyName(type, "Programmable"), false);
}

private static string GetSubKeyName(Type type,
  string subKeyName)
{
  System.Text.StringBuilder s =
    new System.Text.StringBuilder();
  s.Append(@"CLSID\{");
  s.Append(type.GUID.ToString().ToUpper());
  s.Append(@"}\");
  s.Append(subKeyName);
  return s.ToString();
}  

В переводе на VB.NET это эквивалентно:

'VB.NET:

<ComRegisterFunctionAttribute()> _
Public Shared Sub RegisterFunction(ByVal type As Type)
    Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"))
    Dim key As RegistryKey = Registry.ClassesRoot.OpenSubKey(GetSubKeyName(type, "InprocServer32"), true)
    key.SetValue("", (System.Environment.SystemDirectory + "\mscoree.dll"), RegistryValueKind.String)
End Sub

<ComUnregisterFunctionAttribute()> _
Public Shared Sub UnregisterFunction(ByVal type As Type)
    Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type, "Programmable"), false)
End Sub

Private Shared Function GetSubKeyName(ByVal type As Type, ByVal subKeyName As String) As String
    Dim s As System.Text.StringBuilder = New System.Text.StringBuilder
    s.Append ("CLSID\{")
    s.Append(type.GUID.ToString.ToUpper)
    s.Append ("}\")
    s.Append (subKeyName)
    Return s.ToString
End Function

Это работает, но имеет ту же самую проблему, когда сборка правильно регистрируется при запуске RegAsm на локальном компьютере, но не удается при попытке использовать это в проекте установки Visual Studio.

Решение, опять же, заключается в добавлении наших собственных ключей реестра. На этот раз, однако, нам нужно будет создать значение по умолчанию, которое использует свойство [SystemFolder], которое эквивалентно вызову System.Environment.SystemDirectory, используемому в коде Эрика Картера выше.

Для этого добавьте ключ с именем InprocServer32 под ключом CLSID\\{GUID}, который мы создали ранее. Затем щелкните правой кнопкой мыши новый ключ InprocServer32 и выберите «Создать», затем «Строковое значение». Результатом будет новое значение с именем New Value #1, но вы перейдете в режим редактирования, позволяющий переименовать его. Здесь вы хотите удалить все символы, а затем нажать Enter . Удаляя все символы из имени, вы создаете значение по умолчанию, а значок значения реестра будет автоматически переименован в «(По умолчанию)». Затем щелкните правой кнопкой мыши на значке по умолчанию и выберите «Окно свойств». В окне свойств установите для свойства Value значение "[SystemFolder]mscoree.dll" (без кавычек).

Затем вы можете щелкнуть правой кнопкой мыши по вашему проекту установки и выбрать «Build», после чего вы готовы к развертыванию.

Есть только одна последняя вещь, о которой нужно беспокоиться. Если вы устанавливаете в Excel 2007 или выше, вышесказанное будет работать на 100%. Однако, если вы устанавливаете в Excel 2003 или ниже, вам нужно будет включить следующее:

ИСПРАВЛЕНИЕ: надстройки, смарт-документы или смарт-теги, созданные с помощью Microsoft Visual Studio 2005, не запускаются в Office

Подробное объяснение того, как его развернуть, дано Divo здесь .

Если вы не примените это исправление, все будет зарегистрировано правильно, и вы даже сможете успешно добавить свою надстройку автоматизации - все выглядит хорошо - но ваши функции листа не будут работать, и вы все равно получите #NAME? ошибки в результате. (Но, опять же, вам не нужно это для Excel 2007 и выше.)

Так, в конце концов, TLB не имеет значения. Во всех моих тестах я использовал RegAsm без ключа / TLB и не включал TLB при регистрации через проект установки. Поэтому у меня не было проблем с этим из Vista, , которая имеет проблемы при попытке добавить файл TLB в проект установки .

Надеюсь, это поможет, Хью, и, надеюсь, кому-нибудь еще, кто может наткнуться на эту ветку в будущем ...

Mike

...