暴露给VBA(COM)的C#属性:运行时错误’424’:需要对象

这个C#代码在.NET 4.5 ComVisible程序集中:

C#代码

 [InterfaceType(ComInterfaceType.InterfaceIsDual)] [Guid("22341123-9264-12AB-C1A4-B4F112014C31")] public interface IComExposed { double[] DoubleArray { get; set; } object[] ObjectArray { get; set; } object PlainObject { get; set; } double ScalarDouble { get; set; } } [ClassInterface(ClassInterfaceType.None)] [Guid("E4F27EA4-1932-2186-1234-111CF2722C42")] [ProgId("ComExposed")] public class ComExposed : IComExposed { public double[] DoubleArray { get; set; } public object[] ObjectArray { get; set; } public object PlainObject { get; set; } public double ScalarDouble { get; set; } } 

从Excel 2010 32位VBA,我有以下行为:

VBA代码

 Dim VBArray(1 To 3) As Double VBArray(1) = 1 VBArray(2) = 2 VBArray(3) = 3 Dim oComExposedEarlyBinding As New ComExposed ' Works oComExposedEarlyBinding.ScalarDouble = 5 ' Compile Error: Function or interface marked as restricted, ' or the function uses an Automation type not supported in Visual Basic oComExposedEarlyBinding.DoubleArray = VBArray ' Compile Error: Function or interface marked as restricted, ' or the function uses an Automation type not supported in Visual Basic oComExposedEarlyBinding.ObjectArray = VBArray ' Run-time error '424': Object required oComExposedEarlyBinding.PlainObject = VBArray ' Run-time error '424': Object required oComExposedEarlyBinding.PlainObject = 5 Dim oComExposedLateBinding As Variant Set oComExposedLateBinding = New ComExposed ' Works oComExposedLateBinding.ScalarDouble = 5 ' Run-time error '5': Invalid procedure call or argument oComExposedLateBinding.DoubleArray = VBArray ' Run-time error '13': Type mismatch oComExposedLateBinding.ObjectArray = VBArray ' Works oComExposedLateBinding.PlainObject = VBArray ' Works oComExposedLateBinding.PlainObject = 5 

正如您已经注意到PlainObject正在以后期绑定模式工作,但显然是以丢失键入为代价,因此在VBA中丢失了自动完成(IntelliSense),这在我的场景中是不可接受的。

我在我的示例中关注的行是以下行:

 oComExposedEarlyBinding.DoubleArray = VBArray oComExposedEarlyBinding.ObjectArray = VBArray oComExposedEarlyBinding.PlainObject = VBArray 

使上述三行中的任何一行都能满足我的需求,那么你是否有任何解决方法或解决方案可以使这项工作(注意我对将数组作为参数传递给函数不感兴趣)?

更新:将此问题提交给Microsoft的支持并等待将近三周后。 他们确认这是一个错误,这是KB: http : //support.microsoft.com/kb/327084,C#中唯一的解决方法是标记为下面的解决方案。 但是,如果使用C ++ / CLI编写,我可以确认此代码按预期工作。

VBA数组必须为零,并且在c#中使用ref参数,示例:

 Option Explicit Sub test() Dim VBArray(0 To 2) As Double VBArray(0) = 1 VBArray(1) = 2 VBArray(2) = 3 Dim oComExposedEarlyBinding As New ComExposed oComExposedEarlyBinding.SetDoubleArray VBArray End Sub 

 using System.Runtime.InteropServices; namespace COMVisibleTest { [InterfaceType(ComInterfaceType.InterfaceIsDual)] [Guid("22341123-9264-12AB-C1A4-B4F112014C31")] public interface IComExposed { void SetDoubleArray(ref double[] doubleArray); } [ClassInterface(ClassInterfaceType.None)] [Guid("E4F27EA4-1932-2186-1234-111CF2722C42")] [ProgId("ComExposed")] public class ComExposed : IComExposed { private double[] _doubleArray; public void SetDoubleArray(ref double[] doubleArray) { _doubleArray = doubleArray; } } } 

VBA始终通过引用(VT_VARIANT | VT_BYREF)传递包含在变体中的数组,其中包含实际数组的另一个变体,因此在指定元素类型时不能在属性中使用数组,您需要使用方法以便指定参数为“通过参考”。

 [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] [Guid("22341123-9264-12AB-C1A4-B4F112014C31")] public interface IComExposed { void setDoubleArray(ref double[] myArray); //(...) } 

一个类似的问题:
使用com-interop将数组从vba传递给c#

对该问题的回答提到了使用用户定义的集合而不是基本类型数组的选项,也许这也可以解决您的问题。

文件中的相关参考文献:

Marshaling ByRef Variants

WinAPI中的VARIANT和VARIANTARG

Mars中的MarshalAsAttribute类

将数组传递给.Net中的COM