混合语言编程、VB 和 C++、了解 API 和指针
我的问题是理解混合语言编程的细节 以及访问外部库中的 API。 我的 C++ 技能根本不存在 而在VB,则平庸。
我编译了一个 C++ dll(portaudio 库),并尝试从 VB 访问它 (视觉工作室 2005)。 我在调用函数时收到 MarshallDirectiveException 错误,我相信是因为 我与 dll 的交互不正确。
C++ 函数和结构定义如下:
标头信息:
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 );
来自文档的程序用法:
const PaDeviceInfo* Pa_GetDeviceInfo ( PaDeviceIndex device )
检索指向包含有关指定信息的 PaDeviceInfo 结构的指针 设备。
返回: 指向不可变 PaDeviceInfo 结构的指针。 如果设备参数超出范围 该函数返回 NULL。
参数: device 范围为 0 到 (Pa_GetDeviceCount()-1) 的有效设备索引
在 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)
这感觉不对,因为文档状态 Pa_GetDeviceInfo 返回指向包含信息的结构的指针 关于结构,意味着函数最初创建了结构。
我对混合语言编程完全陌生,是一个彻头彻尾的 C++ 菜鸟,也是一个糟糕的 VB 程序员。 谁能指导我以正确的方式解决这个问题? 我的感觉是我需要了解如何让 VB 引用在内存中创建的结构 dll,所以我需要让 vb 将“指向事物的指针”理解为函数返回。
非常感谢所提供的任何帮助。 请不要只说 rtfm,我已经在调频了 那一刻,我只是不知道该看哪里。
非常感谢, 大卫
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.
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.
the C++ function and structures are defined as follows:
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:
const PaDeviceInfo* Pa_GetDeviceInfo ( PaDeviceIndex device )
Retrieve a pointer to a PaDeviceInfo structure containing information about the specified
device.
Returns:
A pointer to an immutable PaDeviceInfo structure. If the device parameter is out of range
the function returns NULL.
Parameters:
device A valid device index in the range 0 to (Pa_GetDeviceCount()-1)
In the VB program I have:
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.
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.
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.
Many thanks,
David
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你的API函数声明是错误的。 该函数返回一个指针,该指针未反映在您的代码中。 签名转换为 VB 如下:
当然,直接使用
IntPtr
并不容易。 事实上,涉及相当多的编组:(或多或少重要)旁注:由于您的 DLL 显然在内存中创建了一个新对象,因此它还需要释放/销毁它。 使用该结构后请务必调用适当的函数。
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:
Of course, using an
IntPtr
directly is not easy. In fact, quite some marshalling is involved:(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.
是的,你的结构是错误的。 您确实必须获取一个指针,然后读取它“指向”的内存。
我以前用 C++ 做过外部 DLL 调用,它通常涉及大量的文档。 我认为这里没有人会为你做这件事,但我会尽力为你指明正确的方向。
首先,指针是一个地址,一个“指向”内存中某个位置的值。 “取消引用”指针正在读取指针所指向的内存(如果您读取或写入了错误的内存,内存可能会感到不安并杀死您的程序)。
此外,在低级别上,调用 DLL 涉及将信息位复制到堆栈,然后让函数检索它们。 “调用约定”准确地描述了这是如何完成的 - 有“c”、pascal 和其他此类约定。
您将需要调用 DLL 的函数、获取指针、将指向的信息复制到本地结构中,然后继续。 困难的事情是弄清楚如何声明 DLL 函数。 如果您的库文档有一些示例代码,那么可能就从这里开始。
简短的 Google 甚至根本没有显示任何一致的方法来处理 VB 中的指针。 一种想法是创建一个简短的 C++ 程序,该程序将调用 DLL 并按值返回一个对象。 我不知道这是否有帮助,但在处理外部库时会出现这样的问题。
祝你好运
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.
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.
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.
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.
Good Luck