Custom Variant Wrapper for TDataset - Part 2

In Part 1 of this series we discussed the data structure needed to hold your custom variant data.  In this article we will discuss the code needed to create an instance of your custom variant.

A Variant variable is opaque to the user’s application, that is, the user’s application cannot see any of the internal structure of the Variant.  This means that you have to provide a function that will allow the user to create an instance of your custom variant.  For our TDataset wrapper, the Variant data structure (our TVarData equivalent) looks like this:


TDatasetData = packed record
VType: TVarType;
Reserved1, Reserved2, Reserved3: Word;
VDataset: TDataset;
Reserved4: LongWord;
end;

What we need to do now is define a function that will initialize a TDatasetData record and return it as a Variant.  This is actually quite easy to do.  We just need to create a function that takes the TDataset that the user wants wrapped as an argument and return a TDatasetData record cast to a Variant.  The function looks like this:


function VarDatasetCreate(ds: TDataset): Variant;
begin
VarClear(Result);
TDatasetData(Result).VType := DatasetVariant.VarType;
TDatasetData(Result).VDataset := ds;
end;

Let’s look at this line by line.

VarClear(Result); is a VCL supplied procedure that initializes the Variant that we are going to be returning (Result) to an empty Variant.

 TDatasetData(Result).VType := DatasetVariant.VarType;  In this line we cast Result to our custom variant data structure (TDatasetData) and set the variant’s type (VType) to our custom variant type.  Don’t worry about where DatasetVariant.VarType comes from for now, we will cover that in a little while.  Notice that you can simply cast a Variant to the equivalent TVarData (TDatasetData in our case) record and vice versa.

TDatasetData(Result).VDataset := ds; In this line we set our variant’s data (VDataset) to reference the TDataset (ds) supplied by the user.  We will use the TDataset reference later to access the value of  the dataset’s fields.

Now that we have a function to initialize our variant’s data structure, we need to derive a class from TCustomVariantType, or one of its descendants, to provide the code required to allow our variant to do useful work.

TCustomVariantType and its descendants are used by the Delphi run time to perform operations on your variant like casting it to another type, casting another type to your variant, using your variant in arithmetic and boolean expressions, etc.  To do that, the Delphi run time invokes methods from your derived class passing an instance of your variant (among other things) as an argument.  This means that you don’t need an instance of this class for each instance of your custom variant.  Only one instance of the class is required for the entire run time session.

To get started all we need to do is derive a class and instantiate it.  The class definition looks like this:


TDatasetVariant = class(TCustomVariantType)
end;

To instantiate it we just need to create an instance in the initialization section and free it in the finalization section.  Like this:


initialization
DatasetVariant := TDatasetVariant.Create;

finalization
FreeAndNil(DatasetVariant);

As I mentioned earlier, this single instance of the derived class will be used to manipulate all instances of your custom variant.

Now we get to the part you have all been waiting for.  Where did the value for the custom variant type that we used to initialize TDatasetData.VType come from.  Well, the answer to that lies in TCustomVariantType.Create.  As shown in Part 1, every Variant has a variant type.  The variant type is just a 16 bit integer value.  Delphi’s system assigned variant types are less than $0100.  These are hard coded in System.pas.  Custom variant types start at $010f.  The value of the next available custom variant type is stored in a global variable in Variants.pas.  TCustomVariantType.Create uses this value as our custom variant type, stores it in the VarType property and increments the global variable.  This means that you never know what your custom variant type is going to be.  It can only be determined by referencing the TCustomVariantType.VarType property.

2 Responses to “Custom Variant Wrapper for TDataset - Part 2”

  1. UGG Boots Says:

    I found this article useful in a paper I am writing at university. Hopefully, I get an A+ now!

    Thanks

    Bernice Franklin

    UGG Boots
    UGG Boats
    UGG Purses

  2. ugg boots Says:

    Thank you very much for sharing your experience!

Leave a Reply