【发布时间】:2020-04-19 13:12:30
【问题描述】:
我有一个带有 C# 方法的 .NET Dll,我在 Excel VBA 中使用它。它是通过 VBA 的 COM 包装器调用的。该方法将两个双精度数组作为参数。
当双数组在 VBA 中定义为下边界为 1,并通过 COM 传递给 C# 方法时,Excel 失败并出现以下错误:
运行时错误 5 (无效的过程调用或参数)
虽然这听起来很疯狂,但我希望能够将下界为 1 的 VBA/COM 数组传递给 C# .NET。这可能吗?
这是 C# 函数的声明方式:
public double LinearInterpolation(
double[] psaXvector,
double[] psaYvector,
double Xvalue)
{
C# 中的 COM 包装器
[Guid("CE93D637-0673-4EBC-8FFA-6CE162959262")]
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IMixedTools
{
[DispId(1)]
[return: MarshalAs(UnmanagedType.R8)] double
LinearInterpolation(
[MarshalAs(UnmanagedType.SafeArray)]double[] psaXvector,
[MarshalAs(UnmanagedType.SafeArray)]double[] psaYvector,
[MarshalAs(UnmanagedType.R8)]double Xvalue);
这是生成的 .tlh 文件的样子
struct __declspec(uuid("ce93d637-0673-4ebc-8ffa-6ce162959262"))
IMixedTools : IDispatch
{
virtual HRESULT __stdcall LinearInterpolation (
/*[in]*/ SAFEARRAY * psaXvector,
/*[in]*/ SAFEARRAY * psaYvector,
/*[in]*/ double Xvalue,
/*[out,retval]*/ double * pRetVal ) = 0;
调用 VBA 代码
Dim mixu As Object
Set mixu = CreateObject("TlibCOM.CMixedTools")
Dim Xarr() As Double
Dim Yarr() As Double
ReDim Xarr(1 To 4) As Double
ReDim Yarr(1 To 4) As Double
Dim x As Double
Xarr(1) = 1
Xarr(2) = 2
Xarr(3) = 5
Xarr(4) = 7.5
Yarr(1) = 14
Yarr(2) = 9
Yarr(3) = 4
Yarr(4) = -3
x = 4
result = mixu.LinearInterpolation(Xarr, Yarr, x)
Set mixu = Nothing
如果我定义下边界为 0 的数组,该函数将起作用。但是我有一个相当大的遗留代码库,其中数组可以用 0 或 1 作为数组的下边界来定义,因此以数组作为参数的函数需要能够处理这个问题。
C# .NET DLL 是一个方法库,取代了传统的 ATL COM 函数。以前,无论从 VBA 传递的双精度数组的下限是 1 还是 0,这都不是问题。
有没有办法绕过这个限制,以便 VBA 可以将低边界为 1 的数组传递给 DLL 中的 C# 方法?
【问题讨论】:
-
“以前”是什么意思? “以前”是什么时候?发生了什么变化?您的意思是当您迁移到 C# 时出现问题?据我所知,C# 一直支持 only 基于 0 的数组。 VBA 支持基于 1 或 0。关于 ATL 我不知道...
-
这里有一些关于什么有效,什么无效的提示。 stackoverflow.com/questions/56446/net-arrays-with-lower-bound-0 使用 ToArray() 您可以随时快速创建基于 0 的数组副本,如果这已经足够的话。
-
当您在 VBA 中使用下边界为 1 的数组时,仍然有一个没有数据的索引零。因此,如果您将数组传递给 c#,则不会发生任何变化。 c#数组有一个GetLowerBound属性,就像VBA一样,你确定你在改变之前完全编译过。再次尝试确保它适用于下边界零。
-
您必须将参数类型更改为
Array并在属性中声明SafeArraySubType。使用 Array 方法访问 C# 代码中的数组(GetLowerBound、GetUpperBound、GetValue)。 -
是的。您使用 double[] 参数声明了 LinearInterpolation(),它需要是 Array 参数才能让 VBA 代码传递不符合要求的数组。