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会报错退出?
实在是不知道怎么回事,小弟没有很长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会报错退出?
解决方案 »
- 一个非常烦人的问题。例如想用.Value=true让程序选中选项钮,却在暗中自动激发了它的click事件。类似的问题,在一个有5万行以上的代码中如何去发现它呢?难道要经常一句一句的去调试跟踪?有专门软
- 请问用Quartz.dll如何控制声道?
- 用app以后,再用errorhandler,会向事件查看器里不停的写记录??
- 如何动态的添加用户控件
- 菜鸟报道,顺便问个问题
- 高手请进 条码打印问题 急!!!!!!!!!!!!
- 控件汉化
- 关于VB中字符宽度和字符高度的问题
- 急急急急急急!请zyl910(910:分儿,我来了!) 进来看看(帮忙顶一顶)
- 寻找一个程序,用vb编写的转盘抽奖程序
- VB连接SQL时语句区别
- CreateCompatibleDC
Public Declare Function write_info Lib "Card.dll" (ByRef disobey_info As val) As Longval是我定义的结构然后在vb里面调用此函数
write_info wfsz 'wfsz为已赋过值的结构体
vc:
struct vb_struct
{
char a[1];
char b[31];
int c;
}
名字我给改了一下
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
我试过了 参数是用户自定义结构类型的,所以LONG不可以吧?
还有byref吧,传值会报自定义类型不能用的错误
这个申明中传递给write_info函数的是自定义类型变量的首地址,必须用ByVal,不能用ByRef。
您有QQ吗?
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也是保留字,不要使用,容易引起莫名其妙的问题。
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两种类型,因为没有具体错误提示所以很困惑希望能帮小弟我一把:)
==》
CopyMemory wfxws.drv(0), a(0), 31另外,你的意思,是不是你的程序中传递的结构不光这一种,还有不少类似的结构在程序中使用?若是这样,就不好说了,按指针传递结构情况很复杂,VB的结构有时会在元素间加上衬垫,以便于32位CPU的处理(4字节为一个单位,因不能让某一个元素跨在两个单位之间,有时需补字节衬垫),我的经验,一般可用Len与LenB测一下结构的长度,若二者相同,适合按指针传递。否则,就很麻烦,需手工复制进Byte数组,再传递。
楼主的BYTE数组没有考虑到汉字的情况,会有溢出错误的。Public Declare Function write_info Lib "Card.dll" (disobey_info As any) As Long
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都不大会有字节对齐方面的问题。楼主还是先检查看*到底是哪一句*让程序崩溃了
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)
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从你原义可见,似乎应该使用后者。
我是按您说的那样先ASC转换然后再CBYTE赋值的,另外问一下VC结构中有INT型的参数在VB中调用时用LONG型的相对应,在赋值的时候直接用 val.SS=CLNG(WFSZ(2))这种写法可以吧?
我一直在试,可是总是崩溃。。我按您的方法输出了所有要传的值,结果都可以显示出来,只是因为有的长度和VC提供的长度不符,都用CBYTE(0)补齐了,既然在C的结构中是以char bianliang [31]这种形式定义的,那我在VB里面定义相应的BYTE型的数组然后传过去应该也是可以的吧,为什么总是崩溃。。
再考虑怎么解决 数据正确传递的问题 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程序退出
{
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;
}