【问题标题】:how to use SAFEARRAY in c# for c++ dll functiont written for Excel vba如何在 c# 中为 Excel vba 编写的 c++ dll 函数使用 SAFEARRAY
【发布时间】:2016-11-22 09:51:44
【问题描述】:

我有一个 Excel 工作表中的 vba 代码使用的 dll。一切正常 - 除了有一个功能需要 SAFEARRAY。

缩写的 Excel VBA 代码如下所示:

Private sub ExcelFoo()
    Dim v(115,17)
    ...stuff ...
    MyFunctionCollectionLib.SetMatrix v

这调用了一个用 C++ 编写的 Dll。 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 最初是一个 double[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)

【问题讨论】:

标签: c# c++


【解决方案1】:

好的,显然它想重新定义 c#“包装器”或其他任何名称:

[DllImport( "MyFunctionCollectionLib.dll", CallingConvention = CallingConvention.StdCall )]
[In][MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_R8)] double[,] pArrayOfDouble  

然后我可以在没有 ref 的情况下对其进行编码:

var tMatrix = _TestData.ReadDefaultValues();
DllWrapper.DllWrapper.SetMatrix(tMatrix);

我没有看到 VT_R8 定义了双打。现在至少这件事不再抱怨数据类型之类的了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-10
    • 2011-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 1970-01-01
    相关资源
    最近更新 更多