本帖最后由 kampan 于 2009-11-06 10:17:57 编辑

解决方案 »

  1.   

    FreeMem(RandAndEndata);  把这句注释掉试下,理由:GetMem(RandAndEndata,256);  rtndata.sBack := RandAndEndata 可能只是把Sback指向randandendata的内存地址,如果你释放了可能会出现无效地址rtndata.sBack:=strpas(RandAndEndata) 这个过程会分配一个内存块 你再释放的话应该没问题了
      

  2.   

    八成是调用约定不对,也就是 TParameterElseUpdate 有问题,破坏了 stack
    1楼纯粹就是瞎扯淡了
      

  3.   

    TO:风之谷
    你那种方式,我之前也尝试过,但效果一样,另外rtndata.sBack := RandAndEndata; 应该是拷贝,FreeMem(RandAndEndata)之后,对rtndata.sBack 没有影响
      

  4.   

    TO Seamour:
    此动态库不止TParameterElseUpdate这么一个接口,如果调用约定不对的话,其他同样方式调用的函数应该也出问题,但惟独这个有问题,当然也不能完全排除你说的这种可能。
      

  5.   

    注:贴中有一处写错,更正一下if idHandle = 0 then 应为if DllHandle = 0
      

  6.   

           GetMem(RandAndEndata,256); 
            iRtn := TheFn(sDiv, sEsam,RandAndEndata); 
            RtnData.iLen := iRtn; 
            rtndata.sBack := RandAndEndata; 
            FreeMem(RandAndEndata); 这一块 rtndata.sBack有值吗
      

  7.   


    有值,而且3步中
      reBack := ParamElseUpdate(Pchar(s1), PChar(s2)); //此处调用之后Result变为inaccessible value   s := inttostr(reBack.iLen) + ';' + reBack.sBack + ';'; 
    s可得到正确的返回值。
      

  8.   

    TParameterElseUpdate = function(sDiv: pchar;sEsam:pchar; RandAndEndata: PChar): Integer; stdcall;估计那个DLL的调用约定不是stdcall, 而是cdecl 。这个地方的调用约定申明不一致,将造成栈空间的混乱。
      

  9.   

    要是懂汇编的话其实就很容易调的,记住 Result 的地址在 stack 的哪个位置,然后看什么时候那的值被改了就完了。调用约定有没有问题也更容易看出来,直接看 TParameterElseUpdate 调用的返回是不是 ret 12 就知道了,如果是别的值那就是参数的数量不对导致 stack 被破坏了
      

  10.   


    cdecl这种方式试过,也是一样出问题,厂家给的接口没说什么方式调用,原型如下:
    函数名称 ParameterElseUpdate(char *RandDivApduData,
    char *EsamNum,char *dataout)
    函数功能密文+MAC 更新参数
      

  11.   

    reBack := ParamElseUpdate(Pchar(s1), PChar(s2)); //此处调用之后Result变为inaccessible value 关于这一块,不是错误的 函数的返回值是由栈来管理的.
      

  12.   


    我传上来一个,有兴趣的可以下载下来试试
    http://d.download.csdn.net/down/1795836/kampan
      

  13.   

    d7,没有重现你所说的错误:program Project2;{$APPTYPE CONSOLE}uses
      SysUtils,
      Windows,
      StrUtils;type
      ReturnChar = record
        iLen : integer;
        sBack: string;
      end;
      TParameterElseUpdate = function(sDiv: PChar; sEsam:PChar; RandAndEndata: PChar): Integer; stdcall;function ParamElseUpdate(sDiv:pchar;sEsam:pchar):ReturnChar;
    var
      idHandle: THandle;
      TheFn: TParameterElseUpdate; 
      RandAndEndata: PChar; 
      iRtn: Integer;
    begin
      Result.iLen := -1;
      Result.sBack := '';
      idHandle := LoadLibrary('TestZhuzhan.dll');
      if idHandle = 0 then Exit;  try
        TheFn := GetProcAddress(idHandle, 'ParameterElseUpdate');
        if not Assigned(TheFn) then Exit;
        GetMem(RandAndEndata,256);
        try
          (*FillChar(RandAndEndata^, 255, '.');
          RandAndEndata[255] := #0;*)
          iRtn := TheFn(sDiv, sEsam, RandAndEndata);
          Result.iLen := iRtn;
          Result.sBack := RandAndEndata;
        finally
          FreeMem(RandAndEndata);
        end;
      finally
        FreeLibrary(idHandle);
      end; 
    end;function GetEncrypt(const sIn: string): string;
    var
      i: integer;
      str: string;
      s1,s2: string;
      s: string;
    begin
      Result := '';
      i := Pos(';',sIn); 
      if i <= 0 then 
        exit;  str := RightStr(sIn,Length(sIn) - i);
      i := Pos(';', str);
      s1 := LeftStr(str,i - 1);
      str := RightStr(sIn,Length(str) - i);
      i := Pos(';',str);
      if (i > 0) then
        s2 := LeftStr(str,i - 1);  with ParamElseUpdate(Pchar(s1), PChar(s2)) do
        s := IntToStr(iLen) + ';' + sBack + ';';
      Result := s;
    end;begin
      ChDir('E:\Temp\Test接口\');
      Writeln(GetEncrypt('5;BF48F7A0000022000000000004D6890009040001060912050401;1000000000000001;'));
      Readln;
    end.看过反汇编了,ParameterElseUpdate 的确是3个参数的 stdcall
      

  14.   

    D7没有报错.结果为: 200;&E;
      

  15.   

    多谢Seamour!
    你的程序我试了一下,的确没报错,但不知为何RandAndEndata始终为空值(在你的Console Application 工程下),另外,我将你的两个函数替换掉我原来程序里的,主程序调用稍微改了下
    procedure TfrmMain.Button1Click(Sender: TObject);
    var
      s: String;
    begin
      s := GetEncrypt('5;BF48F7A0000022000000000004D6890009040001060912050401;1000000000000001;');
      Edit1.Text := s;
    end;
    运行倒是也没报错,RandAndEndata也得到了值,但单步跟踪 s 一直为空,得不到GetEncrypt的返回值。
    如果可以,你抽空试试在非控制台程序下调试,看看结果。 
      

  16.   


    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, StrUtils;
    type 
      ReturnChar = record 
        iLen : integer; 
        sBack: string; 
    end;TParameterElseUpdate = function(sDiv: pchar;sEsam:pchar; RandAndEndata: PChar): Integer; stdcall;type
      TForm1 = class(TForm)
        Button1: TButton;
        Edit1: TEdit;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}function GetEncrypt(sIn: string): string;
    function ParamElseUpdate(sDiv:pchar;sEsam:pchar):ReturnChar;//??????
    var
      DllHandle: THandle;
      TheFn: TParameterElseUpdate;
      RandAndEndata: PChar;
      RtnData: ReturnChar;
      iRtn: Integer;
    begin
      DLLHandle := LoadLibrary('TestZhuzhan.dll');
      try
        if dllHandle = 0 then
        begin
          RtnData.iLen := -1;
          RtnData.sBack := '';
        end
        else
        begin
          @TheFn := GetProcAddress(dllHandle, 'ParameterElseUpdate');
          if @TheFn <> nil then
          begin
            GetMem(RandAndEndata,256);
            iRtn := TheFn(sDiv, sEsam,RandAndEndata);
            RtnData.iLen := iRtn;
            rtndata.sBack := RandAndEndata;
            FreeMem(RandAndEndata);
          end
          else
          begin
            RtnData.iLen := -1;
            RtnData.sBack := '';
          end;
        end;
      finally
        FreeLibrary(DLLHandle);
      end;
      Result := RtnData;
    end;var 
      i: integer; 
      str: string; 
      reBack: ReturnChar; 
      s1,s2: string; 
      s: string; 
    begin 
      result := ''; 
      i := Pos(';',sIn); 
      if i <= 0 then 
        exit;   str := RightStr(sIn,Length(sIn) - i);
      //??1 
      i := Pos(';', str); 
      s1 := LeftStr(str,i - 1); 
      str := RightStr(sIn,Length(str) - i);
      //??2 
      i := Pos(';',str);
      if (i > 0) then 
        s2 := LeftStr(str,i - 1);   reBack := ParamElseUpdate(Pchar(s1), PChar(s2)); //??????Result??inaccessible value  s := inttostr(reBack.iLen) + ';' + reBack.sBack + ';'; 
      result := s; //???????? 
    end;
    procedure TForm1.Button1Click(Sender: TObject);
    begin
    Edit1.Text := GetEncrypt('5;BF48F7A0000022000000000004D6890009040001060912050401;1000000000000001;');
    end;end.
      

  17.   

    To dinoalex:
    你的代码只不过是将我写的那两个函数包在一起而已,我拿过来调试,结果依旧,呵呵,也是D7啊,你那没错?!!
      

  18.   

    我晕,EMail:[email protected] 发给我吧 ,我在我这跑一下
    MSN:[email protected] 可以的话做个朋友,呵呵
      

  19.   

    建议楼主把dll调用方式改为静态调用试试!
    如果没问题的话,说明是动态调用时,某些资源被提前释放了!
      

  20.   

    function TForm1.GetEncrypt(sIn: AnsiString): AnsiString;
    var 
      i: integer; 
      str: AnsiString; 
      reBack: ReturnChar; 
      s1,s2: AnsiString; 
      s: AnsiString; 
    begin 
      result := ''; 
      i := Pos(';',sIn); 
      if i <= 0 then 
        exit;   str := RightStr(sIn,Length(sIn) - i); 
      //参数1 
      i := Pos(';', str); 
      s1 := LeftStr(str,i - 1); 
      str := RightStr(sIn,Length(str) - i); 
      //参数2 
      i := Pos(';',str); 
      if (i > 0) then 
        s2 := LeftStr(str,i - 1);   reBack := ParamElseUpdate(Pansichar(s1), PAnsiChar(s2)); //此处调用之后Result变为inaccessible value   result := inttostr(reBack.iLen) + ';' + reBack.sBack + ';'   // 就改了这里.  end;
     我是2009,所以String => AnsiString   PChar => PansiChar  ;  其它用了你的. 
    结果是: 200;?4;
      

  21.   

    另外你的   Function  没有   return  所以你打个断点看  Result .  应该提示你那个是对的.
      

  22.   

    又来了!
    目前情况如下:
        dinoalex将含有20楼代码的整个工程文件打包发给我,在我这编译运行正常;但,我新建一个工程界面与之一样(界面就一个Edit 一个Button),保存后将dinoalex工程文件中唯一的一个.pas文件Unit1.pas覆盖我新建的文件(将整个Unit1单元代码覆盖也试过),这样再编译运行又出现最开始的问题!
        将我建的工程传给dinoalex编译运行也出问题,而他将其中的代码再次复制到他另建的工程则运行正常!
        
        抛开这个不说,我就搞不明白我自己写的代码为什么就过不去!??
        华仔看到留言,留个Email 我把工程发给你,在你机器上试试!
      

  23.   

    多谢各位,尤其是dinoalex和华仔陪同一起调试,后来我又在D2010上试过,之前问题同样发生,目前无暇追究根源,先把分散了!
      

  24.   

    这样赋值是不是有问题?
      ReturnChar = record
        iLen : integer;
        sBack: string;
    end;  TParameterElseUpdate = function(sDiv: pchar;sEsam:pchar; RandAndEndata: PChar): Integer; stdcall;....
      reBack := ParamElseUpdate(Pchar(s1), PChar(s2)); //此处调用之后Result是ReturnChar 型,而函数返回整型。ReturnChar 类型跟整型没有任何关联。即使不报错堆栈已经混乱不堪
    ....
      result := s; //函数退出是需要清理堆栈,此时自然报错。
      

  25.   

    建议不要将Integer类型的返回结果赋值给record
      

  26.   

    我也在调这个dll
    就是不知道8字节分散因子怎么弄
    调用IdentityAuthentication总返回203(失败)
      

  27.   

    请注意看变量的定义
    reBack: ReturnChar; 
      

  28.   

    这个地方改改也许就对了 @TheFn := GetProcAddress(idHandle, 'ParameterElseUpdate');
          if @TheFn <> nil then 
    改为
     TheFn := GetProcAddress(idHandle, 'ParameterElseUpdate');
          if TheFn <> nil then 
    我向来都这样调
      

  29.   

    楼主的弄好没.请问下
    8字节分散因子怎么弄 
    调用IdentityAuthentication总返回203
    (这个函数第一个参数要传什么)
      

  30.   

    IdentityAuthentication
    我也是返回 203 是用插入“测试母卡” 在调用IdentityAuthentication 吧
      

  31.   

    我用VB调用这个Testzhuzhan.dll的接口函数,也是遇到同样的问题,就是那个ParameterElseUpdate这个函数会报错误,其他的都不会,有谁解决过