2

此 C# 代码位于 .NET 4.5ComVisible程序集中:

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 32bit 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 中丢失了自动完成(智能感知),这在我的场景中是不可接受的。

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

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

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

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

4

2 回答 2

3

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;
        }
    }
}
于 2012-10-19T19:46:02.697 回答
1

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

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

一个类似的问题:
Pass an array from vba to c# using com-interop

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

文档中的相关参考:

编组 ByRef 变体

WinAPI 中的 VARIANT 和 VARIANTARG

.Net 中的 MarshalAsAttribute 类

在 .Net 中将数组传递给 COM

于 2012-10-19T14:55:15.487 回答