我试图在循环中将主机EXE中的字符串数组传递给DLL。主机EXE是一个支持脚本的外部应用程序(由具有某些限制的delphi类编译器编译和执行)。 DLL是由我在Delphi 2010中编写的。
所以问题是 - 当我将Widestring数组传递给DLL时,我无法摆脱访问冲突。无论我做了什么 - 我迟早会得到AV。即使没有,我的静态加载的DLL被主机应用程序锁定,我无法重命名或删除DLL,所以出了点问题。
有一个代码示例,它描述了如何使用接口(对我来说很新,我非常喜欢)。像魅力一样工作,DLL文件没有被锁定。
常规定义(DLL + EXE)
type
// Your "structure"
TSomething = record
A: Integer;
S: WideString;
end;
// Your "structure list"
TSomethingArray = array of TSomething;
// The DLL and the EXE exchange data via Interface
IArray = interface
['{EE7F1553-D21F-4E0E-A9DA-C08B01011DBE}'] // press Ctrl+Shift+G to generate id
// protected
function GetCount: Integer; safecall;
function GetItem(const AIndex: Integer): TSomething; safecall;
// public
property Count: Integer read GetCount;
property Items[const AIndex: Integer]: TSomething read GetItem; default;
end;
DLL
// DLL, auxilary code:
type
// IArray implementation, which will be passed from DLL to EXE
TBaseArray = class(TInterfacedObject, IArray)
protected
FArray: TSomethingArray;
function GetCount: Integer; safecall;
function GetItem(const AIndex: Integer): TSomething; safecall;
end;
// Copying an array - for static and open arrays
TArray = class(TBaseArray)
public
constructor Create(const AArray: array of TSomething);
end;
// We don't have to copy an array for dynamic arrays
TArrayRef = class(TBaseArray)
public
constructor Create(const AArray: TSomethingArray);
end;
// We could create 1 class instead of 3 (TArray),
// but with 2 constructors (CreateByArr, CreateByDynArr).
// Or even with 1 constructor, if you work with 1 type of array.
// But it doesn't really matter, it's a matter of convenience.
// What really matters is a class which implements an interface.
{ TBaseArray }
function TBaseArray.GetCount: Integer;
begin
Result := Length(FArray);
end;
function TBaseArray.GetItem(const AIndex: Integer): TSomething;
begin
Result := FArray[AIndex];
end;
{ TArray }
constructor TArray.Create(const AArray: array of TSomething);
var
ArrIndex: Integer;
begin
inherited Create;
SetLength(FArray, Length(AArray));
for ArrIndex := 0 to High(AArray) do
FArray[ArrIndex] := AArray[ArrIndex];
end;
{ TArrayRef }
constructor TArrayRef.Create(const AArray: TSomethingArray);
begin
inherited Create;
FArray := AArray;
end;
// DLL, applied code:
function DoSomething1: IArray; stdcall;
var
A: array[0..2] of TSomething;
begin
// Some operations with array...
A[0].A := 1;
A[0].S := 'S1';
A[1].A := 2;
A[1].S := 'S2';
A[2].A := 3;
A[2].S := 'S3';
// Returning result
Result := TArray.Create(A); // <- An array is copied here
end;
function DoSomething2: IArray; stdcall;
var
A: TSomethingArray;
begin
// Some operations with array...
SetLength(A, 3);
A[0].A := 1;
A[0].S := 'S1';
A[1].A := 2;
A[1].S := 'S2';
A[2].A := 3;
A[2].S := 'S3';
// Returning result
Result := TArrayRef.Create(A); // An array isn't copied here, only reference counting
// We could also write:
// Result := TArray.Create(A);
// but the array would be copied in this case
end;
exports
DoSomething1, DoSomething2;
EXE
function DoSomething1: IArray; stdcall; external 'Project2.dll';
function DoSomething2: IArray; stdcall; external 'Project2.dll';
procedure TForm1.Button1Click(Sender: TObject);
var
A: IArray;
X: Integer;
begin
A := DoSomething1; // or DoSomething2
for X := 0 to A.Count - 1 do
OutputDebugString(PChar(IntToStr(A[X].A) + ' ' + A[X].S));
end;
此代码适用于我的主机应用程序(当所有OOP逻辑都在DLL中时)。但我需要将数据从EXE传递到DLL。
所以我交换了代码,EXE变成了更重的&#39;部分,一切都很好,但前提是DLL和EXE都是用Delphi 2010编写的。
如果我使用我的主机应用程序和静态数组,我的主机应用程序中的编译器会报告“不兼容的类型”。 DoSomething1中的字符串错误:
Result := TArray.Create(A);
写作时
Result := TArray.Create(A) as IArray;
它编译但应用程序崩溃。
如果我使用动态数组,编译器将在地址0D92062B报告&#34;访问冲突。读取地址FFFFFFF8&#34;这里:
function TBaseArray.GetItem(const AIndex: Integer): TSomething;
begin
Result := FArray[AIndex];
end;
此代码的作者说,如果我们想将数据从EXE传递到DLL,我们需要使用回调。我只是交换了代码。也许这就是问题?如果是这样,我应该如何在这里使用回调?