如何获得在VB.NET中编写的COM服务器安装并注册在自动化服务器列表中? [英] How to get COM Server for Excel written in VB.NET installed and registered in Automation Servers list?
问题描述
版本
Excel 2007,Windows Vista,VB.NET,带.NET 3.5 sp2的Visual Studio 2008,MSI安装程序包。
我想做什么
我有一个用VB.NET编写的Excel UDF。它显示为COM服务器,因为您无法直接使用.NET语言创建Excel UDF。安装是一个真正的痛苦,因为没有一个安装设置似乎得到它很正确;它们都没有为您提供一个安装包,将COM服务器放在客户端计算机上,注册服务器,注册类型库,并且组件在Excel 2007的Automation Server列表中可见。
我试过的
以下是类型库的安装设置,它们的缺陷在编译时和安装时显而易见:
vsdrfComSelfReg
- 在编译安装专案时没有警告
- 模块xxx.tlb无法注册。 HRESULT -2147024703
- 组件的ProgID和GUID在注册表中设置,但组件未显示在自动化服务器列表中
vsdrfDoNotregister
- 在编译期间没有警告
- 当前未注册TLB
vsdrfCOM
- 编译时警告:警告:无法为名为xxx.tlb的文件创建注册信息
- 安装期间未注册类型库
- 用户打开工作表并尝试引用UDF。它没有找到,因为DLL没有加载。 失败
- 用户转到首页| Excel选项|加载项| Excel加载项+ Go,COM服务器未列在加载项对话。 FAIL
- 然后,用户按自动服务器以获取可用的自动服务器列表。 DLL不存在。 失败
- 用户返回到加载项对话框并选择浏览,导航到安装目录,并选择DLL(XXX不是有效加载项)或类型库(您选择的文件不包含新的Automation Server,或者您没有足够的权限...)。 FAIL
正确的设置应该为vsdrfCOM,如此处:
Q。任何人都可以告诉
vsdrfCOM在
Visual Studio的安装项目中的意思是什么?当I
在安装
项目中添加的文件的
属性中检查属性注册时可用。
A。这意味着Visual Studio将
提取COM注册数据在构建
时间,并将其放入MSI文件
(大多数是MSI文件的注册表,
,但也包括类表) 。所以当你
安装它你的代码不需要
自我注册,因为文件得到
复制到磁盘和注册表
条目创建。它还将
通过
创建类型库注册添加一个条目到MSI的TypeLib
表。
许多困难似乎是Vista特有的。特别是,使用 REGCAP实用程序从.TLB文件生成.REG文件在Vista中不工作。如果不是这样,也许这个建议会很有用。
我已经尝试过所有的建议在此StackOverflow post 。这篇文章有一个很好的描述的技术问题:
引用对话框
框中的条目来自HKCR\\ \\ TypeLib
注册表项,而不是从HKCR \CLSID。如果
你的程序集不出现在
引用对话框中,但编译的DLL的
仍然可以使用你的COM程序集,它
意味着类和接口是
正确注册
问题
对于程序集,但
类型库本身不是。
任何人都知道如何使安装注册组件和类型库?我无法访问Windows XP计算机。
详细说明为什么会出现
.TLB不是任何编译代码调用它所必需的。我没有尝试部署一个Excel Automation加载项,正如你所做的,但我的猜测是UDF应该加载和运行很好。
在Excel中不是这样。
据我所知,用户必须从命令行运行regasm.exe以使Excel UDF / COM服务器可用。
strong>编辑2009-10-04
Mike的评论和指示真棒。我不知道的关键是,安装程序有一个内置注册表编辑器添加注册表项。噢,并且具有ComRegisterFunctionAttribute属性的安装函数没有被Microsoft安装程序调用。
我拍摄了一个部署一个自动化add-在周末。事实证明,它是非常复杂(不是你的惊喜!),我可以找到绝对没有在互联网上的资源如何正确地做到这一点。没有。
有些来源描述了如何使用 RegAsm
,但没有如何正确使用安装项目注册自动化加载项,这与您的标准COM加载项略有不同。
幸运的是,我能够解决它。这是我发现的:
如果你阅读一些关于如何创建和注册你的C#自动化加载项的文章,你会看到,你需要添加在 HKEY\_CLASSES\_ROOT\CLSID\\ {GUID}
下命名为 Programmable
{GUID}
是您的COM可见类的GUID。
这通常通过添加一个对由 ComRegisterFunctionAttribute 标记的方法和 ComUnregisterFunctionAttribute 。一个很好的例子来自文章 Gabhan Berry在C#中编写自定义Excel工作表函数
// 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);
}
私人静态字符串GetSubKeyName(Type type){
string s = @CLSID \ {+ type.GUID.ToString()。ToUpper }\可编程的;
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
私有共享函数GetSubKeyName (ByVal type As Type)As String
Dim s As String =(CLSID\ {_
+(type.GUID.ToString.ToUpper +} \Programmable))
返回s
结束函数
由 ComRegisterFunctionAttribute当注册此类的程序集时,
。当此类的程序集通过 RegAsm
会自动调用注销时,
切换。 ComUnregisterFunctionAttribute
标记的方法会自动调用 RegAsm
c $ c> / u
问题是 ComRegisterFunctionAttribute
ComUnregisterFunctionAttribute
在通过Visual Studio安装项目安装时完全被忽略。
令人惊讶的是,由于Visual Studio安装程序使用 / regfile
开关运行 RegAsm
,以生成.REG文件包含所有必需的注册表项。它是这个.REG文件,然后利用然后.MSI包在客户端站点运行。
使用 / regfile
开关,但是,我注意到可编程
开关不是被包括。然后我把日志记录在我的方法标记的 ComRegisterFunctionAttribute
和 ComUnregisterFunctionAttribute
,发现它们都被调用时运行<$没有 / regfile
切换的 / regfile
切换,也不通过由Visual Studio安装项目创建的.MSI包运行。
Regasm.exe的帮助文件确认此(加入):
您可以使用
/ regfile
选项到
generate一个包含
注册表项的.reg文件,而不是让
直接更改到注册表。您
可以通过使用
注册表编辑器工具(Regedit.exe)导入.reg文件来更新计算机上的注册表
。
请注意.reg文件不包含任何注册表更新,可以通过用户定义的注册
函数
。
然后,解决方案是添加 Programmable
键。可以这样做:
- 在安装程序项目中,打开注册表编辑器。右键单击
HKEY_CLASSES_ROOT $>,在
HKEY_CLASSES_ROOT
下创建一个名为CLSID
c $ c>文件夹,然后选择新建,然后选择键。 - 在
CLSID
- 在您添加的新GUID密钥下,添加名为
Programmable
的密钥。你不需要在这个键中放任何值;然而,我们确实需要强制它被创造。因此,右键单击可编程
键并选择属性窗口。然后将AlwaysCreate
属性更改为True
。
一旦你这样做,你不再需要标记ComRegisterFunctionAttribute和ComUnregisterFunctionAttribute的方法,但是我仍然会留在那些场合,当你通过RegAsm而不是通过安装项目。
此时,您已准备好部署。构建您的解决方案,然后右键单击您的安装项目并选择构建。然后,您可以使用创建的Setup.exe和.MSI文件将其部署到客户端计算机。
但是,需要考虑的是,在Excel的加载项对话框中,将显示一条错误消息,指出无法找到Mscoree.dll,您要删除加载项吗?或者非常相似的东西。
这个错误讯息可以被忽略,并且您的加载项无论您回答什么都会运行,但是可能会让安装您的加载项的客户端感到惊讶。情况和如何解决它的解释,在 问题是 Eric Carter通过修改 翻译为VB.NET,相当于: 这样可以正常工作,在本地机器上运行 解决方案,再次,是添加我们自己的注册表项。这一次,我们必须创建一个使用 要执行此操作,请添加一个名为 您可以右键单击安装项目并选择生成,然后您就可以部署。 只剩下最后一件事了。如果要安装到Excel 2007或更高版本,上述内容将工作100%。但是,如果要在Excel 2003或更低版本上安装,则需要包含以下内容: FIX:您通过使用Microsoft Visual Studio 2005创建的加载项,智能文档或智能标记不在Office 中运行 有关如何部署它的详细解释由Divo 此处。 如果您不应用此修复程序,一切都会正确注册,您甚至可以成功添加自动加载项 - 一切似乎很好 - 但您的工作表函数将失败,您仍然会获得#NAME?错误结果。 (但是,再次,你不需要这个Excel 2007及以上。) 所以,最后,TLB没有关系。在我的所有测试中,我使用RegAsm与/ TLB开关,并没有包括任何TLB通过安装项目注册。所以我没有麻烦这样做从Vista,,当尝试添加一个TLB文件到安装程序时有问题。 我希望这有助于,休,希望任何人 Mike Excel 2007, Windows Vista, VB.NET, Visual Studio 2008 with .NET 3.5 sp2, MSI setup package. I have an Excel UDF that is written in VB.NET. It is exposed as a COM Server because you cannot create Excel UDFs in .NET languages directly. Installation is a real pain because none of the installation settings seem to get it quite right; none of them gives you an installation package that puts the COM Server on the client machine with the server registered, the type library registered, and the component visible in the Excel 2007's list of Automation Servers. Here are the installation settings for type libraries, with their defects apparent at compile-time and install-time: vsdrfComSelfReg vsdrfDoNotregister vsdrfCOM The correct setting should be vsdrfCOM, as explained here: Q. Can anyone please tell what does
vsdrfCOM mean in a setup project of
Visual Studio? It is available when I
check the property "Register" among
properties of added files in a Setup
project. A. It means that Visual Studio will
extract COM registration data at build
time and put it in the MSI file
(mostly the MSI file's registry table,
but also the class table). So when you
install it your code doesn't need to
self-register because the file gets
copied to disk and the registry
entries get created. It will also
create type library registration by
adding an entry to the MSI's TypeLib
table. Many of the difficulties appear to be Vista-specific. In particular, using the REGCAP utility to produce a .REG file from a .TLB file does not work in Vista. If not for that, perhaps this advice would be useful. Instead, it produces empty .REG files when it works at all. I've tried all of the advice in this StackOverflow post. That post has a pretty good description of the technical problem: The entries in the References dialog
box come from the HKCR\TypeLib
registry key, not from HKCR\CLSID. If
your assembly does not show up in the
References dialog but compiled DLL's
can still use your COM assembly, it
means the classes and interfaces were
correctly registered for your
assembly, but that the type library
itself was not.
Anyone have an idea of how to make the installation register the component and the type library? I don't have access to a Windows XP machine. Elaboration on why this sucks The .TLB is not necessary for any compiled code to call it. I've not tried deploying an Excel Automation add-in, as you are doing, but my guess is that the UDFs should load and run just fine. It's not quite like that in Excel. As far as I can tell, the user has to run regasm.exe from the command line to make the Excel UDF/COM server available. How would you feel about telling people to run regasm from the command line to install an add-in to Excel? Edit 2009-10-04 Mike's comments and directions below are awesome. The key thing I did not know was that the setup program has a built-in registry editor for adding registry keys. Oh, and that the installation function with attribute ComRegisterFunctionAttribute was not being called by the Microsoft installer. I already had the directions about writing installer functions from the sources he cited. I took a shot at deploying an automation add-in over the weekend. It turns out that it is enormously complicated (not a surprise to you!) and I could find absolutely no sources on the internet on how to do this properly. None. There are sources that describe how to use Fortunately, I was able to solve it. Here's what I found out: If you read some of the articles on how to create and register your C# automation add-in, you'll see that you need to add a registry key named This is generally done by adding a pair of methods marked by the ComRegisterFunctionAttribute and the ComUnregisterFunctionAttribute. A good example of this comes from the article Writing Custom Excel Worksheet Functions in C# by Gabhan Berry: Translated to VB.NET, this works out to: The method marked by the The problem is that the This seems surprising at first, because the Visual Studio Setup Project runs From Build and Deploy a .NET COM Assembly by Phil Wilson: How does Visual Studio work out the
COM class registration entries? Well,
if you have configured the Fusion Log
Viewer (Fuslogvw.exe in the .NET 2.0
SDK) to record assembly loading, run
it after the build of your setup and
you'll notice that Regasm.exe actually
runs during the build of your setup
project. However, it doesn't perform
any registration. What happens is that
Visual Studio runs Regasm with the
Upon running RegAsm myself using the The help files for Regasm.exe confirm this (emphasis added): You can use the The solution, then, is to add the Once you've done this, you no longer need the methods marked with ComRegisterFunctionAttribute and ComUnregisterFunctionAttribute, but I would still leave them in for those occasions when you intall via RegAsm and not via the Setup Project. At this point you are ready to deploy. Build your solution and then right click on your Setup Project and choose 'Build'. You can then use the created Setup.exe and .MSI files to deploy to a client machine. Something else to consider, however, is that when adding the automation add-in via Excel's add-ins dialog box, an error message will be shown stating that "Mscoree.dll cannot be found, would you like to delete the add-in?" or something very similar. This error message can be ignored, and your add-in will run no matter what you answer, but it can be alarming to a client installing your add-in. This situation, and the explanation of how to solve it, is well described in the article Writing user defined functions for Excel in .NET by Eric Carter. The problem is that the default value for the Eric Carter handles this by modifying the methods marked by the Translated to VB.NET, this is equivalent to: This works, but has the same exact problem where the assembly is properly registered when running The solution, again, is to add our own registry keys. This time, however, we'll have to create a default value that makes use of the To do this, add a Key named You can then right-click on your Setup Project and choose 'Build' and then you are ready to deploy. There is just one last thing to worry about. If you are installing to Excel 2007 or above, the foregoing will work 100%. If you are installing on Excel 2003 or below, however, you will need to include the following: A detailed explaination of how to deploy it is given by Divo here. If you do not apply this fix, everything will register correctly, and you can even add your automation add-in successfully -- everything seems fine -- but your worksheet functions will fail and you'll still get #NAME? errors as a result. (But, again, you don't need this for Excel 2007 and above.) So, in the end, the TLB does not matter. In all my testing I used RegAsm witout the /TLB switch and did not include any TLB when registering via the Setup Project. So I had no trouble doing this from Vista, which has issues when attempting to add a TLB file to a Setup Project. I hope this helps, Hugh, and hopefully anyone else who might stumble onto this thread in the future... Mike 这篇关于如何获得在VB.NET中编写的COM服务器安装并注册在自动化服务器列表中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
的缺省值是< InprocServer32
键只是 mscorree.dll
,这足以让.NET找到它,但会导致Excel抱怨。解决方案是确保InprocServer32密钥的默认值包括系统目录的完整路径。例如,在32位窗口上,应该读取 C:\Windows \system32\ mscoree.dll
。但是,此路径需要变化,具体取决于安装的系统。
ComRegisterFunctionAttribute
标记的方法来处理这个问题。和 ComUnregisterFunctionAttribute
为以下内容:
// C#:
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
Registry.ClassesRoot.CreateSubKey(
GetSubKeyName ));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(
GetSubKeyName(type,InprocServer32),true);
key.SetValue(,
System.Environment.SystemDirectory + @\mscoree.dll,
RegistryValueKind.String);
}
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{
Registry.ClassesRoot.DeleteSubKey(
GetSubKeyName(type,Programmable),false);
}
私有静态字符串GetSubKeyName(类型类型,
string subKeyName)
{
System.Text.StringBuilder s =
new System .Text.StringBuilder();
s.Append(@CLSID\ {);
s.Append(type.GUID.ToString()。ToUpper());
s.Append(@} \);
s.Append(subKeyName);
return s.ToString();
}
'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
私有共享函数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)
返回s.ToString
结束函数
RegAsm
,但尝试在Visual Studio安装项目中使用时失败。
[SystemFolder]
属性的默认值,这相当于 System。
的键。InprocServer32
在您之前创建的 CLSID\\ {GUID}
键下。然后右键单击新的 InprocServer32
键,选择新建,然后选择字符串值。结果将是一个名为新值#1
的新值,但您将处于编辑模式,您可以重命名它。您要在此处执行的操作是删除所有字符,然后按Enter键。通过从名称中删除所有字符,您将创建一个默认值,并且注册表值的图标将自动重命名为(默认)。然后右键单击此默认值图标,并选择属性窗口。在属性窗口中,将Value属性设置为[SystemFolder] mscoree.dll
(不带引号)。
Versions
What I am trying to do
What I've tried
The question
RegAsm
, but none how to correctly use a Setup Project to register an automation add-in, which is a little different from your standard COM add-in.Programmable
at HKEY\_CLASSES\_ROOT\CLSID\\{GUID}
, where {GUID}
is the GUID of your COM-visible class.// 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:
<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
ComRegisterFunctionAttribute
is automatically called by RegAsm
when the assembly for this class is registered. The method marked by the ComUnregisterFunctionAttribute
is automatically called by RegAsm
when the assembly for this class is being unregistered via the /u
switch.ComRegisterFunctionAttribute
and ComUnregisterFunctionAttribute
are completely ignored when installing via a Visual Studio Setup Project.RegAsm
using the /regfile
switch in order to generate a .REG file containing all of the required registry keys. It is this .REG file that is then utilized then the .MSI package is run at the client site.
/regfile
option to create a .reg file
containing the registry entries
required to get the information for
step 1, and this .reg file is
internally imported into the setup
project. So if you want to see what
class registration entries Visual
Studio will create in the MSI setup,
you can run Regasm yourself with the
/regfile
option/regfile
switch, however, I noticed that the Programmable
switch was not being included. I then put logging within my methods marked by the ComRegisterFunctionAttribute
and ComUnregisterFunctionAttribute
and found that they are both called when running RegAsm
without the /regfile
switch, but are not called when run with the /regfile
switch, nor are they called when run via the .MSI package created by the Visual Studio Setup Project.
/regfile
option to
generate a .reg file that contains the
registry entries instead of making the
changes directly to the registry. You
can update the registry on a computer
by importing the .reg file with the
Registry Editor tool (Regedit.exe).
Note that the .reg file does not contain any registry updates that can
be made by user-defined register
functions.Programmable
key ourselves. This can be done as follows:
CLSID
under HKEY_CLASSES_ROOT
by right-clicking on the HKEY_CLASSES_ROOT
folder, then choosing 'New', and then 'Key'.CLSID
key, add a new key named for your GUID, including the curly braces.Programmable
. You don't need to put any value within this key; however, we do need to force it to be created. Therefore, right-click on the Programmable
key and choose 'Properties Window'. Then change the AlwaysCreate
property to True
.InprocServer32
key is simply mscorree.dll
, which is sufficient for .NET to find it, but causes Excel to complain. The solution is to make sure that the default value for the InprocServer32 key includes the full path to your system directory. For example, on 32 bit windows, it should read C:\Windows\system32\mscoree.dll
. This path needs to vary, however, depending on the system it is installed on. So this path should not be hard-coded.ComRegisterFunctionAttribute
and ComUnregisterFunctionAttribute
to be the following:// C#:
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
Registry.ClassesRoot.CreateSubKey(
GetSubKeyName(type, "Programmable"));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(
GetSubKeyName(type, "InprocServer32"), true);
key.SetValue("",
System.Environment.SystemDirectory + @"\mscoree.dll",
RegistryValueKind.String);
}
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{
Registry.ClassesRoot.DeleteSubKey(
GetSubKeyName(type, "Programmable"), false);
}
private static string GetSubKeyName(Type type,
string subKeyName)
{
System.Text.StringBuilder s =
new System.Text.StringBuilder();
s.Append(@"CLSID\{");
s.Append(type.GUID.ToString().ToUpper());
s.Append(@"}\");
s.Append(subKeyName);
return s.ToString();
}
'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
RegAsm
on the local machine, but fails when attempting to use this within a Visual Studio Setup Project.[SystemFolder]
property, which is equivalent to the System.Environment.SystemDirectory
call used within Eric Carter's code, above.InprocServer32
under your CLSID\\{GUID}
key that we created previously. Then right-click on the new InprocServer32
key and choose 'New' then 'String Value'. The result will be a new Value named New Value #1
, but you will be in edit mode allowing you to re-name it. What you want to do here is delete all the characters and then hit enter. By deleting all the characters from the name, you are creating a default value and the icon for the registry value will be automatically renamed "(Default)". Then right-click on this Default Value icon and choose 'Properties Window'. Within the properties window, set the Value property to "[SystemFolder]mscoree.dll"
(without the quotes).