typinfo.pp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Florian Klaempfl
  5. member of the Free Pascal development team
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. { This unit provides the same Functionality as the TypInfo Unit }
  13. { of Delphi }
  14. unit typinfo;
  15. interface
  16. {$MODE objfpc}
  17. uses SysUtils;
  18. // temporary types:
  19. type
  20. //{$ifndef HASVARIANT}
  21. Variant = Pointer;
  22. //{$endif}
  23. {$MINENUMSIZE 1 this saves a lot of memory }
  24. // if you change one of the following enumeration types
  25. // you have also to change the compiler in an appropriate way !
  26. TTypeKind = (tkUnknown,tkInteger,tkChar,tkEnumeration,
  27. tkFloat,tkSet,tkMethod,tkSString,tkLString,tkAString,
  28. tkWString,tkVariant,tkArray,tkRecord,tkInterface,
  29. tkClass,tkObject,tkWChar,tkBool,tkInt64,tkQWord,
  30. tkDynArray,tkInterfaceRaw);
  31. TTOrdType = (otSByte,otUByte,otSWord,otUWord,otSLong,otULong);
  32. TFloatType = (ftSingle,ftDouble,ftExtended,ftComp,ftCurr);
  33. TMethodKind = (mkProcedure,mkFunction,mkConstructor,mkDestructor,
  34. mkClassProcedure, mkClassFunction);
  35. TParamFlags = set of (pfVar,pfConst,pfArray,pfAddress,pfReference,pfOut);
  36. TIntfFlags = set of (ifHasGuid,ifDispInterface,ifDispatch);
  37. {$MINENUMSIZE DEFAULT}
  38. const
  39. ptField = 0;
  40. ptStatic = 1;
  41. ptVirtual = 2;
  42. ptConst = 3;
  43. tkString = tkSString;
  44. type
  45. TTypeKinds = set of TTypeKind;
  46. {$PACKRECORDS 1}
  47. TTypeInfo = record
  48. Kind : TTypeKind;
  49. Name : ShortString;
  50. // here the type data follows as TTypeData record
  51. end;
  52. PTypeInfo = ^TTypeInfo;
  53. PPTypeInfo = ^PTypeInfo;
  54. PTypeData = ^TTypeData;
  55. TTypeData = packed record
  56. case TTypeKind of
  57. tkUnKnown,tkLString,tkWString,tkAString,tkVariant:
  58. ();
  59. tkInteger,tkChar,tkEnumeration,tkWChar:
  60. (OrdType : TTOrdType;
  61. case TTypeKind of
  62. tkInteger,tkChar,tkEnumeration,tkBool,tkWChar : (
  63. MinValue,MaxValue : Longint;
  64. case TTypeKind of
  65. tkEnumeration:
  66. (
  67. BaseType : PTypeInfo;
  68. NameList : ShortString)
  69. );
  70. tkSet:
  71. (CompType : PTypeInfo)
  72. );
  73. tkFloat:
  74. (FloatType : TFloatType);
  75. tkSString:
  76. (MaxLength : Byte);
  77. tkClass:
  78. (ClassType : TClass;
  79. ParentInfo : PTypeInfo;
  80. PropCount : SmallInt;
  81. UnitName : ShortString
  82. // here the properties follow as array of TPropInfo
  83. );
  84. tkMethod:
  85. (MethodKind : TMethodKind;
  86. ParamCount : Byte;
  87. ParamList : array[0..1023] of Char
  88. {in reality ParamList is a array[1..ParamCount] of:
  89. record
  90. Flags : TParamFlags;
  91. ParamName : ShortString;
  92. TypeName : ShortString;
  93. end;
  94. followed by
  95. ResultType : ShortString}
  96. );
  97. tkInt64:
  98. (MinInt64Value, MaxInt64Value: Int64);
  99. tkQWord:
  100. (MinQWordValue, MaxQWordValue: QWord);
  101. tkInterface,
  102. tkInterfaceRaw:
  103. (
  104. IntfParent: PPTypeInfo;
  105. IID: PGUID;
  106. IIDStr: ShortString;
  107. IntfUnit: ShortString;
  108. );
  109. end;
  110. // unsed, just for completeness
  111. TPropData = packed record
  112. PropCount : Word;
  113. PropList : record end;
  114. end;
  115. PPropInfo = ^TPropInfo;
  116. TPropInfo = packed record
  117. PropType : PTypeInfo;
  118. GetProc : Pointer;
  119. SetProc : Pointer;
  120. StoredProc : Pointer;
  121. Index : Integer;
  122. Default : Longint;
  123. NameIndex : SmallInt;
  124. // contains the type of the Get/Set/Storedproc, see also ptxxx
  125. // bit 0..1 GetProc
  126. // 2..3 SetProc
  127. // 4..5 StoredProc
  128. // 6 : true, constant index property
  129. PropProcs : Byte;
  130. Name : ShortString;
  131. end;
  132. TProcInfoProc = Procedure(PropInfo : PPropInfo) of object;
  133. PPropList = ^TPropList;
  134. TPropList = array[0..65535] of PPropInfo;
  135. const
  136. tkAny = [Low(TTypeKind)..High(TTypeKind)];
  137. tkMethods = [tkMethod];
  138. tkProperties = tkAny-tkMethods-[tkUnknown];
  139. // general property handling
  140. Function GetTypeData(TypeInfo : PTypeInfo) : PTypeData;
  141. Function GetPropInfo(TypeInfo : PTypeInfo;const PropName : string) : PPropInfo;
  142. Function GetPropInfo(TypeInfo : PTypeInfo;const PropName : string; AKinds : TTypeKinds) : PPropInfo;
  143. Function GetPropInfo(Instance: TObject; const PropName: string; AKinds: TTypeKinds) : PPropInfo;
  144. Function GetPropInfo(Instance: TObject; const PropName: string): PPropInfo;
  145. Function GetPropInfo(AClass: TClass; const PropName: string; AKinds: TTypeKinds) : PPropInfo;
  146. Function GetPropInfo(AClass: TClass; const PropName: string): PPropInfo;
  147. Function FindPropInfo(Instance: TObject; const PropName: string): PPropInfo;
  148. Function FindPropInfo(AClass:TClass;const PropName: string): PPropInfo;
  149. Procedure GetPropInfos(TypeInfo : PTypeInfo;PropList : PPropList);
  150. Function GetPropList(TypeInfo : PTypeInfo;TypeKinds : TTypeKinds; PropList : PPropList) : Integer;
  151. // Property information routines.
  152. Function IsStoredProp(Instance: TObject;PropInfo : PPropInfo) : Boolean;
  153. Function IsStoredProp(Instance: TObject; const PropName: string): Boolean;
  154. Function IsPublishedProp(Instance: TObject; const PropName: string): Boolean;
  155. Function IsPublishedProp(AClass: TClass; const PropName: string): Boolean;
  156. Function PropType(Instance: TObject; const PropName: string): TTypeKind;
  157. Function PropType(AClass: TClass; const PropName: string): TTypeKind;
  158. Function PropIsType(Instance: TObject; const PropName: string; TypeKind: TTypeKind): Boolean;
  159. Function PropIsType(AClass: TClass; const PropName: string; TypeKind: TTypeKind): Boolean;
  160. // subroutines to read/write properties
  161. Function GetOrdProp(Instance: TObject; PropInfo : PPropInfo) : Longint;
  162. Function GetOrdProp(Instance: TObject; const PropName: string): Longint;
  163. Procedure SetOrdProp(Instance: TObject; PropInfo : PPropInfo; Value : Longint);
  164. Procedure SetOrdProp(Instance: TObject; const PropName: string; Value: Longint);
  165. Function GetEnumProp(Instance: TObject; const PropName: string): string;
  166. Function GetEnumProp(Instance: TObject; const PropInfo: PPropInfo): string;
  167. Procedure SetEnumProp(Instance: TObject; const PropName: string;const Value: string);
  168. Procedure SetEnumProp(Instance: TObject; const PropInfo: PPropInfo;const Value: string);
  169. Function GetSetProp(Instance: TObject; const PropName: string): string;
  170. Function GetSetProp(Instance: TObject; const PropName: string; Brackets: Boolean): string;
  171. Function GetSetProp(Instance: TObject; const PropInfo: PPropInfo; Brackets: Boolean): string;
  172. Procedure SetSetProp(Instance: TObject; const PropName: string; const Value: string);
  173. Procedure SetSetProp(Instance: TObject; const PropInfo: PPropInfo; const Value: string);
  174. Function GetStrProp(Instance: TObject; PropInfo : PPropInfo) : Ansistring;
  175. Function GetStrProp(Instance: TObject; const PropName: string): string;
  176. Procedure SetStrProp(Instance: TObject; const PropName: string; const Value: AnsiString);
  177. Procedure SetStrProp(Instance: TObject; PropInfo : PPropInfo; const Value : Ansistring);
  178. Function GetFloatProp(Instance: TObject; PropInfo : PPropInfo) : Extended;
  179. Function GetFloatProp(Instance: TObject; const PropName: string): Extended;
  180. Procedure SetFloatProp(Instance: TObject; const PropName: string; Value: Extended);
  181. Procedure SetFloatProp(Instance: TObject; PropInfo : PPropInfo; Value : Extended);
  182. Function GetVariantProp(Instance: TObject; PropInfo : PPropInfo): Variant;
  183. Function GetVariantProp(Instance: TObject; const PropName: string): Variant;
  184. Procedure SetVariantProp(Instance: TObject; const PropName: string; const Value: Variant);
  185. Procedure SetVariantProp(Instance: TObject; PropInfo : PPropInfo; const Value: Variant);
  186. Function GetObjectProp(Instance: TObject; const PropName: string): TObject;
  187. Function GetObjectProp(Instance: TObject; const PropName: string; MinClass: TClass): TObject;
  188. Function GetObjectProp(Instance: TObject; PropInfo: PPropInfo; MinClass: TClass): TObject;
  189. Procedure SetObjectProp(Instance: TObject; const PropName: string; Value: TObject);
  190. Procedure SetObjectProp(Instance: TObject; PropInfo: PPropInfo; Value: TObject);
  191. Function GetObjectPropClass(Instance: TObject; const PropName: string): TClass;
  192. Function GetMethodProp(Instance: TObject; PropInfo: PPropInfo) : TMethod;
  193. Function GetMethodProp(Instance: TObject; const PropName: string): TMethod;
  194. Procedure SetMethodProp(Instance: TObject; PropInfo: PPropInfo; const Value : TMethod);
  195. Procedure SetMethodProp(Instance: TObject; const PropName: string; const Value: TMethod);
  196. Function GetInt64Prop(Instance: TObject; PropInfo: PPropInfo): Int64;
  197. Function GetInt64Prop(Instance: TObject; const PropName: string): Int64;
  198. Procedure SetInt64Prop(Instance: TObject; PropInfo: PPropInfo; const Value: Int64);
  199. Procedure SetInt64Prop(Instance: TObject; const PropName: string; const Value: Int64);
  200. Function GetPropValue(Instance: TObject; const PropName: string): Variant;
  201. Function GetPropValue(Instance: TObject; const PropName: string; PreferStrings: Boolean): Variant;
  202. Procedure SetPropValue(Instance: TObject; const PropName: string; const Value: Variant);
  203. // Auxiliary routines, which may be useful
  204. Function GetEnumName(TypeInfo : PTypeInfo;Value : Integer) : string;
  205. Function GetEnumValue(TypeInfo : PTypeInfo;const Name : string) : Integer;
  206. function SetToString(PropInfo: PPropInfo; Value: Integer; Brackets: Boolean) : String;
  207. function SetToString(PropInfo: PPropInfo; Value: Integer) : String;
  208. function StringToSet(PropInfo: PPropInfo; const Value: string): Integer;
  209. const
  210. BooleanIdents: array[Boolean] of String = ('False', 'True');
  211. DotSep: String = '.';
  212. Type
  213. EPropertyError = Class(Exception);
  214. Implementation
  215. ResourceString
  216. SErrPropertyNotFound = 'Unknown property: "%s"';
  217. SErrUnknownEnumValue = 'Unknown enumeration value: "%s"';
  218. type
  219. PMethod = ^TMethod;
  220. { ---------------------------------------------------------------------
  221. Auxiliary methods
  222. ---------------------------------------------------------------------}
  223. Function GetEnumName(TypeInfo : PTypeInfo;Value : Integer) : string;
  224. Var PS : PShortString;
  225. PT : PTypeData;
  226. begin
  227. PT:=GetTypeData(TypeInfo);
  228. // ^.BaseType);
  229. // If PT^.MinValue<0 then Value:=Ord(Value<>0); {map to 0/1}
  230. PS:=@PT^.NameList;
  231. While Value>0 Do
  232. begin
  233. PS:=PShortString(pointer(PS)+PByte(PS)^+1);
  234. Dec(Value);
  235. end;
  236. Result:=PS^;
  237. end;
  238. Function GetEnumValue(TypeInfo : PTypeInfo;const Name : string) : Integer;
  239. Var PS : PShortString;
  240. PT : PTypeData;
  241. Count : longint;
  242. begin
  243. If Length(Name)=0 then exit(-1);
  244. PT:=GetTypeData(TypeInfo);
  245. Count:=0;
  246. Result:=-1;
  247. PS:=@PT^.NameList;
  248. While (Result=-1) and (PByte(PS)^<>0) do
  249. begin
  250. If CompareText(PS^, Name) = 0 then
  251. Result:=Count;
  252. PS:=PShortString(pointer(PS)+PByte(PS)^+1);
  253. Inc(Count);
  254. end;
  255. end;
  256. Function SetToString(PropInfo: PPropInfo; Value: Integer; Brackets: Boolean) : String;
  257. Var
  258. I : Integer;
  259. PTI : PTypeInfo;
  260. begin
  261. PTI:=GetTypeData(PropInfo^.PropType)^.CompType;
  262. Result:='';
  263. For I:=0 to SizeOf(Integer)*8-1 do
  264. begin
  265. if ((Value and 1)<>0) then
  266. begin
  267. If Result='' then
  268. Result:=GetEnumName(PTI,i)
  269. else
  270. Result:=Result+','+GetEnumName(PTI,I);
  271. end;
  272. Value:=Value shr 1;
  273. end;
  274. if Brackets then
  275. Result:='['+Result+']';
  276. end;
  277. Function SetToString(PropInfo: PPropInfo; Value: Integer) : String;
  278. begin
  279. Result:=SetToString(PropInfo,Value,False);
  280. end;
  281. Const
  282. SetDelim = ['[',']',',',' '];
  283. Function GetNextElement(Var S : String) : String;
  284. Var
  285. J : Integer;
  286. begin
  287. J:=1;
  288. Result:='';
  289. If Length(S)>0 then
  290. begin
  291. While (J<=Length(S)) and Not (S[j] in SetDelim) do
  292. Inc(j);
  293. Result:=Copy(S,1,j-1);
  294. Delete(S,1,j);
  295. end;
  296. end;
  297. Function StringToSet(PropInfo: PPropInfo; const Value: string): Integer;
  298. Var
  299. S,T : String;
  300. I : Integer;
  301. PTI : PTypeInfo;
  302. begin
  303. Result:=0;
  304. PTI:=GetTypeData(PropInfo^.PropType)^.Comptype;
  305. S:=Value;
  306. I:=1;
  307. If Length(S)>0 then
  308. begin
  309. While (I<=Length(S)) and (S[i] in SetDelim) do
  310. Inc(I);
  311. Delete(S,1,i-1);
  312. end;
  313. While (S<>'') do
  314. begin
  315. T:=GetNextElement(S);
  316. if T<>'' then
  317. begin
  318. I:=GetEnumValue(PTI,T);
  319. if (I<0) then
  320. raise EPropertyError.CreateFmt(SErrUnknownEnumValue, [T]);
  321. Result:=Result or (1 shl i);
  322. end;
  323. end;
  324. end;
  325. Function GetTypeData(TypeInfo : PTypeInfo) : PTypeData;
  326. begin
  327. GetTypeData:=PTypeData(pointer(TypeInfo)+2+PByte(pointer(TypeInfo)+1)^);
  328. end;
  329. { ---------------------------------------------------------------------
  330. Low-level calling of methods.
  331. ---------------------------------------------------------------------}
  332. {$I typinfo.inc}
  333. { ---------------------------------------------------------------------
  334. Basic Type information functions.
  335. ---------------------------------------------------------------------}
  336. Function GetPropInfo(TypeInfo : PTypeInfo;const PropName : string) : PPropInfo;
  337. var
  338. hp : PTypeData;
  339. i : longint;
  340. p : string;
  341. begin
  342. P:=UpCase(PropName);
  343. while Assigned(TypeInfo) do
  344. begin
  345. // skip the name
  346. hp:=GetTypeData(Typeinfo);
  347. // the class info rtti the property rtti follows immediatly
  348. Result:=PPropInfo(pointer(@hp^.UnitName)+Length(hp^.UnitName)+1+SizeOF(Word));
  349. for i:=1 to hp^.PropCount do
  350. begin
  351. // found a property of that name ?
  352. if Upcase(Result^.Name)=P then
  353. exit;
  354. // skip to next property
  355. Result:=PPropInfo(pointer(@Result^.Name)+byte(Result^.Name[0])+1);
  356. end;
  357. // parent class
  358. Typeinfo:=hp^.ParentInfo;
  359. end;
  360. Result:=Nil;
  361. end;
  362. Function GetPropInfo(TypeInfo : PTypeInfo;const PropName : string; Akinds : TTypeKinds) : PPropInfo;
  363. begin
  364. Result:=GetPropInfo(TypeInfo,PropName);
  365. If (Akinds<>[]) then
  366. If (Result<>Nil) then
  367. If Not (Result^.PropType^.Kind in AKinds) then
  368. Result:=Nil;
  369. end;
  370. Function GetPropInfo(AClass: TClass; const PropName: string; AKinds: TTypeKinds) : PPropInfo;
  371. begin
  372. Result:=GetPropInfo(PTypeInfo(AClass.ClassInfo),PropName,AKinds);
  373. end;
  374. Function GetPropInfo(Instance: TObject; const PropName: string; AKinds: TTypeKinds) : PPropInfo;
  375. begin
  376. Result:=GetPropInfo(Instance.ClassType,PropName,AKinds);
  377. end;
  378. Function GetPropInfo(Instance: TObject; const PropName: string): PPropInfo;
  379. begin
  380. Result:=GetPropInfo(Instance,PropName,[]);
  381. end;
  382. Function GetPropInfo(AClass: TClass; const PropName: string): PPropInfo;
  383. begin
  384. Result:=GetPropInfo(AClass,PropName,[]);
  385. end;
  386. Function FindPropInfo(Instance: TObject; const PropName: string): PPropInfo;
  387. begin
  388. result:=GetPropInfo(Instance, PropName);
  389. if Result=nil then
  390. Raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]);
  391. end;
  392. Function FindPropInfo(AClass:TClass;const PropName: string): PPropInfo;
  393. begin
  394. result:=GetPropInfo(AClass,PropName);
  395. if result=nil then
  396. Raise EPropertyError.CreateFmt(SErrPropertyNotFound, [PropName]);
  397. end;
  398. Function IsStoredProp(Instance : TObject;PropInfo : PPropInfo) : Boolean;
  399. begin
  400. case (PropInfo^.PropProcs shr 4) and 3 of
  401. ptfield:
  402. IsStoredProp:=PBoolean(Pointer(Instance)+Longint(PropInfo^.StoredProc))^;
  403. ptstatic:
  404. IsStoredProp:=CallBooleanFunc(Instance,PropInfo^.StoredProc,0,0);
  405. ptvirtual:
  406. IsStoredProp:=CallBooleanFunc(Instance,ppointer(Pointer(Instance.ClassType)+Longint(PropInfo^.StoredProc))^,0,0);
  407. ptconst:
  408. IsStoredProp:=LongBool(PropInfo^.StoredProc);
  409. end;
  410. end;
  411. Procedure GetPropInfos(TypeInfo : PTypeInfo;PropList : PPropList);
  412. {
  413. Store Pointers to property information in the list pointed
  414. to by proplist. PRopList must contain enough space to hold ALL
  415. properties.
  416. }
  417. Type PWord = ^Word;
  418. Var TD : PTypeData;
  419. TP : PPropInfo;
  420. Count : Longint;
  421. begin
  422. TD:=GetTypeData(TypeInfo);
  423. // Get this objects TOTAL published properties count
  424. TP:=(@TD^.UnitName+Length(TD^.UnitName)+1);
  425. Count:=PWord(TP)^;
  426. // Now point TP to first propinfo record.
  427. Inc(Longint(TP),SizeOF(Word));
  428. While Count>0 do
  429. begin
  430. PropList^[0]:=TP;
  431. Inc(Longint(PropList),SizeOf(Pointer));
  432. // Point to TP next propinfo record.
  433. // Located at Name[Length(Name)+1] !
  434. TP:=PPropInfo(pointer(@TP^.Name)+PByte(@TP^.Name)^+1);
  435. Dec(Count);
  436. end;
  437. // recursive call for parent info.
  438. If TD^.Parentinfo<>Nil then
  439. GetPropInfos (TD^.ParentInfo,PropList);
  440. end;
  441. Procedure InsertProp (PL : PProplist;PI : PPropInfo; Count : longint);
  442. Var I : Longint;
  443. begin
  444. I:=0;
  445. While (I<Count) and (PI^.Name>PL^[I]^.Name) do Inc(I);
  446. If I<Count then
  447. Move(PL^[I], PL^[I+1], (Count - I) * SizeOf(Pointer));
  448. PL^[I]:=PI;
  449. end;
  450. Function GetPropList(TypeInfo : PTypeInfo;TypeKinds : TTypeKinds;
  451. PropList : PPropList) : Integer;
  452. {
  453. Store Pointers to property information OF A CERTAIN KIND in the list pointed
  454. to by proplist. PRopList must contain enough space to hold ALL
  455. properties.
  456. }
  457. Var TempList : PPropList;
  458. PropInfo : PPropinfo;
  459. I,Count : longint;
  460. begin
  461. Result:=0;
  462. Count:=GetTypeData(TypeInfo)^.Propcount;
  463. If Count>0 then
  464. begin
  465. GetMem(TempList,Count*SizeOf(Pointer));
  466. Try
  467. GetPropInfos(TypeInfo,TempList);
  468. For I:=0 to Count-1 do
  469. begin
  470. PropInfo:=TempList^[i];
  471. If PropInfo^.PropType^.Kind in TypeKinds then
  472. begin
  473. InsertProp(PropList,PropInfo,Result);
  474. Inc(Result);
  475. end;
  476. end;
  477. finally
  478. FreeMem(TempList,Count*SizeOf(Pointer));
  479. end;
  480. end;
  481. end;
  482. Procedure SetIndexValues (P: PPRopInfo; Var Index,IValue : Longint);
  483. begin
  484. Index:=((P^.PropProcs shr 6) and 1);
  485. If Index<>0 then
  486. IValue:=P^.Index
  487. else
  488. IValue:=0;
  489. end;
  490. { ---------------------------------------------------------------------
  491. Property access functions
  492. ---------------------------------------------------------------------}
  493. { ---------------------------------------------------------------------
  494. Ordinal properties
  495. ---------------------------------------------------------------------}
  496. Function GetOrdProp(Instance : TObject;PropInfo : PPropInfo) : Longint;
  497. var
  498. value,Index,Ivalue : longint;
  499. TypeInfo: PTypeInfo;
  500. begin
  501. SetIndexValues(PropInfo,Index,Ivalue);
  502. case (PropInfo^.PropProcs) and 3 of
  503. ptfield:
  504. Value:=PLongint(Pointer(Instance)+Longint(PropInfo^.GetProc))^;
  505. ptstatic:
  506. Value:=CallIntegerFunc(Instance,PropInfo^.GetProc,Index,IValue);
  507. ptvirtual:
  508. Value:=CallIntegerFunc(Instance,PPointer(Pointer(Instance.ClassType)+Longint(PropInfo^.GetProc))^,Index,IValue);
  509. end;
  510. { cut off unnecessary stuff }
  511. TypeInfo := PropInfo^.PropType;
  512. case TypeInfo^.Kind of
  513. tkChar, tkBool:
  514. Value:=Value and $ff;
  515. tkWChar:
  516. Value:=Value and $ffff;
  517. tkInteger:
  518. case GetTypeData(TypeInfo)^.OrdType of
  519. otSWord,otUWord:
  520. Value:=Value and $ffff;
  521. otSByte,otUByte:
  522. Value:=Value and $ff;
  523. end;
  524. end;
  525. GetOrdProp:=Value;
  526. end;
  527. Procedure SetOrdProp(Instance : TObject;PropInfo : PPropInfo;
  528. Value : Longint);
  529. var
  530. Index,IValue : Longint;
  531. DataSize: Integer;
  532. begin
  533. if PropInfo^.PropType^.Kind <> tkClass then
  534. { cut off unnecessary stuff }
  535. case GetTypeData(PropInfo^.PropType)^.OrdType of
  536. otSWord,otUWord:
  537. begin
  538. Value:=Value and $ffff;
  539. DataSize := 2;
  540. end;
  541. otSByte,otUByte:
  542. begin
  543. Value:=Value and $ff;
  544. DataSize := 1;
  545. end;
  546. else
  547. DataSize := 4;
  548. end
  549. else
  550. DataSize := 4;
  551. SetIndexValues(PropInfo,Index,Ivalue);
  552. case (PropInfo^.PropProcs shr 2) and 3 of
  553. ptfield:
  554. case DataSize of
  555. 1: PByte(Pointer(Instance)+Longint(PropInfo^.SetProc))^:=Byte(Value);
  556. 2: PWord(Pointer(Instance)+Longint(PropInfo^.SetProc))^:=Word(Value);
  557. 4: PLongint(Pointer(Instance)+Longint(PropInfo^.SetProc))^:=Value;
  558. end;
  559. ptstatic:
  560. CallIntegerProc(Instance,PropInfo^.SetProc,Value,Index,IValue);
  561. ptvirtual:
  562. CallIntegerProc(Instance,PPointer(Pointer(Instance.ClassType)+Longint(PropInfo^.SetProc))^,Value,Index,IValue);
  563. end;
  564. end;
  565. Function GetOrdProp(Instance: TObject; const PropName: string): Longint;
  566. begin
  567. Result:=GetOrdProp(Instance,FindPropInfo(Instance,PropName));
  568. end;
  569. Procedure SetOrdProp(Instance: TObject; const PropName: string; Value: Longint);
  570. begin
  571. SetOrdProp(Instance,FindPropInfo(Instance,PropName),Value);
  572. end;
  573. Function GetEnumProp(Instance: TObject; Const PropInfo: PPropInfo): string;
  574. begin
  575. Result:=GetEnumName(PropInfo^.PropType, GetOrdProp(Instance, PropInfo));
  576. end;
  577. Function GetEnumProp(Instance: TObject; const PropName: string): string;
  578. begin
  579. Result:=GetEnumProp(Instance,FindPropInfo(Instance,PropName));
  580. end;
  581. Procedure SetEnumProp(Instance: TObject; const PropName: string; const Value: string);
  582. begin
  583. SetEnumProp(Instance,FindPropInfo(Instance,PropName),Value);
  584. end;
  585. Procedure SetEnumProp(Instance: TObject; Const PropInfo : PPropInfo; const Value: string);
  586. Var
  587. PV : Longint;
  588. begin
  589. If PropInfo<>Nil then
  590. begin
  591. PV:=GetEnumValue(PropInfo^.PropType, Value);
  592. if (PV<0) then
  593. raise EPropertyError.CreateFmt(SErrUnknownEnumValue, [Value]);
  594. SetOrdProp(Instance, PropInfo,PV);
  595. end;
  596. end;
  597. { ---------------------------------------------------------------------
  598. Set properties
  599. ---------------------------------------------------------------------}
  600. Function GetSetProp(Instance: TObject; const PropName: string): string;
  601. begin
  602. Result:=GetSetProp(Instance,PropName,False);
  603. end;
  604. Function GetSetProp(Instance: TObject; const PropName: string; Brackets: Boolean): string;
  605. begin
  606. Result:=GetSetProp(Instance,FindPropInfo(Instance,PropName),Brackets);
  607. end;
  608. Function GetSetProp(Instance: TObject; const PropInfo: PPropInfo; Brackets: Boolean): string;
  609. begin
  610. Result:=SetToString(PropInfo,GetOrdProp(Instance,PropInfo),Brackets);
  611. end;
  612. Procedure SetSetProp(Instance: TObject; const PropName: string; const Value: string);
  613. begin
  614. SetSetProp(Instance,FindPropInfo(Instance,PropName),Value);
  615. end;
  616. Procedure SetSetProp(Instance: TObject; const PropInfo: PPropInfo; const Value: string);
  617. begin
  618. SetOrdProp(Instance,PropInfo,StringToSet(PropInfo,Value));
  619. end;
  620. { ---------------------------------------------------------------------
  621. Object properties
  622. ---------------------------------------------------------------------}
  623. Function GetObjectProp(Instance: TObject; const PropName: string): TObject;
  624. begin
  625. Result:=GetObjectProp(Instance,PropName,Nil);
  626. end;
  627. Function GetObjectProp(Instance: TObject; const PropName: string; MinClass: TClass): TObject;
  628. begin
  629. Result:=GetObjectProp(Instance,FindPropInfo(Instance,PropName),MinClass);
  630. end;
  631. Function GetObjectProp(Instance: TObject; PropInfo : PPropInfo; MinClass: TClass): TObject;
  632. begin
  633. Result:=TObject(GetOrdProp(Instance,PropInfo));
  634. If (MinClass<>Nil) and (Result<>Nil) Then
  635. If Not Result.InheritsFrom(MinClass) then
  636. Result:=Nil;
  637. end;
  638. Procedure SetObjectProp(Instance: TObject; const PropName: string; Value: TObject);
  639. begin
  640. SetObjectProp(Instance,FindPropInfo(Instance,PropName),Value);
  641. end;
  642. Procedure SetObjectProp(Instance: TObject; PropInfo : PPropInfo; Value: TObject);
  643. begin
  644. SetOrdProp(Instance,PropInfo,Integer(Value));
  645. end;
  646. Function GetObjectPropClass(Instance: TObject; const PropName: string): TClass;
  647. begin
  648. Result:=GetTypeData(FindPropInfo(Instance,PropName)^.PropType)^.ClassType;
  649. end;
  650. { ---------------------------------------------------------------------
  651. String properties
  652. ---------------------------------------------------------------------}
  653. Function GetStrProp(Instance: TObject; PropInfo: PPropInfo): AnsiString;
  654. var
  655. Index, IValue: LongInt;
  656. ShortResult: ShortString;
  657. begin
  658. SetIndexValues(PropInfo, Index, IValue);
  659. case Propinfo^.PropType^.Kind of
  660. tkSString:
  661. case (PropInfo^.PropProcs) and 3 of
  662. ptField:
  663. Result := PShortString(Pointer(Instance) + LongWord(PropInfo^.GetProc))^;
  664. ptStatic:
  665. begin
  666. CallSStringFunc(Instance, PropInfo^.GetProc, Index, IValue, ShortResult);
  667. Result := ShortResult;
  668. end;
  669. ptVirtual:
  670. begin
  671. CallSStringFunc(Instance, PPointer(Pointer(Instance.ClassType) +
  672. LongWord(PropInfo^.GetProc))^, Index, IValue, ShortResult);
  673. Result := ShortResult;
  674. end;
  675. end;
  676. tkAString:
  677. case (PropInfo^.PropProcs) and 3 of
  678. ptField:
  679. Result := PAnsiString(Pointer(Instance) + LongWord(PropInfo^.GetProc))^;
  680. ptStatic:
  681. Pointer(Result) := Pointer(LongWord(CallIntegerFunc(Instance, PropInfo^.GetProc, Index, IValue)));
  682. ptVirtual:
  683. Pointer(Result) := Pointer(LongWord(CallIntegerFunc(Instance,
  684. PPointer(Pointer(Instance.ClassType) + LongWord(PropInfo^.GetProc))^, Index, IValue)));
  685. end;
  686. else
  687. // Property is neither of type AnsiString nor of type ShortString
  688. SetLength(Result, 0);
  689. end;
  690. end;
  691. Procedure SetAStrProp(Instance : TObject;PropInfo : PPropInfo;
  692. const Value : AnsiString);
  693. {
  694. Dirty trick based on fact that AnsiString is just a pointer,
  695. hence can be treated like an integer type.
  696. }
  697. var
  698. Index,Ivalue : Longint;
  699. begin
  700. SetIndexValues(PropInfo,Index,IValue);
  701. case (PropInfo^.PropProcs shr 2) and 3 of
  702. ptfield:
  703. PAnsiString(Pointer(Instance) + Longint(PropInfo^.SetProc))^ := Value;
  704. ptstatic:
  705. CallIntegerProc(Instance,PropInfo^.SetProc,Longint(Pointer(Value)),Index,IValue);
  706. ptvirtual:
  707. CallIntegerProc(Instance,PPointer(Pointer(Instance.ClassType)+Longint(PropInfo^.SetProc))^,Longint(Pointer(Value)),Index,IValue);
  708. end;
  709. end;
  710. Procedure SetSStrProp(Instance : TObject;PropInfo : PPropInfo;
  711. const Value : ShortString);
  712. Var Index,IValue: longint;
  713. begin
  714. SetIndexValues(PRopInfo,Index,IValue);
  715. case (PropInfo^.PropProcs shr 2) and 3 of
  716. ptfield:
  717. PShortString(Pointer(Instance)+Longint(PropInfo^.SetProc))^:=Value;
  718. ptstatic:
  719. CallSStringProc(Instance,PropInfo^.SetProc,Value,Index,IValue);
  720. ptvirtual:
  721. CallSStringProc(Instance,PPointer(Pointer(Instance.ClassType)+Longint(PropInfo^.SetProc))^,Value,Index,IValue);
  722. end;
  723. end;
  724. Procedure SetStrProp(Instance : TObject;PropInfo : PPropInfo;
  725. const Value : AnsiString);
  726. begin
  727. Case Propinfo^.PropType^.Kind of
  728. tkSString : SetSStrProp(Instance,PropInfo,Value);
  729. tkAString : SetAStrProp(Instance,Propinfo,Value);
  730. end;
  731. end;
  732. Function GetStrProp(Instance: TObject; const PropName: string): string;
  733. begin
  734. Result:=GetStrProp(Instance,FindPropInfo(Instance,PropName));
  735. end;
  736. Procedure SetStrProp(Instance: TObject; const PropName: string; const Value: AnsiString);
  737. begin
  738. SetStrProp(Instance,FindPropInfo(Instance,PropName),Value);
  739. end;
  740. { ---------------------------------------------------------------------
  741. Float properties
  742. ---------------------------------------------------------------------}
  743. Function GetFloatProp(Instance : TObject;PropInfo : PPropInfo) : Extended;
  744. var
  745. Index,Ivalue : longint;
  746. Value : Extended;
  747. begin
  748. SetIndexValues(PropInfo,Index,Ivalue);
  749. case (PropInfo^.PropProcs) and 3 of
  750. ptfield:
  751. Case GetTypeData(PropInfo^.PropType)^.FloatType of
  752. ftSingle:
  753. Value:=PSingle(Pointer(Instance)+Longint(PropInfo^.GetProc))^;
  754. ftDouble:
  755. Value:=PDouble(Pointer(Instance)+Longint(PropInfo^.GetProc))^;
  756. ftExtended:
  757. Value:=PExtended(Pointer(Instance)+Longint(PropInfo^.GetProc))^;
  758. {$ifndef m68k}
  759. ftcomp:
  760. Value:=PComp(Pointer(Instance)+Longint(PropInfo^.GetProc))^;
  761. {$endif m68k}
  762. end;
  763. ptstatic:
  764. Value:=CallExtendedFunc(Instance,PropInfo^.GetProc,Index,IValue);
  765. ptvirtual:
  766. Value:=CallExtendedFunc(Instance,PPointer(Pointer(Instance.ClassType)+Longint(PropInfo^.GetProc))^,Index,IValue);
  767. end;
  768. Result:=Value;
  769. end;
  770. Procedure SetFloatProp(Instance : TObject;PropInfo : PPropInfo;
  771. Value : Extended);
  772. Var IValue,Index : longint;
  773. begin
  774. SetIndexValues(PropInfo,Index,Ivalue);
  775. case (PropInfo^.PropProcs shr 2) and 3 of
  776. ptfield:
  777. Case GetTypeData(PropInfo^.PropType)^.FloatType of
  778. ftSingle:
  779. PSingle(Pointer(Instance)+Longint(PropInfo^.SetProc))^:=Value;
  780. ftDouble:
  781. PDouble(Pointer(Instance)+Longint(PropInfo^.SetProc))^:=Value;
  782. ftExtended:
  783. PExtended(Pointer(Instance)+Longint(PropInfo^.SetProc))^:=Value;
  784. {$ifndef m68k}
  785. ftcomp:
  786. PComp(Pointer(Instance)+Longint(PropInfo^.SetProc))^:=Comp(Value);
  787. {$endif m68k}
  788. end;
  789. ptstatic:
  790. CallExtendedProc(Instance,PropInfo^.SetProc,Value,Index,IValue);
  791. ptvirtual:
  792. CallExtendedProc(Instance,PPointer(Pointer(Instance.ClassType)+Longint(PropInfo^.SetProc))^,Value,Index,IValue);
  793. end;
  794. end;
  795. Function GetFloatProp(Instance: TObject; const PropName: string): Extended;
  796. begin
  797. Result:=GetFloatProp(Instance,FindPropInfo(Instance,PropName))
  798. end;
  799. Procedure SetFloatProp(Instance: TObject; const PropName: string; Value: Extended);
  800. begin
  801. SetFloatProp(Instance,FindPropInfo(Instance,PropName),Value);
  802. end;
  803. { ---------------------------------------------------------------------
  804. Variant properties
  805. ---------------------------------------------------------------------}
  806. Function GetVariantProp(Instance : TObject;PropInfo : PPropInfo): Variant;
  807. begin
  808. {!!!!!!!!!!!}
  809. Result:=nil;
  810. end;
  811. Procedure SetVariantProp(Instance : TObject;PropInfo : PPropInfo;
  812. const Value: Variant);
  813. begin
  814. {!!!!!!!!!!!}
  815. end;
  816. Function GetVariantProp(Instance: TObject; const PropName: string): Variant;
  817. begin
  818. Result:=GetVariantProp(Instance,FindPropInfo(Instance,PropName));
  819. end;
  820. Procedure SetVariantProp(Instance: TObject; const PropName: string; const Value: Variant);
  821. begin
  822. SetVariantprop(instance,FindpropInfo(Instance,PropName),Value);
  823. end;
  824. { ---------------------------------------------------------------------
  825. Method properties
  826. ---------------------------------------------------------------------}
  827. Function GetMethodProp(Instance : TObject;PropInfo : PPropInfo) : TMethod;
  828. var
  829. value: PMethod;
  830. Index,Ivalue : longint;
  831. begin
  832. SetIndexValues(PropInfo,Index,Ivalue);
  833. case (PropInfo^.PropProcs) and 3 of
  834. ptfield:
  835. Value:=PMethod(Pointer(Instance)+Longint(PropInfo^.GetProc));
  836. ptstatic:
  837. Value:=PMethod(LongInt(CallIntegerFunc(Instance,PropInfo^.GetProc,Index,IValue)));
  838. ptvirtual:
  839. Value:=PMethod(LongInt(CallIntegerFunc(Instance,PPointer(Pointer(Instance.ClassType)+Longint(PropInfo^.GetProc))^,Index,IValue)));
  840. end;
  841. GetMethodProp:=Value^;
  842. end;
  843. Procedure SetMethodProp(Instance : TObject;PropInfo : PPropInfo;
  844. const Value : TMethod);
  845. var
  846. Index,IValue : Longint;
  847. begin
  848. SetIndexValues(PropInfo,Index,Ivalue);
  849. case (PropInfo^.PropProcs shr 2) and 3 of
  850. ptfield:
  851. PMethod(Pointer(Instance)+Longint(PropInfo^.SetProc))^ := Value;
  852. ptstatic:
  853. CallIntegerProc(Instance,PropInfo^.SetProc,Integer(@Value), Index, IValue);
  854. ptvirtual:
  855. CallIntegerProc(Instance,
  856. PPointer(Pointer(Instance.ClassType)+Longint(PropInfo^.SetProc))^,
  857. Integer(@Value), Index, IValue);
  858. end;
  859. end;
  860. Function GetMethodProp(Instance: TObject; const PropName: string): TMethod;
  861. begin
  862. Result:=GetMethodProp(Instance,FindPropInfo(Instance,PropName));
  863. end;
  864. Procedure SetMethodProp(Instance: TObject; const PropName: string; const Value: TMethod);
  865. begin
  866. SetMethodProp(Instance,FindPropInfo(Instance,PropName),Value);
  867. end;
  868. { ---------------------------------------------------------------------
  869. Int64 properties
  870. ---------------------------------------------------------------------}
  871. Function GetInt64Prop(Instance: TObject; PropInfo: PPropInfo): Int64;
  872. var
  873. Index, IValue: LongInt;
  874. begin
  875. SetIndexValues(PropInfo,Index,Ivalue);
  876. case PropInfo^.PropProcs and 3 of
  877. ptfield:
  878. Result := PInt64(Pointer(Instance)+Longint(PropInfo^.GetProc))^;
  879. ptstatic:
  880. Result := CallIntegerFunc(Instance, PropInfo^.GetProc, Index, IValue);
  881. ptvirtual:
  882. Result := CallIntegerFunc(Instance,
  883. PPointer(Pointer(Instance.ClassType) + LongInt(PropInfo^.GetProc))^,
  884. Index, IValue);
  885. end;
  886. end;
  887. procedure SetInt64Prop(Instance: TObject; PropInfo: PPropInfo; const Value: Int64);
  888. var
  889. Index, IValue: LongInt;
  890. begin
  891. SetIndexValues(PropInfo,Index,Ivalue);
  892. case PropInfo^.PropProcs and 3 of
  893. ptfield:
  894. PInt64(Pointer(Instance)+Longint(PropInfo^.GetProc))^ := Value;
  895. ptstatic:
  896. CallIntegerProc(Instance,PropInfo^.SetProc,Value,Index,IValue);
  897. ptvirtual:
  898. CallIntegerProc(Instance,PPointer(Pointer(Instance.ClassType)+Longint(PropInfo^.SetProc))^,Value,Index,IValue);
  899. end;
  900. end;
  901. Function GetInt64Prop(Instance: TObject; const PropName: string): Int64;
  902. begin
  903. Result:=GetInt64Prop(Instance,FindPropInfo(Instance,PropName));
  904. end;
  905. Procedure SetInt64Prop(Instance: TObject; const PropName: string; const Value: Int64);
  906. begin
  907. SetInt64Prop(Instance,FindPropInfo(Instance,PropName),Value);
  908. end;
  909. { ---------------------------------------------------------------------
  910. All properties through variant.
  911. ---------------------------------------------------------------------}
  912. Function GetPropValue(Instance: TObject; const PropName: string): Variant;
  913. begin
  914. Result:=GetPropValue(Instance,PropName,True);
  915. end;
  916. Function GetPropValue(Instance: TObject; const PropName: string; PreferStrings: Boolean): Variant;
  917. begin
  918. end;
  919. Procedure SetPropValue(Instance: TObject; const PropName: string; const Value: Variant);
  920. begin
  921. end;
  922. { ---------------------------------------------------------------------
  923. Easy access methods that appeared in Delphi 5
  924. ---------------------------------------------------------------------}
  925. Function IsPublishedProp(Instance: TObject; const PropName: string): Boolean;
  926. begin
  927. Result:=GetPropInfo(Instance,PropName)<>Nil;
  928. end;
  929. Function IsPublishedProp(AClass: TClass; const PropName: string): Boolean;
  930. begin
  931. Result:=GetPropInfo(AClass,PropName)<>Nil;
  932. end;
  933. Function PropIsType(Instance: TObject; const PropName: string; TypeKind: TTypeKind): Boolean;
  934. begin
  935. Result:=FindPropInfo(Instance,PropName)^.PropType^.Kind=TypeKind
  936. end;
  937. Function PropIsType(AClass: TClass; const PropName: string; TypeKind: TTypeKind): Boolean;
  938. begin
  939. Result:=PropType(AClass,PropName)=TypeKind
  940. end;
  941. Function PropType(Instance: TObject; const PropName: string): TTypeKind;
  942. begin
  943. Result:=FindPropInfo(Instance,PropName)^.PropType^.Kind;
  944. end;
  945. Function PropType(AClass: TClass; const PropName: string): TTypeKind;
  946. begin
  947. Result:=FindPropInfo(AClass,PropName)^.PropType^.Kind;
  948. end;
  949. Function IsStoredProp(Instance: TObject; const PropName: string): Boolean;
  950. begin
  951. Result:=IsStoredProp(instance,FindPropInfo(Instance,PropName));
  952. end;
  953. end.
  954. {
  955. $Log$
  956. Revision 1.12 2001-08-04 11:03:42 peter
  957. * moved i386 specific code to include file
  958. Revision 1.11 2001/07/29 13:50:44 peter
  959. * merged updates from v10
  960. Revision 1.9 2001/07/06 14:56:06 peter
  961. * merged more D5/D6 stuff from v10
  962. Revision 1.8 2001/06/27 21:37:38 peter
  963. * v10 merges
  964. Revision 1.7 2001/02/15 22:40:22 sg
  965. * Fixed SetOrdProp for class instance properties (merged from fixbranch)
  966. Revision 1.6 2000/12/13 23:28:17 sg
  967. * Merged bugfix for bug 1273 from fixbranch
  968. * Fixed typo in SetFloatProp
  969. * Rewrote GetStrProp, now all AnsiString will be correctly
  970. reference counted
  971. Revision 1.5 2000/11/25 18:36:55 sg
  972. * (Final) fix for AnsiString reference counter problem in SetStrProp
  973. Revision 1.4 2000/11/04 16:28:26 florian
  974. * interfaces support
  975. Revision 1.3 2000/07/17 08:37:58 sg
  976. * Fixed GetEnumValue (bug #1049, reported by Neil Graham)
  977. Revision 1.2 2000/07/13 11:33:52 michael
  978. + removed logs
  979. }