【问题标题】:Pass C# object to COM by value按值将 C# 对象传递给 COM
【发布时间】:2016-07-29 12:23:58
【问题描述】:

我正在尝试使用 C# 中的 COM 接口,该接口公开 tlbimp 生成的以下接口:

[Guid("7DDCEDF4-3B78-460E-BB34-C7496FD3CD56")]
[TypeLibType(TypeLibTypeFlags.FDual | TypeLibTypeFlags.FNonExtensible | TypeLibTypeFlags.FDispatchable)]
public interface IFred 
{
    [DispId(1)]
    IBarney Pall { get; set; }
}

[Guid("E390230E-EE9C-4819-BC19-08DAB808AEA9")]
[TypeLibType(TypeLibTypeFlags.FDual | TypeLibTypeFlags.FNonExtensible | TypeLibTypeFlags.FDispatchable)]
public interface IBarney
{
    [DispId(1)]
    double Wilma { get; set; }
}

生成的包装程序集不包含IBarney 接口的实现。我创建了一个实现IBarney 接口的C# 结构,如下所示:

[Guid("2C61BA37-7047-43DB-84B1-83B4268CF77B")]
[ComVisible(true)]
public struct Barney : IBarney
{
    public double Wilma { get; set; }
}

哪个“有效”,现在的问题是,Barney 实例是按值编组还是按引用编组?由于涉及到网络开销,这一点很重要。理想情况下执行如下操作:

fredInstance.Pall = new Barney { Wilma = 0.37 };

将导致单次网络往返。我如何验证这一点,或者如何告诉 COM 互操作我的 Barney 结构应该始终按值编组?

更新:

鉴于 Hans Passant 的评论。设计这个的“正确”方法是什么?允许一个简单结构用作 COM 接口的“属性”值所需的 IDL 是什么?查看生成接口的 IDL,我目前正在使用添加一个带有默认 IBarney 接口的 coclass 声明就足够了,对吧?

【问题讨论】:

  • 无需检查,COM 从不关心对象是如何实现的,只对接口指针起作用。这将是每个属性访问的往返。从技术上讲,这可以通过自定义代理/存根来解决,但这对于 .NET 来说是遥不可及的。考虑实施 IPersistStream。
  • @HansPassant:我猜你的意思是在 COM/native 端实现 IPersistStream?由于谷歌搜索它只会显示对非 .NET 内容的引用。
  • 您是否在两端都使用 C# 工作?或者是否涉及任何其他语言?即:你为什么首先创建COM接口?为什么你使用idl来定义你的接口?您需要自动化兼容接口吗?你知道“纯”COM 和 COM+自动化之间的区别吗?
  • 我在一家同时使用 .NET 和 C++ 的公司工作,两个世界之间的互操作是使用 COM 完成的。我个人参与了 .NET 开发。要更改 IDL/COM 部分,必须进行一些协商,但原则上可以更改。 COM 接口的原始要求之一是它们与 OLE 自动化兼容。我(正如您可能猜到的)对 COM 不了解,我不知道 COM 和 COM+ 自动化之间的区别。感谢任何指向资源的指针。
  • 好的,所以你需要 C++ 和自动化(我说的不是 COM+,而是 COM+ 自动化 :-)。在这种情况下,您必须知道自动化将大大减少您可以使用的类型(它也有其优点):msdn.microsoft.com/en-us/library/cc237562.aspx(请注意,并非所有客户端都支持 VT_RECORD,这是一个较晚的添加)。最简单的是使用 SAFEARRAY(UI1 的)或 VARIANT(可以包装任何自动化类型)。 PS:当您想发表评论时,不要忘记添加@ 。我刚刚路过,发现你回复了我

标签: c# com marshalling com-interop


【解决方案1】:

几个cmets...不知道这是否会是一个答案...

1) 我认为你应该让你的界面 [ComVisible(true)]

2) 为什么将 Barney 定义为结构?应该是一堂课。与 C++ 中类和结构之间的唯一区别是私有成员和公共成员的默认区别不同,C# 结构和类根本不同。

【讨论】:

  • Ad 1) 代码取自 tlbimp 生成的程序集的反汇编,我假设它在生成的代码中某处使用 [assembly: ComVisible(true)]。广告 2) Barney 是一个结构,强调它应该被视为一个值类型,在示例中是一个双精度的“转储”容器。实际上,它是一种包含两个双精度值的数据类型。我已经将它实现为 .NET 端的结构,并且一切都“正常工作”。然而,正如汉斯提到的,这仍然会导致许多远程调用。我只想将结构作为单个数据项传递到“围栏”的另一侧。
  • 如果您担心网络开销并且想要初始化结构,请尝试以文本 blob 的形式传递——XML 或 JSON,甚至是逗号分隔的列表。
  • 我并不一定担心额外的开销,我只是觉得当前的解决方案是“次优的”,并且想知道当前的情况是否可以通过符合以下要求的方式得到改善COM 是如何“应该被使用”的。我对引入 hack 不感兴趣,比如传递必须在另一端解析的文本字符串。
  • 我认为你犯了两个基本错误。第一个是你肯定还没有测量任何东西,你不知道这是否是实际上你需要做的事情。第二个是更大的一个,问题中根本没有暗示这是实际上一个DCOM场景。属性访问实际上可能很慢并且会产生网络往返开销的场景。当您从 ServicedComponent 类派生类时,仅在 .NET 中直接支持,显然您的结构不支持。问题太大了,看不到你应该实施什么。
猜你喜欢
  • 2012-08-21
  • 2018-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多