Я сделал снимок при развертывании надстройки автоматизации в выходные дни. Оказывается, это чрезвычайно сложно (не удивительно для вас!), И я не смог найти абсолютно никаких источников в интернете о том, как сделать это правильно. Никто.
Существуют источники, которые описывают, как использовать 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
самостоятельно. Это можно сделать следующим образом:
- В проекте установки откройте редактор реестра. Создайте новый ключ с именем
CLSID
в HKEY_CLASSES_ROOT
, щелкнув правой кнопкой мыши папку HKEY_CLASSES_ROOT
, выбрав «Новый», а затем «Ключ». - Под ключом
CLSID
добавьте новый ключ с именем GUID, включая фигурные скобки.
- Под новым ключом 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