meller92
meller92

Reputation: 455

Pointers passed by reference in Delphi (import functions from DLL)

I want to use a function declared in a DLL which takes pointers as in/out parameters to fill up a record with non-pointer parameters.

Function from DLL:

function WFS_GetMlaData(   handle: WFS_HDL;
                           mla_idx: Integer;
                           mla_name:  TCharWFSBufferArray;
                       var cam_pitch_um: PDouble;
                       var lenslet_pitch_um: PDouble;
                       var center_spot_offset_x: PDouble;
                       var center_spot_offset_y: PDouble;
                       var lenslet_f_um: PDouble;
                       var grd_corr_0: PDouble;
                       var grd_corr_45: PDouble): Integer stdcall;

Record:

MlaInfo = record
    i : Integer;
    idx : Integer;
    name : TCharWFSBufferArray;
    camPitchUm : double;
    lensletPitchUm : double;
    spotOffsetx : double;
    spotOffsety : double;
    lensletFocalLengthUm : double;
    grdCorr0 : double;
    grdCorr45 : double;
end;

Function call:

if err = WFS_GetMlaData(handle,
                        MlaList[i].idx,
                        MlaList[i].name,
                        PDouble(MlaList[i].camPitchUm),
                        PDouble(MlaList[i].lensletPitchUm),
                        PDouble(MlaList[i].spotOffsetx),
                        PDouble(MlaList[i].spotOffsety),
                        PDouble(MlaList[i].lensletFocalLengthUm),
                        PDouble(MlaList[i].grdCorr0),
                        PDouble(MlaList[i].grdCorr45) ) then MyWFS_HandleErrors(handle, err);

With a similar function which passes pointers to integer it works, in the case above I have Invalid Typecast error.

Upvotes: 2

Views: 2068

Answers (2)

Rob Kennedy
Rob Kennedy

Reputation: 163247

Your DLL function is declared incorrectly. The original C code has all those parameters as pointers to double — double*. The sure-fire, can't-go-wrong solution is for you to change the function declaration to match the C code. Remove the var modifiers from all the function parameters.

The alternative solution is again for you to change the function declaration, but this time to make it look a little more like idiomatic Delphi. Keep the var modifiers, but change the parameters' type to Double instead of PDouble.

If you make the first change, then you would call the function by passing pointers to the record members: @MlaList[i].camPitchUm with no type casting. If you make the second change instead, then you would call the function by passing the record members directly, again with no type casting: MlaList[i].camPitchUm.

Upvotes: 4

fantaghirocco
fantaghirocco

Reputation: 4868

The answer is in the Parameters (Delphi) - Value and Variable Parameters documentation. My bold emphasizes it:

If a routine's declaration specifies a var parameter, you must pass an assignable expression - that is, a variable, typed constant (in the {$J+} state), dereferenced pointer, field, or indexed variable to the routine when you call it.


Regarding your case, my advice is to declare a new type:

PMlaInfo = ^TMlaInfo;

And change the signature of the function:

function WFS_GetMlaData(AHandle: WFS_HDL; const AMlaInfo: PMlaInfo): Integer stdcall;

But there's a sort of "hack" (dereferenced pointer):

PDouble((@MlaList[i].camPitchUm)^)

Upvotes: 2

Related Questions