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)
每次都出错,希望能给出解释,多谢

解决方案 »

  1.   

    (ByRef GetList As Long) 改成 ByVal
    回掉要放到过程里面。
    参看 mk:@MSITStore:C:\Program%20Files\Microsoft%20Visual%20Studio\MSDN98\98VS\2052\vbcon98.chm::/Html/vbconpassingfunctionpointerstodllprocedurestypelibraries.htm
    (如果你的 MSDN 安装在默认位置)
      

  2.   

    to: caozhy
    回调已经放到过程里面了,参数也改成byval,怎么还是出错呢!!!
    如果有必要,我可以把dll发给你
      

  3.   

    Public Function GetList(iCount As Long, info1 As PVEH_INFO)

    Public Sub GetList(ByVal iCount As Long, ByVal info1 As PVEH_INFO)
      

  4.   

    Declare Function WimDev_List Lib "WtSys_DLL.dll" (byval GetList As Long) As Long
    回调函数为 Public Function GetList(byval iCount As Long, info1 As PVEH_INFO)
            MsgBox iCount + info1.weight + info1.axistype + info1.speed
            GetList = 0
                End Function
      

  5.   

    to caozhy:  按你的方法修改,ByVal info1 as PVEH_INFO不能通过编译,自定义结构变量不能传值吧,改成Public Sub GetList(ByVal iCount As Long, info1 As PVEH_INFO)还是不行,不过不是直接崩溃了,出来了一个c++的错误提示框,而且返回值也不对
    to pigsanddos: 按你的方法修改,程序返回一个错误数值后直接崩溃不管怎样还是谢谢你们的回复,毕竟是看了我的东西的,感谢!!!如果有必要,我觉得还是把dll发给你们实验一下比较好
      

  6.   

    to:pigsanddogs(我爱吃猪肉,但是长不胖,为什么??) 每天晚上一瓶啤酒+花生米就可以了,肉那么爱吃,再来半斤效果更好:)
      

  7.   

    Public Function GetList(iCount As Long, info1 As PVEH_INFO)
            MsgBox iCount + info1.weight + info1.axistype + info1.speed
            GetList = 0
                End Function你写的GETLIST函数可不是什么回调函数,从头到尾一次性结束(我不讨论参数是传数值还是地址,明显第一个是需要数值,第二个才是地址),哪里有回调(递归)啦,你写之前应该看看该DLL对回调函数的说明规范。
      

  8.   

    to province_(雍昊): 看来你没弄过回调函数吧,回调跟递归有什么关系
      

  9.   

    函数改成这样基本就可以了,如果还有错,那就请查看下你的PVEH_INFO声明Declare Function WimDev_List Lib "WtSys_DLL.dll" (ByVal GetList As Long) As LongPublic Sub GetList(ByVal iCount As Long, info1 As PVEH_INFO)
            MsgBox iCount + info1.weight + info1.axistype + info1.speed
    End Function
      

  10.   

    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;
       }
    这里面有丝毫回调的迹象吗?执行了一次GETLIST返回后(而且还是不看返回数据的)就结束。
    WimDev_List又何必把函数定义为RECALL呢,充其量就是调用了一次子函数,最多列举出一个设备名,所以我觉得奇怪。
    用递归来理解确实不妥,回调来枚举集合元素应该是一个循环调用子函数的过程,循环退出的条件取决于子函数的返回值。
      

  11.   

    当然有必要, 因为在这里是一个接口, 为以后扩充起作用. 这样vb代码就可以不改动
    这里虽然dll是立刻调用了.
    但以后呢. 说不定会创建一个线程立刻返回.  线程中等待某个事件, 然后去回调.
      

  12.   

    上述方法都不行啊
    typedef struct {
    long weight;
    long axistype;
    double speed;
    }VEH_INFO, *PVEH_INFO;  
      

  13.   

    TO爱吃肉的兄弟
    我只是就题目论题目,没有考虑后续发展,如果说后续的工作,那干脆不要回调函数,由DLL把列举的信息放到全局内存块里去,再另外提供类似GETFIRST、GETNEXT的API,末了再加上一个释放的API,这样一来要用的就不必在按值传递还是按地址传递上纠缠不清了。把困难推给DLL的作者,用的人享享福吧。:)
      

  14.   

    所有vb代码已经贴出,请帮忙分析看看,还是老话,有必要可以把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
      

  15.   

    Public Sub GetList(ByVal iCount As Long, info1 As PVEH_INFO)
    MsgBox iCount + info1.weight + info1.axistype + info1.speed
    GetList = 0
    End Sub中的GetList = 0去掉
      

  16.   

    还是不行,我看大家还是去下载我的dll实验一下最好!!!
    下载地址:http://www.pc2n.com/index/register_do.jsp
    用户名: [email protected]
    口令:   www.pc2n.com
    文件: WtSys_dll.dll
    接口见上,多谢大家,测试成功立刻结贴给分!!!!!!
      

  17.   

    void (CALLBACK *GetList)(int count, PVEH_INFO info) )的声明有问题你没有把GetList函数声明为__stdcall类型
      

  18.   

    CALLBACK 就是__stdcall#ifdef _MAC
    #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
      

  19.   

    100DEB1C                          51               PUSH ECX
    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 等都没问题.
      

  20.   

    是你dll写的有问题, 你在怎么在vb上改都没办法.
      

  21.   

    如果你有疑问, 你把你的提供下载的 dll
    中偏移量为0x2cb23的3个字节改成0x90 0x90 0x90就OK了。
      

  22.   

    我有个小小的意见哦~~~虽然我用回调用得不多,但从系统的回调里来看,好象还没有发现直接回调时就传个结构过来的?我觉得LZ是否应该参考下WINDOWS的做法?就是在回调时,传回一个指针,而不是结构~~~然后在VB的回调过程里,用CopyMemory来把指针所指内存复制到VB里定义好的一个结构时vb定义 Declare Function WimDev_List Lib "WtSys_DLL.dll" (ByVal 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改为 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我一点都不会~~~~~~希望对你有帮助.
      

  23.   

    to:pigsanddogs(我爱吃猪肉,但是长不胖,为什么??) 
    多谢你把问题引申到一个新的高度,越来越有意思了,你能告诉我为什么我用vc可以调用,而用
    vb不能吗?????????
      

  24.   

    我看看了DLL库中除了WimDev_List函数外,还有一个WimDev_Init函数,所以我感觉问题出现的原因在于使用WimDev_List函数前,是不是还需要调用别的函数。
    我仿照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
      

  25.   

    to:benyfeifei(狒狒)
    你调用的有问题吗?如果需要我可以把我更详细的代码发给你看!
    多谢大家,我想要的就是知其所以然.感谢
    顺便说句不是地方的话,我痛恨中国足协!!!(特鲁西埃才是中国队的希望)
      

  26.   

    我的调用没有问题。
    至于所以然,我现在还说不清楚,因为你的库里有很多其它函数,他们之间的关系我现在不清楚。就回调来说,你除了把WimDev_List函数的ByRef改成ByVal,其它没有什么问题。详细代码发给我吧:[email protected]
      

  27.   

    大家好,这一段忙别活了,现在必须把这个弄好了
    vc 的调用函数已经全部写完,没有任何问题,主要还是这个vb回调的问题了
      

  28.   

    lz你理解力真的有问题
    我下了你的dll. 在我电脑上测试通过了. 给dll打了个补丁,把add esp,8 给nop掉了.
    都说了是你的callback函数不是stdcall声名造成.
    你那个debug 的dll很明显报了一个stack check error. 
    还要怎么说呢.
      

  29.   

    因为c++, 如果不做额外声明(比如工程中声明成__stdcall), 他自己就是__cdecl,
    所以自己调自己当然没问题.但是所有的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点, 一是完全没有明白我在说什么.
    二是稍懂一点, 却自己不愿动脑, 而是在等别人答案.
      

  30.   

    你的DLL编译的时候要加上声明,是_stdcall才行,傻瓜。
      

  31.   

    zzmwz(zzmwz) ( ) 信誉:85    Blog  2006-8-21 16:19:26  得分: 0  
     
     
       
    顺便拜托各位能不能从头看一看,不要重复提出问题,多谢
    是你求人,不是别人求你好心帮你想了不少的,白忙了不说,还被说一通.实在对LZ是PF得不得了!!!!!
      

  32.   

    to:pigsanddogs(我爱吃猪肉,但是长不胖,为什么??) 
    我也遇到类似vb调用别人的dll文件崩溃的情况,难道这些都是你说vb是用__stdcall方式,而C/C++默认用的是_cdecl方式?
    那如果别人在编写这个dll文件时没有考虑到其它语言来调用它的话,那么是否可以用VC对这个dll文件再次封装来解决这个问题呢?
      

  33.   

    可以用__stdcall重新包装过,也可以直接在vb里打patch
      

  34.   

    我没有我所调用的dll的源代码,但是我在bc中看到别人能够正常调用,就和楼主说的一样,那么如果,我想要调用它里面的函数该怎么办呢?是在把它的dll文件从新封装一遍成新的dll,还是在vb中可以修改,避免这样的情况呢?
      

  35.   

    pigsanddogs(我爱吃猪肉,但是长不胖,为什么??) 
    是你对,还是多谢你!
      

  36.   

    我是玩VB开发的,看我能不能解答,
    把dll动态链接库和整个vc测试和整个vb发过来。
      

  37.   

    我是玩VB开发的,看我能不能解答,
    把dll动态链接库和整个vc测试和整个vb发过来。
    [email protected]