VB调用c++写的Dll的一点总结

最近,写了一个VB应用程序,这个APP主要是用来演示三个C++写的视频处理动态链接库的使用方式。第一次写VB的代码,确实遇到了很多问题,现在回想一下,真的是很多东西走了或多或少的弯路,现在把这些东西总结并记录下来,期望以后写兼容VB的动态库,可以注意接口的定义,并不是所有的接口定义方式,都方便VB使用,再者,就是在VB中使用的一些知识积累。

C++写的DLL接口定义需注意的事项

1.       接口中自定义数据类型不能ByVal传递

这次就遇到了这个问题,而且花了很长的时间去验证这个问题,在Dll中有一个函数,如下:

Struct Color

{

Long lBrightness;

Long lcontrast;

Long lhue;

Long lsaturation;

}Color;

BOOL SetColorColor stuColor;

VB下需调用此函数,则定义相应的自定义数据和函数:

Type Color

lBrightness  As Long

lcontrast  As Long

lhue  As Long

lsaturation  As Long

End Type

Declare Function SetColor lib”A.dll”(ByVal StuColor As Color)As Long

这样看似可以将自定义数据结构中的四个变量都传送下去,但是这在编译时是通过不了的。

最初的时候是期望不用修改dll的接口,只是变换VB的代码将结构中四个数据都传送下去,试了以下方式:

a.       采用ByRef的方式,这样编译可以通过了,但是每次传下去的都是结构的首地址,并没有把数据传下去;

b.       传送结构的地址(Varptrcolor)),同方法一,不行;

c.       传送结构的首元素(Color.lBrightness),期望dll可以根据第一个参数的地址,自动查找其他的数据,可惜,并不如愿;

d.      

试了很多方法,结果都是不行,我就纳闷了,怎么就不行呢,于是开始在网上查找资料,看别人都是怎么办的,果然有很多文章介绍这种自定义数据类型的使用,但都是用ByRef的方式传送,到后来,经过头允许把dll的接口改成BOOL SetColorColor * stuColor;才把这个问题给解决了。对于自定义数据类型,VB不提供直接传值的方式,所以遇到类似的问题,dll接口定义的时候,就应该用指针。

2.       接口中函数指针的传递

在注册回调函数时,需要将函数指针通过接口传送下去,在dll中有一个回调函数注册函数设计成,将三个回调函数指针放到一个结构体中,在用在指针传递,如下;

Struct FucntionPtr

{

BeginFunc fptFunctionPtr1;

ProcFunc fptFunctionPtr2;

EndFunc fptFunctionPtr3;

}CallbackFunc;

Bool SetCallBackFunction(CallbackFunc * pFunction);

VB中就需要定义一个含有三个函数指针的自定义数据结构:

Type CallbackFunc

fptFunctionPtr1 As Long

fptFunctionPtr2 As Long

fptFunctionPtr3 As Long

End Type

Declare function SetCallbackFunction Lib”B.dll”(ByRef pCallbackFunc As CallbackFunc)As long

Dim pCallbackFunc As Calllbackfunction

pCallbackFunc. fptFunctionPtr1=定义在标准模块中的回调函数的指针;

VB中有一个函数AddressOf可获得函数的指针,但是这个函数,获取的指针只能直接作为函数参数,不能直接获取,赋给一个变量,如:

pCallbackFunc. fptFunctionPtr1=AddressOf BeginFunc;

是编译不通过的;

在网上搜了一篇资料介绍如何在VB中获取函数指针,但也非常复杂,所以将Dll中的注册函数的参数改为直接传递函数指针,而不是指针结构的指针,在以后编写兼容VB的动态库的时候也需要注意这一点。

3.       VB中使用回调函数

因为回调函数的问题耽误了我很多的时间,大部分时间都在查找Debug下程序可以运行,但是EXE运行老是会报错,而且Debug下运行特别不稳定,调试呀调试,老是不行,有人说VB下用回调函数就是有问题,但是用定时器做了个试验,在定时器的回调函数中调用系统API,动态库的API都没有问题,但是在自己写的回调函数中调用这些函数都有问题。后来问我们的老大,他说是线程切换时出的问题,在微软的Support上说,VBCallback函数中调用的API函数,在EXE运行时会出现“ 0x660bd3b1 指令引用 0x0000009c内存。 无法写入内存”错误,发生错误的原因是:不创建 Visual Basic 的一个线程调用回调函数。这些 API 函数使用一个忙线程模型,但 Visual Basic 仅支持 Apartment-模型线程处理。 此外,必须小心其他相关与哪些代码在回调函数可以执行。 在回调函数内以下的使用可能导致意外结果:

file I/O

错误处理。

固定大小数组。

设置语句。

COM 方法调用的返回 HRESULT (如任何 Visual Basic ActiveX 对象)。

声明调用。

全局对象 (如 Application 对象。

Visual Basic run-time files of most

于是,就将dll回送数据的方式改为消息的方式,就OK了,很稳定。

不知道在VB中创建一个线程,并在该线程中调用回调函数,EXE能不能跑,如果在回调函数中使用了上述的不稳定因素,程序会不会真的不稳定。

VB兼容的dll一定要考虑callback的问题。

4.       接口中字符串的传递

Dll中很多函数都需要传递字符串,传递字符串不能用传址方式,如果用传址方式的话那么传递的是指向字符串指针的指针,API将不能返回数据,并且造成访问数据出错,所以需要用ByVal传递字符串指针。

在自定义结构体中的string的传递,声明为String

5.       VB中文件的处理

一开始不知道有Commondialog这个好用的DD来实现Openfile功能,就自己写了一个,那三个文件操作控件虽然好用,但是,比起系统提供的对话框,自己写的就难看了好多,后来就全改成commondialog了,浪费我时间,要是早点知道有这么个东东就好咯。

6.       还有很多细节,如果没有注意也会很浪费调试时间,VB中,默认的函数参数的传递方式是ByRel,如果什么都不写是传址,而不是传值,结果编程时忽略了这个问题,害得我以为Dll有问题,调了大半天的dll,结果偶然才发现,自己没写ByVal,晕死了!

你可能感兴趣的:(VB)