Mega Code Archive

 
Categories / Delphi / Examples
 

Storing pointers in variants

Title: Storing pointers in variants Question: Delphi's help says "By default, Variants can hold values of any type except records, sets, static arrays, files, classes, class references, and pointers. In other words, variants can hold anything but structured types and pointers." True, but a little imagination may help us bypass this rule. Answer: The solutionis not that dificult : Pointers and integers are both stored on 4 bytes. And variants can hold integer, so the solution will simply be to cast our pointer to an integer , and store this integer in a variant, then cast it "back" on the other side, to be able to use it. Her is an excerpt of the source of a larger subject, showing an implementation example : type // -1- We declare a record type. TPointedRec = Record anInteger: Integer; aSender: TObject; End; // and a pointer to instances of it: PPointedRec = ^TPointedRec; {...} // ----------------------------------------------------------------------------- // --- On the caller side (main unit) : // ----------------------------------------------------------------------------- procedure TForm1.Button3Click(Sender: TObject); // Declare a variable of the pointer type we're about to use : // it will be : aPointedRec: PPointedRec; var aPointedRec: PPointedRec; v: Variant; aPArserInstance: TLittleParser; begin inc(appelCount); // Let's declare an instance of a TPointedRec record new(aPointedRec); aPointedRec.anInteger := appelCount; // a counter aPointedRec.aSender := Sender; // To store our pointer in a variant, just cast it to a legal type : // (integers and pointers are both stored on 4 bytes.) v := Integer(aPointedRec); // call the wanted function, and use it's return aParserInstance := TLittleParser.Create; aPArserInstance.HandlePointerValues( v ); // be kind, free memory Dispose(aPointedRec); end; // ----------------------------------------------------------------------------- // --- On the called side (parser unit) : // ----------------------------------------------------------------------------- function TLittleParser.HandlePointerValues(Const value: Variant): Variant; var v: Variant; i: Integer; s: String; Begin // The variant received ("value") contains a pointer to a record of kind TPointedRec; // To read this record we'll just need to cast our variant back to an integer, // then to a ^TPointedRec : i := StrToInt( VarToStr( value )); // "i" now stores our pointer, but doesn't know it yet. // Casting it to some type will do the trick. Eg: PPointedRec(i) casts it // to a pointer to a record of kind TPointedRec. If PPointedRec(i).aSender is TButton Then s := TButton( PPointedRec(i).aSender ).Caption Else s := '(Sender is not a button)'; v := 'This function has been called ' + VarToStr( PPointedRec(i).anInteger ) + ' times.' + #13#10 + ' The caller is this time : ' + s; result := v; End; That's it. Olivier. As stated earlier, this is an excerpt of a larger article illustrating the use of the MethodAddress() function in Objects ("Accessing a published method of a class by its name used as string"). The whole article is maybe a bit too big to fit here, but is freely available at the address provided in the "Reference" field above (with source and demo).