老问题,vc里面回调函数的参数是个结构体,下面这样
struct B2B_API B2B_SpotRate
{
char szID[33];
char szRateName[7];
long lValueDate;
double dblBid;
double dblAsk;
long lBidLimit;
long lAskLimit;
char szLimitCcy[4];
BOOL fTradable;
int nTicksize;
int nDisplayDecs;
long lTimestamp;
long lServerTimestamp;
};
在vb写回调函数时,那个对应的结构体不会写(主要是char数组那里搞不定),
另外想问一下,我在vb的ide运行程序完毕后,总有些资源没有释放掉的样子,
第二次运行该程序结果不一样,要退出ide再进入才正常,有什么方法解决?

解决方案 »

  1.   

    char数组用string*33,如果还不行就用szid(32) as byte
      

  2.   

    偶喜歡全部定義long 阿,呵呵
      

  3.   

    'struct B2B_API B2B_SpotRate
    type B2B_API B2B_SpotRate
    '{
    ' char szID[33];
    szID(32&) as byte
    ' char szRateName[7];
    szRateName(6&) as byte
    ' long lValueDate;
    lValueDate as long
    ' double dblBid;
    dblBid as double
    ' double dblAsk;
    dblAsk as double
    ' long lBidLimit;
    lBidLimit as long
    ' long lAskLimit;
    lAskLimit as long
    ' char szLimitCcy[4];
    szLimitCcy(3&) as byte
    ' BOOL fTradable;
    fTradable as long
    ' int nTicksize;
    nTicksize as long
    ' int nDisplayDecs;
    nDisplayDecs as long
    ' long lTimestamp;
    lTimestamp as long
    ' long lServerTimestamp;
    lServerTimestamp as long
    '};
    end type
      

  4.   

    改了就变得奇怪了,我在vb开发环境下运行程序就没有什么问题,但是生成exe运行就老是报内存出错,用dll源程序调试是ACCESS VOILATION得错误
      

  5.   

    哦,是copymemory出错,我vb中的回调函数基本上是这样写
        Dim rate As b2b_spotrate
        CopyMemory ByVal VarPtr(rate), ByVal lpTyp, Len(rate)
    不过老是回出现读内存错误(运行exe的情况下)
    另外,我vc上struct的修饰B2B_API是__declspec(dllexport)的意思,
    跟这个有没有关系呢
      

  6.   

    那你在执行copymemory之前最好先检查一下指针是否有效
    IsBadPtr或者直接lpTyp<>0我碰到好几个朋友都是因为调用约定的问题而出现了莫名其妙的访问违规错误,你也检查一下函数的调用约定看
      

  7.   

    我想如果有约定问题也是上面struct的修饰问题了,如前述声明是这样
    struct B2B_API B2B_SpotRate,
    也就是
    struct __declspec(dllexport) B2B_SpotRate
    这个我把修饰的B2B_API去掉后也出错,换用__stdcall出了一大堆错,没辙了
      

  8.   

    在vc版问了一下,stdcall是调用约定,只是作用于函数,所以问题应该不是出在结构定义上,如绿豆所言,我加了指针检查,但是还是那样,比较奇怪的就是在IDE运行就没有问题,
    但是生成Exe运行就出现地址访问错,在vb跟踪callback函数也不行,IDE直接关闭并弹出访问
    内存错,救命啊
      

  9.   

    你先缩小错误范围,看看哪里出问题,你在vb里选中生成调试信息后编译成exe,然后在vc里面进行调试比较好
      

  10.   

    声明好像没问题了阿,我还是对你的调用比较感兴趣。特别是回调的时候VB这一块,ByRef ByVal不能有闪失。
      

  11.   

    to supergreenbean
      已经是编译成exe,然后在vc环境下调试了,情况是每次走到回调函数那步就报access violation 的错误出来,估计就是在回调函数里面的copymemory出错了,我的copymemory
    这样声明
    Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    to pigpag
       除了copymemory外,其他dll里面的函数,如果有参数的话都是是用byval修饰的,
      

  12.   

    不好意思,汇编不了解,vc调试出现access violation时自动切换到汇编指令里面
    帮忙看看好么:
    6A29DB58   test        byte ptr [eax+76h],2
    6A29DB5C   mov         esi,dword ptr [ebp+0Ch]
    6A29DB5F   jne         6A2C590E
    6A29DB65   mov         eax,dword ptr [ebp+8]
    6A29DB68   xor         edi,edi
    6A29DB6A   cmp         eax,edi
    6A29DB6C   mov         dword ptr [ebp+0Ch],eax
    6A29DB6F   jl          6A2C5922
    6A29DB75   pop         edi
    6A29DB76   pop         esi
    6A29DB77   pop         ebx
    6A29DB78   leave
    6A29DB79   ret         8
    以上是其中一段,出错是在MSVBVM60.DLL
      

  13.   

    可以肯定的是,至少这段代码不是copymemory里的。错误的时候指在哪一句?
    里面写的语句看来看去最有可能在 mov         dword ptr [ebp+0Ch],eax上出问题,就是把eax的值赋给第2个参数,也就是[ebp+0Ch],你察看一下,是不是有什么应该传个变量来接受值的时候却传了个什么数字进去
      

  14.   

    这句就已经有可能有问题了:
    6A29DB5C   mov         esi,dword ptr [ebp+0Ch]
      

  15.   

    to james0001
    如何跟踪
    to supergreenbean
    我看了一下dll的编译参数,是使用/MD参数的,这是否表示该dll是多线程的,另外,为什么
    vb调用多线程dll会出问题
      

  16.   

    DLL有/MD倒没有什么题,只是说你的程序里面如果有CreateThread那就可能有问题了
      

  17.   

    因为dll是使用jni调用java类的,看运行信息还是会有
    The thread 0x82C has exited with code 0 (0x0).
    The thread 0x84C has exited with code 0 (0x0).
    The thread 0x82C has exited with code 0 (0x0).
    The thread 0x84C has exited with code 0 (0x0).
    The thread 0x7A8 has exited with code 0 (0x0).
    这样的信息,这个dll应该是多线程的
      

  18.   

    呵呵,原来是这么死的test        byte ptr [eax+76h],2这句上面是不是个 call 指令啊可能你的程序要修改一下了哦
      

  19.   

    是啊,你怎么知道,
    6A29DB52   call        dword ptr ds:[6A2810B8h]
    就是这句,你能说清楚一点么,是dll程序修改还是vb程序修改
      

  20.   

    test        byte ptr [eax+76h],2就是这句的问题,上面的 call 是 call API 函数 TlsGetValue(获取线程本地存储里的值),而得到的值是一个指针。如果在主线程内运行的话,此指针是有效的;但如果在其他线程的上下文里运行的话,此指针将会是无效的(NULL),因为线程本地存储里的值对每一个线程来说都是不一样的。VB运行库中有一些函数会调用这段会出错的代码,其中包括:
    __vbaNew2  -  New 语句时调用, 
    __vbaCastObj  -  对对象赋值时调用, 
    __vbaRedim  -  ReDim 语句时调用, 
    __vbaSetSystemError  -  调用以 Declare 语句声明的函数(API)后调用由此可见,在你的VB程序中,当回调函数在非主线程的上下文里调用完 CopyMemory 以后,立即会调用__vbaSetSystemError函数,而__vbaSetSystemError函数会调用以上出错的代码,接而产生AV错误。这也是 vb 多线程程序通常产生错误的原因所在。如果要解决此问题的话,可以把每一个线程里相对应的线程本地存储值都换成和主线程一样的,或者可以让vb程序在调用完api后不调用__vbaSetSystemError函数,或者可以让 dll 在主线程的上下文里调用回调函数,也可以避免使用 api 和其他一些可能调用以上运行库函数的代码。以上只是我的一些研究成果 :),希望各位补充和指正。
      

  21.   

    James0001说得没错。只是,VB里面TlsGetValue太多,很难避免,除非你只用自定的API函数类型库中声明的API来进行编程。
      

  22.   

    这一句有问题:
    CopyMemory ByVal VarPtr(rate), ByVal lpTyp, Len(rate)如果用默认的声明:Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    就这样写:CopyMemory rate, ByVal lpTyp, Len(rate)如果用修改的申明:Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Dest As Long, ByVal Src As Long, ByVal Length As Long)
    就这样写:CopyMemory VarPtr(rate), lpTyp, Len(rate)
      

  23.   

    CopyMemory ByVal VarPtr(rate), ByVal lpTyp, Len(rate)
    这样就不会错啦