【问题标题】:Exposing C# struct to COM breaks for VB6 app将 C# 结构暴露给 VB6 应用程序的 COM 中断
【发布时间】:2009-07-25 21:55:13
【问题描述】:

最后更新时间: 2009-08-11 美国东部时间下午 2:30

几天前,我在this question 上发布了一些非常奇怪的问题。好吧,我弄清楚了具体是什么导致一台机器上的构建无法在其他机器上运行,甚至想出了一个解决方法,但现在它给我留下了一个很好的具体问题:为什么?

为了重现该问题,我创建了一个新的 InteropUserControl 并执行以下操作:

  1. 添加一个新的public struct MyStruct
  2. 给它一个 GUID 和 ComVisible 属性
  3. _InteropUserControl接口中添加GetMyStruct成员,并在InteropUserControl中实现。

MyStruct:

[Guid("49E803EC-BED9-4a08-B42B-E0499864A169")]
[ComVisible(true)]
public struct MyStruct {
    public int mynumber;
}

_InteropUserControl.GetMyStruct():

[DispId(7)]
void getMyStruct( int num, ref MyStruct data );

(我也尝试返回 MyStruct 而不是通过引用传递。)

InteropUserControl.GetMyStruct() 实现:

public void getMyStruct( int num, ref MyStruct data ) {
    data = new MyStruct();
    data.mynumber = num * 2;
}

我还签署了程序集并将其安装到 GAC 并在 Regasm 注册。将其添加到新的 VB6 项目并添加对 GetMyStruct() 的调用并在我们的构建机器上编译后,它拒绝在其他机器上运行。

为了解决这个问题,我不得不向 COM 公开一个类而不是结构,并且基本上将 GetMyStruct 更改为:

public void GetMyData( int num, MyClass data ) {
    data.mynumber = num * 2;
}

在我的实际项目中,我在内部检索结构,然后将结构中的所有字段值复制到客户端传递给方法的类实例上的匹配成员。

那么为什么结构会导致这种行为,而类却可以正常工作呢?将结构暴露给 COM 以便在 VB6 中使用有什么魔力吗?

我认为这可能与 OLE 自动化有关。

注意:我也尝试返回结构而不是使用 ref 参数,但这并没有改变行为。

编辑以添加项目模板的链接:

Interop Forms Toolkit 2.0 是原始的 VB.NET 项目模板和 dll。我没有引用 dll,所以你可能不需要安装它。

C# Translations of templates on CodeProject 是我用来创建我的(项目模板,而不是项目模板)。 VB.NET 版本自动生成__InteropUserControl 事件接口、_InteropUserControl 接口和一些相关属性。这些是在 C# 版本中显式编码的,这就是两者之间的所有不同之处。

【问题讨论】:

  • 在getMyStruct中,什么是ms?应该是数据吗?
  • 你能提供一个简短但完整的复制吗?
  • @SwDevMan81:是的,应该。错字就我而言。它会在一秒钟内修复。
  • @AnthonyWJones:它太大了。 InteropUserControl 项目模板从 396 行 ActiveXControlHelpers.cs 开始,它具有注册/取消注册功能,InteropUserControl.cs 超过 280 行。但是,我已经提供了我添加到此起始模板的所有内容,并且我将在我的问题中添加指向项目模板的链接。您将能够获得相同的代码,但重现性也与编译机的配置有关。
  • 在顶部,public class MyStruct 应该是代码中的 public struct MyStruct 吧?我不是想成为一个混蛋,只是想确保我拥有正确的东西。

标签: c# com vb6 struct


【解决方案1】:

我想我找到了解决这个问题的方法。 我遇到了同样的问题,通过传递结构调用互操作库的方法时 vb6 中断。这是我为测试 DLL 互操作而创建的项目,所以我的项目中只有一个表单。但我有另一个项目(主应用程序)具有相同的参考,它工作正常。

阅读 Joel 的帖子后,我想测试他的解决方案,事实上 id 确实有效(使用类而不是结构)。但是我在使用结构的地方还有其他互操作,所以我非常担心我的应用程序在任何时候都可能失败。此外,我不想做额外的工作来创建和公开接口以及替换结构的类。

所以,我从表单中取出代码并将其移动到模块中的公共子目录中。它立即起作用。顺便说一句,这就是我在主应用程序中实现调用的方式,它工作正常。

我希望它可以帮助其他人。

【讨论】:

  • 有趣。我将不得不尝试再次设置这样的测试项目并从 VB6 中的模块调用。不幸的是,这对我的应用程序没有帮助,因为主要的互操作对象是一个必须驻留在表单上的控件(视觉显示)。但是,这是一个非常有趣的信息。
  • 我决定继续并将您的答案标记为已接受。在我的情况下,将调用代码移动到模块是不可能的,但它似乎是两种解决方案中的一种。
【解决方案2】:

暴露一个人有什么魔力吗 struct 到 COM 以便在 VB6 中使用?

MSDN 上的文章COM Data Types* 说支持结构。具体来说,MSDN 文章说 COM 结构定义为:

ByRef VALUETYPE< MyStruct >

在页面底部还有几篇关于自定义 COM 可调用包装器的文章,您不妨查看这些文章。

  • 编辑 (2016):原始链接已损坏,因此我将其修复为 .Net Framework 3.5 版。

【讨论】:

  • +1:感谢您的尝试。我知道他们应该工作(在某种程度上,他们确实如此)。我也尝试了一些自定义,尤其是MarshalAsAttribute,但没有任何改变我描述的行为。
猜你喜欢
  • 1970-01-01
  • 2011-06-19
  • 2010-12-24
  • 1970-01-01
  • 1970-01-01
  • 2013-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多