Advertisement
RandomClear

Custom invokable variant for TObject

Mar 14th, 2016
451
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 19.01 KB | None | 0 0
  1. unit VarObject;
  2.  
  3. interface
  4.  
  5. uses
  6.   SysUtils, Variants;
  7.  
  8. function VarObjectCreate(const AObject: TObject): Variant;
  9.  
  10. function VarObjectType: TVarType;
  11. function VarDataIsObject(const AVarData: TVarData): Boolean;
  12. function VarTypeIsObject(const AVarType: TVarType): Boolean;
  13. function VarIsObject(const AValue: Variant): Boolean;
  14. function VarToObject(const AValue: Variant): TObject;
  15. function VarToObjectDef(const AValue: Variant; const ADefault: TObject = nil): TObject;
  16.  
  17. type
  18.   IGetImplement = interface
  19.   ['{33A0A83F-7D7C-49F0-88D6-926CF995D6AE}']
  20.     function GetSelf: TObject;
  21.   end;
  22.  
  23. implementation
  24.  
  25. uses
  26.   TypInfo, Classes, ComObj, Rtti;
  27.  
  28. type
  29.   TObjectVariantType = class(TPublishableVariantType)
  30.   strict private
  31.     function TValueFromVarData(const V: TVarData): TValue;
  32.     function TValueToVarData(const V: TValue): TVarData;
  33.   protected
  34.     { IVarInstanceReference }
  35.     function GetInstance(const V: TVarData): TObject; override;
  36.     { TCustomVariantType }
  37.     function LeftPromotion(const V: TVarData; const Operator: TVarOp; out RequiredVarType: TVarType): Boolean; override;
  38.     function RightPromotion(const V: TVarData; const Operator: TVarOp; out RequiredVarType: TVarType): Boolean; override;
  39.     function OlePromotion(const V: TVarData; out RequiredVarType: TVarType): Boolean; override;
  40.   public
  41.     procedure Clear(var V: TVarData); override;
  42.     function IsClear(const V: TVarData): Boolean; override;
  43.     procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override;
  44.  
  45.     procedure BinaryOp(var Left: TVarData; const Right: TVarData; const Operator: TVarOp); override;
  46.     procedure Compare(const Left: TVarData; const Right: TVarData; var Relationship: TVarCompareResult); override;
  47.  
  48.     function GetProperty(var Dest: TVarData; const V: TVarData; const Name: string): Boolean; override;
  49.     function DoFunction(var Dest: TVarData; const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean; override;
  50.     function DoProcedure(const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean; override;
  51.  
  52.     procedure Cast(var Dest: TVarData; const Source: TVarData); override;
  53.     procedure CastTo(var Dest: TVarData; const Source: TVarData; const AVarType: Word); override;
  54.   end;
  55.  
  56.   TObjectVarData = packed record
  57.     VType: TVarType;
  58.     Reserved1, Reserved2, Reserved3: Word;
  59.     VObject: TObject;
  60.     Reserved4: LongWord;
  61.   end;
  62.  
  63. var
  64.   ObjectVariantType: TObjectVariantType;
  65.  
  66. function VarObjectCreate(const AObject: TObject): Variant;
  67. begin
  68.   VarClear(Result);
  69.   TObjectVarData(Result).VType := VarObjectType;
  70.   TObjectVarData(Result).VObject := AObject;
  71. end;
  72.  
  73. function VarObjectType: TVarType;
  74. begin
  75.   Result := ObjectVariantType.VarType;
  76. end;
  77.  
  78. function VarDataIsObject(const AVarData: TVarData): Boolean;
  79. begin
  80.   Result := VarTypeIsObject(AVarData.VType);
  81. end;
  82.  
  83. function VarTypeIsObject(const AVarType: TVarType): Boolean;
  84. begin
  85.   Result := ((AVarType and varTypeMask) = VarObjectType);
  86. end;
  87.  
  88. function VarIsObject(const AValue: Variant): Boolean;
  89. begin
  90.   Result := VarTypeIsObject(TVarData(AValue).VType and varTypeMask);
  91. end;
  92.  
  93. function VarToObject(const AValue: Variant): TObject;
  94. var
  95.   LSource, LDest: TVarType;
  96. begin
  97.   Result := VarToObjectDef(AValue, TObject(666));
  98.   if Result = TObject(666) then
  99.   begin
  100.     LSource := TVarData(AValue).VType and varTypeMask;
  101.     LDest := VarObjectType;
  102.     VarCastError(LSource, LDest);
  103.   end;
  104. end;
  105.  
  106. function VarToObjectDef(const AValue: Variant; const ADefault: TObject = nil): TObject;
  107. var
  108.   LDest: Variant;
  109. begin
  110.   if VarIsEmpty(AValue) then
  111.     Result := nil
  112.   else
  113.   if VarIsNull(AValue) then
  114.   begin
  115.     if NullStrictConvert then
  116.       Result := ADefault
  117.     else
  118.       Result := nil;
  119.   end
  120.   else
  121.   if VarIsObject(AValue) then
  122.     Result := TObjectVarData(AValue).VObject
  123.   else
  124.   begin
  125.     try
  126.       VarCast(LDest, AValue, VarObjectType);
  127.       Result := TObjectVarData(LDest).VObject;
  128.     except
  129.       Result := ADefault;
  130.     end;
  131.   end;
  132. end;
  133.  
  134. //________________________________________________________________________________________
  135.  
  136. { TObjectVariantType }
  137.  
  138. function TObjectVariantType.GetInstance(const V: TVarData): TObject;
  139. begin
  140.   Result := TObjectVarData(V).VObject;
  141. end;
  142.  
  143. procedure TObjectVariantType.Cast(var Dest: TVarData; const Source: TVarData);
  144. const
  145.   ObjCastGUID: TGUID = '{CEDF24DE-80A4-447D-8C75-EB871DC121FD}';
  146. var
  147.   UI: NativeUInt;
  148.   S: String;
  149.   X: Integer;
  150.   I: IInterface;
  151.   D: IDispatch;
  152.   O: TObject;
  153.   GetImpl: IGetImplement;
  154.   GetComp: IInterfaceComponentReference;
  155. begin
  156.   if VarDataIsOrdinal(Source) then
  157.   begin
  158.     UI := Variant(Source);
  159.     VarDataClear(Dest);
  160.     TObjectVarData(Dest).VObject := TObject(UI);
  161.     Dest.VType := VarObjectType;
  162.     Exit;
  163.   end;
  164.  
  165.   if Source.VType = varUnknown then
  166.   begin
  167.     I := IInterface(Source.VUnknown);
  168.     if Supports(I, ObjCastGUID, O) then
  169.     begin
  170.       VarDataClear(Dest);
  171.       TObjectVarData(Dest).VObject := O;
  172.       Dest.VType := VarObjectType;
  173.     end
  174.     else
  175.     if Supports(I, IInterfaceComponentReference, GetComp) then
  176.     begin
  177.       VarDataClear(Dest);
  178.       TObjectVarData(Dest).VObject := GetComp.GetComponent;
  179.       Dest.VType := VarObjectType;
  180.     end
  181.     else
  182.     if Supports(I, IGetImplement, GetImpl) then
  183.     begin
  184.       VarDataClear(Dest);
  185.       TObjectVarData(Dest).VObject := GetImpl.GetSelf;
  186.       Dest.VType := VarObjectType;
  187.     end
  188.  
  189.     else
  190.       VarCastError(Source.VType, VarObjectType);
  191.     Exit;
  192.   end;
  193.  
  194.   if Source.VType = varDispatch then
  195.   begin
  196.     D := IDispatch(Source.VDispatch);
  197.     if Supports(D, ObjCastGUID, O) then
  198.     begin
  199.       VarDataClear(Dest);
  200.       TObjectVarData(Dest).VObject := O;
  201.       Dest.VType := VarObjectType;
  202.     end
  203.     else
  204.     if Supports(D, IInterfaceComponentReference, GetComp) then
  205.     begin
  206.       VarDataClear(Dest);
  207.       TObjectVarData(Dest).VObject := GetComp.GetComponent;
  208.       Dest.VType := VarObjectType;
  209.     end
  210.     else
  211.     if Supports(D, IGetImplement, GetImpl) then
  212.     begin
  213.       VarDataClear(Dest);
  214.       TObjectVarData(Dest).VObject := GetImpl.GetSelf;
  215.       Dest.VType := VarObjectType;
  216.     end
  217.     else
  218.       VarCastError(Source.VType, VarObjectType);
  219.     Exit;
  220.   end;
  221.  
  222.   S := Trim(AdjustLineBreaks(VarDataToStr(Source)));
  223.   X := Pos(sLineBreak, S);
  224.   if X > 0 then
  225.   begin
  226.     SetLength(S, X - 1);
  227.     S := Trim(S);
  228.   end;
  229.  
  230.   if {$IFDEF CPUX64}TryStrToInt64{$ELSE}TryStrToInt{$ENDIF}(S, {$IFDEF CPUX64}Int64{$ELSE}Integer{$ENDIF}(UI)) then
  231.   begin
  232.     VarDataClear(Dest);
  233.     TObjectVarData(Dest).VObject := TObject(UI);
  234.     Dest.VType := VarObjectType;
  235.   end
  236.   else
  237.     VarCastError(Source.VType, VarObjectType);
  238. end;
  239.  
  240. procedure TObjectVariantType.CastTo(var Dest: TVarData; const Source: TVarData; const AVarType: Word);
  241. var
  242.   I: IInterface;
  243.   D: IDispatch;
  244. begin
  245.   Assert(Source.VType = VarObjectType);
  246.   case AVarType of
  247.     varUnknown:
  248.     begin
  249.       if Supports(TObjectVarData(Source).VObject, IInterface, I) then
  250.       begin
  251.         VarDataClear(Dest);
  252.         Dest.VDispatch := nil;
  253.         Dest.VType := varUnknown;
  254.         IInterface(Dest.VUnknown) := I;
  255.       end
  256.       else
  257.         VarCastError(Source.VType, AVarType);
  258.     end;
  259.     varDispatch:
  260.     begin
  261.       if Supports(TObjectVarData(Source).VObject, IDispatch, D) then
  262.       begin
  263.         VarDataClear(Dest);
  264.         Dest.VDispatch := nil;
  265.         Dest.VType := varDispatch;
  266.         IInterface(Dest.VDispatch) := D;
  267.       end
  268.       else
  269.         VarCastError(Source.VType, AVarType);
  270.     end;
  271.     varOleStr:
  272.       VarDataFromOleStr(Dest, '$' + IntToHex(NativeUInt(TObjectVarData(Source).VObject), SizeOf(Pointer)) + sLineBreak + TObjectVarData(Source).VObject.ToString);
  273.     varString:
  274.       VarDataFromStr(Dest, '$' + IntToHex(NativeUInt(TObjectVarData(Source).VObject), SizeOf(Pointer)) + sLineBreak + TObjectVarData(Source).VObject.ToString);
  275.     varUString:
  276.       VarDataFromStr(Dest, '$' + IntToHex(NativeUInt(TObjectVarData(Source).VObject), SizeOf(Pointer)) + sLineBreak + TObjectVarData(Source).VObject.ToString);
  277.     varSmallint, varInteger, varShortInt, varByte, varWord, varLongWord, varInt64, varUInt64, varSingle, varDouble, varCurrency:
  278.     begin
  279.       VarDataClear(Dest);
  280.       Dest.VType := varUInt64;
  281.       Dest.VUInt64 := NativeUInt(TObjectVarData(Source).VObject);
  282.       if AVarType <> varUInt64 then
  283.         VarDataCastTo(Dest, AVarType);
  284.     end;
  285.     varBoolean:
  286.     begin
  287.       VarDataClear(Dest);
  288.       Dest.VType := varBoolean;
  289.       Dest.VBoolean := (TObjectVarData(Source).VObject <> nil);
  290.     end;
  291.   else
  292.     VarCastError(Source.VType, AVarType);
  293.   end;
  294. end;
  295.  
  296. procedure TObjectVariantType.Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean);
  297. begin
  298.   SimplisticCopy(Dest, Source, Indirect);
  299. end;
  300.  
  301. procedure TObjectVariantType.Clear(var V: TVarData);
  302. begin
  303.   SimplisticClear(V);
  304. end;
  305.  
  306. function TObjectVariantType.IsClear(const V: TVarData): Boolean;
  307. begin
  308.   Result := TObjectVarData(V).VObject = nil;
  309. end;
  310.  
  311. procedure TObjectVariantType.BinaryOp(var Left: TVarData; const Right: TVarData; const Operator: TVarOp);
  312. var
  313.   I: UInt64;
  314.   F: Extended;
  315.   S: String;
  316.   L, R: Variant;
  317. begin
  318.   if VarDataIsObject(Left) then
  319.   begin
  320.     if VarDataIsStr(Right) then
  321.     begin
  322.       S := Variant(Left);
  323.       L := S;
  324.     end
  325.     else
  326.     begin
  327.       I := NativeUInt(TObjectVarData(Left).VObject);
  328.       L := I;
  329.     end;
  330.   end
  331.   else
  332.   if VarDataIsOrdinal(Left) then
  333.   begin
  334.     I := Variant(Left);
  335.     L := I;
  336.   end
  337.   else
  338.   if VarDataIsFloat(Left) then
  339.   begin
  340.     F := Variant(Left);
  341.     L := F;
  342.   end
  343.   else
  344.   if VarDataIsStr(Left) then
  345.   begin
  346.     S := Variant(Left);
  347.     L := S;
  348.   end
  349.   else
  350.     L := Variant(Left);
  351.  
  352.   if VarDataIsObject(Right) then
  353.   begin
  354.     if VarIsStr(L) then
  355.     begin
  356.       S := Variant(Right);
  357.       R := S;
  358.     end
  359.     else
  360.     begin
  361.       I := NativeUInt(TObjectVarData(Right).VObject);
  362.       R := I;
  363.     end;
  364.   end
  365.   else
  366.   if VarDataIsOrdinal(Right) then
  367.   begin
  368.     I := Variant(Right);
  369.     R := I;
  370.   end
  371.   else
  372.   if VarDataIsFloat(Right) then
  373.   begin
  374.     F := Variant(Right);
  375.     R := F;
  376.   end
  377.   else
  378.   if VarDataIsStr(Right) then
  379.   begin
  380.     S := Variant(Right);
  381.     R := S;
  382.   end
  383.   else
  384.     R := Variant(Right);
  385.  
  386.   case Operator of
  387.     opAdd:
  388.       R := L + R;
  389.     opSubtract:
  390.       R := L - R;
  391.     opMultiply:
  392.       R := L * R;
  393.     opDivide:
  394.       R := L / R;
  395.     opIntDivide:
  396.       R := L div R;
  397.     opModulus:
  398.       R := L mod R;
  399.     opShiftLeft:
  400.       R := L shl R;
  401.     opShiftRight:
  402.       R := L shr R;
  403.     opAnd:
  404.       R := L and R;
  405.     opOr:
  406.       R := L or R;
  407.     opXor:
  408.       R := L xor R;
  409.   else
  410.     RaiseInvalidOp;
  411.   end;
  412.  
  413.   VarDataClear(Left);
  414.   Left := TVarData(R);
  415.   FillChar(R, SizeOf(R), 0);
  416. end;
  417.  
  418. procedure TObjectVariantType.Compare(const Left, Right: TVarData; var Relationship: TVarCompareResult);
  419. var
  420.   LLeft: NativeUInt;
  421.   LRight: NativeUInt;
  422. begin
  423.   if Left.VType = VarObjectType then
  424.     LLeft := NativeUInt(TObjectVarData(Left).VObject)
  425.   else
  426.   if VarDataIsStr(Left) then
  427.     LLeft := NativeUInt(VarToObjectDef(Variant(Left)))
  428.   else
  429.     LLeft := Variant(Left);
  430.   if Right.VType = VarObjectType then
  431.     LRight := NativeUInt(TObjectVarData(Right).VObject)
  432.   else
  433.   if VarDataIsStr(Right) then
  434.     LRight := NativeUInt(VarToObjectDef(Variant(Right)))
  435.   else
  436.     LRight := Variant(Right);
  437.  
  438.   if LLeft = LRight then
  439.     Relationship := crEqual
  440.   else
  441.   if LLeft < LRight then
  442.     Relationship := crLessThan
  443.   else
  444.     Relationship := crGreaterThan
  445. end;
  446.  
  447. function TObjectVariantType.LeftPromotion(const V: TVarData; const Operator: TVarOp; out RequiredVarType: TVarType): Boolean;
  448. begin
  449.   if VarDataIsObject(V) then
  450.   begin
  451.     Result := False;
  452.     Exit;
  453.   end;
  454.  
  455.   if VarDataIsOrdinal(V) then
  456.     RequiredVarType := {$IFDEF CPUX64}varLongWord{$ELSE}varUInt64{$ENDIF}
  457.   else
  458.   if VarDataIsStr(V) then
  459.     RequiredVarType := varString
  460.   else
  461.     RequiredVarType := VarType;
  462.   Result := True;
  463. end;
  464.  
  465. function TObjectVariantType.RightPromotion(const V: TVarData; const Operator: TVarOp; out RequiredVarType: TVarType): Boolean;
  466. begin
  467.   if VarDataIsObject(V) then
  468.   begin
  469.     Result := False;
  470.     Exit;
  471.   end;
  472.  
  473.   if VarDataIsOrdinal(V) then
  474.     RequiredVarType := {$IFDEF CPUX64}varLongWord{$ELSE}varUInt64{$ENDIF}
  475.   else
  476.   if VarDataIsStr(V) then
  477.     RequiredVarType := varString
  478.   else
  479.     RequiredVarType := VarType;
  480.   Result := True;
  481. end;
  482.  
  483. function TObjectVariantType.OlePromotion(const V: TVarData; out RequiredVarType: TVarType): Boolean;
  484. var
  485.   D: IDispatch;
  486. begin
  487.   if Supports(TObjectVarData(V).VObject, IDispatch, D) then
  488.     RequiredVarType := varDispatch
  489.   else
  490.     RequiredVarType := varUnknown;
  491.   Result := True;
  492. end;
  493.  
  494. function TObjectVariantType.GetProperty(var Dest: TVarData; const V: TVarData; const Name: string): Boolean;
  495. var
  496.   O: TObject;
  497. begin
  498.   if UpperCase(Name) = 'SELF' then
  499.   begin
  500.     O := GetInstance(V);
  501.     VarDataClear(Dest);
  502.     {$IFDEF CPUX64}
  503.     Dest.VType := varUInt64;
  504.     Dest.VLongWord := NativeUInt(O);
  505.     {$ELSE}
  506.     Dest.VType := varLongWord;
  507.     Dest.VLongWord := NativeUInt(O);
  508.     {$ENDIF}
  509.     Result := True;
  510.   end
  511.   else
  512.     Result := inherited GetProperty(Dest, V, Name);
  513. end;
  514.  
  515. function TObjectVariantType.DoFunction(var Dest: TVarData; const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean;
  516. var
  517.   LContext: TRttiContext;
  518.   LType: TRttiInstanceType;
  519.   LMethod: TRttiMethod;
  520.   LObj: TObject;
  521.   LParams: array of TValue;
  522.   LResult: TValue;
  523.   LArgBase, X: Integer;
  524. begin
  525.   Result := True;
  526.   LObj := GetInstance(V);
  527.  
  528.   LContext := TRttiContext.Create; // record, not object, do not call FreeAndNil
  529.   try
  530.     LType := TRttiInstanceType(LContext.GetType(LObj.ClassType));
  531.     try
  532.       LMethod := LType.GetMethod(Name);
  533.  
  534.       if (not Assigned(LMethod)) or
  535.          (LMethod.Visibility in [mvPrivate, mvProtected]) or
  536.          LMethod.IsConstructor or
  537.          LMethod.IsDestructor then
  538.       begin
  539.         Result := False;
  540.         Exit;
  541.       end;
  542.  
  543.       LArgBase := 0;
  544.       if Length(Arguments) > 0 then
  545.       begin
  546.         if Arguments[0].VType = varError then
  547.           Inc(LArgBase);
  548.  
  549.         SetLength(LParams, Length(Arguments) - LArgBase);
  550.  
  551.         for X := LArgBase to Length(Arguments) - 1 do
  552.           LParams[X - LArgBase] := TValueFromVarData(Arguments[X]);
  553.       end
  554.       else
  555.         LParams := nil;
  556.  
  557.       if LMethod.IsClassMethod or LMethod.IsStatic then
  558.         LResult := LMethod.Invoke(LObj.ClassType, LParams)
  559.       else
  560.         LResult := LMethod.Invoke(LObj, LParams);
  561.  
  562.       Dest := TValueToVarData(LResult);
  563.  
  564.       if Length(Arguments) > 0 then
  565.       begin
  566.         for X := LArgBase to Length(Arguments) - 1 do
  567.           if VarDataIsByRef(Arguments[X]) then
  568.             TVarData(Arguments[X].VPointer^) := TValueToVarData(LParams[X - LArgBase]);
  569.       end;
  570.     finally
  571.       FreeAndNil(LType);
  572.     end;
  573.   finally
  574.     LContext.Free;
  575.   end;
  576. end;
  577.  
  578. function TObjectVariantType.DoProcedure(const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean;
  579. var
  580.   LDummy: TVarData;
  581. begin
  582.   Result := DoFunction(LDummy, V, Name, Arguments);
  583.   VarDataClear(LDummy);
  584. end;
  585.  
  586. function TObjectVariantType.TValueFromVarData(const V: TVarData): TValue;
  587. var
  588.   O: TObject;
  589. begin
  590.   if VarDataIsObject(V) then
  591.   begin
  592.     O := TObjectVarData(V).VObject;
  593.     Result := TValue.From(O);
  594.   end
  595.   else
  596.     Result := TValue.FromVariant(Variant(V));
  597. end;
  598.  
  599. function TObjectVariantType.TValueToVarData(const V: TValue): TVarData;
  600. var
  601.   Rslt: Variant;
  602. begin
  603.   VarClear(Rslt);
  604.   if V.IsObject then
  605.     Rslt := VarObjectCreate(V.AsObject)
  606.   else
  607.     Rslt := V.AsVariant;
  608.  
  609.   VarDataClear(Result);
  610.   Result := TVarData(Rslt);
  611.   FillChar(Rslt, SizeOf(Rslt), 0);
  612. end;
  613.  
  614. initialization
  615.   ObjectVariantType := TObjectVariantType.Create;
  616. finalization
  617.   FreeAndNil(ObjectVariantType);
  618. end.
  619.  
  620. {
  621.  
  622. Usage sample:
  623.  
  624. uses
  625.   VarObject;
  626.  
  627. procedure TForm1.Button1Click(Sender: TObject);
  628. var
  629.   B: TButton;
  630.   V: Variant;
  631.   O: TObject;
  632.   S: String;
  633.   OV: OleVariant;
  634.   I: Integer;
  635.   Intf: IUnknown;
  636. begin
  637.   B := Sender as TButton;
  638.  
  639.   // V := B;               // - FAIL: Incompatible types: 'Variant' and 'TButton'
  640.   V := VarObjectCreate(B); // - OK
  641.  
  642.   if VarIsObject(V) then
  643.   begin
  644.     // O := V;             // - FAIL: Incompatible types: 'TObject' and 'Variant'
  645.     O := VarToObject(V);   // - OK
  646.     if O.InheritsFrom(TButton) then
  647.     begin
  648.       B := TButton(O);
  649.       B.Caption := B.Caption + ' 1';
  650.     end;
  651.   end;
  652.  
  653.   B := VarToObject(V) as TButton;    // - OK, shorter version, raises exception on error
  654.   B := VarToObjectDef(V) as TButton; // - OK, shorter version, returns nil on error
  655.   B.Caption := B.Caption + ' 2';
  656.  
  657.   Caption := Caption + ' ' + V;   // - Object is interchable with strings (outputs pointer + .ToString - e.g. '$00123456'#13#10'TButton')
  658.   Caption := V + ' ' + Caption;   // - Works both ways
  659.  
  660.   I := Tag;
  661.   I := I + V;                      // - Integer is interchable with objects
  662.   I := V + I;                      // - Works both ways
  663.   Tag := I;                        // - Here: Tag = 2 * NativeUInt(B)
  664.  
  665.   V := NativeUInt(B);              // - Integer = pointer(Object)
  666.   B := VarToObject(V) as TButton;  // - OK, B does not change (same value)
  667.  
  668.   S := V;                          // - OK, S = '$00123456'#13#10'TButton' (pointer + .ToString)
  669.   V := S;                          // - OK, V = varString
  670.   B := VarToObject(V) as TButton;  // - OK, B does not change (same value)
  671.  
  672.   V := VarObjectCreate(B);         // - Reset to custom variant type, need to support invokes below, since (obviosly) we can not call properties/methods on integer, strings, etc.
  673.   V.Caption := V.Caption + ' 3';   // - OK, works via RTTI/published (see TypInfo.TPublishableVariantType.Get/SetProperty - uses Get/SetPropValue)
  674.  
  675.   Tag := V.Self;                   // - OK, "V.Self" always returns NativeUInt (unlike simple "V", which can return NativeUInt or String - depending on expression)
  676.  
  677.   OV := V;                            // - OK, TButton implements IInterface (via TComponent); OV = IUnknown
  678.   // OV.Caption := OV.Caption + ' 4'; // - FAIL: TButton does not support IDispatch
  679.  
  680.   // Intf := V;                       // - OK, but returns wrong info, current implementation of custom variants returns inteface to custom variant stub, not to actual data
  681.   Intf := OV;                         // - OK, as expected
  682.  
  683.   V := Intf;                          // - OK; here: V = varUnknown
  684.   // V.Caption := V.Caption + ' 5';   // - FAIL, V/Intf is not IDispatch
  685.   VarCast(V, V, VarObjectType);       // - OK, since TButton implements ObjCastGUID (D2010+), alternative is to implement VarObject.IGetImplement
  686.   V.Caption := V.Caption + ' 6';      // - OK, since V is VarObjectType
  687.  
  688.   V.Click;                            // - OK, works in D2010+ only
  689.  
  690.   // infinite recursion: V.Click -> Button1Click -> V.Click -> Button1Click -> ...
  691. end;
  692. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement