123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- {$ifdef fpc}{$mode objfpc}{$h+}{$endif}
- {$apptype console}
- uses Variants, SysUtils;
- type
- TTest = class(TCustomVariantType)
- procedure Clear(var V: TVarData); override;
- procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override;
- procedure DispInvoke(Dest: PVarData; var Source: TVarData; CallDesc: PCallDesc; Params: Pointer); override;
- end;
- procedure TTest.Clear(var V: TVarData);
- begin
- end;
- procedure TTest.Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean);
- begin
- end;
- procedure TTest.DispInvoke(Dest: PVarData; var Source: TVarData; CallDesc: PCallDesc; Params: Pointer);
- var
- tmp: Word;
- begin
- if (CallDesc^.ArgCount =2) and Assigned(Dest) then
- begin
- //writeln(HexStr(PPointer(Params)^), ' ', HexStr(PPointer(Params)[1]));
- WordRec(tmp).Lo := CallDesc^.ArgTypes[0];
- WordRec(tmp).Hi := CallDesc^.ArgTypes[1];
- // !! FPC passes args right-to-left, Delphi does same left-to-right
- // Moreover, IDispatch needs args right-to-left, and Variant Dispatch needs left-to-right. Nice, huh?
- {$ifdef fpc}
- tmp := Swap(tmp);
- {$endif}
- Variant(Dest^) := tmp;
- end;
- end;
- type
- TTestClass=class
- u8: byte;
- u16: word;
- u32: longword;
- {$ifdef fpc}
- u64: qword;
- {$endif}
- s8: shortint;
- s16: smallint;
- s32: longint;
- s64: int64;
- cy: currency;
- b: boolean;
- bb: bytebool;
- wb: wordbool;
- lb: longbool;
- sgl: single;
- dbl: double;
- ext: extended;
- dt: TDateTime;
- fsstr: shortstring;
- fastr: ansistring;
- fwstr: widestring;
- {$ifdef fpc}
- fustr: unicodestring;
- {$endif}
- fvar: Variant;
- fintf: IInterface;
- fdisp: IDispatch;
- property u8prop: Byte read u8;
- property u16prop: Word read u16;
- property u32prop: LongWord read u32;
- {$ifdef fpc}
- property u64prop: QWord read u64;
- {$endif}
- property s8prop: ShortInt read s8;
- property s16prop: SmallInt read s16;
- property s32prop: LongInt read s32;
- property s64prop: Int64 read s64;
- property cyprop: currency read cy;
- property bprop: boolean read b;
- property bbprop: bytebool read bb;
- property wbprop: wordbool read wb;
- property lbprop: longbool read lb;
- property sglprop: single read sgl;
- property dblprop: double read dbl;
- property extprop: extended read ext;
- property dtprop: TDateTime read dt;
- property varprop: Variant read fvar;
- property intfprop: IInterface read fintf;
- property dispprop: IDispatch read fdisp;
- property sstr: shortstring read fsstr;
- property astr: ansistring read fastr;
- property wstr: widestring read fwstr;
- {$ifdef fpc}
- property ustr: unicodestring read fustr;
- {$endif}
- end;
- var
- cv: TCustomVariantType;
- code: Integer;
- cl: TTestClass;
- v: Variant;
- // using negative values of Expected to check that arg is passed by-value only
- procedure test(const id: string; const act: Variant; expected: Integer);
- var
- tmp: word;
- absexp: Integer;
- begin
- tmp := act;
- absexp := abs(expected);
- write(id, WordRec(tmp).Lo,', ', WordRec(tmp).Hi);
- if (expected >= 0) and (WordRec(tmp).Lo <> (expected or $80)) then
- begin
- write(' BYREF failed');
- Code := Code or 1;
- end;
- if WordRec(tmp).Hi <> absexp then
- begin
- write(' BYVAL failed');
- Code := Code or 2;
- end;
- writeln;
- end;
- begin
- Code := 0;
- cv := TTest.Create;
- cl := TTestClass.Create;
- TVarData(v).vType := cv.VarType;
- test('u8: ', v.foo(cl.u8, cl.u8prop), varbyte);
-
- test('u16: ', v.foo(cl.u16, cl.u16prop), varword); // (Uncertain) D7: treated as Integer
- test('u32: ', v.foo(cl.u32, cl.u32prop), varlongword); // (Uncertain) D7: treated as Integer ByRef
- test('s8: ', v.foo(cl.s8, cl.s8prop), varshortint); // (Uncertain) D7: treated as Integer
- test('s16: ', v.foo(cl.s16, cl.s16prop), varsmallint);
- test('s32: ', v.foo(cl.s32, cl.s32prop), varinteger);
- test('s64: ', v.foo(cl.s64, cl.s64prop), varint64);
- {$ifdef fpc}
- test('u64: ', v.foo(cl.u64, cl.u64prop), varword64);
- {$endif}
-
- test('wordbool:', v.foo(cl.wb, cl.wbprop), varBoolean);
- test('curncy: ', v.foo(cl.cy, cl.cyprop), varCurrency);
-
- test('single: ', v.foo(cl.sgl, cl.sglprop), varSingle);
- test('double: ', v.foo(cl.dbl, cl.dblprop), varDouble);
- test('extended:', v.foo(cl.ext, cl.extprop), -varDouble); // not a COM type, passed by value
-
- test('date: ', v.foo(cl.dt, cl.dtprop), varDate);
- test('ansistr: ', v.foo(cl.fastr, cl.astr), varStrArg);
- test('widestr: ', v.foo(cl.fwstr, cl.wstr), varOleStr);
- {$ifdef fpc}
- test('unistr: ', v.foo(cl.fustr, cl.ustr), varUStrArg);
- {$endif}
- test('variant: ', v.foo(cl.fvar, cl.varprop), varVariant);
-
- test('IUnknown:', v.foo(cl.fintf, cl.intfprop), varUnknown);
- test('IDispatch:', v.foo(cl.fdisp, cl.dispprop), varDispatch);
-
- // not an COM type, passed by value; Delphi uses varStrArg
- test('shortstr:', v.foo(cl.fsstr, cl.sstr), -varOleStr);
- // not an COM type, passed by value
- test('longbool:', v.foo(cl.lb, cl.lbprop), -varBoolean);
- // typecasted ordinals (only one arg is actually used)
- test('u8+cast: ', v.foo(byte(55), byte(55)), -varByte);
- test('u16+cast:', v.foo(word(55), word(55)), -varWord);
- test('u32+cast:', v.foo(longword(55), longword(55)), -varLongWord);
- {$ifdef fpc}
- test('u64+cast:', v.foo(qword(55), qword(55)), -varQWord);
- {$endif}
- test('s8+cast:', v.foo(shortint(55), shortint(55)), -varShortInt);
- test('s16+cast:', v.foo(smallint(55), smallint(55)), -varSmallInt);
- test('s32+cast:', v.foo(longint(55), longint(55)), -varInteger);
- test('s64+cast:', v.foo(int64(55), int64(55)), -varInt64);
- cl.Free;
- if Code <> 0 then
- writeln('Errors: ', Code);
- Halt(Code);
- end.
|