使用接口将数据从exe传递到Delphi中的dll

时间:2015-01-25 12:53:18

标签: delphi dll interface callback access-violation

我试图在循环中将主机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,我们需要使用回调。我只是交换了代码。也许这就是问题?如果是这样,我应该如何在这里使用回调?

0 个答案:

没有答案
相关问题