混合语言编程,VB和C ++,理解API和指针

时间:2022-09-01 20:55:58

My problem is with understanding the finer point of mixed langage programming and accessing API's in external libraries. My skills at C++ are nonexistent and at VB, mediocre.

我的问题是理解混合语言编程的精细点和访问外部库中的API。我在C ++的技能是不存在的,在VB,平庸。

I have a c++ dll compiled (portaudio library), and am trying to access it from VB (Visual Studio 2005). I am getting MarshallDirectiveException errors when calling a function, I believe because I am interacting incorrectly with the dll.

我有一个c ++ DLL编译(portaudio库),我试图从VB(Visual Studio 2005)访问它。我在调用函数时遇到MarshallDirectiveException错误,我相信因为我与dll交互不正确。


the C++ function and structures are defined as follows:

C ++函数和结构定义如下:

header info:

typedef int PaHostApiIndex;
...
typedef double PaTime;
...
typedef struct PaDeviceInfo
 {
     int structVersion;  /* this is struct version 2 */
     const char *name;
     PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/
     int maxInputChannels;
     int maxOutputChannels;
     PaTime defaultLowInputLatency;
     PaTime defaultLowOutputLatency;
     PaTime defaultHighInputLatency;
     PaTime defaultHighOutputLatency;
     double defaultSampleRate;
 } PaDeviceInfo;
 ...
 const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device );

program usage from docs:

来自docs的程序用法:

const PaDeviceInfo* Pa_GetDeviceInfo    (   PaDeviceIndex   device   )  

Retrieve a pointer to a PaDeviceInfo structure containing information about the specified device.

检索指向PaDeviceInfo结构的指针,该结构包含有关指定设备的信息。

Returns: A pointer to an immutable PaDeviceInfo structure. If the device parameter is out of range the function returns NULL.

返回:指向不可变PaDeviceInfo结构的指针。如果device参数超出范围,则该函数返回NULL。

Parameters: device A valid device index in the range 0 to (Pa_GetDeviceCount()-1)

参数:device 0到(Pa_GetDeviceCount() - 1)范围内的有效设备索引


In the VB program I have:

在VB程序中我有:

Private Declare Function Pa_GetDeviceInfo Lib "portaudio_x86.dll" (ByVal dindex As Integer) As PaDeviceInfo
...
Private Structure PaDeviceInfo
        Dim structVersion As Integer
        <MarshalAs(Runtime.InteropServices.UnmanagedType.LPStr)> Dim name As String
        Dim hostapi As Integer
        Dim maxInputChannels As Integer
        Dim maxOutputChannels As Integer
        Dim defaultLowInputLatency As Double
        Dim defaultLowOutputLatency As Double
        Dim defaultHighInputLatency As Double
        Dim defaultHighOutputLatency As Double
        Dim defaultSampleRate As Double
End Structure
...
        Dim di As New PaDeviceInfo
        di = Pa_GetDeviceInfo(outputParameters.device)

This feels wrong as docs state Pa_GetDeviceInfo returns a POINTER to a structure containing info about the structure, implying function creates the structure initially.

这感觉错误,因为文档状态Pa_GetDeviceInfo将POINTER返回到包含有关结构的信息的结构,暗示函数最初创建结构。

I am completely new to mixed language programming, a c++ utter noob, and a poor VB programmer. Can anyone guide me in the correct way to attack this problem ? My feeling is that I need to understand how to get VB to reference a struct in memry created in the dll, so I need to get vb to understand 'pointer to thing' as a function return.

我是混合语言编程,c ++完全菜鸟和糟糕的VB程序员的新手。任何人都可以用正确的方式指导我来解决这个问题吗?我的感觉是我需要了解如何让VB引用在dll中创建的memry中的结构,所以我需要让vb理解“指向事物的指针”作为函数返回。

Much appreciation for any assistance rendered. Please don't just say rtfm, I'm up to my eyes in FM's at the minute, I just don't know where to look.

对所提供的任何援助表示赞赏。请不要只说rtfm,我现在在FM的眼里,我只是不知道在哪里看。

Many thanks, David

非常感谢,大卫

2 个解决方案

#1


Your API function declaration is wrong. The function returns a pointer which is not reflected in your code. The signature translates to VB as follows:

您的API函数声明是错误的。该函数返回一个未反映在代码中的指针。签名转换为VB如下:

Private Declare Function Pa_GetDeviceInfo Lib "portaudio_x86.dll" ( _
    ByVal dindex As Integer _
) As IntPtr

Of course, using an IntPtr directly is not easy. In fact, quite some marshalling is involved:

当然,直接使用IntPtr并不容易。事实上,涉及到一些编组:

Dim obj As PaDeviceInfo = _
    DirectCast(Marshal.PtrToStructure(ptr, GetType(PaDeviceInfo)), PaDeviceInfo)

(More or less important) side note: since your DLL apparently creates a new object in memory, it also needs to release/destroy it. Be sure to call the appropriate function after using the structure.

(或多或少)侧注:由于你的DLL显然在内存中创建了一个新对象,它还需要释放/销毁它。使用该结构后,请务必调用相应的函数。

#2


Yes, your structure is wrong. You indeed have to get a pointer and then read the memory to which it "points".

是的,你的结构是错误的。你确实必须得到一个指针,然后读取它“指向”的内存。

I've done external DLL calling in C++ before and it generally involves a huge wading-through of documentation. I don't think anyone here is going to do that for you but I'll try to point you in the proper direction.

我以前用C ++做过外部DLL调用,它通常涉及文档的大量涉猎。我不认为这里的任何人会为你做那件事,但我会试着指出你正确的方向。

First, a pointer is an address, a value which "points" to some location in memory. "dereferencing" a pointer is reading the memory that the pointers to (and if you read or write the wrong memory, the memory can get upset and kill your program).

首先,指针是一个地址,一个“指向”内存中某个位置的值。 “解除引用”指针正在读取指向指针的内存(如果你读取或写入错误的内存,内存可能会被扰乱并杀死你的程序)。

Further, at a low level, calling a DLL involves copying bits of information to the stack and then having the function retrieve them. The "calling conventions" describe exactly how this is done - there are "c", pascal, and other such conventions.

此外,在较低级别,调用DLL涉及将信息位复制到堆栈,然后让函数检索它们。 “调用约定”确切地描述了这是如何完成的 - 有“c”,pascal和其他类似的约定。

You will want to call the DLL's function, get a pointer, copy the information pointed-to into your local structure and then continue. The hard thing will be figuring out exactly how to declare the DLL function. If your library documentation has some sample code, that might be where to start.

您将需要调用DLL的函数,获取指针,将指向的信息复制到本地结构中,然后继续。难以确定如何声明DLL函数。如果您的库文档有一些示例代码,那么可能就是从哪里开始的。

A short Google does not even show any consistent way to deal with pointers in VB at all. One idea would be to create a short C++ program which would call the DLL and return an object by value. I don't know if this would help but such kludges come up when dealing with external libraries.

一个简短的谷歌甚至没有显示任何一致的方式来处理VB中的指针。一个想法是创建一个简短的C ++程序,它将调用DLL并按值返回一个对象。我不知道这是否会有所帮助,但在处理外部库时会出现这样的问题。

Good Luck

#1


Your API function declaration is wrong. The function returns a pointer which is not reflected in your code. The signature translates to VB as follows:

您的API函数声明是错误的。该函数返回一个未反映在代码中的指针。签名转换为VB如下:

Private Declare Function Pa_GetDeviceInfo Lib "portaudio_x86.dll" ( _
    ByVal dindex As Integer _
) As IntPtr

Of course, using an IntPtr directly is not easy. In fact, quite some marshalling is involved:

当然,直接使用IntPtr并不容易。事实上,涉及到一些编组:

Dim obj As PaDeviceInfo = _
    DirectCast(Marshal.PtrToStructure(ptr, GetType(PaDeviceInfo)), PaDeviceInfo)

(More or less important) side note: since your DLL apparently creates a new object in memory, it also needs to release/destroy it. Be sure to call the appropriate function after using the structure.

(或多或少)侧注:由于你的DLL显然在内存中创建了一个新对象,它还需要释放/销毁它。使用该结构后,请务必调用相应的函数。

#2


Yes, your structure is wrong. You indeed have to get a pointer and then read the memory to which it "points".

是的,你的结构是错误的。你确实必须得到一个指针,然后读取它“指向”的内存。

I've done external DLL calling in C++ before and it generally involves a huge wading-through of documentation. I don't think anyone here is going to do that for you but I'll try to point you in the proper direction.

我以前用C ++做过外部DLL调用,它通常涉及文档的大量涉猎。我不认为这里的任何人会为你做那件事,但我会试着指出你正确的方向。

First, a pointer is an address, a value which "points" to some location in memory. "dereferencing" a pointer is reading the memory that the pointers to (and if you read or write the wrong memory, the memory can get upset and kill your program).

首先,指针是一个地址,一个“指向”内存中某个位置的值。 “解除引用”指针正在读取指向指针的内存(如果你读取或写入错误的内存,内存可能会被扰乱并杀死你的程序)。

Further, at a low level, calling a DLL involves copying bits of information to the stack and then having the function retrieve them. The "calling conventions" describe exactly how this is done - there are "c", pascal, and other such conventions.

此外,在较低级别,调用DLL涉及将信息位复制到堆栈,然后让函数检索它们。 “调用约定”确切地描述了这是如何完成的 - 有“c”,pascal和其他类似的约定。

You will want to call the DLL's function, get a pointer, copy the information pointed-to into your local structure and then continue. The hard thing will be figuring out exactly how to declare the DLL function. If your library documentation has some sample code, that might be where to start.

您将需要调用DLL的函数,获取指针,将指向的信息复制到本地结构中,然后继续。难以确定如何声明DLL函数。如果您的库文档有一些示例代码,那么可能就是从哪里开始的。

A short Google does not even show any consistent way to deal with pointers in VB at all. One idea would be to create a short C++ program which would call the DLL and return an object by value. I don't know if this would help but such kludges come up when dealing with external libraries.

一个简短的谷歌甚至没有显示任何一致的方式来处理VB中的指针。一个想法是创建一个简短的C ++程序,它将调用DLL并按值返回一个对象。我不知道这是否会有所帮助,但在处理外部库时会出现这样的问题。

Good Luck