请教VB如何声明一个_cdecl函数,用来被调用?开发过海康威视的朋友进

时间:2023-01-21 03:22:53
请教VB如何声明一个_cdecl函数,用来被调用?

标题有点不容易理解,具体是这样的,我在进行海康威视视频采集卡的二次开发,这里录像的功能,他的SDK要求注册一个回调函数,然后在回调函数里进行数据处理。

注册回调函数的声明是:
int __stdcall RegisterStreamDirectReadCallback(STREAM_DIRECT_READ_CALLBACK StreamDirectReadCallback,void *Context)

被回调的函数的声明是:
int __cdecl StreamDirectReadCallback(ULONG channelNum,void *DataBuf,DWORD Length,int frameType,void *context)

我的代码是按常规的VB回调方法写的,模块中代码:

Public Declare Function RegisterStreamDirectReadCallback Lib "DS40xxSDK.dll" (ByVal Callback As Long, ByVal Context As Long) As Long    '声明RegisterStreamDirectReadCallback()

Public Function StreamDirectReadCallback(ByVal channelNumber As Long, DataBuf As Long, ByVal Length As Long, ByVal FrameType As Long, ByVal Context As Long) As Long
    Debug.Print Length
    Debug.Print Time
End Function


窗体中代码:


Private Sub Form_Load()
    
    Me.BackColor = RGB(10, 10, 10)
    CardIni Me.hWnd, 704, 576
    GetVPara b, c, s, H
    HScroll1.value = b
    HScroll2.value = c
    HScroll3.value = s
    HScroll4.value = H'上边那些代码是正常初始化,关系不大
    
    RegisterStreamDirectReadCallback AddressOf StreamDirectReadCallback, 0&
End Sub


代码运行结果是进行第一次回调后(两个debug都有输出)IDE崩溃:
“0x00000001”指令引用的“0x00000001”内存。该内存不能为“read”。

    对于该奇怪的问题,我查了__cdecl与__stdcall的区别。最大的区别是,__stdcall是被调用者清理参数堆栈,__cdecl是调用者清理参数堆栈。那么VB自己写的函数是不是stdcall函数?如果是的话,那么我分析就是我的回调函数执行完后在堆栈中清理了参数,然后回调函数又帮我清理了一次堆栈,从而导致这样的错误?是这样么?请高手帮忙。

8 个解决方案

#1


vb只支持_stdcall

#2


沉了?网上有内嵌汇编调用__cdecl函数的,可我这里需要声明一个__cdecl函数来被调用。应该有办法吧,等高手

#3


mov esi,esp
add esi,4
sub esp,20
mov edi,esp
mov ecx,5
rep movsd
mov eax, addressof StreamDirectReadCallback
call eax
ret

把这段代码想办法弄成机器码,然后存到数组中,将数组(0) 的地址传给 RegisterStreamDirectReadCallback 的第1个参数调用,应该就行了

上面 mov eax,addressof xxx 是要你自己获取 StreamDirectReadCallback 回调地址,然后修改这里


请教VB如何声明一个_cdecl函数,用来被调用?开发过海康威视的朋友进 那段汇编代码要是有错,概不负责

#4


你的这段我理解不了。。。

虽然这个问题我通过其他方法变通的解决了,可我还是希望能弄明白VB声明一个_cdecl的方法。。。

#5


对于普通的c call 函数,可以直接调用,在调试运行的时候 ide 会报错,不过在编译后可以运行
但是这样做可能导致程序崩溃

好的办法是将 c call 函数写到一个函数中,这个函数只做api调用,然后自己调用这个函数,通过这种办法
可以做到防止崩溃,但vb ide 一样会报错

对于 c call 的 callback 调用,只能用这种内嵌汇编的方法了,否则出错的几率会更大

#6


引用 4 楼 zjl1234567 的回复:
你的这段我理解不了。。。

虽然这个问题我通过其他方法变通的解决了,可我还是希望能弄明白VB声明一个_cdecl的方法。。。

搞明白这个毫无意义。不要让VB做它不支持的事情。

#7


用可这样来解决:
用C语言写一个help.dll.
在help.dll写回调函数,在这个回调函数里面调用VB中的回调函数。用dll中的回调函数注册。

#8


看来真的要转投VB.net门下了。以上这些.net都是支持的。断断续续用VB6也七八年了,真有点舍不得呢。

#1


vb只支持_stdcall

#2


沉了?网上有内嵌汇编调用__cdecl函数的,可我这里需要声明一个__cdecl函数来被调用。应该有办法吧,等高手

#3


mov esi,esp
add esi,4
sub esp,20
mov edi,esp
mov ecx,5
rep movsd
mov eax, addressof StreamDirectReadCallback
call eax
ret

把这段代码想办法弄成机器码,然后存到数组中,将数组(0) 的地址传给 RegisterStreamDirectReadCallback 的第1个参数调用,应该就行了

上面 mov eax,addressof xxx 是要你自己获取 StreamDirectReadCallback 回调地址,然后修改这里


请教VB如何声明一个_cdecl函数,用来被调用?开发过海康威视的朋友进 那段汇编代码要是有错,概不负责

#4


你的这段我理解不了。。。

虽然这个问题我通过其他方法变通的解决了,可我还是希望能弄明白VB声明一个_cdecl的方法。。。

#5


对于普通的c call 函数,可以直接调用,在调试运行的时候 ide 会报错,不过在编译后可以运行
但是这样做可能导致程序崩溃

好的办法是将 c call 函数写到一个函数中,这个函数只做api调用,然后自己调用这个函数,通过这种办法
可以做到防止崩溃,但vb ide 一样会报错

对于 c call 的 callback 调用,只能用这种内嵌汇编的方法了,否则出错的几率会更大

#6


引用 4 楼 zjl1234567 的回复:
你的这段我理解不了。。。

虽然这个问题我通过其他方法变通的解决了,可我还是希望能弄明白VB声明一个_cdecl的方法。。。

搞明白这个毫无意义。不要让VB做它不支持的事情。

#7


用可这样来解决:
用C语言写一个help.dll.
在help.dll写回调函数,在这个回调函数里面调用VB中的回调函数。用dll中的回调函数注册。

#8


看来真的要转投VB.net门下了。以上这些.net都是支持的。断断续续用VB6也七八年了,真有点舍不得呢。