如何在自动化服务器列表中安装并注册VB.NET中编写的COM Server for Excel? 版本
Excel 2007、Windows Vista、VB.NET、Visual Studio 2008以及.NET 3.5 sp2、MSI安装程序包 我想做什么 我有一个用VB.NET编写的Excel自定义项。它作为COM服务器公开,因为您无法直接用.NET语言创建Excel UDF。安装是一个真正的痛苦,因为没有安装设置似乎得到它完全正确;它们都没有为您提供一个安装包,该安装包将COM服务器放在客户机上,服务器已注册,类型库已注册,组件在Excel2007的自动化服务器列表中可见 我试过的 以下是类型库的安装设置,其缺陷在编译时和安装时很明显: vsdrfComSelfReg如何在自动化服务器列表中安装并注册VB.NET中编写的COM Server for Excel? 版本,.net,excel,com,installation,.net,Excel,Com,Installation,Excel 2007、Windows Vista、VB.NET、Visual Studio 2008以及.NET 3.5 sp2、MSI安装程序包 我想做什么 我有一个用VB.NET编写的Excel自定义项。它作为COM服务器公开,因为您无法直接用.NET语言创建Excel UDF。安装是一个真正的痛苦,因为没有安装设置似乎得到它完全正确;它们都没有为您提供一个安装包,该安装包将COM服务器放在客户机上,服务器已注册,类型库已注册,组件在Excel2007的自动化服务器列表中可见 我试过的 以下
- 编译安装项目期间没有警告
- 模块xxx.tlb注册失败。HRESULT-2147024703
- 组件的ProgID和GUID在注册表中设置,但该组件不显示在自动化服务器列表中
- 编译期间没有警告
- 安装工程,但TLB当然未注册
- 编译时警告:警告:无法为名为“xxx.tlb”的文件创建注册信息
- 安装期间未注册类型库
详细说明为什么这很糟糕 任何编译代码都不需要.TLB来调用它。我没有像您这样尝试部署Excel自动化外接程序,但我想UDF应该可以正常加载和运行 在Excel中不是这样的
- 用户打开工作表并尝试引用自定义项。未找到,因为未加载DLL失败
- 用户进入主页| Excel选项|加载项| Excel加载项+Go,COM服务器未在加载项对话框中列出失败
- 然后,用户按下Automation Servers以获取可用自动化服务器的列表。DLL不在那里失败
- 用户返回“加载项”对话框并选择“浏览”,导航到安装目录,然后选择DLL(“XXX不是有效的加载项”)或类型库(“您选择的文件不包含新的自动化服务器,或者您没有足够的权限…”)失败
编辑2009-10-04
迈克在下面的评论和指导非常棒。我不知道的关键是,安装程序有一个内置的注册表编辑器,用于添加注册表项。哦,而且Microsoft安装程序没有调用属性为ComRegisterFunctionAttribute的安装函数。我已经从他引用的源代码中得到了编写安装程序函数的指导。我在周末尝试部署一个自动化插件。事实证明,这是非常复杂的(你不感到惊讶!),我在互联网上完全找不到关于如何正确完成这项工作的资料。没有 有一些源代码描述了如何使用
RegAsm
,但没有一个源代码描述了如何正确使用安装项目来注册自动化加载项,这与标准COM加载项略有不同
幸运的是,我能够解决它。以下是我发现的:
如果您阅读了一些关于如何创建和注册C#automation外接程序的文章,您将看到需要在HKEY\\U CLASSES\\U ROOT\CLSID\\{GUID}
处添加一个名为Programmable
的注册表项,其中{GUID}
是COM可见类的GUID
这通常是通过添加一对由和标记的方法来完成的。Gabhan Berry的文章就是一个很好的例子:
// 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
转换为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
”VB.NET:
_
公共共享子注册表函数(ByVal类型作为类型)
Registry.ClassesRoot.CreateSubKey(GetSubKeyName(类型,“可编程”))
调暗键为Regi
'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