我有一个我用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 中解析它。详细信息取决于您要发送的字符串类型。
PAnsiChar
或 PWideChar
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 ) );
或者
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 );
或者
PAnsiChar
或 PWideChar
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/