二代证、很奇怪的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

请各位高手不吝赐教!
...全文
1154 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一下
内容概要:本文围绕“空地多无人平台协同路径规划技术”的论文复现展开,重点介绍了基于Matlab的多无人机与地面无人平台协同路径规划的算法实现与仿真研究。研究系统性地整合了无人机三维路径规划、动态避障、多机协同、任务分配及防撞机制等核心技术,结合智能优化算法(如遗传算法、粒子群算法、灰狼优化算法等)与经典路径规划模型(如Dubins路径、A*、RRT等),在复杂威胁环境下实现了高效、安全的协同路径规划。文中提供了完整的Matlab代码支持,便于科研人员进行算法验证、性能对比与二次开发,并强调通过复现高水平学术论文(如EI、SCI期刊及硕博论文)深入掌握该领域的前沿方法与技术路线。; 适合人群:具备一定Matlab编程基础,从事无人机系统、自动化控制、人工智能、路径规划等相关领域研究的研究生、科研人员及工程技术人员,尤其适用于正在开展科研项目、撰写学位论文或希望提升算法实践能力的研究者。; 使用场景及目标:① 复现并深入理解空地协同路径规划领域的高水平论文算法;② 掌握Matlab在多智能体路径规划中的建模、仿真与可视化方法;③ 应用于科研课题、毕业设计、项目申报及算法创新实践中,提升研究的技术深度与工程可行性。; 阅读建议:建议结合文中提供的网盘资源(含完整代码、仿真模型及参考文献资料)同步学习,优先选择与自身研究方向契合的案例进行复现,注重算法原理与代码实现之间的映射关系,并在掌握基础方案后尝试进行参数调优、算法融合或引入新约束条件以实现改进与创新。

1,488

社区成员

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

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