最近,我在C#中编写了一个类库,用于Office应用程序,包括约70人使用的关键Access应用程序。对于具有管理员权限的用户,注册DLL很简单,但在其他计算机上运行DLL是有问题的。
RegAsm YourDll.dll /tlb /codebase
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 rights,Register COM DLL for use by VBA,Register DLL (ActiveX) for non-admin user,Unable to register .NET COM DLL,COM Interop without regasm),但他们的解决方案是复杂(例如需要注册表重定向)或不完整(假设您已经知道至少一半的答案)或者不能在混合的64/32位环境中工作(例如Win64,Office32)。
那么如何在没有管理权限的情况下注册在Visual Studio中创建的COM DLL,以便在当前用户的VBA 32和64位环境中使用?
答案 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
这些脚本不需要引用,也不需要管理员访问。通常,它们应该运行得很快,并允许在应用程序启动时进行设置,并在应用程序关闭时进行清理(如果可能会引起冲突)。