我在Excel工作表中有一个vba代码使用的dll。事情很好 - 除了有一个需要SAFEARRAY的功能。
缩写的Excel VBA代码如下所示:
Private sub ExcelFoo()
Dim v(115,17)
...stuff ...
MyFunctionCollectionLib.SetMatrix v
这用d ++编写,用c ++编写。 c ++函数如下所示:
void _stdcall SetMatrix(SAFEARRAY **psaMatrix)
... store matrix somewhere ...
在Excel中一切正常。
现在我想在C#中使用相同的功能。 对象浏览器显示有关该函数的以下信息(在dll中):
Sub SetMatrix(psaMatrix() As Double)
所以我写了一个Dll包装器如下:
// void _stdcall SetMatrix(SAFEARRAY **psaMatrix)
[DllImport( "MyFunctionCollectionLib.dll", CallingConvention = CallingConvention.StdCall )]
public extern static void SetMatrix(ref double[,] psaMatrix);
然后在C#中我尝试按如下方式使用它:
public void ReadDefaultValues()
{
double[,] tMatrix = _TestData.ReadDefaultValues();
DllWrapper.DllWrapper.SetMatrix(ref tMatrix);
调试器向我显示tMatrix最初是双[115,17] - 如定义的那样,但在SetMatrix()调用之后它会变为double [1]。
还有一些其他奇怪的事情让我怀疑我是否正确地这样做了。我真的不了解Excel / vba以及所有这些。所以我被许多"陷阱"因为我真的离开了我的领域。
是否有关于SAFEARRAY的文档易于使用? (它不是必须易于阅读)我的谷歌搜索带来了许多关于COM和编组的有些模糊的页面。 这些页面似乎不能直接解决我正在寻找的问题。 Microsoft文档描述了SAFEARRAY结构,但似乎没有提供任何有关使用的详细说明。
=============================================== ========================
如果我理解建议的文档,我需要做的是更改我的包装器:
// void _stdcall SetMatrix(SAFEARRAY **psaMatrix)
[DllImport( "MyFunctionCollectionLib.dll", CallingConvention = CallingConvention.StdCall )]
[In][Out][MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] double[,] pArrayOfDouble
对于包装器,有一个VT_DECIMAL,但没有VT_DOUBLE类型 - 所以我假设我应该使用VT_VARIANT作为类型。
上面的代码失败(在这里复制):
double[,] tMatrix = _TestData.ReadDefaultValues();
DllWrapper.DllWrapper.SetMatrix(ref tMatrix);
当我尝试使用var(这是c#变体吗?)时它也失败了
var tMatrix = _TestData.ReadDefaultValues();
DllWrapper.DllWrapper.SetMatrix(ref tMatrix);
两种情况下的错误消息是:指定的数组不是预期的类型。
我在哪里可以找到预期的类型?堆栈跟踪显示:
at MyFunctionCOllection.MyFunctionCOllectionWrapper.SetMatrix(Double[,] pArrayOfDouble)
答案 0 :(得分:0)
[DllImport( "MyFunctionCollectionLib.dll", CallingConvention = CallingConvention.StdCall )]
[In][MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_R8)] double[,] pArrayOfDouble
然后我可以在没有参考的情况下对其进行编码:
var tMatrix = _TestData.ReadDefaultValues();
DllWrapper.DllWrapper.SetMatrix(tMatrix);
我没有看到VT_R8是定义双打。现在至少停止抱怨数据类型等等。