.net - 如何在自动化服务器列表中安装和注册用 VB.NET 编写的 COM Server for Excel?

标签 .net excel com installation

版本

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 的自动化服务器列表中可见。

我试过的

以下是类型库的安装设置,它们的缺陷在编译时和安装时很明显:

vsdrfComSelfReg

  • 编译安装项目时没有警告
  • 模块 xxx.tlb 注册失败。 HRESULT -2147024703
  • 组件的 ProgID 和 GUID 在注册表中设置,但组件未出现在自动化服务器列表中

  • vsdrfDoNotregister
  • 编译时没有警告
  • 安装有效,但当然 TLB 未注册

  • VSDRFCOM
  • 编译时警告:警告:无法为名为“xxx.tlb”的文件创建注册信息
  • 安装时未注册类型库

  • 正确的设置应该是 vsdrfCOM,如 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.



    许多困难似乎是 Vista 特有的。特别是,使用 REGCAP utility从 .TLB 文件生成 .REG 文件在 Vista 中不起作用。如果不是这样,也许 this advice would be useful .相反,它在工作时会生成空的 .REG 文件。

    我已经尝试了 this StackOverflow post 中的所有建议.那篇文章对技术问题有很好的描述:

    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.



    问题

    任何人都知道如何使安装注册组件和类型库?我无权访问 Windows XP 机器。

    详细说明为什么这很糟糕

    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.



    在 Excel 中并不是这样。
  • 用户打开工作表并尝试引用 UDF。未找到它,因为未加载 DLL。 失败
  • 用户转到 Home|Excel Options|Add-Ins|Excel Add-Ins+Go,并且 COM Server 未列在 Add-Ins 对话框中。 失败
  • 用户然后按自动化服务器以获取可用自动化服务器的列表。 DLL 不存在。 失败
  • 用户返回到“加载项”对话框并选择“浏览”,导航到安装目录,然后选择 DLL(“XXX 不是有效的加载项”)或类型库(“您选择的文件不包含新自动化服务器,或者您没有足够的权限...”)。 失败

  • 据我所知,用户必须从命令行运行 regasm.exe 才能使 Excel UDF/COM 服务器可用。如果告诉人们从命令行运行 regasm 以将加载项安装到 Excel,您有何感受?

    编辑 2009-10-04

    Mike 在下面的评论和说明很棒。我不知道的关键是安装程序具有用于添加注册表项的内置注册表编辑器。哦,Microsoft 安装程序没有调用具有 ComRegisterFunctionAttribute 属性的安装函数。我已经从他引用的来源获得了有关编写安装程序功能的说明。

    最佳答案

    我在周末尝试部署了一个自动化插件。事实证明它非常复杂(这对您来说并不奇怪!)而且我在互联网上绝对找不到有关如何正确执行此操作的资源。没有任何。

    有资料来源描述如何使用 RegAsm ,但没有说明如何正确使用安装项目来注册自动化加载项,这与您的标准 COM 加载项略有不同。

    幸运的是,我能够解决它。这是我发现的:

    如果您阅读了一些关于如何创建和注册 C# 自动化加载项的文章,您会发现需要添加一个名为 Programmable 的注册表项。在 HKEY\_CLASSES\_ROOT\CLSID\\{GUID} ,其中 {GUID}是您的 COM 可见类的 GUID。

    这通常通过添加一对由 ComRegisterFunctionAttribute 标记的方法来完成。和 ComUnregisterFunctionAttribute .一个很好的例子来自文章 Writing Custom Excel Worksheet Functions in C#加类·贝瑞:

    // 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
    
    ComRegisterFunctionAttribute标记的方法由 RegAsm 自动调用注册此类的程序集时。 ComUnregisterFunctionAttribute标记的方法由 RegAsm 自动调用当此类的程序集通过 /u 注销时转变。

    问题在于ComRegisterFunctionAttributeComUnregisterFunctionAttribute通过 Visual Studio 安装项目安装时完全忽略。

    这起初似乎令人惊讶,因为 Visual Studio 安装项目运行 RegAsm使用 /regfile切换以生成包含所有必需注册表项的 .REG 文件。然后使用此 .REG 文件,然后在客户端站点运行 .MSI 包。

    来自 Build and Deploy a .NET COM Assembly菲尔·威尔逊:

    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 /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 运行 RegAsm 时然而,我注意到 Programmable开关不包括在内。然后我将日志记录放入我标记为 ComRegisterFunctionAttribute 的方法中。和 ComUnregisterFunctionAttribute并发现它们在运行 RegAsm 时都被调用了没有 /regfile开关,但在使用 /regfile 运行时不会被调用开关,在通过 Visual Studio 安装项目创建的 .MSI 包运行时也不会调用它们。

    help files for Regasm.exe确认这一点(强调):

    You can use the /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关键我们自己。这可以按如下方式完成:
  • 在安装项目中,打开注册表编辑器。创建一个名为 CLSID 的新 key 下 HKEY_CLASSES_ROOT通过右键单击 HKEY_CLASSES_ROOT文件夹,然后选择“新建”,然后选择“ key ”。
  • CLSID键,添加一个以您的 GUID 命名的新键,包括花括号。
  • 在您添加的新 GUID 键下,添加一个名为 Programmable 的键。 .您不需要在此键中放置任何值;但是,我们确实需要强制创建它。因此,右键单击 Programmable键并选择“属性窗口”。然后更改AlwaysCreate属性(property)到True .

  • 完成此操作后,您不再需要标有 ComRegisterFunctionAttribute 和 ComUnregisterFunctionAttribute 的方法,但是当您通过 RegAsm 而不是通过安装项目安装时,我仍然会将它们保留在那些场合。

    此时,您已准备好部署。构建您的解决方案,然后右键单击您的安装项目并选择“构建”。然后,您可以使用创建的 Setup.exe 和 .MSI 文件部署到客户端计算机。

    但是,还需要考虑的是,当通过 Excel 的加载项对话框添加自动化加载项时,将显示一条错误消息,指出“找不到 Mscoree.dll,您要删除加载项吗? ”或非常相似的东西。可以忽略此错误消息,无论您回答什么,您的加载项都将运行,但它可能会让安装加载项的客户端感到震惊。

    这种情况以及如何解决它的说明在文章 Writing user defined functions for Excel in .NET 中有很好的描述。通过埃里克卡特。

    问题在于 InprocServer32 的默认值关键是 mscorree.dll ,这足以让 .NET 找到它,但会导致 Excel 提示。解决方案是确保 InprocServer32 键的默认值包括系统目录的完整路径。例如,在 32 位窗口上,它应该是 C:\Windows\system32\mscoree.dll .但是,此路径需要有所不同,具体取决于安装它的系统。所以这条路径不应该被硬编码。

    Eric Carter 通过修改 ComRegisterFunctionAttribute 标记的方法来处理这个问题。和 ComUnregisterFunctionAttribute如下:
    // 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,这相当于:
    '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 时正确注册程序集的问题完全相同。在本地机器上,但在 Visual Studio 安装项目中尝试使用它时失败。

    同样,解决方案是添加我们自己的注册表项。然而,这一次,我们必须创建一个使用 [SystemFolder] 的默认值。属性,相当于 System.Environment.SystemDirectory上面 Eric Carter 的代码中使用的调用。

    为此,添加一个名为 InprocServer32 的 key 。在您的 CLSID\\{GUID} 下我们之前创建的 key 。然后右击新建InprocServer32键并选择“新建”,然后选择“字符串值”。结果将是一个名为 New Value #1 的新值。 ,但您将处于编辑模式,允许您重命名它。您在这里要做的是删除所有字符,然后按回车键。通过删除名称中的所有字符,您将创建一个默认值,并且注册表值的图标将自动重命名为“(默认)”。然后右键单击此默认值图标并选择“属性窗口”。在属性窗口中,将 Value 属性设置为 "[SystemFolder]mscoree.dll" (没有引号)。

    然后您可以右键单击您的安装项目并选择“构建”,然后您就可以部署了。

    只有最后一件事需要担心。如果您安装到 Excel 2007 或更高版本,上述内容将 100% 工作。但是,如果您在 Excel 2003 或更低版本上安装,则需要包括以下内容:

    FIX: Add-ins, smart documents, or smart tags that you create by using Microsoft Visual Studio 2005 do not run in Office

    Divo here详细解释了如何部署它.

    如果您不应用此修复程序,一切都会正确注册,您甚至可以成功添加自动化加载项——一切看起来都很好——但您的工作表功能将失败,您仍然会得到#NAME?结果错误。 (但是,同样,对于 Excel 2007 及更高版本,您不需要这个。)

    所以,最终,TLB 无关紧要。在我所有的测试中,我使用了没有/TLB 开关的 RegAsm,并且在通过设置项目注册时没有包含任何 TLB。所以我从 Vista 中做到这一点没有问题,which has issues when attempting to add a TLB file to a Setup Project .

    我希望这会有所帮助,休,并希望其他任何人将来可能会偶然发现这个线程......

    麦克风

    关于.net - 如何在自动化服务器列表中安装和注册用 VB.NET 编写的 COM Server for Excel?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1506858/

    相关文章:

    c# - 从 .NET DLL 文件生成 PDB?

    .net - app.config 中的多个相同的自定义配置部分

    excel - 需要一个查找功能来搜索一张纸的一列

    Excel VBA : Delete entire row if cell in column A is blank (Long Dataset)

    excel - Excel 运算顺序(不同的结果,仅限除法/乘法)

    .net - 尝试访问 NHibernate 中的类型鉴别器字段

    c# - 为什么无法捕获 MissingMethodException?

    c# - 使用 ComVisible(false) 时指定 Guid 有什么意义吗?

    C# COM 互操作 : exposing function with a managed object as parameter

    javascript - 在 Firefox 或 Chrome 中运行 COM 对象