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