加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Inno在Delphi DLL中设置Unicode版本和字符串参数

发布时间:2020-12-15 09:15:48 所属栏目:大数据 来源:网络整理
导读:我在Delphi 10.1中编写了一个DLL,它使用Devart IBDac组件来允许在安装中备份和恢复Firebird DB(将应用程序从Firebird 1.5升级到3).使用Ansi Inno Setup 5.5.9一切正常.因为我想避免AnsiString和PAnsiChar作为参数(为了更方便地使用Delphi)我安装了Inno Setup
我在Delphi 10.1中编写了一个DLL,它使用Devart IBDac组件来允许在安装中备份和恢复Firebird DB(将应用程序从Firebird 1.5升级到3).使用Ansi Inno Setup 5.5.9一切正常.因为我想避免AnsiString和PAnsiChar作为参数(为了更方便地使用Delphi)我安装了Inno Setup Unicode版本5.5.9(u)并将参数从AnsiString / PAnsiChar更改为DLL中的String以及Inno Setup Script .我也在Inno Setup脚本中尝试过WideString,但这根本不起作用. Inno Setup不承认PChar.

奇怪的是脚本部分工作,参数被正确传输到DLL但我在与参数无关的情况下遇到GPF:

>在DLL中的字符串上使用trim(无参数!)会创建GPF.
>创建DBConnection-Object也会创建GPF.

我认为参数类型是这种邪恶的根源.这是我在DLL和脚本中唯一改变的东西. AnsiString的版本仍然运行良好.

感谢您分享任何想法,我在这里做错了什么.

更新:请求的示例代码:

从资源运行脚本的Delphi过程在第一个语句中失败.在第一行的MessageBox中,我验证了所有参数都正确到达.

procedure runScript(aServer,aDatabase,aUser,aPW,aPort,DLL,script: String); stdcall;
var
  ResStream: TResourceStream;
  DB: TIBCConnection;
  SC: TIBCScript;
  { Muss Ansistring sein wegen Resourcestream }
  s: ansistring;
begin
  try
    DB := TIBCConnection.create(nil);
    SC := TIBCScript.create(nil);
    SC.Connection := DB;
    try
      DB.clientlibrary := DLL;
      DB.Database := aDatabase;
      DB.Server := aServer;
      DB.Username := aUser;
      DB.Password := aPW;
      DB.Port := aPort;
      DB.connected := true;
      ResStream := TResourceStream.create(hInstance,script,RT_RCDATA);
      setlength(s,ResStream.size);
      ResStream.ReadBuffer(s[1],ResStream.size);
      SC.SQL.Text := String(s);
      SC.Execute;
      DB.close;
    finally
      SC.free;
      DB.free;
    end;
  except
    on e: Exception do
    begin
      MessageBox(0,PChar(e.message),PChar('Setup - Fehler in "' + script + '"'),mb_ok);
      raise;
    end;
  end;
end;

Inno Setup(Unicode)中过程的定义.其他必需的DLL在第一个函数定义中声明,因此它们都存在.它适用于AnsiString / PAnsiChar!

procedure runScript(aServer,script: String); 
    external 'runScript@files:itcsetupfb.dll stdcall setuponly';

此恢复功能有效但仅当我在函数中不使用TRIM()时:

procedure restoreDB(destServer,destDatabase,destSysdbaPW,aBackupfile,DLL: String; PBRange: integer;
  PbHandle,LblHandle,WizHandle: THandle); stdcall;
var
  IBCRestoreService1: TIBCRestoreService;
  cnt: integer;
  s: String;
  Msg: TMsg;
begin
  IBCRestoreService1 := TIBCRestoreService.create(nil);
  SendMessage(PbHandle,PBM_SETRANGE,PBRange shl 16);
  cnt := 0;
  try
    try
      with IBCRestoreService1 do
      begin
        clientlibrary := DLL;
        Database.Text := destDatabase;
        Server := destServer;
        Username := 'sysdba';
        Password := destSysdbaPW;
        Port := aPort;
        Options := [roFixFssMetadata,roNoValidityCheck,roFixFssData,roOneRelationAtATime,roDeactivateIndexes];
        FixFssCharset := 'ISO8859_1';
        BackupFile.Text := aBackupfile;
        PageSize := 16384;
        verbose := true;
        Attach;
        try
          ServiceStart;
          while IsServiceRunning do
          begin
            inc(cnt);
            if cnt > PBRange then
              cnt := 0;
            s := GetNextLine + ' ';
            { this was formerly s:=trim(strinGreplace(s,'gbak:','',}
            { [rfReplaceall,rfIgnoreCase])). I Identified the trim to be the  }
            { cause of the GPF. Very strange. }
            delete(s,1,5);
            while (length(s) > 0) and (s[1] = #32) do
              delete(s,1);
            { if we have no message file (local fb15) }
            if pos('format message',s) > 0 then
              s := 'Arbeite ...';
            SendMessage(LblHandle,$0C,longint(s));
            SendMessage(PbHandle,PBM_SETPOS,cnt,0);
            while PeekMessage(Msg,WizHandle,PM_REMOVE) do
            begin
              TranslateMessage(Msg);
              DispatchMessage(Msg);
            end;
            UpdateWindow(PbHandle);
          end;
        finally
          detach;
        end;
      end;
    finally
      IBCRestoreService1.free;
    end;
  except
    on e: Exception do
    begin
      MessageBox(0,PChar('Die Wiederherstellung der EMILpro Datenbank ist leider fehlgeschlagen. Folgender Fehler trat auf: ' +
        #13#10#10 + e.message),'Setup - Fehler bei Wiederherstellung',mb_ok);
      raise;
    end;
  end;
end;

这个函数在Inno Setup中声明如下:

procedure restoreDB(destServer,DLL: String; 
         PBRange: integer; PbHandle,WizHandle: THandle); 
         external 'restoreDB@files:itcsetupfb.dll,fbclient.dll,gds32.dll,icudt52.dll,icudt52l.dat,icuin52.dll,icuuc52.dll,fbintl.dll,firebird.conf,firebird.msg,ib_util.dll,engine12.dll,msvcp100.dll,msvcr100.dll,fbintl.conf stdcall setuponly';

解决方法

您不能在Inno Setup的DLL API中使用字符串类型,原因至少有两个:

>当您将函数参数声明为字符串时,Inno Setup将始终假定实际参数类型为PChar.
>字符串是“智能”类型,用于执行内部分配和引用计数.这样的类不能传递DLL边界,因为DLL不能释放由应用程序分配的内存,反之亦然,因为每个都有自己的内存管理器.更多内存布局和类的内部逻辑可能因Delphi版本(用于构建Inno Setup和DLL的版本)而异.

在Delphi中将参数实现为PWideChar(= PChar),并在Unicode Inno Setup中将参数声明为(宽)字符串.我认为在Delphi中使用PWideChar进行“in”参数没有任何不便.您可以在任何可以使用字符串的地方使用它.

有关类似的讨论,请参阅
Exchanging strings (PChar) between a Freepascal compiled DLL and a Delphi compiled EXE

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读