65.9K
CodeProject 正在变化。 阅读更多。
Home

从 Excel VBA 将双精度数组发送到 C#( 使用 COM 互操作)

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.20/5 (6投票s)

2005年12月20日

2分钟阅读

viewsIcon

92979

downloadIcon

374

关于从 Excel VBA 向 C# 发送数据数组的技巧。

引言

Excel VBA 方法可以通过 COM 互操作调用 C# 对象方法。基本起点是通过 COM 互操作暴露 .Net 对象(如下所述)。然后您可以调用 .net 对象方法并传递参数——但是,如果其中一个参数是 double[],VBA 会在您尝试运行时抱怨。


"函数或接口被标记为受限,或者函数使用了 Visual Basic 中不支持的自动化类型"

如果您想要一种技术和一些代码片段,帮助您从 VBA 函数向 C# 方法发送数据数组,那么本文就是为您准备的。

背景 - 关于如何设置 VBA 以使用 C# 对象的一般信息

可能还有其他(也许更好/更简单)的技术,但这是我发现我必须做的事情。我想要调用的 C# 类必须实现一个接口 (interfaceExposer)。interfaceExposer 必须暴露我在 VBA 中想要访问的方法。
//interfaceExposer.cs
using System; 
 
namespace blah
{ 
         public interface interfaceExposer 
         { 
                 int callableMethodSimple(double a); 
         }
} 
您的类应该实现此方法
//cssClass.cs
using System;
namespace blah
{
         public class callableClass : interfaceExposer
         {
                 public int callableMethodSimple(double a)
                 {
                          return (int)a;
                 }
         }
}

重要提示:指定您希望将此项目注册为 COM 互操作。转到项目菜单/项目属性,选择配置属性/生成,然后将“注册 COM 互操作”设置为 TRUE。
准备好尝试调用 callableClass.callableMethodSimple() 时进行编译

在 VBA 中:选择工具/引用,然后选择 COM 对象(在我的例子中为 SendArray)。要实例化类

'VBA code
Public cssObject As New SendArray.callableClass
'SendArray is the name of the project in which callableClass resides.
Dim iClass As interfaceExposer
 
Sub MyRoutine()
         Set iClass = cssObject
         Dim result As Integer
         result = IClass.callableMethodSimple(5.0)
End Sub

但是,当您想要将数组发送到您的 cssObject 方法时…

如果您只是指定类似的内容,您会收到一个错误

...
public int callableMethodArray(double[] inputArray)
// this will not work at run time.
{
    …
}

"函数或接口被标记为受限,或者函数使用了 Visual Basic 中不支持的自动化类型"。以下是您需要做的事情。首先在 interfaceExposer 上工作

//interfaceExposer.cs
using System; 
 
namespace blah
{ 
    public interface interfaceExposer 
    { 
         int callableMethodSimple(double a); 
         int callableMethodArray(object a);
         // notice you are using object not a double[]
    }
} 


然后修复类代码
//cssClass.cs
using System;
namespace blah
{
    public class callableClass : interfaceExposer
    {
        .. .
 
        public int callableMethodArray(object a)
        {
            return 0;
        }
    }

现在,如果您要单步执行代码,当它进入 callableMethodArray() 时,您会看到对象 a 是一个包含数组元素的数组。

实际上使用数组的元素

您可能会想到将对象转换为 double[],然后像往常一样使用您的数据。但是类型转换不起作用
//cssClass.cs
using System;
namespace blah
{
    public class callableClass : interfaceExposer
    {
        .. .
 
        public int callableMethodArray(object a)
        {
            double[] receiverArray = new double[10];
            receiverArray = (double[])a;
            // will bomb at run time

            return 0;
        }
    }

您可以使用反射从通用对象“a”中提取数据到 double[]。幸运的是,如果您计划接收一维 double[],这里有一个您可以使用的示例方法。您可以使用此方法作为原型,为其他格式的数组创建更多方法。

//cssClass.cs
using System;
using System.Reflection; // ADD THIS.
 
namespace blah
{
    public class callableClass : interfaceExposer
    {
        .. .
 
        public int callableMethodArray(object a)
        {
            double[] thisVect = 
              LoadComObjectIntoDoubleArray(a);                  
                          return 0;
        }
 
        private double[] LoadComObjectIntoDoubleArray(object comObject)
        {
            Type thisType = comObject.GetType();
            Type dblType = Type.GetType("System.Double[*]");
            double[] doubleArray = new double[1];
            // temporary allocation to keep compiler happy.
            if(thisType == dblType)
            {
                object[] args = new object[1];
                int numEntries = (int)thisType.InvokeMember("Length", 
                                         BindingFlags.GetProperty, 
                                         null, comObject, null);
                doubleArray = new double[numEntries];
                for(int j1=0; j1 < numEntries; j1++)
                {
                    args[0] = j1+1; // since VB arrays index from 1
                    doubleArray[j1] = 
                        (double)thisType.InvokeMember("GetValue", 
                                       BindingFlags.InvokeMethod, 
                                          null, comObject, args);
                }
             } // End if(thisType == dblType)
             return doubleArray;
         } // End LoadComObjectIntoDoubleArray()
     }
}

这将成功地将您的数组数据从 VBA 导入到 C# 方法。要从 VBA 调用此方法,请查看下面的代码示例。

'VBA code
Public cssObject As New SendArray.callableClass
'SendArray is the name of the project 
'in which callableClass resides.
 
Dim iClass As interfaceExposer
 
Sub MyRoutine()
    Set iClass = cssObject
    Dim result As Integer
    Dim SendArray(1 To 2) As Double
    SendArray(1) = 5.2
    SendArray(2) = 7.5
    result = iClass.callableMethodArray(SendArray)
End Sub

联系方式

请就讨论论坛中的澄清或建议给我写信。祝您愉快。

© . All rights reserved.