Регистрация .Net COM DLL без прав администратора/regasm
Недавно я написал библиотеку классов в С# для использования в приложениях Office, включая критическое приложение Access, используемое ~ 70 людьми. Для пользователей с правами администратора регистрация DLL тривиальна, но получение DLL, работающей на других машинах, было проблематичным.
Регистрация DLL для использования с правами администратора
- Создайте DLL в Visual Studio. Убедитесь, что эти параметры выбраны на вкладке Прикладная проекта:
- Тип вывода: библиотека классов
- Информация о сборке: сделать сборку COM-видимой: проверено
- Используйте командную строку с повышенными правами для регистрации сборки:
-
RegAsm YourDll.dll /tlb /codebase
- Добавить ссылку на
YourDll.tlb
в VBA: Инструменты → Ссылки
- Убедитесь, что вы можете создать экземпляр своего объекта
Что происходит?
Regasm здесь делает несколько вещей. Во-первых, он создает библиотеку типов (YourDLL.tlb), которая предоставляет информацию о классах, которые находятся в вашей DLL. Во-вторых, он хранит информацию о библиотеке в реестре, чтобы система "знала", что вы имеете в виду, когда вы просите создать экземпляр класса как объекта.
Чтобы узнать, какие записи реестра добавляется Regasm, вы можете запустить его с параметром /regfile
:
Regasm YourDLL.dll /codebase /regfile
(Параметр /regfile
недействителен с параметром /tlb
.)
Если параметр /codebase
сообщает Regasm включить информацию о том, где YourDLL.dll
находится на диске, что важно для создания объектов.
Если вы откроете YourDLL.reg
в текстовом редакторе, вы увидите записи, которые Regasm добавляет в реестр: записи в HKEY_Classes_Root
(что на самом деле является просто перенаправлением на HKLM\Software\Classes
). К сожалению, вам нужны права администратора для изменения HKLM
, поэтому это не будет работать для других наших пользователей.
Есть несколько других потоков (например Регистрация COM без прав администратора, Зарегистрировать COM DLL для использования VBA, Регистрация DLL (ActiveX) для пользователей, не являющихся администраторами, Невозможно зарегистрировать .NET COM DLL, COM Interop без regasm), которые обсуждают проблему, но их решения сложны (например, требуют перенаправления реестра) или неполные (предположим, что вы уже знаете, по крайней мере, половину ответа) или не работают в смешанных средах с 64/32 бит (например, Win64, Office32).
Итак, как вы регистрируете COM-DLL, созданную в Visual Studio, для использования в VBA 32 и 64-разрядных средах для текущего пользователя без административных привилегий?
Ответы
Ответ 1
Настройка файлов реестра
Чтобы зарегистрировать компоненты для использования в 32- и 64-разрядных средах, нам потребуется изменить файл реестра, который мы создали в нашем тестовом примере. Откройте его в своем любимом текстовом редакторе. Записи должны выглядеть примерно так:
[HKEY_CLASSES_ROOT\\YourAssembly.Class]
@="YourAssembly.Class"
[HKEY_CLASSES_ROOT\\YourAssembly.Class\\CLSID]
@="{YourClassGUID}"
Убедитесь, что он содержит записи "CodeBase"=
.
Сделайте глобальный поиск/замену:
- Измените
HKEY_CLASSES_ROOT
(который является псевдонимом HKLM\Software\Classes
)
- К
HKEY_CURRENT_USER\Software\Classes
Скопируйте все ключи реестра (и их значения, перечисленные ниже ключей) во второй текстовый файл. Во втором текстовом файле:
- Удалите все ключи (и связанные с ними значения), которые не содержат
\CLSID\
- Сделайте глобальный поиск/замену:
- Изменить
Classes\CLSID
- Кому:
Classes\Wow6432Node\CLSID
Скопируйте все ключи из второго текстового файла в исходный REG файл и сохраните его.
Удалите записи из HKLM
с помощью regasm:
Regasm YourDLL.dll /unregister
Убедитесь, что все не работает
Чтобы убедиться, что наше изменение сработало (и что вы не просто успешны из-за регистрации, которую вы сделали с regasm изначально), нам нужно убедиться, что VBA не может создать объект прямо сейчас.
Откройте свое любимое приложение VBA и добавьте ссылку на YourDLL.tlb
. Создайте новую процедуру, которая выглядит примерно так:
Public Sub TestYourDLL()
Dim x as AssemblyName.ClassName
Set x = New AssemblyName.ClassName
Debug.Print "Apparently this worked."
End Sub
Запустите TestYourDLL
. Вы должны получить сообщение об ошибке:
Run-time error '429':
ActiveX component can't create object
(Если вы не получили сообщение об ошибке, ваша DLL все еще зарегистрирована.)
Сохраните и выйдите из приложения VBA.
Убедитесь, что они работают
Теперь запустите YourDLL.reg
, который вы создали ранее, чтобы импортировать записи в реестр. (Если вы получили сообщение "Отказано в доступе", вы забыли изменить с HKEY_CLASSES_ROOT
на HKEY_CURRENT_USER\Software\Classes
)
Откройте приложение VBA еще раз и запустите TestYourDLL
. Теперь вы должны увидеть "Видимо, это сработало". в вашем ближайшем окне. Поздравления! Вы зарегистрировали DLL! (Если вы получили сообщение об ошибке "Ошибка автоматизации: система не может найти указанный файл", в вашем файле реестра либо отсутствуют записи Codebase
, либо они не указывают на фактическое местоположение вашей DLL.)
Дополнительные шаги
В моем случае я собираюсь установить DLL на кучу компьютеров других пользователей вместе с моим приложением, поэтому во время установки я обновляю значение Codebase
, чтобы ссылаться на местоположение, где я установка DLL, и я также установлю записи реестра через код, а не выполнив файл .reg. Но теперь, когда я знаю необходимые записи, это тривиально.
Ответ 2
C Белый ответ отлично, если вы можете сделать это вручную на каждом компьютере.
Для автоматического добавления необходимых записей реестра я использую следующий код. Он отвечает за 32-битный Office в 64-битной Windows и может быть впоследствии очищен.
Public Sub RegisterDLL(DLLPath As String)
Dim RegasmPath As String
RegasmPath = "C:\Windows\Microsoft.NET\Framework\" & Dir("C:\Windows\Microsoft.NET\Framework\v4*", vbDirectory) & "\RegAsm.exe" 'Path to RegAsm, adjust to the version of the .Net framework you're targeting
#If Win64 Then
Const Win64 = True
#Else
Const Win64 = False
#End If
Dim LibraryPath As String
LibraryPath = Left(DLLPath, Len(DLLPath) - 4)
If Dir(DLLPath) = "" Then 'Check if file exists
Err.Raise 1, Description:="Missing DLL!"
Exit Sub
End If
CreateObject("WScript.Shell").Run """" & RegasmPath & """ """ & DLLPath & """ /codebase /regfile", 0, True 'Create .reg file using RegAsm
Dim strNewRegPath As String
If Not Win64 And Environ$("ProgramW6432") <> vbNullString Then
strNewRegPath = "HKEY_CURRENT_USER\SOFTWARE\Classes\Wow6432Node" '32 bits Office on Win 64
Else
strNewRegPath = "HKEY_CURRENT_USER\SOFTWARE\Classes" 'Default registry path
End If
Dim strRegFileContent As String
Dim fileNo As Integer
fileNo = FreeFile
Open LibraryPath & ".reg" For Binary Access Read Write As #fileNo
strRegFileContent = String(LOF(fileNo), vbNullChar)
Get #fileNo, , strRegFileContent 'Read reg contents
strRegFileContent = Replace(strRegFileContent, "HKEY_CLASSES_ROOT", strNewRegPath) 'Change reg path
Put #fileNo, 1, strRegFileContent 'Overwrite, always extends so no need to truncate
Close #fileNo
CreateObject("WScript.Shell").Run "regedit.exe /s """ & LibraryPath & ".reg""", 0, True 'Merge silently into registry
Kill LibraryPath & ".reg" 'Clean up registry
End Sub
Просто используйте RegisterDLL "C:\Path\To\File.DLL"
для автоматического добавления необходимых записей.
Для очистки при удалении вы можете использовать следующее:
Public Sub UnregisterDLL(DLLPath As String)
Dim RegasmPath As String
RegasmPath = "C:\Windows\Microsoft.NET\Framework\" & Dir("C:\Windows\Microsoft.NET\Framework\v4*", vbDirectory) & "\RegAsm.exe" 'Path to RegAsm, adjust to the version of the .Net framework you're targeting
#If Win64 Then
Const Win64 = True
#Else
Const Win64 = False
#End If
Dim LibraryPath As String
LibraryPath = Left(DLLPath, Len(DLLPath) - 4)
If Dir(DLLPath) = "" Then 'Check if file exists
Err.Raise 1, Description:="Missing DLL!"
Exit Sub
End If
CreateObject("WScript.Shell").Run """" & RegasmPath & """ """ & DLLPath & """ /codebase /regfile", 0, True 'Create .reg file using RegAsm
Dim strNewRegPath As String
If Not Win64 And Environ$("ProgramW6432") <> vbNullString Then
strNewRegPath = "HKEY_CURRENT_USER\SOFTWARE\Classes\Wow6432Node" '32 bits Office on Win 64
Else
strNewRegPath = "HKEY_CURRENT_USER\SOFTWARE\Classes" 'Default registry path
End If
Dim strRegFileContent As String
Dim fileNo As Integer
fileNo = FreeFile
Dim fileOutput As Integer
fileOutput = FreeFile + 1
Open LibraryPath & ".reg" For Input As #fileNo
Open LibraryPath & "remove.reg" For Output As #fileOutput
Line Input #fileNo, strRegFileContent 'Read reg contents
Print #fileOutput, strRegFileContent 'Copy first line blindly
Do While Not EOF(fileNo)
Line Input #fileNo, strRegFileContent 'Read reg contents
strRegFileContent = Replace(strRegFileContent, "HKEY_CLASSES_ROOT", strNewRegPath) 'Change reg path
If Left(strRegFileContent, 1) = "[" Then 'If new key
Print #fileOutput, "[-" & Mid(strRegFileContent, 2) 'Change to remove key
End If
Loop
Close #fileOutput
Close #fileNo
Kill LibraryPath & ".reg" 'Remove create file
Shell "regedit.exe /s """ & LibraryPath & "remove.reg""" 'Merge silently into registry
Kill LibraryPath & "remove.reg" 'Remove delete file
End Sub
Эти сценарии не требуют ссылок и доступа администратора. Как правило, они должны работать быстро и разрешать настройку при запуске приложения и очистку при завершении работы приложения, если конфликты могут быть проблемой.