C写的DLL用DELPHI调用的问题,实在是找不到哪儿错了。请各位富翁救命。 200分送上 ( 积分: 200 )

冷涯

Unregistered / Unconfirmed
GUEST, unregistred user!
DLL主要功能是用来读指定型号的IC卡,总共有六七个对外提供的函数,但其中有一个参数最多,也是最重要的函数怎么试也不行,就是无法将所有参数信息都正确的读出来,请大家多提点建议,到底应该怎么办呢?十万火急,救命哪。
关于DLL函数的声明文档如下:(就是这个函数,一旦正确读到卡内信息,它就会抛出一个异常,并且TRY不住,读到的值也只有部分正确。好几天了,试了无数种办法,怎么都不行,快崩溃了。)
Siic32.dll接口函数说明
iReadBasicInfo
String : pchar
long iReadBasicInfo(HANDLE hCom, char* Pin, char* CardCode,
char* SiCode, char* Name, char* Sex, char* Nation, char* Personid,
char* UnitCode, char* UnitName, char* Address, char* PostCode,
char* Tel, char* PersonType, char* Issueid, char* ExpireDate,
char* ErrMsg)

输入参数:
参数 涵义 数据类型 长度
Hcom HANDLE
Pin 字符串 6

输出参数:
参数 涵义 数据类型 长度
CardCode 字符串 9
SiCode 字符串 18
Name 字符串 30
Sex 字符串 1
Nation 字符串 2
Personid 字符串 18
UnitCode 字符串 9
UnitName 字符串 70
Address 字符串 80
PostCode 字符串 6
Tel 字符串 15
PersonType 字符串 2
Issueid 字符串 24
ExpireDate 字符串 8
ErrMsg 字符串

返回值:
返回值类型:整数
返回值 涵义
0 处理成功
其它 处理失败

我在DELPHI中是这样做的:

unit Unit1;

interface

uses
ShareMem, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Label1: TLabel;
Edit1: TEdit;
Label2: TLabel;
Edit2: TEdit;
Button1: TButton;
Label3: TLabel;
Edit3: TEdit;
Label4: TLabel;
Edit4: TEdit;
Label5: TLabel;
Edit5: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

uses CommUnit2;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
Var
li_com : Pointer;
li_rtn:Integer;
ls_rtn:String;
ls_card:pAnsiChar;
ls_CardCode :pChar;
ls_SiCode:pChar;
ls_Name:pChar;
ls_Sex:pChar;
ls_Nation:pChar;
ls_Personid:pChar;
ls_UnitCode:pChar;
ls_UnitName:pChar;
ls_Address:pChar;
ls_PostCode:pChar;
ls_Tel:pChar;
ls_PersonType:pChar;
ls_Issueid:pChar;
ls_ExpireDate:pChar;
ls_ErrMsg:pChar;
begin
ls_rtn := ' ';
li_com := MyCom_Open(1,ls_rtn);
Edit1.Text := '1 ';
If li_com = pinteger(0) THen
Begin
ShowMessage(ls_rtn);
Exit;
End;
ShowMessage( 'open ok ');
ls_rtn := ' ';
li_rtn := MyCom_Test(li_com,ls_rtn);
if li_rtn < > 0 then
Begin
ShowMessage(ls_rtn);
MyCom_Close(li_com,ls_rtn);
Exit;
end;
ShowMessage( 'test ok '+ls_rtn);
ls_rtn := ' ';
li_rtn := Myicc_testcard(li_com,ls_rtn);
If li_rtn < >0 Then
Begin
ShowMessage( '请插入IC卡! '+ls_rtn);
MyCom_Close(li_com,ls_rtn);
Exit;
end;
ShowMessage( 'testcard ok '+ls_rtn);
ls_rtn := ' ';
ls_card := ' ';
li_rtn := MyiGetCardCode(li_com,ls_rtn);
if li_rtn < > 0 then
begin
Application.MessageBox(pchar(ls_rtn), '错误消息 ',MB_OK+MB_ICONERROR);
exit;
end;
Edit3.Text := ls_rtn;
ShowMessage( 'cardcode ok '+ls_rtn);
if MY_iReadBasicInfo(li_com,PChar(Edit2.Text),ls_CardCode,ls_SiCode,ls_Name,
ls_Sex,ls_Nation,ls_Personid,ls_UnitCode,ls_UnitName,
ls_Address,ls_PostCode,ls_Tel,ls_PersonType,ls_Issueid,
ls_ExpireDate,ls_ErrMsg,ls_rtn) < > 0 then
begin
Application.MessageBox(pchar(ls_rtn), '错误消息 ',MB_OK+MB_ICONERROR);
end
else
begin

// FillChar(@ls_CardCode,9,0);
// FillChar(@ls_SiCode,18,0);
// FillChar(@ls_Name,30,0);
// FillChar(@ls_Sex,1,0);
//// FillChar(@ls_Nation,2,0);
// FillChar(@ls_Personid,18,0);
// FillChar(@ls_UnitCode,9,0);
// FillChar(@ls_UnitName,70,0);
// FillChar(@ls_Address,80,0);
// FillChar(@ls_PostCode,6,0);
// FillChar(@ls_Tel,15,0);
// FillChar(@ls_PersonType,2,0);
// FillChar(@ls_Issueid,24,0);
// FillChar(@ls_ExpireDate,8,0);
{ ShowMessage( 'ok ');
Memo1.Lines.Add(pchar(@ls_cardCode));
Memo1.Lines.Add(pchar(@ls_SiCode));
Memo1.Lines.Add(pchar(@ls_Name));
Memo1.Lines.Add(pchar(@ls_Sex));
Memo1.Lines.Add(pchar(@ls_Nation));
Memo1.Lines.Add(pchar(@ls_Personid));
Memo1.Lines.Add(pchar(@ls_UnitCode));
Memo1.Lines.Add(pchar(@ls_UnitName));
Memo1.Lines.Add(pchar(@ls_Address));
Memo1.Lines.Add(pchar(@ls_PostCode));
Memo1.Lines.Add(pchar(@ls_Tel));
Memo1.Lines.Add(pchar(@ls_PersonType));
Memo1.Lines.Add(pchar(@ls_Issueid));
Memo1.Lines.Add(pchar(@ls_ExpireDate));}

Edit3.Text := pchar(@ls_CardCode);
Edit4.Text := pchar(@ls_SiCode);
Edit5.Text := pchar(@ls_Name);
ShowMessage( 'readbasicinfo ok ');
ls_rtn := ' ';
Mycpu_power_off(li_com,ls_rtn);
ShowMessage( 'power_off ok '+ls_rtn);
ls_rtn := ' ';
MyCom_Close(li_com,ls_rtn);
ShowMessage( 'close ok ' +ls_rtn);

end;
end;

end.

unit CommUnit2;
interface
uses
ShareMem,SysUtils,Windows,StrUtils,Classes,db,adodb,forms;
Function MyCom_Open(icdev: Integer; var ls_rtn :String):pointer;
procedure MyCom_Close(hcom: Pointer; var ls_rtn :String);
Function MyCom_Test(hcom: Pointer; var ls_rtn :String) :integer;
Function Myicc_testcard(hcom: Pointer; var ls_rtn :String) :integer;
Function Mycpu_power_off(hcom: Pointer; var ls_rtn :String) :integer;
Function MY_iReadBasicInfo(hCom: Pointer; Pin: Pchar; out CardCode: Pchar; out SiCode :
Pchar; out Name: Pchar;out Sex: Pchar; out Nation: Pchar; out Personid: Pchar; out UnitCode: Pchar; out UnitName: Pchar;out Address: Pchar; out PostCode: Pchar; out Tel: Pchar; out PersonType: Pchar; out Issueid: Pchar;
out ExpireDate: Pchar; out ErrMsg: Pchar; var ls_rtn :String): Integer;
Function MyiGetCardCode(hcom: Pointer; var ls_rtn :String) :integer;
Var
gs_COM_PORT:String;
implementation
Function iGetCardCode(hCom: Pointer;out CardCode:pChar;out ErrMsg:pChar):Integer;stdcall;
external 'Siic32.dll ';

Function iReadBasicInfo(hcom: Pointer; Pin: PChar; out CardCode: Pchar; out SiCode : Pchar;
out Name: Pchar;out Sex: Pchar; out Nation: Pchar; out Personid: Pchar; out UnitCode: Pchar; out UnitName: Pchar;out Address: Pchar; out PostCode: Pchar; out Tel: Pchar; out PersonType: Pchar; out Issueid: Pchar;out ExpireDate: Pchar; out ErrMsg: Pchar):integer; stdcall; external 'Siic32.dll ' name 'iReadBasicInfo ';

Function MyCom_open(icdev: Integer; var ls_rtn :String):pointer;
Type
TCom_open = Function(icdev: Integer):pointer;stdcall;
Var
Com_open:TCom_open;
h: THandle;
com_flag : Pointer;
Begin
Result := 0;
com_flag := 0;
ls_rtn := ' ';

h := LoadLibrary( 'Hnic32.dll ' );
If h = 0 Then
Begin
ls_rtn := '装入DLL文件(Hnic32)失败! ';
Exit;
End;

Try
@Com_open := GetProcAddress(h, PChar( 'com_open '));

If @Com_open < > Nil Then
com_flag := Com_open(icdev)
Else
ls_rtn := '装入方法( ' + 'com_open ' + ')失败! ';
Finally
FreeLibrary(h);
End;

if com_flag = pinteger(0) then
ls_rtn := '打开读卡器通讯端口COM '+inttostr(icdev)+ '失败! '
else
Result := com_flag;
end;

//关闭新乡医保读卡器通信端口
procedure MyCom_Close(hcom: Pointer; var ls_rtn :String);
Type
TCom_close = procedure(hcom: Pointer);stdcall;
Var
Com_close:TCom_close;
h: THandle;
Begin
ls_rtn := ' ';

h := LoadLibrary( 'Hnic32.dll ' );
If h = 0 Then
Begin
ls_rtn := '装入DLL文件(Hnic32)失败! ';
Exit;
End;
Try
@Com_close := GetProcAddress(h, PChar( 'com_close '));

If @Com_close < > Nil Then
Com_close(hcom)
Else
ls_rtn := '装入方法( ' + 'Com_close ' + ')失败! ';
except
on E: Exception do
begin
ls_rtn := '半闭读卡器通讯端口COM '+gs_COM_PORT+ '失败! '+^M+^J+E.Message;
end;
End;
FreeLibrary(h);
end;
//检测读写器与通讯端口是否联结
Function MyCom_Test(hcom: Pointer; var ls_rtn :String) :integer;
Type
TCom_Test = Function(hcom: Pointer):integer;stdcall;
Var
Com_Test:TCom_Test;
h: THandle;
com_flag :integer;
Begin
Result := 1;
com_flag := 1;
ls_rtn := ' ';

h := LoadLibrary( 'Hnic32.dll ' );
If h = 0 Then
Begin
ls_rtn := '装入DLL文件(Hnic32)失败! ';
Exit;
End;

Try
@Com_Test := GetProcAddress(h, PChar( 'com_test '));

If @Com_Test < > Nil Then
com_flag := Com_Test(hcom)
Else
ls_rtn := '装入方法( ' + 'Com_Test ' + ')失败! ';
Finally
FreeLibrary(h);
End;

if com_flag = 1 then
begin
if ls_rtn = ' ' then
ls_rtn := '读卡器与通讯端口COM '+gs_COM_PORT+ '未正常建立联结! ';
end
else
Result := com_flag;
end;

//查询读写器中当前卡座的卡片状态
Function Myicc_testcard(hcom: Pointer; var ls_rtn :String) :integer;
Type
Ticc_testcard = Function(hcom: Pointer):integer;stdcall;
Var
icc_testcard: Ticc_testcard;
h: THandle;
Begin
Result := -1;
ls_rtn := ' ';

h := LoadLibrary( 'Hnic32.dll ' );
If h = 0 Then
Begin
ls_rtn := '装入DLL文件(Hnic32)失败! ';
Exit;
End;

Try
@icc_testcard := GetProcAddress(h, PChar( 'icc_testcard '));

If @icc_testcard < > Nil Then
Result := icc_testcard(hcom)
Else
ls_rtn := '装入方法( ' + 'icc_testcard ' + ')失败! ';
except
on E: Exception do
begin
Result := -2;
ls_rtn := '查询读卡器中当前卡座的卡片状态失败! '+^M+^J+E.Message;
end;
End;
FreeLibrary(h);
end;

//给IC卡下电
Function Mycpu_power_off(hcom: Pointer; var ls_rtn :String) :integer;
Type
Tcpu_power_off = Function(hcom: Pointer):integer;stdcall;
Var
cpu_power_off: Tcpu_power_off;
h: THandle;
Begin
Result := -1;
ls_rtn := ' ';

h := LoadLibrary( 'Hnic32.dll ' );
If h = 0 Then
Begin
ls_rtn := '装入DLL文件(Hnic32)失败! ';
Exit;
End;
Try
@cpu_power_off := GetProcAddress(h, PChar( 'cpu_power_off '));

If @cpu_power_off < > Nil Then
Result := cpu_power_off(hcom)
Else
ls_rtn := '装入方法( ' + 'icc_testcard ' + ')失败! ';
except
on E: Exception do
begin
Result := -1;
ls_rtn := '给IC卡下电失败! '+^M+^J+E.Message;
end;
End;
FreeLibrary(h);
end;

//读卡基本信息
Function MY_iReadBasicInfo(hCom: Pointer; Pin: Pchar; out CardCode: Pchar; out SiCode :
Pchar; out Name: Pchar;out Sex: Pchar; out Nation: Pchar; out Personid: Pchar; out UnitCode: Pchar; out UnitName: Pchar;out Address: Pchar; out PostCode: Pchar; out Tel: Pchar; out PersonType: Pchar; out Issueid: Pchar;out ExpireDate: Pchar; out ErrMsg: Pchar; var ls_rtn :String): Integer;
Type
TiReadBasicInfo = Function(hcom: Pointer; Pin: Pchar; out CardCode: Pchar; out SiCode :
Pchar; out Name: Pchar;out Sex: Pchar; out Nation: Pchar; out Personid: Pchar; out UnitCode: Pchar; out UnitName: Pchar;out Address: Pchar; out PostCode: Pchar; out Tel: Pchar; out PersonType: Pchar; outIssueid: Pchar;out ExpireDate: Pchar; out ErrMsg: Pchar):integer; stdcall;
Var
tReadBasicInfo: TiReadBasicInfo;
h: THandle;
Begin
Result := -1;
ls_rtn := ' ';
h := LoadLibrary( 'Siic32.dll ' );
If h = 0 Then
Begin
ls_rtn := '装入DLL文件(Siic32)失败! ';
Exit;
End;
Try
@tReadBasicInfo := GetProcAddress(h, PChar( 'iReadBasicInfo '));

If @iReadBasicInfo < > Nil Then
begin
Result := tReadBasicInfo

(hCom,Pin,CardCode,SiCode,Name,Sex,Nation,Personid,UnitCode,UnitName,Address,PostCode,Tel,
PersonType,Issueid,ExpireDate,ErrMsg);
//以上为动态调用读卡信息的方法
//此注释部分为静态调用代码
{ if iReadBasicInfo(hCom,Pin,
CardCode,
SiCode,
Name,
Sex,
Nation,
Personid,
UnitCode,
UnitName,
Address,
PostCode,
Tel,
PersonType,
Issueid,
ExpireDate,
ErrMsg
) < > 0 then
begin
ls_rtn := pchar(@ErrMsg);
if trim(ls_rtn) = ' ' then
ls_rtn := '调用(Siic32.dll)中的iReadBasicInfo函数出现异常! ';
end
else
Result := 0; }
end
Else
ls_rtn := '装入方法( ' + 'iReadBasicInfo ' + ')失败! ';
except
on E: Exception do
begin
Result := -1;
ls_rtn := '读IC卡基本信息出现异常! '+^M+^J+E.Message;
end;
End;
if Result = -2 then
ls_rtn := '密码不在规定的输入范围之内! '
else
if Result < > 0 then
ls_rtn := pchar(@ErrMsg);
Application.MessageBox(pchar(inttostr(Result)), '返回值 ',MB_OK);
FreeLibrary(h);
end;
end.
这是我写的测试程序的第二个函数单元。
 
代码太多,没看完,先确定能否正确载入方法。动态库提供的接口也可以优化一下,这么多输出完全可以做一个结构体。你的主单元中的pchar使用也有问题,注意分配内存
getmem(....) ,FreeMem(...);可以分布调试一下看具体问题在哪
 
定义一个结构吧 字节数一定要与原来的对齐
 
试试把
CardCode 字符串 9
SiCode 字符串 18
...
定义成
CardCode : array[0..8] of char;
SiCode : array[0..17] of char;
 
问题在于函数参数的传递顺序约定上,DLL是用C写的,采用了默认的C参数传递方式。
而在DELPHI中你把参数传递方式定义为stdcall,肯定是不行了,改为cdecl方式应该就可以了。
 
@tReadBasicInfo := GetProcAddress(h, PChar( 'iReadBasicInfo '));

If @iReadBasicInfo < > Nil Then

这样你的函数能调上??@iReadBasicInfo @tReadBasicInfo
 
调用惯例的确要注意,最好把出错信息发出来!!
 
各位实在是不好意思,这个问题是我2007-10-29日晚上发的,当时实在是太急了,必须得解决掉。不能拖过第二天。最后我在网上等了几小时没结果,后在QQ上幸遇一位老友,在他的提示下最终把问题解决了。所以不好意思,这些分我将来只能分给他了。
不过还是谢谢各位的的热心回复。
我看了各位的回复,大家说的都有些对。当时贴这个贴的时候大家说的方法我也都试过,但总是差那么一点点儿的火候,让人很是郁闷。
最后再次感谢大家。
 
说说怎么解决的?我也碰到过类似问题,到现在还没解决.
 
幸好我以前遇到此类问题已经解决了。解决思路已经给了这位先生,希望它能将自己的解决方案再次公布!以利大家共享!
 
接受答案了.
 
顶部