从 VBA 访问 C++ 中的嵌套结构

Accessing a nested structure in C++ from VBA

问题

我有一个用 C++ 编写并使用 Visual Studio 2010 编译为 DLL 的库。DLL 有多个导出函数。使用 Declare Function.

从 Excel 访问导出的函数

我正在尝试在程序中实现一项新功能,该功能需要 C++ 部分中的嵌套结构,然后可以从 VBA 访问这些结构。 C++ 代码如下所示。

第一个结构

struct Parameter {
    double value;   
    char* label;     
    char* description;
    char* units;  
};

二级结构

此结构用于构建另一个结构如下:

struct Output {
    Parameter field_1;
    Parameter field_2;
    Parameter field_3;
};

我正在考虑从 VBA 访问结构的几种方法。其中之一来自这样的 void 函数。

void Function1(Output* output_function1);

另一种是returnsOutput结构的函数,比如这个

Output Function2();

以上两个函数的内部结构此时无关紧要。我已验证这两种实现都按 C++ 代码中的预期工作。

问题

我无法使用 Function1Function2 从 VBA 访问这两个结构。

我在 VBA 中声明了两个自定义类型。

Type Parameter
    Value as Double
    Label as String
    Description as String
    Units as String
End Type

Type Output
    Field1 as Parameter
    Field2 as Parameter
    Field3 as Parameter
End Type

对于Function1我声明导出函数如下。

Declare Sub Function1 Lib "C:\Path\to\library.dll" (ByRef OutputStruct as Output)

对于 Function2,以下。

Declare Sub Function2 Lib "C:\Path\to\library.dll" () as Output

Function2 崩溃 Excel 和 Function1 给我错误 vba byref argument type mismatch.

我在这里做错了什么?正确的做法是什么?

您不能将 VBA Types 作为参数传递。 (我知道。我知道。VBA.....)

您需要做的是传递 in/out 各个属性。像这样的东西(我不懂 C++,所以请耐心等待。)

void Function1(Output* Field1, Output* Field2, Output* Field3)

然后在VBA这边

Declare PtrSafe Sub Function1 Lib "C:\Path\to\library.dll" (ByRef Field1 As LongPtr, ByRef Field2 As LongPtr, ByRef Field3 As LongPtr)

或任何合适的数据类型。 MSDN doc on the Declare statement 也可能有所帮助。

尝试调用 DLL 时不要嵌套 Type。而是创建一个包含所有成员的复合 Type

Type Output
    Value1 as Double
    Label1 as String
    Description1 as String
    Units1 as String
    Value2 as Double
    Label2 as String
    Description2 as String
    Units2 as String
    Value3 as Double
    Label3 as String
    Description3 as String
    Units3 as String
End Type

不幸的是,我不认为你可以按照你想要的方式将 String 放入 Type 并使其与 C 兼容。你只需要将 Long 在那里保存指针并使用访问函数在 LongString

之间进行转换

如果将结构的定义包含在 #pragma pack(4) ... #pragma pack() 指令中,Function1 将正常工作。

https://msdn.microsoft.com/en-US/en-en/library/office/bb687915.aspx

C:

#pragma pack(4)
struct Parameter{
    double value;   
    char* label;     
    char* description;
    char* units;  
};

struct Output{
    struct Parameter field_1;
    struct Parameter field_2;
    struct Parameter field_3;
};
#pragma pack()


static char Buffer [4096];

static void Append_Field_Values (struct Parameter* field)
{
    static char b [1024];
    sprintf (b, "%f %s %s %s\n", field -> value, field ->label, field -> description, field -> units);
    strcat (Buffer, b);
}

void _stdcall Function1(struct Output* output_function1)
{
    Buffer [0] = 0;
    Append_Field_Values (&output_function1 -> field_1);
    Append_Field_Values (&output_function1 -> field_2);
    Append_Field_Values (&output_function1 -> field_3);
    MessageBox (0, Buffer, "FUNCTION1", 0);
}

VB:

Type Parameter
    Value As Double
    Label As String
    Description As String
    Units As String
End Type

Type Output
    Field1 As Parameter
    Field2 As Parameter
    Field3 As Parameter
End Type

Declare Sub Function1 Lib "E:\Serge\Whosebug\NestedStructures\Debug\NestedStructures.dll" (ByRef OutputStruct As Output)

Dim Out1 As Output

Sub Test1()
    Out1.Field1.Value = 3.14
    Out1.Field1.Label = "ARINC 429"
    Out1.Field2.Units = "Miles and Inches"
    Out1.Field3.Description = "Read MSDN"

    Call Function1(Out1)
End Sub