gpt4 book ai didi

delphi - Inno Setup Delphi DLL中的Unicode版本和字符串参数

转载 作者:行者123 更新时间:2023-12-03 15:30:18 25 4
gpt4 key购买 nike

我在 Delphi 10.1 中编写了一个 DLL,它使用 Devart IBDac 组件来允许在安装中备份和恢复 Firebird DB(应用程序从 Firebird 1.5 升级到 3)。使用 Ansi Inno Setup 5.5.9 一切正常。正如我想避免 AnsiStringPAnsiChar作为参数(为了更方便地从 Delphi 使用)我安装了 Inno Setup Unicode 版本 5.5.9(u) 并从 AnsiString 更改了参数/PAnsiCharString在 DLL 和 Inno 安装脚本中。我也尝试过WideString在 Inno Setup 脚本中但这根本不起作用。 PChar Inno Setup 无法识别。

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

  • 对 DLL 中的字符串使用 TRIM(无参数!)创建 GPF。
  • 创建 DBConnection 对象也会创建 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, aDatabase, aUser, aPW, aPort, DLL, script: String); 
external 'runScript@files:itcsetupfb.dll stdcall setuponly';

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

procedure restoreDB(destServer, destDatabase, destSysdbaPW, aBackupfile, aPort, 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, 0, 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, 1);
{ if we have no message file (local fb15) }
if pos('format message', s) > 0 then
s := 'Arbeite ...';
SendMessage(LblHandle, $0C, 0, longint(s));
SendMessage(PbHandle, PBM_SETPOS, cnt, 0);
while PeekMessage(Msg, WizHandle, 0, 0, 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, destDatabase, destSysdbaPW, aBackupfile, aPort, DLL: String; 
PBRange: integer; PbHandle,LblHandle,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 中使用 string 类型,至少有两个原因:

  • 当您将函数参数声明为 string 时,Inno Setup 将始终假定实际参数类型为 PChar

  • string 是“智能”类型,它执行内部分配和引用计数。此类无法通过 DLL 边界,因为 DLL 无法释放应用程序分配的内存,反之亦然,因为每个类都有自己的内存管理器。此外,类的内存布局和内部逻辑可能因 Delphi 版本(用于构建 Inno Setup 和 DLL 的版本)而异。

在 Delphi 中将参数实现为 PWideChar (= PChar),并在 Unicode Inno Setup 中将参数声明为 (wide) string。我没有看到在 Delphi 中使用 PWideChar 作为“in”参数有任何不便。您可以在任何可以使用字符串的地方使用它。

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

关于delphi - Inno Setup Delphi DLL中的Unicode版本和字符串参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40362634/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com