DLL为VC开发(读写IC卡),由VB调用,现在读卡没有问题,可是在写卡的时候却VB总是退出。
实在是不知道怎么回事,小弟没有很长DLL开发经验,希望大虾指点
vc:
struct vb_struct
{
char a[1];
char b[31];
int c;
}
vb:
Type val
  Dim ver As Byte
  Dim name(30) As Byte
  Dim ss As Long
End Type赋值语句如下:   If wfsz(7) <> "" Then'要给结构中NAME赋值的变量(存在数组中的)
   For i = 1 To 31'数组维数
   If i <= Len(wfsz(7)) Then'如果维数小于等于值的长度则进行转换,否则赋成0
   wfxws.name(i - 1) = CByte(Asc(Mid(wfsz(7), i, 1)))
   Else
   wfxws.name(i - 1) = CByte(0)
   End If
   Next
   Else'如果变量为空值的话则全部为cbyte(0)
     For i = 1 To 31
      wfxws.name(i - 1) = CByte(0)
      Next
   End If'''''''''''''''''''''''''''''''''''''''''''If wfsz(8) <> "" Then
wfxws.ss = CLng(wfsz(8))
Else
wfxws.ss = 0
End If请问这样写有没有问题?为什么VB会报错退出?

解决方案 »

  1.   

    因为这样,vb和vc的结构体是不同的,因为vb的占用字节数比vc大,因此参数是结构体的vb没法给vc传值我不会传得方法也许有高手
      

  2.   

    这种结构应该是可以传的。关键是:dll中函数是怎么声明的?你的结构是怎么传的?出错有提示吗?
      

  3.   

    int WINAPI write__info(drv_info *info);这是DLL中声明的函数,
    Public Declare Function write_info Lib "Card.dll" (ByRef disobey_info As val) As Longval是我定义的结构然后在vb里面调用此函数
    write_info wfsz 'wfsz为已赋过值的结构体
      

  4.   

    drv_info是VC里的定义的结构
    vc:
    struct vb_struct
    {
    char a[1];
    char b[31];
    int c;
    }
    名字我给改了一下
      

  5.   

    申明:
    Public Declare Function write_info Lib "Card.dll" (ByVal disobey_info As Long) As Long调用:
    write_info(VarPtr(wfsz))另外你的val类型申明应该是:
    Type val
      ver As Byte             '原来你写的Dim都是多余的
      AName(30) As Byte       'Name是保留字, 不能用
      ss As Long
    End Type
      

  6.   

    楼上的大哥,谢谢你
    我试过了 参数是用户自定义结构类型的,所以LONG不可以吧?
    还有byref吧,传值会报自定义类型不能用的错误
      

  7.   

    VarPtr(wfsz)函数返回的是这个自定义类型变量的首地址, 是个LONG类型的值。Public Declare Function write_info Lib "Card.dll" (ByVal disobey_info As Long) As Long
    这个申明中传递给write_info函数的是自定义类型变量的首地址,必须用ByVal,不能用ByRef。
      

  8.   

    我改了代码,可是VB程序退出了
    您有QQ吗?
      

  9.   

    再问一遍:
    VB退出是指什么?有错误提示吗?若有是什么提示?jadeluo(秀峰)的写法是可以的,你要再仔细看一下,自己是不是有什么地方忽略了?
    此外,你的原代码也有问题,wfxws.name这样赋值会产生岐义,且不支持中文。可改成这样:
    dim a() as Byte
    a=strconv(wfsz(7),vbfromunicode)
    redim preserve a(30)
    copymemory  wfxws.aname(0),a(0),31另外除Name不要用之外,Val也是保留字,不要使用,容易引起莫名其妙的问题。
      

  10.   

    对不起,前面写的有些乱,我现在重新整理一下
    VC结构如下:
    struct vb_struct
    {
    char a[1];
    char b[31];
    int c;
    }
    VB结构如下:
    vb:
    Type temp
      Dim ver As Byte
      Dim drv(30) As Byte
      Dim ss As Long
    End Type程序调用:
    Public Declare Function write_info Lib "Card.dll" (ByVal disobey_info As Long) As Long
    定义数组WFSZ()为结构中的各值传值
    Dim a() As Bytewfxws.ver=cbyte(wfsz(0))a = StrConv(wfsz(1), vbFromUnicode)
    ReDim Preserve a(30)
    CopyMemory wfxws.drv(0), b(0), 31wfxws.ss=clng(wfsz(2))然后调用DLL中的函数
    test= write_info(VarPtr(wfxws))
    这样写对吗?回小吉大哥:
    退出就是指的VB程序在运行时,一调用DLL里的写卡函数时程序就报VB遇到问题需要关闭,点对话框按钮VB就退出了,还要重新加开VB程序我调试的程序结构定义的比较多,不过就是CHAR 和INT两种类型,因为没有具体错误提示所以很困惑希望能帮小弟我一把:)
      

  11.   

    CopyMemory wfxws.drv(0), b(0), 31 ??????
    ==》
    CopyMemory wfxws.drv(0), a(0), 31另外,你的意思,是不是你的程序中传递的结构不光这一种,还有不少类似的结构在程序中使用?若是这样,就不好说了,按指针传递结构情况很复杂,VB的结构有时会在元素间加上衬垫,以便于32位CPU的处理(4字节为一个单位,因不能让某一个元素跨在两个单位之间,有时需补字节衬垫),我的经验,一般可用Len与LenB测一下结构的长度,若二者相同,适合按指针传递。否则,就很麻烦,需手工复制进Byte数组,再传递。
      

  12.   

    我的经验是需要向API传递结构参数则声明成ANY,有人说VB的结构不好传给VC写的DLL是不对的,许多API都需要结构作参数,而MSDN中全是C形式的,完全可以用VB来仿照,关键是你必须把参数声明成ANY,只要把地址传给API就可以了。
    楼主的BYTE数组没有考虑到汉字的情况,会有溢出错误的。Public Declare Function write_info Lib "Card.dll" (disobey_info As any) As Long
      

  13.   

    单就你这个temp结构来说,肯定是不会有对齐问题的,因为所有变量大小加起来刚好是4的倍数Type temp
      ver As Byte'1字节
      drv(30) As Byte'31字节
      ss As Long'4字节
    End Type但是如果结构中相邻的几个成员的大小不为4的倍数的话那就会有对齐问题了,比如你的结构改成
    Type temp
      ver As Byte'1字节
      drv(29) As Byte'30字节
      ss As Long'4字节
    End Type那么在drv(29)成员和ss成员之间就会被插入1个空字节。在这种情况下,如果调用函数所在dll的对齐方式如果也和vb的对齐方式是同样的话(4字节对齐),那么基本上就没什么问题。但如果两者的对齐方式不一样,那就麻烦了。要么你改变dll的对齐方式,然后重新编译;要么你就按照dll对齐方式排列vb中数据,一般也就是把成员按照dll对齐方式复制到1个字节数组中,然后把数组首元素地址传过去。
    你程序出错退出原因可能是多方面的,并不一定就是在write_info这个函数的调用上,而且一般象这种开发商提供的dll都不大会有字节对齐方面的问题。楼主还是先检查看*到底是哪一句*让程序崩溃了
      

  14.   

    我定义的是BYTE型的,也就是传过来的数据我都转成BYTE型然后赋给数组,目前要写到卡里的数据都是数字
    Dim wfsz(19) As String
     If wfsz(1) <> "" Then
       For i = 1 To 31
       If i <= Len(wfsz(1)) Then
       wfxws.doc_no(i - 1) = CByte(Asc(Mid(wfsz(1), i, 1)))
       Else
       wfxws.doc_no(i - 1) = CByte(0)
       End If
       Next
       Else
         For i = 1 To 31
          wfxws.doc_no(i - 1) = CByte(0)
          Next
       End If用这种方法把数据赋到结构中,在断点测试中看到结构中已经赋值成功了。不知道这样写行不行。。
    导致崩溃就是调用那个写卡函数的时候,因为把断点设在那里前面的语句都没有问题,可是一按F8就完了
    小吉大哥:
    在我要调的DLL里面有很多CHAR〔〕型的,长度也不一样,都是根据数据要求设定的长度如:写入日期就是char write_date[5]最后一位补CBYTE(0)
      

  15.   

    这种写法不适合中文,但对于纯数字,除了速度极慢外,也是可以的。若都是按前面所述方法调用,格式上看不出什么问题,所以你要考虑是不是数据不对引起的。wfxws.doc_no赋值后,你可以用
    Debug.print strconv(wfxws.doc_no,vbunicode)
    看看,输出的数据是不是你要传递的数据?还有Cbyte在处理数字时,容易发生岐义,要看Dll是需要String,还是Byte,否则很容易弄错,比如:wfxws.Ver是一个字节的数据,它如果解释为字节,那么可表示0-255种版本,若解释为String则只能表示0-9种版本在用Cbyte转换时很容易弄错,如表示版本2
    wfsz(0)="2"若解释为Byte则
    wfxws.Ver=cbyte(wfsz(0)) '该字节为&H2若解释为String则
    wfxws.Ver=cbyte(Asc(wfsz(0))) '该字节为&H32从你原义可见,似乎应该使用后者。
      

  16.   

    照上面你所写的,那么的确可能就是因为你数据错误而引起的。在现在这种情况下最快找出问题的办法就是调试跟踪进入你所调用的dll
      

  17.   

    楼上的大哥,请问怎么样跟踪进入我调用的DLL?我对调用DLL不是很熟悉小吉大哥:
    我是按您说的那样先ASC转换然后再CBYTE赋值的,另外问一下VC结构中有INT型的参数在VB中调用时用LONG型的相对应,在赋值的时候直接用 val.SS=CLNG(WFSZ(2))这种写法可以吧?
      

  18.   

    可以的,VC中的INT对应VB中的Long。你没有Dll的源码,不了解Dll,至少应该弄这个结构在Dll中的用途,每个元素在其内部是怎么处理的,按什么类型去处理?在取值是什么的情况下属于非法数据。Byte数组是最基本的数据类型,可以表示任何其他数据类型,不明白Dll中处理的类型需求,是很难找出问题根源的。
      

  19.   

    您有QQ吗?我管别人要了一个VC调用这个DLL的例子,可以详细跟您请教一下吗?我的QQ是559135
    我一直在试,可是总是崩溃。。我按您的方法输出了所有要传的值,结果都可以显示出来,只是因为有的长度和VC提供的长度不符,都用CBYTE(0)补齐了,既然在C的结构中是以char bianliang [31]这种形式定义的,那我在VB里面定义相应的BYTE型的数组然后传过去应该也是可以的吧,为什么总是崩溃。。
      

  20.   

    我觉得楼主应该先解决vb程序退出的问题
    再考虑怎么解决 数据正确传递的问题 Type drv_info
       Data as String * 36 '因为一共占了36个字节
    End Type
    Public Declare Function write_info Lib "Card.dll" (disobey_info As drv_info) As Long调用的时候可以先
    Dim ret as long
    Dim wfxws as drv_info
    '给这个wfxws分配空间
    wfxws.Data=string(36,chr(0)) 'space(36) 
    '调用API
    ret=write_info(wfxws)看看运行会不会非法关闭或者用Type drv_info
       Data(1 to 36) as Byte '定义Byte数组时,最好指定下标 上标 
    '因为Option Base 0 Option Base 1 的含义完全不同
    End Type
    Public Declare Function write_info Lib "Card.dll" (disobey_info As drv_info) As Long调用
    Dim ret as long
    Dim i as integer
    Dim wfxws as drv_info
    '给这个wfxws分配空间
    For i=1 to 36
     wfxws.Data(i)= 0
    Next
    '调用API
    ret=write_info(wfxws)看看运行会不会非法关闭
    我们写这些的目的都不是为了传递数值 而是看要传多少个字节的值过去才不会造成 vb程序退出
      

  21.   

    一般象vc之类的调试工具都可以用来跟踪调试你的dll,但是看你对此应该不是很熟悉。你还是仔细看看dll的相关文档或其他语言的调用例子。方便的话你把vc的例子贴来大家看看吧
      

  22.   

    这是C的一个调用,“drv_disobey_info”是结构名称LRESULT CALLBACK Drv(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
    drv_disobey_info dd_info;
    int ret; switch (message)
    {
    case WM_INITDIALOG:
    return TRUE; case WM_COMMAND:
    if (LOWORD(wParam) == IDC_READ ) 
    {
    GetDlgItemText(hDlg,IDC_EDIT1,dd_info.doc_type,sizeof(dd_info.doc_type));
    GetDlgItemText(hDlg,IDC_EDIT2,dd_info.doc_no,sizeof(dd_info.doc_no));
    ....
    .... open_mc900(1);
    ret=write_drv_disobey_info(&dd_info);
    close_mc900();
    if (ret==0)
    {
    return TRUE;
    } else {
    show_mess(hDlg,ret);
    return FALSE;
    }
    }
    if (LOWORD(wParam) == IDCANCEL) 
    {
    EndDialog(hDlg, LOWORD(wParam));
    return TRUE;
    }
    break;
    }
        return FALSE;
    }
      

  23.   

    drv_disobey_info结构好象在上面没有出现过嘛,这个结构VC怎么声明的?
      

  24.   

    hoho,这样问来问去太麻烦,我加你QQ吧