gpt4 book ai didi

delphi - 如何将 "array of strings"从 inno setup 传递到 Delphi Dll?

转载 作者:行者123 更新时间:2023-12-03 19:40:11 25 4
gpt4 key购买 nike

我有一个我用delphi编写的dll。它需要传递给它的字符串数组。如果我从另一个 delphi 应用程序调用 dll 进行测试,它可以工作。

我以为我让它在 inno 中工作,但已经改变了它,以便在注入(inject)文件后从向导页面调用它。

我没有收到任何错误,但没有输入 dll,因为我在 dll 中有一个消息框说它正在运行。

下面是代码,有人可以告诉我为什么我的 dll 不运行。

[files]
......
Source: "mydll.dll"; Flags: dontcopy; [code]
procedure GenKey(Details: array of string);
external 'GenKey@files:mydll.dll stdcall setuponly';
.....

function RegistrationComplete(Page: TWizardPage): boolean;
var
Details: array[0..15] of String;
begin
....Load the details array of strings.....

GenKey(Details);
Result := True;
end;


procedure InitializeWizard();
begin
Page := CreateCustomPage( wpInstalling, ExpandConstant('{cm:Registration_Caption}'), ExpandConstant('{cm:Registration_Description}') );
with Page do
begin
OnNextButtonClick := @RegistrationComplete;
end;

end;

好的,到目前为止,我通过一些研究和搜索得出了这个结论。但我仍然需要澄清。让它工作。我知道我需要使用 PChar 作为指向我声明为字符串的缓冲区的指针。使用 delphi 作为测试平台,这一切都有效,但是当指针值传递给 dll 时,字符串似乎丢失了。

因此,当我从 inno 调用 dll 时,我收到此错误消息“内部异常 EEDFADE”

Inno 代码如下
var
Buff: string;

procedure GenKey(Buff: PChar);
external 'GenKey@files:mydll.dll stdcall';

function PadZero(src: string; Width: Integer): String;
var
I : Integer;
Temp: string;
begin
Temp := '';
for i := (Length(Src)+1) to width do
Temp := Temp + '0';
if Length(Src) > width then Src := Copy( Src, 1, width);
Result := Temp + Src;
end;


{ CustomForm_NextkButtonClick }

function RegistrationComplete(Page: TWizardPage): boolean;
var
Details: TStringList;
BuffLen: integer;
begin
Details := TStringList.Create;
....
Load string list
....

Buff := Details.Text;

BuffLen := Length(Buff) + 1;
Buff := PadZero(InttoStr(BuffLen),4) + Buff;

GenKey(PChar(Buff));
Result := True;
end;

delphi XE6开发的DLL例程
procedure GenKey (Buff: PChar);
var
I: Integer;
Details : TStringList;
S: string;
BuffLen: integer;
begin
S := '';
for I := 0 to 3 do
begin
S := S + Buff^;
inc(Buff)
end;

BuffLen := strtoint(S);

Details := TStringList.Create;
S := '';
for I := 1 to BuffLen do
begin
S := S + (Buff^);
inc(Buff);
end;
Details.Text := S;
showmessage(S);

Details.Free;
end;

最佳答案

如果没有提前采取特殊措施,您无法安全地将复杂对象(如引用计数字符串)传递到与语言无关的无类型安全 DLL 中(前提是您知道足够好的低级 Delphi 编译器实现来设计此类脚手架)

您也不能传递特定于语言的对象,例如 open arrays出于同样的原因进入 DLL。

那么你必须做什么?你必须像 Windows 那样做:传递一个包含所有字符串的缓冲区并在 DLL 中解析它。详细信息取决于您要发送的字符串类型。

  • 方法:多个 ASCIIZ 字符串。
  • 限制:不允许空字符串,字符串不能包含#0 char
  • 参数类型:PAnsiCharPWideChar
  • 数据样本:'abcde'#0'fgh'#0'ijklmn'#0#0 - 字符串以 #0 结尾;空字符串(两个连续的#0)表示数据包结束

  • DLL impl草案:
       {$T+}  {$POINTERMATH ON}
    type PMyStrings = PAnsiChar;
    procedure GenKey( Details: PMyStrings );
    var a: AnsiString;
    w: string; // would be UTF-16 String in Delphi 2009 and above
    begin
    repeat
    a := Details; // conversion next ASCIIZ string to Delphi string
    if a = '' then break; // empty string - end of data

    Inc( Details, Length(a) + 1 ); // shifting pointer to next string in buffer
    w := a; // conversion fixed 8-bits string to Delphi-default string;
    { process each string `w` }
    until false;
    end;

    EXE impl草案:
       type PMyStrings = PAnsiChar; 
    var isl: iJclStringList; a: AnsiString;

    isl := JclStringList();
    isl.Add( 'abcde' );
    isl.Add( 'fgh' );
    isl.Add( 'ijklmn' );
    isl.Add( '' ); // empty string - end of data marker

    a := AnsiString ( isl.Join( #0 ) );
    GenKey( PMyStrings( a ) );

    EXE impl 2 草案:
     type PMyStrings = PAnsiChar; 
    var a: AnsiString; s: string;

    s := '';

    s := s + 'abcde' + #0;
    s := s + 'fgh' + #0;
    s := s + 'ijklmn' + #0;

    a := AnsiString ( s );
    GenKey( PMyStrings( a ) );

    或者
  • 方法:反前缀缓冲区
  • 限制:几乎没有;选择的前缀大小(byte、smallint、longint)可能会限制字符串的总数和每个字符串的最大长度。您还必须决定是否使用 AnsiChar 或 WideChar 来存储数据 - 类型安全将完全由您负责。
  • 参数类型:指针 - 您可以在解析缓冲区时将其类型转换为不同的类型
  • 数据样本:{32位整数,字符串总数} 3,{32位整数,第一个字符串长度} 5,'a','b','c','d','e',{32 -bits 整数,第二个字符串长度} 3, 'f','g','h', {32 位整数, 第三个字符串长度} 6, 'i','j','k','l', 'm','n'

  • DLL impl草案:
       {$T+}  {$POINTERMATH ON}
    type PrefCount = UInt32; PPrefCount = ^PrefCount;
    PrefStrLen = UInt32; PPrefStrLen = ^PrefStrLen;
    PStrData = PAnsiChar;
    procedure GenKey( Details: Pointer );
    var pc: PPrefCount; pl: PPrefStrLen; pd: PStrData;
    Count: PrefCount; Len: PrefStrLen;

    a: AnsiString;
    w: string; // would be UTF-16 String in Delphi 2009 and above
    begin
    pc := Details;
    Count := pc^;
    Inc(pc); Details := pc; // shifting the pointer past the counter cell

    while Count > 0 do begin
    pl := Details;
    Len := pl^;
    Inc(pl); Details := pl; // shifting the pointer past the n-th string length cell

    SetLength(a, Len);
    if Len > 0 then begin
    pd := Details;
    Assert( sizeof( a[1] ) = sizeof( pd^ ) );
    Move( pd^, a[1], Len * sizeof( a[1] ) );

    Inc( pd, Len );
    Details := pd;
    end;

    w := a; // conversion fixed 8-bits string to Delphi-default string;
    { process each string `w` }
    Dec( Count );
    end;
    end;

    EXE impl草案:
       {$T+}  {$POINTERMATH ON}
    type PrefCount = UInt32; PPrefCount = ^PrefCount;
    PrefStrLen = UInt32; PPrefStrLen = ^PrefStrLen;
    PStrData = PAnsiChar;
    var isl: iJclStringList;
    buffer: TBytes;
    s: string; a: AnsiString;
    L: integer;
    pc: PPrefCount; pl: PPrefStrLen; pd: PStrData;
    data: Pointer;

    isl := JclStringList();
    isl.Add( 'abcde' );
    isl.Add( 'fgh' );
    isl.Add( 'ijklmn' );

    Assert( sizeof( a[1] ) = sizeof( pd^ ) );

    L := 0;
    for s in isl do
    Inc( L, Length(s) );
    L := L * sizeof( pd^ );
    Inc( L, isl.Count * sizeof( PrefStrLen ) );
    Inc( L, sizeof( PrefCount ) );

    SetLength( buffer, L );
    data := @buff[ Low(buff) ];

    pc := data;
    pc^ := isl.Count;
    Inc(pc);
    data := pc;

    for s in isl do begin
    pl := data;
    pl^ := Length(s);
    Inc(pl);
    data := pl;

    if s > '' then begin
    a := AnsiString(s);
    pd := data;
    Move( a[1], pd^, pl^ * sizeof( pd^ ) );
    Inc( pd, pl^ );
    data := pd;
    end;
    end;

    Dec( PByte( data ) ); // should point to next byte past the buffer
    Assert( data = @buff[ High(buff) ] ); // if Length was correctly calculated and adjusted

    data := @buff[ Low(buff) ];
    GenKey( data );

    或者
  • 方法:带有辅助分隔符的 ASCIIZ 字符串。
  • 限制:字符串既不能包含 #0 字符,也不能包含其他用作内部分隔符的预定义字符
  • 参数类型:PAnsiCharPWideChar
  • 数据样本:'abcde'#1'fgh'#1'ijklmn'#0 - 此处的字符串由 #1 分隔(并且该字符被禁止成为合法数据的一部分)。 #0 标志着巨型字符串的结束(因此所有字符串)。

  • DLL impl草案:
       type PMyStrings = PAnsiChar; 
    const AuxSeparator = #1;
    procedure GenKey( Details: PMyStrings );
    var isl: iJclStringList;
    a: AnsiString;
    w: string; // would be UTF-16 String in Delphi 2009 and above
    begin
    a := Details; // conversion ASCIIZ string to Delphi string
    w := a; // conversion fixed 8-bits string to Delphi-default string;
    isl := JclStringList();
    isl.Split( w, AuxSeparator ); // parsing mega-string into separate strings

    for w in isl do begin
    { process each string `w` }
    end;
    end;

    EXE impl草案:
       type PMyStrings = PAnsiChar; 
    const AuxSeparator = #1;
    var isl: iJclStringList; a: AnsiString;

    isl := JclStringList();
    isl.Add( 'abcde' );
    isl.Add( 'fgh' );
    isl.Add( 'ijklmn' );

    a := AnsiString ( isl.Join( AuxSeparator ) );
    GenKey( PMyStrings( a ) );

    EXE impl 2 草案:
     type PMyStrings = PAnsiChar; 
    const AuxSeparator = #1;
    var a: AnsiString; s: string;

    s := '';

    s := s + 'abcde' + AuxSeparator;
    s := s + 'fgh' + AuxSeparator;
    s := s + 'ijklmn'; // no internal separator for last string

    a := AnsiString ( s );
    GenKey( PMyStrings( a ) );

    您还可以组合这些方法或在 DLL 中使用多个参数,例如您可以发送指向 ASCIIZ 字符串的指针数组
       {$T+}  {$POINTERMATH ON}
    type PMyStrings = ^PAnsiChar;
    procedure GenKey(Count: integer; Details: PMyStrings);
    var a: AnsiString; p: PAnsiChar;
    w: string;
    begin
    while Count > 0 do begin
    p := Details^;
    a := p;
    Inc( Details );
    Dec( Count );

    w := a;
    { process string `w` }
    end;
    end;

    然后是EXE
       type PMy1String = PAnsiChar;
    var data: packed array of PMy1String;

    SetLength( data, 3 );
    data[0] := PMy1String( 'abcde' );
    data[1] := PMy1String( 'fgh' );
    data[2] := PMy1String( 'ijklmn' );

    GenKey( Length(data), @data[0] );

    或者任何最适合你的东西。只是对低级数据表示非常谨慎。例如不同语言中 AnsiChar 和 WideChar 之间的差异 - 现在跟踪它是您的责任,而不是编译器的责任。

    关于delphi - 如何将 "array of strings"从 inno setup 传递到 Delphi Dll?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31427925/

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