【问题标题】:How to expose class array parameter to COM using Interopservices?如何使用 Interopservices 向 COM 公开类数组参数?
【发布时间】:2014-01-20 06:14:41
【问题描述】:

我已经搜索了几天,仍然没有找到正确的答案。我确实找到了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 数组。我收到对象不匹配错误。需要使用 GetData() 函数将这些数据作为对象属性的一部分进行检索。我完全不知道该怎么做。我可以从 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 进行设置。这也不起作用,我得到同样的错误“类型不匹配”。

我错过了什么?

【问题讨论】:

    标签: c# arrays vb6 com-interop


    【解决方案1】:

    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();
            }
        }
    }
    

    【讨论】:

    • 感谢您的建议,但这并不能解决问题。我现在没有收到“错误类型不匹配”,但我看不到数组,甚至无法在 VB6 代码中将 Accounts 识别为数组,上面的打印语句。运行时错误现在是“参数数量错误或属性分配无效”。如果我在我的 VB6 代码中创建一个 Variant 类型的数组,并尝试使用 data.ProcessingInfo.Accounts 中的数据进行设置,我仍然会收到类型不匹配错误。
    • @Norseratio,感谢您一直以来的努力。对不起,我已经很久才回到这个话题。不幸的是,这似乎不是这种情况下的解决方案。我发现,允许我访问数组中任何实际数据的唯一方法是将 ProcessingInformation 上的类接口从 None 更改为 AutoDual。这对我来说不是最好的情况,它允许访问 ProcessingInformation 中不属于界面的其他项目。
    猜你喜欢
    • 2010-09-09
    • 1970-01-01
    • 2011-01-01
    • 1970-01-01
    • 2011-09-07
    • 1970-01-01
    • 2010-12-31
    • 1970-01-01
    • 2012-09-20
    相关资源
    最近更新 更多