【问题标题】:Is there a cleaner method of making COM visible applications?是否有更简洁的方法使 COM 可见应用程序?
【发布时间】:2018-07-30 20:53:01
【问题描述】:

给定一个特定的类:

public class Klass
{
    public int value;
    public void doSomething(){
        return;
    }
}

据我所知,要使 COM 类可见,需要做几件事:

  1. 导入System.Runtime.InteropServices
  2. 为类创建一个接口。
  3. 扩展创建的界面。
  4. 创建 2 个唯一的 GUID,一个用于接口,另一个用于类。
  5. 向界面添加调度 ID。

生产类似的东西:

[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
public interface IKlass
{
    [DispId(0)]
    public int value;
    [DispId(1)]
    public void doSomething();
}

[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"),
    ClassInterface(ClassInterfaceType.None)]
public class Klass : IKlass
{
    public int value;
    public void doSomething(){
        return;
    }
}

在我看来,生成的代码看起来非常糟糕……问题是,有没有一种更简单的方法来创建这些 COM 接口?我可以想象自己修改构建过程以提供interop 功能。例如

public interop class Klass
{
    public interop int value;
    //...
}

但是,这是非标准的,它也存在问题。 Visual Studio / C# 中是否有任何内置功能可以让我更轻松/更清洁地构建 COM 接口?

【问题讨论】:

  • 就我个人而言,使用公共成员变量,尤其是在涉及 COM 时,对我来说是非常错误的。
  • @UweKeim 嗯?怎么会? ThisWorkbook.Sheets
  • 如果您认为这很难看,请尝试使用本机 C++ 编写 COM 服务器。您不知道为您处理了多少复杂性。
  • 由于您反复说“界面”,因此可能没有更清洁的方法。否则,您不需要定义接口。
  • @ZoharPeled 呵呵...根据stackoverflow.com/questions/3699767/…,您可能是对的...“使程序集 COM 可见”是使程序集中的所有公共类型 [ComVisible] 的大锤。我需要试一试!

标签: c# .net


【解决方案1】:

正如Zohar Peled 所建议的,最好的方法是使用RegAsm.exe

  1. 创建一些 C# 类库“TestProject”:

using System.Windows.Forms;
namespace TestProject
{
    // Note. Only public classes are exported to COM!
    public class Test
    {
        // Note. Only public methods are exported to COM!
        public void testIt() {
            MessageBox.Show("Yellow world");
        }
    }
}

重要提示: 只有公共类被导出到 COM。并且只有这些类的公共方法可以通过 COM 对象实例使用。


  1. 签署项目。

  2. 在 AssemblyInfo.cs 中将 [assembly: ComVisible(false)] 设置为 [assembly: ComVisible(true)]注意:您还可以在要公开给 COM 的每个类之前使用属性 [ComVisible(true)]。这只是将默认值设置为true,以便在构建 API 时更容易使用

  3. 构建项目。

  4. 运行 regasm。请记住使用正确版本的 Regasm(32 位/64 位)和适用于您的 .NET 框架的版本:


# .NET v4.5 64-bit
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" -tlb -codebase "C:\Users\sancarn\Desktop\tbd\TestProject\TestProject\bin\Debug\TestProject.dll" -verbose

# .NET v4.5 32-bit
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" -tlb -codebase "C:\Users\sancarn\Desktop\tbd\TestProject\TestProject\bin\Debug\TestProject.dll" -verbose

...

Regasm 应该输出如下内容:

Microsoft .NET Framework Assembly Registration Utility version 4.7.3056.0
for Microsoft .NET Framework version 4.7.3056.0
Copyright (C) Microsoft Corporation.  All rights reserved.

Types registered successfully
Type 'TestProject.Test' exported.
Assembly exported to 'C:\Users\sancarn\Desktop\tbd\TestProject\TestProject\bin\Debug\TestProject.tlb', and the type library was registered successfully

现在您可以在 VBScript 中测试文件,例如:

Dim o As Object
Set o = CreateObject("TestProject.Test")
Call o.testIt

【讨论】:

    【解决方案2】:

    Sancarn 回答了您的问题,但请注意,这会使您项目中的所有与 COM 兼容的类也成为 COM 可见的,这可能是您不希望的(请参阅 herehere)。如果您没有显式设置 UUID,如果您使用 VB 或 VBA 等早期绑定客户端(而不是后期绑定的 VBScript)访问类,那么您在部署时就会遇到问题。

    是的,它不是“干净的”,但 COM 也不是,尤其是当您想将它公开给后期绑定客户端实时 VBScript 时。

    我还将您的公共字段更改为属性,这对公共成员来说更标准:

        [Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
        public interface IKlass
        {
            [DispId(0)]
            public int value {get; set;}
            [DispId(1)]
            public void doSomething();
        }
    

    【讨论】:

    • 感谢您提供额外信息!我个人确实想要一个完全 COM 可见的程序集。如果要禁用此功能或禁用 AssemblyInformation 中的设置,可以始终使用 [ComVisible(false)]。您确定 Guid 是个问题吗?我假设 GUID 将根据您项目的签名密钥从种子生成(因此将是一致的)。另外,是的,您显然不能在 COM 接口中拥有字段,因此确实需要一个可见的 COM get/set
    • @Sancarn 它可能会有所变化(我很久没有做过 COM),但有时您可能会根据编译器获得不同的 GUID。我已经经历了足够多的“DLL 地狱”,想要自己控制所有这些细节。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-14
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    • 2016-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多