如何使用Interopservices将类数组参数公开给COM?

时间:2014-01-02 18:09:48

标签: c# arrays vb6 com-interop

我一直在搜索几天但仍未找到正确的答案。我确实找到了this类似的问题,可能正朝着正确的方向发展。我正在使用VS2008在C#中工作,需要与VB6应用程序通信。我的问题是我需要通过COM公开许多配置类型类,以便VB6应用程序可以访问包含的数据。我做得非常好,直到我的一个类需要公开一个类数组参数。我的C#代码是这样的:

    [Guid("..."),InterfaceType(ComInterface.InterfaceIsDual)]
    public interface iClientComInterop
    {
       [DispID(1) Properties GetData();
    }


    [Guid("..."), ClassInterfaceAttribute(ClassInterfaceType.None),ProgIdAttribute("ClientComInterop"),ComDefaultInterfaceAttribute(typeof(iClientComInterop))]
    public class ClientComInterop : iClientComInterop
    {
        public ClientComInterop()
        {
        }
        public Properties GetData()
        {...}

     }
     [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
     [Guid("...")]
     public interface iProperties
     {
         [DispId(1)]
         int Id{get; }
         [DispId(2)]
         ProcessingInformation ProcessingInfo { get;  }
     }

      [ClassInterface(ClassInterfaceType.None)]
      [ProgId("ConfigurationTypes.Properties")]
      [Guid("...")]
      public class Properties : iProperties
      {
        public int Id
        {
          get ;
          set ;
        }
        public ProcessingInformation ProcessingInfo
        {
          get ;
          set ;
        }

    public Properties()
    {
      ...
    }
  }
  [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
  [Guid("...")]
  public interface iProcessingInformation
  {
    [DispId(1)]
    bool Enabled {get; }
    [DispId(2)]
    AccountInformation[] accounts  {  [return:MarshalAs(UnmanagedType.SafeArray)]get; }

  }
  [ClassInterface(ClassInterfaceType.None)]
  [ProgId("ConfigurationTypes.ProcessingInformation")]
  [Guid("...")]
  public class ProcessingInformation : iProcessingInformation
  {
    public bool Enabled
    {
      get ; 
      set ; 
    }
    public AccountInformation[] Accounts
    {
      get;
      set;
    }     
    public ProcessingInformation()
    {
      ...
    }
  }
  [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
  [Guid("...")]
  public interface iAccountInformation
  {
     [DispId(1)]
     int Type {get; }
     [DispId(2)]
     double balance{ get;  }
  }
  [ClassInterface(ClassInterfaceType.None)]
  [ProgId("ConfigurationTypes.AccountInformation")]
  [Guid("...")]
   public class AccountInformation: iAccountInformation
  {
    public int Type
    {
      get ;
      set ;
    }
    public double balance
    {
      get;
      set;
    }
    public AccountInformation()
    {
      ...
    }
  }

这一切都在VB6对象浏览器中编译,注册和显示正确,但我无法从ProcessingInformation检索AccountInformation数组。我收到了Object Mismatch错误。需要使用GetData()函数将此数据作为对象Properties的一部分进行检索。我完全不知道应该如何解决这个问题。我可以从Properties和ProcessingInformation中提取任何其他信息,但不能从AccountInformation数组中提取信息。

VB6示例:

Public Client As ClientComInterop.ClientComInteropSet
Client = CreateObject("ClientComInterop")
Dim data as ConfigurationTypes.PropertiesSet
data = Client.GetData()
Print "ID: " ; data.ID    ' This works
Print "Process enabled: "; data.ProcessingInfo.Enabled   ' This works
Print "Accounts Type: "; data.ProcessingInfo.Accounts(0).Type  ' error Type mismatch

我还尝试了其他几个方面,例如创建一个本地帐户数组,并尝试使用data.ProcessingInfo.Accounts设置它。这也不起作用,我得到相同的错误“类型不匹配”。

我错过了什么?

1 个答案:

答案 0 :(得分:0)

尝试accounts属性的此签名:

AccountInformation[] accounts  
{  
    [return:MarshalAs(UnmanagedType.SafeArray, 
        SafeArraySubType = VarEnum.VT_VARIANT)] get; 
}

[更新] 我没有VB6,但这对我来说对VBScript有用。我必须承认,在我花费的合理时间内,我找不到更好的方法,包括如何通过索引直接访问元素(即processInfo.Accounts(0)):

<强>的VBScript:

' this works:
For Each a in processInfo.Accounts 
  MsgBox a.balance
Next 

' this doesn't:
MsgBox processInfo.Accounts(0)

<强> C#:

public interface iProcessingInformation
{
    [DispId(2)]
    object[] Accounts
    {
        [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] get;
        set;
    }
}

public class ProcessingInformation : iProcessingInformation
{
    public object[] Accounts
    {
        get
        {
            return new object[] { new AccountInformation() };
        }
        set
        {
            throw new NotImplementedException();
        }
    }
}