tw17904.pas 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. {$ifdef fpc}{$mode objfpc}{$h+}{$endif}
  2. {$apptype console}
  3. uses Variants, SysUtils;
  4. type
  5. TTest = class(TCustomVariantType)
  6. procedure Clear(var V: TVarData); override;
  7. procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override;
  8. procedure DispInvoke(Dest: PVarData; var Source: TVarData; CallDesc: PCallDesc; Params: Pointer); override;
  9. end;
  10. procedure TTest.Clear(var V: TVarData);
  11. begin
  12. end;
  13. procedure TTest.Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean);
  14. begin
  15. end;
  16. procedure TTest.DispInvoke(Dest: PVarData; var Source: TVarData; CallDesc: PCallDesc; Params: Pointer);
  17. var
  18. tmp: Word;
  19. begin
  20. if (CallDesc^.ArgCount =2) and Assigned(Dest) then
  21. begin
  22. //writeln(HexStr(PPointer(Params)^), ' ', HexStr(PPointer(Params)[1]));
  23. WordRec(tmp).Lo := CallDesc^.ArgTypes[0];
  24. WordRec(tmp).Hi := CallDesc^.ArgTypes[1];
  25. // !! FPC passes args right-to-left, Delphi does same left-to-right
  26. // Moreover, IDispatch needs args right-to-left, and Variant Dispatch needs left-to-right. Nice, huh?
  27. {$ifdef fpc}
  28. tmp := Swap(tmp);
  29. {$endif}
  30. Variant(Dest^) := tmp;
  31. end;
  32. end;
  33. type
  34. TTestClass=class
  35. u8: byte;
  36. u16: word;
  37. u32: longword;
  38. {$ifdef fpc}
  39. u64: qword;
  40. {$endif}
  41. s8: shortint;
  42. s16: smallint;
  43. s32: longint;
  44. s64: int64;
  45. cy: currency;
  46. b: boolean;
  47. bb: bytebool;
  48. wb: wordbool;
  49. lb: longbool;
  50. sgl: single;
  51. dbl: double;
  52. ext: extended;
  53. dt: TDateTime;
  54. fsstr: shortstring;
  55. fastr: ansistring;
  56. fwstr: widestring;
  57. {$ifdef fpc}
  58. fustr: unicodestring;
  59. {$endif}
  60. fvar: Variant;
  61. fintf: IInterface;
  62. fdisp: IDispatch;
  63. property u8prop: Byte read u8;
  64. property u16prop: Word read u16;
  65. property u32prop: LongWord read u32;
  66. {$ifdef fpc}
  67. property u64prop: QWord read u64;
  68. {$endif}
  69. property s8prop: ShortInt read s8;
  70. property s16prop: SmallInt read s16;
  71. property s32prop: LongInt read s32;
  72. property s64prop: Int64 read s64;
  73. property cyprop: currency read cy;
  74. property bprop: boolean read b;
  75. property bbprop: bytebool read bb;
  76. property wbprop: wordbool read wb;
  77. property lbprop: longbool read lb;
  78. property sglprop: single read sgl;
  79. property dblprop: double read dbl;
  80. property extprop: extended read ext;
  81. property dtprop: TDateTime read dt;
  82. property varprop: Variant read fvar;
  83. property intfprop: IInterface read fintf;
  84. property dispprop: IDispatch read fdisp;
  85. property sstr: shortstring read fsstr;
  86. property astr: ansistring read fastr;
  87. property wstr: widestring read fwstr;
  88. {$ifdef fpc}
  89. property ustr: unicodestring read fustr;
  90. {$endif}
  91. end;
  92. var
  93. cv: TCustomVariantType;
  94. code: Integer;
  95. cl: TTestClass;
  96. v: Variant;
  97. // using negative values of Expected to check that arg is passed by-value only
  98. procedure test(const id: string; const act: Variant; expected: Integer);
  99. var
  100. tmp: word;
  101. absexp: Integer;
  102. begin
  103. tmp := act;
  104. absexp := abs(expected);
  105. write(id, WordRec(tmp).Lo,', ', WordRec(tmp).Hi);
  106. if (expected >= 0) and (WordRec(tmp).Lo <> (expected or $80)) then
  107. begin
  108. write(' BYREF failed');
  109. Code := Code or 1;
  110. end;
  111. if WordRec(tmp).Hi <> absexp then
  112. begin
  113. write(' BYVAL failed');
  114. Code := Code or 2;
  115. end;
  116. writeln;
  117. end;
  118. begin
  119. Code := 0;
  120. cv := TTest.Create;
  121. cl := TTestClass.Create;
  122. TVarData(v).vType := cv.VarType;
  123. test('u8: ', v.foo(cl.u8, cl.u8prop), varbyte);
  124. test('u16: ', v.foo(cl.u16, cl.u16prop), varword); // (Uncertain) D7: treated as Integer
  125. test('u32: ', v.foo(cl.u32, cl.u32prop), varlongword); // (Uncertain) D7: treated as Integer ByRef
  126. test('s8: ', v.foo(cl.s8, cl.s8prop), varshortint); // (Uncertain) D7: treated as Integer
  127. test('s16: ', v.foo(cl.s16, cl.s16prop), varsmallint);
  128. test('s32: ', v.foo(cl.s32, cl.s32prop), varinteger);
  129. test('s64: ', v.foo(cl.s64, cl.s64prop), varint64);
  130. {$ifdef fpc}
  131. test('u64: ', v.foo(cl.u64, cl.u64prop), varword64);
  132. {$endif}
  133. test('wordbool:', v.foo(cl.wb, cl.wbprop), varBoolean);
  134. test('curncy: ', v.foo(cl.cy, cl.cyprop), varCurrency);
  135. test('single: ', v.foo(cl.sgl, cl.sglprop), varSingle);
  136. test('double: ', v.foo(cl.dbl, cl.dblprop), varDouble);
  137. test('extended:', v.foo(cl.ext, cl.extprop), -varDouble); // not a COM type, passed by value
  138. test('date: ', v.foo(cl.dt, cl.dtprop), varDate);
  139. test('ansistr: ', v.foo(cl.fastr, cl.astr), varStrArg);
  140. test('widestr: ', v.foo(cl.fwstr, cl.wstr), varOleStr);
  141. {$ifdef fpc}
  142. test('unistr: ', v.foo(cl.fustr, cl.ustr), varUStrArg);
  143. {$endif}
  144. test('variant: ', v.foo(cl.fvar, cl.varprop), varVariant);
  145. test('IUnknown:', v.foo(cl.fintf, cl.intfprop), varUnknown);
  146. test('IDispatch:', v.foo(cl.fdisp, cl.dispprop), varDispatch);
  147. // not an COM type, passed by value; Delphi uses varStrArg
  148. test('shortstr:', v.foo(cl.fsstr, cl.sstr), -varOleStr);
  149. // not an COM type, passed by value
  150. test('longbool:', v.foo(cl.lb, cl.lbprop), -varBoolean);
  151. // typecasted ordinals (only one arg is actually used)
  152. test('u8+cast: ', v.foo(byte(55), byte(55)), -varByte);
  153. test('u16+cast:', v.foo(word(55), word(55)), -varWord);
  154. test('u32+cast:', v.foo(longword(55), longword(55)), -varLongWord);
  155. {$ifdef fpc}
  156. test('u64+cast:', v.foo(qword(55), qword(55)), -varQWord);
  157. {$endif}
  158. test('s8+cast:', v.foo(shortint(55), shortint(55)), -varShortInt);
  159. test('s16+cast:', v.foo(smallint(55), smallint(55)), -varSmallInt);
  160. test('s32+cast:', v.foo(longint(55), longint(55)), -varInteger);
  161. test('s64+cast:', v.foo(int64(55), int64(55)), -varInt64);
  162. cl.Free;
  163. if Code <> 0 then
  164. writeln('Errors: ', Code);
  165. Halt(Code);
  166. end.