== 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;