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

时间:2021-10-12 15:07:37

Problem

I have a library written in C++ and compiled as a DLL using Visual Studio 2010. The DLL has multiple exported functions. The exported functions are accessed from Excel using Declare Function.

我有一个用c++编写的库,并用Visual Studio 2010编译成一个DLL。DLL有多个导出函数。导出的函数可以使用Declare函数从Excel中访问。

I am trying to implement a new feature in the program which requires nested structures in the C++ portion which are then accessed from VBA. The C++ code looks like this.

我正在尝试在程序中实现一个新特性,它需要c++部分中的嵌套结构,然后从VBA访问这些结构。c++代码是这样的。

First Structure

第一个结构

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

Second Structure

第二个结构

This structure is used to build another structure as follows:

这个结构用于构建另一个结构,如下所示:

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

There are couple of ways that I am thinking about accessing the structure from VBA. One of them is from a void function such as this.

我正在考虑从VBA访问结构的几种方式。其中一个来自像这样的虚函数。

void Function1(Output* output_function1);

The other is a function that returns the Output structure, such as this.

另一个是返回输出结构的函数,比如这个。

Output Function2();

The internals of the two functions above do not matter at this point. I have verified that both implementations work as intended in the C++ code.

以上两个函数的内部关系在此时并不重要。我已经验证了这两种实现都是在c++代码中实现的。

Issue

I am unable to access these two structures from VBA using either Function1 or Function2.

我无法使用Function1或Function2从VBA访问这两个结构。

I declared two custom types in 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

For Function1 I declared the exported function as follows.

对于Function1,我声明了导出函数如下所示。

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

and for Function2, the following.

对于Function2,如下。

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

Function2 crashes Excel and Function1 gives me the error vba byref argument type mismatch.

Function2崩溃Excel, Function1给我错误vba byref参数类型不匹配。

What am I doing wrong here? What is the correct approach?

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

3 个解决方案

#1


2  

Function1 will work fine if you enclose definitions of your structures in #pragma pack(4) ... #pragma pack() directives.

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

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

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

C:

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:

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\*\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

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

#2


0  

You can't pass VBA Types as arguments. (I know. I know. VBA....)

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

What you'll need to do is pass in/out the individual properties. Something like this (I don't know C++ so bear with me.)

您需要做的是传入/传出各个属性。类似这样的东西(我不知道c++,所以请见谅。)

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

And then on the VBA side

然后在VBA这边

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

Or whatever data type is appropriate. This MSDN doc on the Declare statement might help as well.

或者任何合适的数据类型。声明语句上的MSDN文档也可能有帮助。

#3


0  

Don't nest Types when you're trying to call into a DLL. Instead make a composite Type that contains all the members:

当您试图调用DLL时,不要嵌套类型。相反,创建一个包含所有成员的复合类型:

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

Unfortunately, I don't think you can put a String in a Type the way you want and have it be compatible with C. You'll have to just put a Long in there to hold the pointer and use accessor functions to convert between the Long and a String

不幸的是,我不认为你可以按照你想要的方式将一个字符串放到一个类型中,并且让它与c兼容

#1


2  

Function1 will work fine if you enclose definitions of your structures in #pragma pack(4) ... #pragma pack() directives.

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

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

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

C:

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:

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\*\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

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

#2


0  

You can't pass VBA Types as arguments. (I know. I know. VBA....)

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

What you'll need to do is pass in/out the individual properties. Something like this (I don't know C++ so bear with me.)

您需要做的是传入/传出各个属性。类似这样的东西(我不知道c++,所以请见谅。)

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

And then on the VBA side

然后在VBA这边

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

Or whatever data type is appropriate. This MSDN doc on the Declare statement might help as well.

或者任何合适的数据类型。声明语句上的MSDN文档也可能有帮助。

#3


0  

Don't nest Types when you're trying to call into a DLL. Instead make a composite Type that contains all the members:

当您试图调用DLL时,不要嵌套类型。相反,创建一个包含所有成员的复合类型:

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

Unfortunately, I don't think you can put a String in a Type the way you want and have it be compatible with C. You'll have to just put a Long in there to hold the pointer and use accessor functions to convert between the Long and a String

不幸的是,我不认为你可以按照你想要的方式将一个字符串放到一个类型中,并且让它与c兼容

相关文章