Working with Variant Types in Delphi
Introduction
The standard function VarType()
returns a variant's type code. The varTypeMask
constant is a bit mask used to extract the code from VarType()
's return value, so that, for example,
(VarType(V) and varTypeMask) = varDouble
returns True
if V
contains a Double or an array of Double. (The mask simply hides the first bit, which indicates whether the variant holds an array.) The TVarData
record type defined in the System unit can be used to typecast variants and gain access to their internal representation.
This example shows how to use the TVarData
type in typecasts of Variant variables to access the internals of a variable. Example:
var V: Variant; begin ... if TVarData(V).VType = varEmpty then ...; ... VarClear(V); TVarData(V).VType := varInteger; TVarData(V).VInteger := 1234567; ... end;
Using Variants in COM Development
Source: Chapter 15: COM DEVELOPMENT, Borland Delphi 6 Developer's Guide, p. 725.
LISTING 15.13 The Server Unit
unit ServObj; interface uses ComObj,ActiveX,Server_TLB; type TBinaryData =class(TAutoObject,IBinaryData) protected function Get_Data:OleVariant;safecall; procedure Set_Data(Value:OleVariant);safecall; end; implementation uses ComServ,ServMain; //------------------------------------------------------------- // description: get data from a Memo and copy to Variant //------------------------------------------------------------- function TBinaryData.Get_Data:OleVariant; var P:Pointer; L:Integer; begin //Move data from memo into array L :=Length(MainForm.Memo.Text); Result :=VarArrayCreate([0,L -1],varByte); P :=VarArrayLock(Result); try Move(MainForm.Memo.Text[1],P^,L); finally VarArrayUnlock(Result); end; end; //------------------------------------------------------------- // description: get data from a Variant and copy to Memo //------------------------------------------------------------- procedure TBinaryData.Set_Data(Value:OleVariant); var P:Pointer; L:Integer; S:string; begin //Move data from array into memo L :=VarArrayHighBound(Value,1)-VarArrayLowBound(Value,1)+1; SetLength(S,L); P :=VarArrayLock(Value); try Move(P^,S[1],L); finally VarArrayUnlock(Value); end; MainForm.Memo.Text :=S; end; initialization TAutoObjectFactory.Create(ComServer,TBinaryData,Class_BinaryData, ciSingleInstance,tmApartment); end.
LISTING 15.14 The Client Unit
unit CliMain; interface uses Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs, StdCtrls,ExtCtrls,Server_TLB; type TMainForm =class(TForm) Memo:TMemo; Panel1:TPanel; SetButton:TButton; GetButton:TButton; OpenButton:TButton; OpenDialog:TOpenDialog; procedure OpenButtonClick(Sender:TObject); procedure FormCreate(Sender:TObject); procedure SetButtonClick(Sender:TObject); procedure GetButtonClick(Sender:TObject); private FServer:IBinaryData; end; var MainForm:TMainForm; implementation {$R *.DFM} procedure TMainForm.FormCreate(Sender:TObject); begin FServer :=CoBinaryData.Create; end; procedure TMainForm.OpenButtonClick(Sender:TObject); begin if OpenDialog.Execute then Memo.Lines.LoadFromFile(OpenDialog.FileName); end; procedure TMainForm.SetButtonClick(Sender:TObject); var P:Pointer; L:Integer; V:OleVariant; begin //Send memo data to server L :=Length(Memo.Text); V :=VarArrayCreate([0,L -1],varByte); P :=VarArrayLock(V); try Move(Memo.Text[1],P^,L); finally VarArrayUnlock(V); end; FServer.Data :=V; end; procedure TMainForm.GetButtonClick(Sender:TObject); var P:Pointer; L:Integer; S:string; V:OleVariant; begin //Get server’s memo data V :=FServer.Data; L :=VarArrayHighBound(V,1)-VarArrayLowBound(V,1)+1; SetLength(S,L); P :=VarArrayLock(V); try Move(P^,S[1],L); finally VarArrayUnlock(V); end; Memo.Text :=S; end; end.
Other Examples
procedure VariantToData(Value: Variant; Var Data; MaxLen: integer); var p: pByte; len: integer; begin assert(maxlen > 0); Try p := VarArrayLock(Value); Len := VarArrayHighBound(Value, 1) + 1; assert(Len <= MaxLen); move(p^, Data, Len); finally VarArrayUnLock(Value); end; end; function DataToVariant(const Data;Len:integer):Variant; var p: pByte; begin Result := VarArrayCreate([0, len-1], varByte); p := VarArrayLock(Result); try move(Data, p^, Len); finally VarArrayUnLock(Result); end; end; function ComponentToString(Component: TComponent): string; var BinStream: TMemoryStream; StrStream: TStringStream; s: string; begin BinStream := TMemoryStream.Create; try StrStream := TStringStream.Create(s); try BinStream.WriteComponent(Component); BinStream.Seek(0, soFromBeginning); ObjectBinaryToText(BinStream, StrStream); StrStream.Seek(0, soFromBeginning); Result := StrStream.DataString; finally StrStream.Free; end; finally BinStream.Free; end; end; function StringToComponent(Value: string): TComponent; var StrStream: TStringStream; BinStream: TMemoryStream; begin StrStream := TStringStream.Create(Value); try BinStream := TMemoryStream.Create; try ObjectTextToBinary(StrStream, BinStream); BinStream.Seek(0, soFromBeginning); Result := BinStream.ReadComponent(nil); finally BinStream.Free; end; finally StrStream.Free; end; end; function ComponentToVariant(Component: TComponent): Variant; var BinStream: TMemoryStream; Data: Pointer; begin BinStream := TMemoryStream.Create; try BinStream.WriteComponent(Component); Result := VarArrayCreate([0, BinStream.Size - 1], varByte); Data := VarArrayLock(Result); try Move(BinStream.Memory^, Data^, BinStream.Size); finally VarArrayUnlock(Result); end; finally BinStream.Free; end; end; function VariantToComponent(Value: Variant): TComponent; var BinStream: TMemoryStream; Data: Pointer; begin BinStream := TMemoryStream.Create; try Data := VarArrayLock(Value); try BinStream.WriteBuffer(Data^, VarArrayHighBound(Value, 1) + 1); finally VarArrayUnlock(Value); end; BinStream.Seek(0, soFromBeginning); Result := BinStream.ReadComponent(nil); finally BinStream.Free; end; end;