使用 COM 在 C++ 中实例化 C# 类成员
Posted
技术标签:
【中文标题】使用 COM 在 C++ 中实例化 C# 类成员【英文标题】:Instantiating C# Class Members in C++ using COM 【发布时间】:2013-04-29 08:37:51 【问题描述】:我想在 C++ 中创建一个 C# 类对象并设置其成员字段。 虽然我能够创建一个 C++ 类对象,但我无法访问它的成员并设置成员字段值。
/// <summary>
/// Class for AQS Entity
/// </summary>
[ClassInterface(ClassInterfaceType.None)]
[Guid("70F12A44-B91D-474D-BD70-32B1ACE041D6")]
[ProgId("AQSEntity")]
public class AQSEntity : IEntity
public AQSEntity()
sRecoveryDBName = String.Empty;
arrSourceMailboxesEntity = null;
sQueryString = String.Empty;
[MarshalAs(UnmanagedType.BStr)]
public string sRecoveryDBName = string.Empty;
[MarshalAs(UnmanagedType.ByValArray)]
public MailBoxCollection arrSourceMailboxesEntity;
[MarshalAs(UnmanagedType.BStr)]
public string sQueryString;
IEntity 类定义如下
[Guid("5C71057E-9FD9-47D5-B022-8D5F9C7007D3")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IEntity
在 C++ 中,
IEntity* pTest1 = NULL;
hr = CoCreateInstance(__uuidof(**AQSEntity**),NULL,CLSCTX_INPROC_SERVER,__uuidof(IEntity),(void**)&pTest1);
我想在 C++ 中访问 AQSEntity 类的成员。但我无法访问它们。
pTest1-> sQueryString
给出错误。
'sQueryString' : 不是 'AsigraExchange::IEntity' C:\PROJECTS\COM\COMClient\COMClient.cpp 168
谁能指出我哪里错了。
谢谢, 加根
【问题讨论】:
您的界面完全是空的。向它添加属性和方法。不要添加字段。 还有其他实现 IEntity 的类。如果我向 IEntity 添加属性和方法,这些类不能从 IEntity 继承。 【参考方案1】:一切都按照应有的方式运行 :)
在您的 C++ 项目中,您可以访问在您的 IEntity
接口上声明的所有方法,这些方法都没有。
您的实现,即AQSEntity
类,应该实现所有IEntity
成员。现在在该类中声明的方法是该类的成员,它们与IEntity
没有任何关系。
这意味着您需要在IEntity
接口中声明所有必需的方法,然后在AQSEntity
中实现它们。请注意,您还公开了类的字段,而不是方法。您必须定义方法(或属性,将转换为 C++ 端的方法)然后实现它们。比如:
public interface IEntity
public string RecoveryDBName get;
您还必须在界面中指定[MarshalAs]
属性,尽管UnmanagedType.BStr
是字符串的默认值,因此您可以省略它们。
编辑:
基于 cmets,IEntity
似乎只是一个标记接口,不打算作为 API 公开(这里的属性可能是更好的选择,因为 IEntity
无论如何都不会在客户端使用)。
在这种情况下,有两种选择:
1) 更好的方法,虽然它需要更多的工作:从IEntity
派生IAQSEntity
接口,在其上声明方法,并在AQSEntity
类上实现它
2) 更少的工作,但更脆弱:将 AQSEntity
标记为 ClassInterfaceType.AutoDual
而不是 ClassInterfaceType.None
- 这会将成员公开给 COM 客户端,但版本化会更加困难,并且还会公开基本类型成员。
这是我会选择的:
[ClassInterface(ClassInterfaceType.None)]
...
[Entity] // instead of IEntity marker interface
public class AQSEntity : IAQSEntity
public string RecoveryDbName get;
[Guid("...")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IAQSEntity // no base interface IEntity!
string RecoveryDbName get;
使用Entity
属性而不是IEntity
标记接口的唯一缺点是,如果您想将该接口用作泛型的约束
【讨论】:
还有其他实现 IEntity 的类。如果我向 IEntity 添加属性和方法,这些类不能从 IEntity 继承。 那么你需要从实体派生的IAQS
接口。除了 COM,您如何在 C# 中通过 IEntity
访问 AQSEntity
成员?没办法-在您的情况下,它似乎是一个标记界面。另一种选择是使用ClassInterfaceType.AutoDual
而不是ClassInterfaceType.None
,但这被认为是一种不好的做法。
我正在根据这篇文章中的建议更改我的设计。谢谢
请务必阅读ClassInterfaceType.AutoDual
上的文档,尤其是如果您走这条路的注意事项 - 它在版本控制和公开基本类型方法方面存在缺陷。【参考方案2】:
您的界面确实不包含任何成员。您需要将成员放入接口中,然后在您的类中实现该接口。
【讨论】:
还有其他实现 IEntity 的类。如果我向 IEntity 添加属性和方法,则这些类不能从 IEntity 继承。我没有向接口添加字段 嗯,这是你的问题,而不是技术问题。为什么要为其他类实现 COM 接口而不是要向 COM 公开的类?不要这样做。您不能添加字段的事实应该告诉您有关您的类设计的一些信息。不要使用公共字段。以上是关于使用 COM 在 C++ 中实例化 C# 类成员的主要内容,如果未能解决你的问题,请参考以下文章