将对象数组从 C# 返回到 COM 中的 C

Posted

技术标签:

【中文标题】将对象数组从 C# 返回到 COM 中的 C【英文标题】:return array of object from C# to C in COM 【发布时间】:2013-04-30 06:56:03 【问题描述】:

我正在使用 COM 在 C++ 和 C# 之间进行通信。

我在 C# 中有以下类

    电子邮件地址

    /// <summary>
    /// Email Address
    /// </summary>
    public class EmailAddress
    
        /// <summary>
        /// SMTP Address
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]        
        public string Address;
    
        /// <summary>
        /// Name
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string Name;
    
    

    邮箱

    /// <summary>
    /// MailBox Entity
    /// </summary>   
    public struct MailBoxEntity
    
        /// <summary>
        /// SMTP Address
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string SMTPAddress;
    
        /// <summary>
        /// Mailbox Display Name
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string Name;
    
        /// <summary>
        /// Mailbox Server Name
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string sServerName;
    
    

    EmailEntity(尚未实现将包含每个字段的属性的 IEmailEntity)

    /// <summary>
    /// Class for Email Entity
    /// </summary>
    public class EmailEntity : IEmailEntity
    
        /// <summary>
        /// BccRecipients
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray)]
        public EmailAddress[] BccRecipients;
    
        /// <summary>
        /// Body
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string Body;
    
        /// <summary>
        /// CcRecipients
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray)]
        public EmailAddress[] CcRecipients;
    
        /// <summary>
        /// Culture
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string Culture;
    
        /// <summary>
        /// DateTimeCreated
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string DateTimeCreated;
    
        /// <summary>
        /// DateTimeReceived
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string DateTimeReceived;
    
        /// <summary>
        /// DateTimeSent
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string DateTimeSent;
    
        /// <summary>
        /// FromAddress
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string FromAddress;
    
        /// <summary>
        /// FromName
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string FromName;
    
    
        /// <summary>
        /// HasAttachments
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string HasAttachments;
    
        /// <summary>
        /// Id
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string Id;
    
        /// <summary>
        /// Importance
        /// </summary>
       [MarshalAs(UnmanagedType.BStr)]
        public string Importance;
    
        /// <summary>
        /// LastModifiedName
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string LastModifiedName;
    
        /// <summary>
        /// LastModifiedTime
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string LastModifiedTime;
    
        /// <summary>
        /// MimeContent
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string MimeContent;
    
        /// <summary>
        /// ParentFolderId
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string ParentFolderId;
    
        /// <summary>
        /// Original Mailbox
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public MailBoxEntity OriginalMailBox;
    
    
        /// <summary>
        /// ParentFolderName
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string ParentFolderName;
    
        /// <summary>
        /// ReceivedByAddress
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string ReceivedByAddress;
    
        /// <summary>
        /// ReceivedByName
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string ReceivedByName;
    
        /// <summary>
        /// Size
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string Size;
    
        /// <summary>
        /// Subject
        /// </summary>
        [MarshalAs(UnmanagedType.BStr)]
        public string Subject;
    
        /// <summary>
        /// ToRecipients
        /// </summary>
        [MarshalAs(UnmanagedType.ByValArray)]
        public EmailAddress[] ToRecipients;
    
    
    

如何访问从 C# 中的函数返回的 EmailEnity 对象数组(在 C++ 中) 并阅读 EmailEntity 类的字段。请注意,EmailEntity 类包含像这样的成员 EmailAddress[] 本身是一个对象数组。 我计划实现接口 IEmailEntity,其中包含访问 EmailEntity 字段的属性 并使用它来访问 C++ 中的字段。这样做对吗?

如何在 C++ 中访问复杂的字段成员,例如 EmailAddress (EmailAddress[] ToRecipients) 的数组。

请提出建议。

谢谢

【问题讨论】:

【参考方案1】:

您可以像这样简化 .NET 代码(删除所有应该自动完成的 MarshalAs):

[ComVisible(true)]
public class MyRootClass : IMyRootClass // some class to start with

    public IEmailEntity[] GetEntities()
    
        List<IEmailEntity> list = new List<IEmailEntity>();
        for(int i = 0; i < 10; i++)
        
            EmailEntity entity = new EmailEntity();
            List<IEmailAddress> addresses = new List<IEmailAddress>();
            addresses.Add(new EmailAddress  Name = "Joe" + i );
            entity.BccRecipients = addresses.ToArray();
            entity.Body = "hello world " + i;
            list.Add(entity);
        
        return list.ToArray();
       


[ComVisible(true)]
public interface IMyRootClass

    IEmailEntity[] GetEntities();


public class EmailEntity : IEmailEntity

    public IEmailAddress[] BccRecipients  get; set; 
    public string Body  get; set; 


public class EmailAddress : IEmailAddress

    public string Address  get; set; 
    public string Name  get; set; 


[ComVisible(true)]
public interface IEmailAddress

    string Address  get; set; 
    string Name  get; set; 


[ComVisible(true)]
public interface IEmailEntity

    IEmailAddress[] BccRecipients  get; set; 
    string Body  get; set; 
    // to be continued...

要将它与 C++ 一起使用,您需要注册 DLL 并构建一个 .TLB(类型库文件),如此处类似答案中所述:Implement a C# DLL COM File In Unmanaged C++ Program

然后,您可以在 C++ 中访问这些类,如下所示:

#include "stdafx.h"
#import  "c:\MyPathToTheTlb\YourAssembly.tlb" // import the COM TLB

using namespace YourAssembly;

int _tmain(int argc, _TCHAR* argv[])

  CoInitialize(NULL);
  IMyRootClassPtr ptr(__uuidof(MyRootClass));
  CComSafeArray<IUnknown*> entities = ptr->GetEntities(); // CComSafeArray needs atlsafe.h in the PCH
  for(int i = entities.GetLowerBound(0); i <= entities.GetUpperBound(0); i++)
  
    IEmailEntityPtr entity;
    entities.GetAt(i).QueryInterface(&entity);
    _bstr_t body = entity->Body;
    printf("%S\n", body.GetBSTR());

    CComSafeArray<IUnknown*> recipients = entity->BccRecipients;
    for(int j = recipients.GetLowerBound(0); j <= recipients.GetUpperBound(0); j++)
    
      IEmailAddressPtr address;
      recipients.GetAt(j).QueryInterface(&address);
      _bstr_t name = address->Name;
      printf(" %S\n", name.GetBSTR());
    
  
  CoUninitialize();

【讨论】:

您需要使用 [InterfaceType] 属性才能使此代码正常工作。目前,接口只能通过后期绑定访问,默认为 ComInterfaceType.InterfaceIsIDispatch。 @HansPassant - 此代码可以正常工作。我相信默认是双重的。 你说得对,把我染成紫色。看起来我必须在这里和那里编辑一些答案:( 调试断言失败。 atlsafe.h 中的表达式 psaSrc!=0 。是否因为正在返回 null entity->BccRecepients 这可能会发生,具体取决于您实际返回的内容。我的示例代码在 BccRecipients 中放置了一个数组,所以我不会得到 NULL。

以上是关于将对象数组从 C# 返回到 COM 中的 C的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 AJAX (jquery) 将嵌套的对象数组传递和接收到 c# WebMethod 中?

C#的枚举数(Enumerator)和可枚举类型(Enumerable)

C#从数组返回对象留下指向数组项的指针

将数组从 JavaScript 传递到 C# 的最佳方法?

将 uint8 字节数组转换为任何 WPF 呈现对象

如何将 JSON 返回反序列化为从 RestSharp 调用到 API 的对象数组?