2

I have a form which allows a use to select a record and this form then returns the ID of the record and an arbitrary number of fields values that the calling form may need. To do this, I have a function which handles creating the select form and passes all the values to and from the calling form:

Function Execute(AOwner: TComponent; AConnection: TADOConnection;
  AEditor: String; AButtons: TViewButtons; Var AID: Integer;
  Var ARtnVals: Array of Variant): TModalResult;
Var
  I: Integer;
Begin
  frmSelectGrid := TfrmSelectGrid.Create(AOwner);
  Try
    With frmSelectGrid Do
    Begin
      Connection := AConnection;
      Editor := AEditor;
      Buttons := AButtons;
      ID := AID;

      Result := ShowModal;
      If Result = mrOK Then
      Begin
        AID := ID;
        //VarArrayRedim(ARtnVals, Length(RtnVals));  !! Won't compile
        //SetLength(ARtnVals, Length(RtnVals));      !! Won't compile either
        For I := 0 To High(RtnVals) Do
          ARtnVals[I] := RtnVals[I];                 // Causes runtime exception
      End;
    End;
  Finally
    FreeAndNil(frmSelectGrid);
  End;
End;

The selector form has the following public properties:

public
  Connection: TADOConnection;
  Editor: String;
  Buttons: TViewButtons;
  ID: Integer;
  RtnVals: Array of Variant;
end;

And in the OK click, I have the following code:

Var
  I, Idx, C: Integer;


  // Count how many fields are being returned
  C := 0;
  For I := 0 To Config.Fields.Count - 1 Do
    If Config.Fields[I].Returned Then
      Inc(C);

  // If no fields to be returned, then just exit.
  If C = 0 Then
    Exit;

  // Set the size of the RtnVals and assign the field values to the array.
  SetLength(RtnVals, C);
  Idx := 0;
  For I := 0 To Config.Fields.Count - 1 Do
    If Config.Fields[I].Returned Then
    Begin
      RtnVals[Idx] := aqItems.FieldByName(Config.Fields[I].FieldName).Value;
      Inc(Idx);
    End;

So, once the user clicks OK to select a record, the RtnVals array is populated with the field values of the fields to be returned. I now need to copy these values to ARtnVals in the Execute function so that they are returned to the calling form.

My question is how do I set the size of the ARtnVals array so that I can copy the fields? SetLength doesn't work like it does in the OK click function above. VarArrayRedim doesn't work either.

1 Answer 1

6

When written in a procedure parameter list, this code

Var ARtnVals: Array of Variant

is an open array, and not a dynamic array. An open array cannot be resized. An open array is no use to you here.

Instead define a type for the array:

type
  TDynamicArrayOfVariant = array of Variant;

Use that type for your parameter, which is actually best as an out parameter:

function Execute(..., out RtnVals: TDynamicArrayOfVariant): TModalResult;

And then pass the function a TDynamicArrayOfVariant to be populated.

Now you have a dynamic array rather than an open array in Execute, and you can use SetLength to size it.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.