Регистрация .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

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