二代证、很奇怪的Dll调用(附汇编代码)

crxwz 2008-12-10 01:02:45
碰到一个很奇怪的问题,百思不得其解,特向高手请教

开发工具:VB6
程序:二代证的读取
条件:读卡器、二代证、stdapi.dll文件、厂家的读卡程序(VB编的)、没有SDK资料
问题:在使用SDT_ReadBaseMsg读取信息时返回“Dll调用约定错误”

函数原型(网络资料):int SDT_ReadBaseMsg(
int iPort,
unsigned char *pucCHMsg,
unsigned int *puiCHMsgLen,
unsigned char *pucPHMsg,
unsigned int *puiPHMsgLen,
int iIfOpen);

南疯大侠的C#声明(参考:http://www.cnblogs.com/name-lh/archive/2007/04/10/324003.html):
public static extern int SDT_ReadBaseMsg(
int iPortID,
string pucCHMsg,
ref int puiCHMsgLen,
string pucPHMsg,
ref int puiPHMsgLen,
int iIfOpen);

VB声明(自己翻译的):Private Declare Function SDT_ReadBaseMsg Lib "sdtapi.dll" (
ByVal iPort As Long,
ByRef pucCHMsg As String,
ByRef pucCHMsgLen As Long,
ByRef puvPHMsg As String,
ByRef puvPHMsgLen As Long,
ByVal iIfOpen As Long)

问题在于不管如何改变参数类型,总是报错,我试过全改成Any,也不行,Byte和数组也不行,改成Long然后传入PtrVar()也不行,厂家的读卡程序一切正常
这是厂家程序调用的汇编代码:
:004F61A7 0B47001800 ImpAdCallI2 ;Call ptr_004F2874; check stack 0018; Push EAX
:004F61AC 706EFF FStI2 ;Pop WORD [LOCAL_0092]
:004F61AF 3C SetLastSystemError ;Kernel GetLastError
:004F61B0 6B6EFF FLdI2 ;Push WORD [LOCAL_0092]
:004F61B3 F39000 LitI2 ;Push 0090
:004F61B6 C6 EqI2 ;
:004F61B7 1CF906 BranchF ;If Pop=0 then ESI=004F66A1
:004F61BA 222400 ImpAdLdPr ;
:004F61BD 895000 MemLdI2 ;Push WORD [[SR]+0050]
:004F61C0 F400 LitI2_Byte ;Push 00
:004F61C2 C6 EqI2 ;
:004F61C3 1C4802 BranchF ;If Pop=0 then ESI=004F61F0
:004F61C6 F500000000 LitI4 ;Push 00000000
:004F61CB F508000000 LitI4 ;Push 00000008
:004F61D0 054600 ImpAdLdRf ;Push ptr
:004F61D3 5968FF PopTmpLdAdStr ;
:004F61D6 4D58FF1160 CVarRef ;
:004F61DB 0448FF FLdRfVar ;Push LOCAL_00B8

请各位高手不吝赐教!
...全文
1153 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
LKY8848 2011-09-17
  • 打赏
  • 举报
回复
提供通用二代身份证WEB终端控件及控件的VB源代码:

提供二代身份证WEB终端控件 lkySfzCard.ocx ,用于WEB开发,并提供该控件的VB源代码,有需要者请联系我。
QQ:150227334

mrwinner 2010-02-08
  • 打赏
  • 举报
回复
谢谢啦 找到问题所在啦
marty2000 2009-04-21
  • 打赏
  • 举报
回复
如需要了解后者购买关于第二代身份证阅读器的信息可以与我联系,本人可提供包括二次开发在内的专业的技术支持。
QQ:35499174
marty2000 2008-12-17
  • 打赏
  • 举报
回复
提供国腾二代证阅读器、接口、二次开发例子。QQ:35499174
crxwz 2008-12-11
  • 打赏
  • 举报
回复
To off123:

还是不行,在两台电脑上都试了,问题依旧,您能否帮我测试一下,代码如下:

Private Declare Function SDT_ReadBaseMsgByStr Lib "sdtapi.dll" Alias "SDT_ReadBaseMsg" ( _
ByVal iPort As Long, _
ByVal pucCHMsg As String, _
ByRef pucCHMsgLen As Long, _
ByVal puvPHMsg As String, _
ByRef puvPHMsgLen As Long, _
ByVal iIfOpen As Long)


Private Declare Function SDT_ReadBaseMsgByByte Lib "sdtapi.dll" Alias "SDT_ReadBaseMsg" ( _
ByVal iPort As Long, _
ByRef pucCHMsg As Byte, _
ByRef pucCHMsgLen As Long, _
ByRef puvPHMsg As Byte, _
ByRef puvPHMsgLen As Long, _
ByVal iIfOpen As Long)

Dim ifOpen As Long
Dim iPort As Long
Dim L1 As Long, L2 As Long

Dim B1(1023) As Byte, B2(1023) As Byte
Dim S1 As String * 1024, S2 As String * 1024

Private Sub Main()
On Error Resume Next
iPort = 1: ifOpen = 1
Err.Clear
SDT_ReadBaseMsgByStr iPort, S1, L1, S2, L2, ifOpen
If Err Then MsgBox "ByStr:" & Err.Description, 64

Err.Clear
SDT_ReadBaseMsgByByte iPort, B1(0), L1, B2(0), L2, ifOpen
If Err Then MsgBox "ByByte:" & Err.Description, 64
End Sub
lsh2216024 2008-12-11
  • 打赏
  • 举报
回复
路過
of123 2008-12-11
  • 打赏
  • 举报
回复

下面是微软网站的说明:

VB "Bad DLL Calling Convention" Means Stack Frame Mismatch

SUMMARY
When you call a dynamic link library (DLL) function from Visual Basic for Window...When you call a dynamic link library (DLL) function from Visual Basic for Windows, the "Bad DLL Calling Convention" error is often caused by incorrectly omitting or including the ByVal keyword from the Declare statement or the Call statement. The ByVal keyword affects the size of data placed on the stack. Visual Basic for Windows checks the change in the position of the stack pointer to detect this error.

When Visual Basic for Windows generates the run time error "Bad DLL Calling Convention," the most common cause when calling API functions is omitting the ByVal keyword from the Declaration of the external function or from the call itself. It can also occur due to including the ByVal keyword when the function is expecting a 4 byte pointer to the parameter instead of the value itself. This changes the size (number of bytes) of the values placed on the stack, and upon return from the DLL, Visual Basic for Windows detects the change in the position of the stack frame and generates the error.

MORE INFORMATION
There are two calling conventions, or inter-language protocols: the Pascal/Basic/FORTRAN calling convention, and the C calling convention. Visual Basic for Windows uses the Pascal calling convention, as do the Microsoft Window API functions and other Microsoft Basic language products. Under the Pascal convention, it is the responsibility of the called procedure to adjust or clean the stack. (In addition, parameters are pushed onto the stack in order from the leftmost parameter to the rightmost.) Because the DLL function is responsible for adjusting the stack based on the type and number of parameters it expects, Visual Basic for Windows checks the position of the stack pointer upon return from the function. If the called routine has adjusted the stack to an unexpected position, then Visual Basic for Windows generates a "Bad DLL Calling Convention" error. Visual Basic for Windows assumes a stack position discrepancy because the DLL function uses the C calling convention. With the C calling convention, the calling program is responsible for adjusting the stack immediately after the called routine returns control.
of123 2008-12-11
  • 打赏
  • 举报
回复

哦,上次没有仔细看你的代码。

String 必须 Byval。因为它已经内部实现了指针。

函数原型(网络资料):int SDT_ReadBaseMsg(
int iPort,
unsigned char *pucCHMsg,
unsigned int *puiCHMsgLen,
unsigned char *pucPHMsg,
unsigned int *puiPHMsgLen,
int iIfOpen);

Private Declare Function SDT_ReadBaseMsg Lib "sdtapi.dll" (
ByVal iPort As Long,
ByVal pucCHMsg As String,
ByRef pucCHMsgLen As Long,
ByVal puvPHMsg As String,
ByRef puvPHMsgLen As Long,
ByVal iIfOpen As Long)

或者

Private Declare Function SDT_ReadBaseMsg Lib "sdtapi.dll" (
ByVal iPort As Long,
ByRef pucCHMsg As Byte,
ByRef pucCHMsgLen As Long,
ByRef puvPHMsg As Byte,
ByRef puvPHMsgLen As Long,
ByVal iIfOpen As Long)

后者调用时,Byte 型参数处采用类似 Buffer(0) 的方式。

crxwz 2008-12-11
  • 打赏
  • 举报
回复
老马还没到吗?嗷嗷叫的老马啊,快来救命啊。
crxwz 2008-12-11
  • 打赏
  • 举报
回复
To:of123

太感谢您了,已经可以了,输出值是Unicode编码,转化一下就可以得到正确结果了,谢谢你了。
of123 2008-12-11
  • 打赏
  • 举报
回复

哦,忽略了一点儿东西。试试:

Private Declare Function SDT_ReadBaseMsg Lib "sdtapi.dll" (
ByVal iPort As Long,
ByVal pucCHMsg As String,
ByRef pucCHMsgLen As Long,
ByVal puvPHMsg As String,
ByRef puvPHMsgLen As Long,
ByVal iIfOpen As Long) As Long

或者

Private Declare Function SDT_ReadBaseMsg Lib "sdtapi.dll" (
ByVal iPort As Long,
ByRef pucCHMsg As Byte,
ByRef pucCHMsgLen As Long,
ByRef puvPHMsg As Byte,
ByRef puvPHMsgLen As Long,
ByVal iIfOpen As Long) As Long

返回值的类型要声明一下。
crxwz 2008-12-11
  • 打赏
  • 举报
回复
用的是华视的CVR-100
前面的返回值正常,调用约定错误和前面的应该不相关的。
aohan 2008-12-11
  • 打赏
  • 举报
回复
用的是哪家公司的读卡器?

最近也做过身份证读取的,不过硬件厂商直接提供了一个Ocx,所以很快就搞定

我试了一下C#部分的是可以读到相关信息,确认一下前面几个部分是否已成功?

比如SDT_OpenPort、SDT_StartFindIDCard、SDT_SelectIDCard

crxwz 2008-12-10
  • 打赏
  • 举报
回复
To:of123
您的意思是该函数不是__stdcall调用吗?厂家的程序也是VB编的,经过分析,
1、应该没有使用中间库
2、从汇编代码看,使用重载的可能也不大,
3、我有怀疑库文件是不是不一样,参数定义不同,就把南疯大侠的库文件替换过去,并修改函数入口,信息可以正确读取。说明参数表是相同的。
of123 2008-12-10
  • 打赏
  • 举报
回复

VB 只能缺省调用 __stdcall 调用规范的函数。

解决方法有二:
1 你用 VC++ 写一个过渡 DLL 文件,原样调用厂家提供的函数,不同在于你的函数统统声明__stdcall 。

2 在 VB 中子类化,下面是例子:

[Visual Basic]

Imports System
Imports Microsoft.VisualBasic
Imports System.Runtime.InteropServices
Public Class LibWrap
' Visual Basic does not support varargs, so all arguments must be
' explicitly defined. CallingConvention.Cdecl must be used since the stack
' is cleaned up by the caller.
' int printf( const char *format [, argument]... )
<DllImport("msvcrt.dll", CallingConvention := CallingConvention.Cdecl)> _
Overloads Shared Function printf ( _
format As String, i As Integer, d As Double) As Integer
End Function
<DllImport("msvcrt.dll", CallingConvention := CallingConvention.Cdecl)> _
Overloads Shared Function printf ( _
format As String, i As Integer, s As String) As Integer
End Function
End Class 'LibWrap
Public Class App
Public Shared Sub Main()
LibWrap.printf(ControlChars.CrLf + "Print params: %i %f", 99,
99.99)
LibWrap.printf(ControlChars.CrLf + "Print params: %i %s", 99, _
"abcd")
End Sub 'Main
End Class 'App

crxwz 2008-12-10
  • 打赏
  • 举报
回复
To:僵哥
1、如果没有分配空间,最多结果不对,也不会调用错误
2、传入定长字符变量,问题依旧,即使是固定Byte数组也不行


stdapi.dll下载地址:http://files.cnblogs.com/name-lh/ICCARD.rar
测试代码:只要不出现调用错误就可以。

Private Declare Function SDT_ReadBaseMsg Lib "sdtapi.dll" ( _
ByVal iPortID As Long, _
ByRef pucCHMsg As String, _
ByRef puiCHMsgLen As Long, _
ByRef pucPHMsg As String, _
ByRef puiPHMsgLen As Long, _
ByVal iIfOpen As Integer)

Dim ifOpen As Long
Dim iPort As Long
Dim L1 As Long, L2 As Long

Dim b1(1023) As Byte, b2(1023) As Byte
Dim s1 As String * 1024, s2 As String * 1024

Private Sub Form_Load()
iPort=1
ifOpen=1
SDT_ReadBaseMsg iPort, s1, L1, s2, L2, ifOpen
End Sub
duyin2004 2008-12-10
  • 打赏
  • 举报
回复
是传值用ByVal变元,还是传址呀用ByRef变元,你的函数参数设定有问题
僵哥 2008-12-10
  • 打赏
  • 举报
回复
unsigned char对于的是Byte,虽然使用string也可以接收数据,但是需要预先分配空间。unsigned int *类似的倒是可以写太 Byref xx as Long
xrongzhen 2008-12-10
  • 打赏
  • 举报
回复
不懂 UP一下
下载代码方式:https://pan.quark.cn/s/dd3561eca308 在软件开发领域,面向对象编程(OOP)是一种普遍采纳的结构化方法,它使得开发者能够借助模拟现实环境中的实体和关系来构建软件系统。在本案例中,我们观察到的是一个关于借助抽象类来执行不同几何图形面积求解的实践应用。现在,让我们详细分析这一议题。 标题 "应用抽象类计算面积" 清晰地表明我们将要讨论一个抽象类,此类设定了一个用于测量图形面积的标准函数,但并未提供实际的执行过程。抽象类在诸如C#或Java等编程语言中通常借助`abstract`修饰符进行声明,它们无法直接创建对象实例,仅能作为其他类的基础模板。 描述部分提及的"图形界面应用"暗示这是一个基于视觉用户界面(GUI)的系统,可能运用了.NET Framework的Windows Forms或WPF技术,或者是Java平台的Swing或JavaFX框架。在这样环境下,用户能够通过视觉元素与这些几何体进行互动,例如输入相关尺寸并观看到计算得出的面积值。 抽象类“几何体”内嵌了“计算面积”这一抽象函数。在代码层面,这可以被表述为: ```csharp public abstract class GeometricShape { public abstract double CalculateArea(); } ``` 随后,有三个派生类:圆(Circle)、矩形(Rectangle)和三角形(Triangle),它们各自提供了这个抽象函数的具体实现。比如,圆的面积是通过π乘以半径的平方得到的,矩形的面积是长和宽的乘积,而三角形的面积可能是底乘以高再除以2的结果。这些类将提供具体实现来计算它们各自的面积: ```csharp p...
内容概要:本文系统研究了移相控制全桥LLC谐振变换器的工作特性,深入分析其在不同工作模式下的运行机理与性能表现,重点探讨了软开关实现、高效率能量转换及宽范围电压调节等关键技术优势。通过Simulink搭建精确的仿真模型,对谐振腔参数、开关频率、电压增益、系统效率等关键指标进行仿真分析,验证了理论设计的正确性。同时,详细研究了移相控制策略对系统动态响应、稳定性和轻载/重载工况适应性的影响,揭示了控制参数与电路参数之间的耦合关系,为高频高效电源设计提供了理论依据和实践指导。; 适合人群:具备电力电子技术、模拟电路及自动控制理论基础,从事开关电源、新能源变换器、电动汽车充电模块或高频电源系统研发的工程师及高校研究生。; 使用场景及目标:①掌握全桥LLC谐振变换器的拓扑结构、工作原理与关键参数设计方法;②理解移相控制在实现零电压开通(ZVS)和零电流关断(ZCS)中的作用机制;③通过Simulink仿真掌握变换器建模、参数优化与性能评估流程,服务于实际产品开发与学术课题研究。; 阅读建议:建议读者结合提供的Simulink仿真模型进行同步操作,重点关注谐振网络(Lr, Lm, Cr)参数与移相角之间的匹配设计,深入理解软开关条件的形成过程,并通过调整负载和输入电压进行多工况仿真,以全面掌握系统动态特性。

1,488

社区成员

发帖
与我相关
我的任务
社区描述
VB API
社区管理员
  • API
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧