0
votes

VB6 DLL

I have written a VB6 DLL which includes the following user-defined type (UDT), consisting only of primitive data types...

Public Type MyResults
  Result1 As Double
  Result2 As Double
  Result3 As Double
  Result4 As Double
  Result5 As Double
End Type

...and the following method...

Public Sub Method1(ByRef Results As Variant)
  Dim myRes As MyResults
  myRes = Results
  MsgBox "MyResults.Result1: " & myRes.Result1
  ...
End Sub

Delphi Test Harness

I have also written a test harness in Delphi and have created an equivalent Delphi record type to mimic the VB UDT, which is defined as follows...

TMyResults = packed record
  Result1: Double;
  Result2: Double;
  Result3: Double;
  Result4: Double;
  Result5: Double;
end;

From Delphi, I would like to call Method1 in the VB6 DLL and pass a variable of this type as an argument, so that VB can interpret it as an equivalent "type". So far, I have tried the following Delphi call...

procedure TMyApp.CallMethod1FromVBDLL(var MyResults: TMyResults);
var
  results: OleVariant;
  dll: Variant;
begin
  results := RecToVariant(MyResults, SizeOf(MyResults));
  dll := CreateOleObject('ApplicationName.ClassName');
  dll.Method1(results);
  ...
end;

...which uses the following function (source: http://www.delphigroups.info/2/2c/462130.html) to convert a record to a variant...

function TMyApp.RecToVariant(var AR; ARecSize: Integer): Variant;
var
  p: Pointer;
begin
  Result := VarArrayCreate([1, ARecSize], varByte);
  p := VarArrayLock(Result);
  try
    Move(AR, p^, ARecSize);
  finally
    VarArrayUnLock(Result); 
  end;
end;

An EOleException is reported back to Delphi due to a Type mismatch on the myRes = Results line in Method1 of the DLL.

Am I preparing and passing the argument correctly in Delphi? How should I be using the argument in VB6?

Any assistance/advice would be gratefully received.

1
Are you sure you need to do this? Can't VB export functions that use UDTs?David Heffernan
If I change the Method1 argument from Variant to MyResults in VB and pass an argument of type TMyResults from Delphi, I get a "Type not allowed in Variant Dispatch call" error when compiling my test harness. So I concluded that I needed to pass an OleVariant instead.w5m

1 Answers

2
votes

The problem is that your Delphi code is creating an OleVariant that contains a byte array (Automation type VT_UI1 or VT_ARRAY), which is not what VB is expecting. It is expecting a UDT record (Automation type VT_RECORD) instead.

MSDN has an article explaining how to pass a UDT inside a Variant:

Passing UDTs

To pass single UDTs or safearrays of UDTs for late binding, the Automation client must have the information necessary to store the type information of the UDT into a VARIANT (and if late-binding, the UDT must be self-described). A VARIANT of type VT_RECORD wraps a RecordInfo object, which contains the necessary information about the UDT and a pointer the UDT itself. The RecordInfo object implements a new interface, IRecordInfo, for access to the information. It is important to know that the actual storage of the UDT is never owned by the VARIANT; the IRecordInfo pointer is the only thing that is owned by the VARIANT.

The data for a UDT includes an IRecordInfo pointer to the description of the UDT, pRecInfo, and a pointer to the data, pvRecord.

In other words, you need to create a class that implements the IRecordInfo interface and wraps your actual record data, then you can store an instance of that class inside the OleVariant using the VT_RECORD type. That will provide both COM and VB with the necessary metadata to marshal and access your record data.