How to transfer "array of string", "array of record", and "array of interface" between Delphi & .NET

Hi again.

As pointed out in http://connect.remobjects.com/discussion/576/import-interfaces-from-.net-assembly-doesn039t-recognize-structs-and-enums-in-custom-interfaces some parameter types must be translated manually. In my case I want to transfer the following parameter types:

  • array of string
  • array of a record type
  • array of an interface

When I specify such parameters on the .NET side and generate Delphi code they all end up as PVarArray. The wiki article http://wiki.remobjects.com/wiki/Passing_interfaces_between_Host_and_Plugins shows how to transfer a record and an array of byte, but I’m unable to figure out how to transfer the parameter types I listed above.

How do I transfer these constructs?

Thanks,
Bernt

You can use something like this to transfer strings and interfaces (unfortunately its not possible to pass an array of custom records, you will need to create an interface that will act as array or list to do so):

uses
VarUtils;

type
TWideStringArray = array of WideString;
TDispatchArray = array of IDispatch;

function SafeArrayAsDispatchArray(ar: PVarArray): TDispatchArray;
var
lb, ub, i: Integer;
ind: array [0…0] of Integer;
begin
SafeArrayGetLBound(ar, 1, lb);
SafeArrayGetUBound(ar, 1, ub);
SetLength(result, ub-lb+1);

for i := lb to ub do begin
ind[0] := i;
SafeArrayGetElement(ar, @ind, @result[i-lb]);
end;
end;

function DispatchArrayAsSafeArray(Arr: TDispatchArray): PVarArray;
var
Bounds: TVarArrayBoundArray;
I: Integer;
ind: array [0…0] of Integer;
begin
Result := nil;
if (Arr = nil) or (Length(Arr) = 0) then
Exit;

Bounds[0].LowBound:=0;
Bounds[0].ElementCount:=Length(Arr);

Result := SafeArrayCreate(varDispatch, 1, Bounds);
for I := 0 to Length(Arr) - 1 do begin
ind[0] := i;
SafeArrayPutElement(Result, @ind, PDispatch(Arr[i]));
end;
end;

function SafeArrayAsStringArray(ar: PVarArray): TWideStringArray;
var
lb, ub, i: Integer;
ind: array [0…0] of Integer;
begin
SafeArrayGetLBound(ar, 1, lb);
SafeArrayGetUBound(ar, 1, ub);
SetLength(result, ub-lb+1);

for i := lb to ub do begin
ind[0] := i;
SafeArrayGetElement(ar, @ind, @result[i-lb]);
end;
end;

function StringArrayAsSafeArray(Arr: TWideStringArray): PVarArray;
var
Bounds: TVarArrayBoundArray;
I: Integer;
ind: array [0…0] of Integer;
begin
Result := nil;
if (Arr = nil) or (Length(Arr) = 0) then
Exit;

Bounds[0].LowBound:=0;
Bounds[0].ElementCount:=Length(Arr);

Result := SafeArrayCreate(varOleStr, 1, Bounds);
for I := 0 to Length(Arr) - 1 do begin
ind[0] := i;
SafeArrayPutElement(Result, @ind, PWideChar(Arr[i]));
end;
end;

Great! Thank you. I’m sure that the article at http://wiki.remobjects.com/wiki/Passing_interfaces_between_Host_and_Plugins would benefit from being extended with the code examples you provided. :slight_smile: