dll接口 int __stdcall WimDev_List(pCallback_GetList GetList)//void (CALLBACK *GetList)(int count, PVEH_INFO info) )
{
GetListFunc = (pCallback_GetList)GetList;
int iCount = 1;
PVEH_INFO pVEH_INFO;
pVEH_INFO = new VEH_INFO;
pVEH_INFO->weight = 2;
pVEH_INFO->axistype = 3;
pVEH_INFO->speed = 4;
GetListFunc(iCount,pVEH_INFO);
return 0;
} VC编写该函数生成dll,在vc应用程序中可以正常调用,可在vb程序中一调用就崩溃.郁闷vb定义 Declare Function WimDev_List Lib "WtSys_DLL.dll" (ByRef GetList As Long) As Long
回调函数为 Public Function GetList(iCount As Long, info1 As PVEH_INFO)
MsgBox iCount + info1.weight + info1.axistype + info1.speed
GetList = 0
End Function
调用方法:Dim ret As Long
ret = WimDev_List(AddressOf GetList)
每次都出错,希望能给出解释,多谢
{
GetListFunc = (pCallback_GetList)GetList;
int iCount = 1;
PVEH_INFO pVEH_INFO;
pVEH_INFO = new VEH_INFO;
pVEH_INFO->weight = 2;
pVEH_INFO->axistype = 3;
pVEH_INFO->speed = 4;
GetListFunc(iCount,pVEH_INFO);
return 0;
} VC编写该函数生成dll,在vc应用程序中可以正常调用,可在vb程序中一调用就崩溃.郁闷vb定义 Declare Function WimDev_List Lib "WtSys_DLL.dll" (ByRef GetList As Long) As Long
回调函数为 Public Function GetList(iCount As Long, info1 As PVEH_INFO)
MsgBox iCount + info1.weight + info1.axistype + info1.speed
GetList = 0
End Function
调用方法:Dim ret As Long
ret = WimDev_List(AddressOf GetList)
每次都出错,希望能给出解释,多谢
回掉要放到过程里面。
参看 mk:@MSITStore:C:\Program%20Files\Microsoft%20Visual%20Studio\MSDN98\98VS\2052\vbcon98.chm::/Html/vbconpassingfunctionpointerstodllprocedurestypelibraries.htm
(如果你的 MSDN 安装在默认位置)
回调已经放到过程里面了,参数也改成byval,怎么还是出错呢!!!
如果有必要,我可以把dll发给你
改
Public Sub GetList(ByVal iCount As Long, ByVal info1 As PVEH_INFO)
回调函数为 Public Function GetList(byval iCount As Long, info1 As PVEH_INFO)
MsgBox iCount + info1.weight + info1.axistype + info1.speed
GetList = 0
End Function
to pigsanddos: 按你的方法修改,程序返回一个错误数值后直接崩溃不管怎样还是谢谢你们的回复,毕竟是看了我的东西的,感谢!!!如果有必要,我觉得还是把dll发给你们实验一下比较好
MsgBox iCount + info1.weight + info1.axistype + info1.speed
GetList = 0
End Function你写的GETLIST函数可不是什么回调函数,从头到尾一次性结束(我不讨论参数是传数值还是地址,明显第一个是需要数值,第二个才是地址),哪里有回调(递归)啦,你写之前应该看看该DLL对回调函数的说明规范。
MsgBox iCount + info1.weight + info1.axistype + info1.speed
End Function
{
GetListFunc = (pCallback_GetList)GetList;
int iCount = 1;
PVEH_INFO pVEH_INFO;
pVEH_INFO = new VEH_INFO;
pVEH_INFO->weight = 2;
pVEH_INFO->axistype = 3;
pVEH_INFO->speed = 4;
GetListFunc(iCount,pVEH_INFO);
return 0;
}
这里面有丝毫回调的迹象吗?执行了一次GETLIST返回后(而且还是不看返回数据的)就结束。
WimDev_List又何必把函数定义为RECALL呢,充其量就是调用了一次子函数,最多列举出一个设备名,所以我觉得奇怪。
用递归来理解确实不妥,回调来枚举集合元素应该是一个循环调用子函数的过程,循环退出的条件取决于子函数的返回值。
这里虽然dll是立刻调用了.
但以后呢. 说不定会创建一个线程立刻返回. 线程中等待某个事件, 然后去回调.
typedef struct {
long weight;
long axistype;
double speed;
}VEH_INFO, *PVEH_INFO;
我只是就题目论题目,没有考虑后续发展,如果说后续的工作,那干脆不要回调函数,由DLL把列举的信息放到全局内存块里去,再另外提供类似GETFIRST、GETNEXT的API,末了再加上一个释放的API,这样一来要用的就不必在按值传递还是按地址传递上纠缠不清了。把困难推给DLL的作者,用的人享享福吧。:)
模块:
Public Type PVEH_INFO
weight As Long
axistype As Long
speed As Double
End TypePublic info_dll As PVEH_INFO
Public count_dll As Long
Declare Function WimDev_List Lib "WtSys_DLL.dll" (ByVal GetList As Long) As Long
Public Sub GetList(ByVal iCount As Long, info1 As PVEH_INFO)
MsgBox iCount + info1.weight + info1.axistype + info1.speed
GetList = 0
End Sub
窗体:
Public Type PVEH_INFO
weight As Long
axistype As Long
speed As Double
End TypePublic info_dll As PVEH_INFO
Public count_dll As Long
窗体:
Private Sub Command10_Click()
Dim ret As Longret = WimDev_List(AddressOf GetList)End Sub
MsgBox iCount + info1.weight + info1.axistype + info1.speed
GetList = 0
End Sub中的GetList = 0去掉
下载地址:http://www.pc2n.com/index/register_do.jsp
用户名: [email protected]
口令: www.pc2n.com
文件: WtSys_dll.dll
接口见上,多谢大家,测试成功立刻结贴给分!!!!!!
#define CALLBACK PASCAL
#define WINAPI CDECL
#define WINAPIV CDECL
#define APIENTRY WINAPI
#define APIPRIVATE CDECL
#ifdef _68K_
#define PASCAL __pascal
#else
#define PASCAL
#endif
#elif (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
#define CALLBACK __stdcall
#define WINAPI __stdcall
#define WINAPIV __cdecl
#define APIENTRY WINAPI
#define APIPRIVATE __stdcall
#define PASCAL __stdcall
#else
#define CALLBACK
#define WINAPI
#define WINAPIV
#define APIENTRY WINAPI
#define APIPRIVATE
#define PASCAL pascal
#endif
100DEB1D FF15 78132D10 CALL DWORD PTR DS:[102D1378] ; Project1.00401B90
100DEB23 83C4 08 ADD ESP,8
这个是你dll的代码其中 [102d1378]存放的是那个回掉函数, 也就是AddressOf GetList
vb中所有的函数都是stdcall的, 所以
call [102d1378]的时候, vb结束的时候, 已经ret 8了
而你这里显然是一个_cdecl call。 看到后面的 ADD ESP,8了吗c/c++中, 默认的call都是_cdecl的, 即调用者自己清栈, 除非你改变c++的编译选项,
或者手动指定为stdcall.GetListFunc = (pCallback_GetList)GetList;也就是说你的 pCallback_GetList定义的有问题.
应该这样
typdef long (__stdcall *pCallback_GetList)(long iCount, VEH_INFO *pvinfo);
当然你把上面的 __stdcall 替换成 CALLBACK, WINAPI 等都没问题.
中偏移量为0x2cb23的3个字节改成0x90 0x90 0x90就OK了。
MsgBox iCount + info1.weight + info1.axistype + info1.speed
GetList = 0
End Function改为 Public Function GetList(iCount As Long, info1 As long)
copymemory mytype,byval info1,lenb(mytype)
MsgBox mytype.weight + mytype.axistype + mytype.speed
GetList = 0
End Function不过VC DLL里应该如何改我就不知道了.VC我一点都不会~~~~~~希望对你有帮助.
多谢你把问题引申到一个新的高度,越来越有意思了,你能告诉我为什么我用vc可以调用,而用
vb不能吗?????????
我仿照LZ给的代码自己做了一个带回调的库,代码如下:
//Test.H
#ifndef _TEST_H_
#define _TEST_H_
typedef struct {
long weight;
long axistype;
double speed;
}VEH_INFO, *PVEH_INFO; typedef void (__stdcall *pCallback_GetList)(int iCount, VEH_INFO *pvinfo);#ifdef __cplusplus
extern "C"{int __stdcall WimDev_List(pCallback_GetList GetList);}#endif#endif//Test.CPp#include "stdafx.h"
#include "test.h"int __stdcall WimDev_List(pCallback_GetList GetList)//void (CALLBACK *GetList)(int count, PVEH_INFO info) )
{
pCallback_GetList GetListFunc = (pCallback_GetList)GetList;
int iCount = 1;
PVEH_INFO pVEH_INFO;
pVEH_INFO = new VEH_INFO;
pVEH_INFO->weight = 2;
pVEH_INFO->axistype = 3;
pVEH_INFO->speed = 4;
GetListFunc(iCount,pVEH_INFO);
return 0;
}VB的测试代码如下:
'模块的代码Public Type VEH_INFO weight As Long
axistype As Long
speed As Double
End Type
Public Declare Function WimDev_List Lib "test.dll" (ByVal pGetList As Long) As Long
Public Sub GetList(ByVal count As Long, info As VEH_INFO)Debug.Print info.weight & ":" & info.axistype & ":" & info.speedEnd Sub
'窗体的代码
Private Sub Command1_Click() MsgBox WimDev_List(AddressOf GetList)
End Sub
你调用的有问题吗?如果需要我可以把我更详细的代码发给你看!
多谢大家,我想要的就是知其所以然.感谢
顺便说句不是地方的话,我痛恨中国足协!!!(特鲁西埃才是中国队的希望)
至于所以然,我现在还说不清楚,因为你的库里有很多其它函数,他们之间的关系我现在不清楚。就回调来说,你除了把WimDev_List函数的ByRef改成ByVal,其它没有什么问题。详细代码发给我吧:[email protected]
vc 的调用函数已经全部写完,没有任何问题,主要还是这个vb回调的问题了
我下了你的dll. 在我电脑上测试通过了. 给dll打了个补丁,把add esp,8 给nop掉了.
都说了是你的callback函数不是stdcall声名造成.
你那个debug 的dll很明显报了一个stack check error.
还要怎么说呢.
所以自己调自己当然没问题.但是所有的api, 以及dll都要声明成__stdcall, 因为考虑其他语言的调用.
而且__stdcall的比__cdecl要好, 最调用着代码要少些.关于调用约定的文章网上实在太多了.
当然你要先理解什么是栈先.void (CALLBACK *GetList)(int count, PVEH_INFO info) )
你这里也知道要用stdcall, CALLBACK就是stdcall, 因为vb要调他那么 typdef long (__stdcall *pCallback_GetList)(long iCount, VEH_INFO *pvinfo);
这里同样要用stdcall, 因为他要去调vb的代码.
你在c++中这里是去callback自己的代码,当然不要你假如把上面的些成了__stdcall, 你的vc的工程肯定编不过去.
你还需要把你vc中的的那个回掉函数也写成 __stdcall
如果你能动一下手搜索下"调用约定", 肯定不会有这么多疑问. 以至与提出
" 那你说为什么vc调用可以!!!!!!!拜托能不能所答是所问 "
这样的问题. 所以归纳成2点, 一是完全没有明白我在说什么.
二是稍懂一点, 却自己不愿动脑, 而是在等别人答案.
顺便拜托各位能不能从头看一看,不要重复提出问题,多谢
是你求人,不是别人求你好心帮你想了不少的,白忙了不说,还被说一通.实在对LZ是PF得不得了!!!!!
我也遇到类似vb调用别人的dll文件崩溃的情况,难道这些都是你说vb是用__stdcall方式,而C/C++默认用的是_cdecl方式?
那如果别人在编写这个dll文件时没有考虑到其它语言来调用它的话,那么是否可以用VC对这个dll文件再次封装来解决这个问题呢?
是你对,还是多谢你!
把dll动态链接库和整个vc测试和整个vb发过来。
把dll动态链接库和整个vc测试和整个vb发过来。
[email protected]