注册没有管理员权限/ regasm的.Net COM DLL

时间:2016-05-12 17:09:59

标签: .net vba dll registry regasm

最近,我在C#中编写了一个类库,用于Office应用程序,包括约70人使用的关键Access应用程序。对于具有管理员权限的用户,注册DLL很简单,但在其他计算机上运行DLL是有问题的。

注册DLL以使用管理员权限

  • 在Visual Studio中构建DLL。确保在项目的应用程序选项卡上选择了这些选项:
    • 输出类型:类库
    • 装配信息使程序集COM可见:已检查
  • 使用提升的命令提示符注册程序集:
    • RegAsm YourDll.dll /tlb /codebase
  • 在VBA中添加对YourDll.tlb的引用:工具 - >参考
  • 确认您可以创建对象的实例

发生了什么事?

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,因此这对我们的其他用户无效。

还有一些讨论问题的其他主题(例如Registering a COM without Admin rightsRegister COM DLL for use by VBARegister DLL (ActiveX) for non-admin userUnable to register .NET COM DLLCOM Interop without regasm),但他们的解决方案是复杂(例如需要注册表重定向)或不完整(假设您已经知道至少一半的答案)或者不能在混合的64/32位环境中工作(例如Win64,Office32)。

那么如何在没有管理权限的情况下注册在Visual Studio中创建的COM DLL,以便在当前用户的VBA 32和64位环境中使用?

2 个答案:

答案 0 :(得分:8)

设置注册表文件

要注册在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文件,然后保存。

使用regasm从<{1}}删除注册条目:

Regasm YourDLL.dll /unregister

确保事情不起作用

为了确保我们的更改有效(并且您因为最初使用regasm进行注册而不仅仅是成功),我们需要确保VBA 无法创建现在的对象。

打开您最喜爱的VBA应用程序,并添加对HKLM的引用。创建一个类似这样的新过程:

YourDLL.tlb

运行Public Sub TestYourDLL() Dim x as AssemblyName.ClassName Set x = New AssemblyName.ClassName Debug.Print "Apparently this worked." End Sub 。您应该收到错误:

Run-time error '429':

ActiveX component can't create object

(如果您没有收到错误,您的DLL仍然会被注册。)

保存并退出您的VBA应用程序。

确保它们正常工作

现在,运行您之前创建的TestYourDLL将条目导入注册表。 (如果您收到&#34;访问被拒绝&#34;消息,则您忘记从YourDLL.reg更改为HKEY_CLASSES_ROOT

再次打开您的VBA应用程序,然后运行HKEY_CURRENT_USER\Software\Classes。你现在应该看到&#34;显然这是有用的。&#34;在你眼前的窗口。恭喜!您已经注册了DLL! (如果您收到&#34;自动化错误:系统找不到指定的文件&#34; -type错误,您的注册表文件要么缺少TestYourDLL条目,要么它们没有指向实际位置你的DLL。)

附加步骤

在我的情况下,我将在其他一些用户上安装DLL&#39;计算机与我的应用程序一起,因此在安装时我会更新Codebase值以引用我安装DLL的位置,并且我还将通过代码安装注册表项而不是通过执行.reg文件。但是,既然我知道所需的条目,那么这样做是微不足道的。

答案 1 :(得分:1)

如果您可以在每台计算机上手动进行操作,则C White的答案很好。

要自动添加必要的注册表项,请使用以下代码。它在64位Windows上占32位Office的大小,以后可以清除。

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

这些脚本不需要引用,也不需要管理员访问。通常,它们应该运行得很快,并允许在应用程序启动时进行设置,并在应用程序关闭时进行清理(如果可能会引起冲突)。