objpas.inc 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. This unit makes Free Pascal as much as possible Delphi compatible
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$ifdef FPC_HAS_FEATURE_VARIANTS}
  12. procedure DoDispCallByIDError(res : Pointer; const disp : IDispatch;desc : PDispDesc; params : Pointer);
  13. begin
  14. handleerroraddrframeind(RuntimeErrorExitCodes[reVarDispatch],
  15. get_pc_addr,get_frame);
  16. end;
  17. procedure fpc_dispatch_by_id(Result: Pointer; const Dispatch: pointer;
  18. DispDesc: Pointer; Params: Pointer); compilerproc;
  19. type
  20. TDispProc = procedure(res : Pointer; const disp : IDispatch;desc : PDispDesc; params : Pointer);
  21. begin
  22. TDispProc(DispCallByIDProc)(Result,IDispatch(Dispatch),DispDesc,Params);
  23. end;
  24. {$endif FPC_HAS_FEATURE_VARIANTS}
  25. {****************************************************************************
  26. Internal Routines called from the Compiler
  27. ****************************************************************************}
  28. { the reverse order of the parameters make code generation easier }
  29. function fpc_do_is(aclass : tclass;aobject : tobject) : boolean;[public,alias: 'FPC_DO_IS']; compilerproc;
  30. begin
  31. fpc_do_is:=assigned(aobject) and assigned(aclass) and
  32. aobject.inheritsfrom(aclass);
  33. end;
  34. {$IFDEF FPC_HAS_FEATURE_THREADING}
  35. threadvar
  36. CastErrorFrom : ShortString;
  37. CastErrorTo : ShortString;
  38. {$ELSE}
  39. var
  40. CastErrorFrom : ShortString = '';
  41. CastErrorTo : ShortString = '';
  42. {$ENDIF}
  43. procedure SetCastErrorInfo(const aFrom,aTo : shortstring);
  44. begin
  45. CastErrorFrom:=aFrom;
  46. CastErrorTo:=aTo;
  47. end;
  48. { the reverse order of the parameters make code generation easier }
  49. function fpc_do_as(aclass : tclass;aobject : tobject): tobject;[public,alias: 'FPC_DO_AS']; compilerproc;
  50. begin
  51. if assigned(aobject) and not(aobject.inheritsfrom(aclass)) then
  52. begin
  53. SetCastErrorInfo(aObject.ClassName,aClass.ClassName);
  54. handleerroraddrframeInd(219,get_pc_addr,get_frame);
  55. end;
  56. result := aobject;
  57. end;
  58. { interface helpers }
  59. procedure fpc_intf_decr_ref(var i: pointer);[public,alias: 'FPC_INTF_DECR_REF']; compilerproc;
  60. var
  61. iFetch: pointer;
  62. begin
  63. iFetch:=i;
  64. if assigned(iFetch) then
  65. begin
  66. i:=nil;
  67. IUnknown(iFetch)._Release;
  68. end;
  69. end;
  70. { local declaration for intf_decr_ref for local access }
  71. procedure intf_decr_ref(var i: pointer); [external name 'FPC_INTF_DECR_REF'];
  72. procedure fpc_intf_incr_ref(i: pointer);[public,alias: 'FPC_INTF_INCR_REF']; compilerproc;
  73. begin
  74. if assigned(i) then
  75. IUnknown(i)._AddRef;
  76. end;
  77. { local declaration of intf_incr_ref for local access }
  78. procedure intf_incr_ref(i: pointer); [external name 'FPC_INTF_INCR_REF'];
  79. procedure fpc_intf_assign(var D: pointer; const S: pointer);[public,alias: 'FPC_INTF_ASSIGN']; compilerproc;
  80. begin
  81. if assigned(S) then
  82. IUnknown(S)._AddRef;
  83. if assigned(D) then
  84. IUnknown(D)._Release;
  85. D:=S;
  86. end;
  87. procedure fpc_intf_assign(var D: pointer; const s: pointer); [external name 'FPC_INTF_ASSIGN'];
  88. {procedure fpc_intf_assign_by_iid(var D: pointer; const S: pointer; const iid: TGUID);[public,alias: 'FPC_INTF_ASSIGN2']; compilerproc;
  89. var
  90. tmp : pointer;
  91. begin
  92. if assigned(S) then
  93. begin
  94. tmp:=nil;
  95. if IUnknown(S).QueryInterface(iid,tmp)<>S_OK then
  96. handleerror(219);
  97. if assigned(D) then
  98. IUnknown(D)._Release;
  99. D:=tmp;
  100. end
  101. else
  102. begin
  103. if assigned(D) then
  104. IUnknown(D)._Release;
  105. D:=nil;
  106. end;
  107. end;}
  108. function fpc_intf_is(const S: pointer; const iid: TGUID): Boolean;[public,alias: 'FPC_INTF_IS']; compilerproc;
  109. var
  110. tmpi: pointer;
  111. begin
  112. tmpi:=nil;
  113. fpc_intf_is:=Assigned(S) and (IUnknown(S).QueryInterface(iid,tmpi)=S_OK);
  114. if Assigned(tmpi) then
  115. IUnknown(tmpi)._Release;
  116. end;
  117. function fpc_intf_is_class(const S: pointer; const aclass: tclass): Boolean;[public,alias: 'FPC_INTF_IS_CLASS']; compilerproc;
  118. var
  119. tmpo: tobject;
  120. begin
  121. fpc_intf_is_class:=Assigned(S) and (IUnknown(S).QueryInterface(IObjectInstance,tmpo)=S_OK) and tmpo.InheritsFrom(aclass);
  122. end;
  123. function fpc_class_is_intf(const S: pointer; const iid: TGUID): Boolean;[public,alias: 'FPC_CLASS_IS_INTF']; compilerproc;
  124. var
  125. tmpi: pointer;
  126. tmpi2: pointer; // weak!
  127. begin
  128. tmpi:=nil;
  129. tmpi2:=nil;
  130. fpc_class_is_intf:=Assigned(S) and ((TObject(S).GetInterfaceWeak(IUnknown,tmpi2) and (IUnknown(tmpi2).QueryInterface(IID,tmpi)=S_OK)) or
  131. TObject(S).GetInterface(IID,tmpi));
  132. if Assigned(tmpi) then
  133. IUnknown(tmpi)._Release;
  134. end;
  135. function fpc_class_is_corbaintf(const S: pointer; const iid: Shortstring): Boolean;[public,alias: 'FPC_CLASS_IS_CORBAINTF']; compilerproc;
  136. begin
  137. fpc_class_is_corbaintf:=Assigned(S) and Assigned(TObject(S).GetInterfaceEntryByStr(iid));
  138. end;
  139. function fpc_intf_cast(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_INTF_CAST']; compilerproc;
  140. var
  141. tmpi: pointer;
  142. begin
  143. tmpi:=nil;
  144. if Assigned(S) and (IUnknown(S).QueryInterface(iid,tmpi)=S_OK) then
  145. pointer(fpc_intf_cast):=tmpi
  146. else
  147. fpc_intf_cast:= nil;
  148. end;
  149. function fpc_intf_cast_class(const S: pointer; const aclass: tclass): pointer;[public,alias: 'FPC_INTF_CAST_CLASS']; compilerproc;
  150. var
  151. tmpo: tobject;
  152. begin
  153. if Assigned(S) and (IUnknown(S).QueryInterface(IObjectInstance,tmpo)=S_OK) and tmpo.InheritsFrom(aclass) then
  154. fpc_intf_cast_class:=tmpo
  155. else
  156. fpc_intf_cast_class:=nil;
  157. end;
  158. function fpc_class_cast_intf(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_CLASS_CAST_INTF']; compilerproc;
  159. var
  160. tmpi: pointer;
  161. tmpi2: pointer; // weak!
  162. begin
  163. tmpi:=nil;
  164. tmpi2:=nil;
  165. if Assigned(S) and ((TObject(S).GetInterfaceWeak(IUnknown,tmpi2) and (IUnknown(tmpi2).QueryInterface(IID,tmpi)=S_OK)) or
  166. TObject(S).GetInterface(IID,tmpi)) then
  167. begin
  168. // decrease reference count
  169. fpc_class_cast_intf:=nil;
  170. pointer(fpc_class_cast_intf):=tmpi
  171. end
  172. else
  173. fpc_class_cast_intf:=nil;
  174. end;
  175. function fpc_class_cast_corbaintf(const S: pointer; const iid: Shortstring): Pointer;[public,alias: 'FPC_CLASS_CAST_CORBAINTF']; compilerproc;
  176. var
  177. tmpi: pointer;
  178. begin
  179. if Assigned(S) and TObject(S).GetInterface(iid,tmpi) then
  180. fpc_class_cast_corbaintf:=tmpi
  181. else
  182. fpc_class_cast_corbaintf:=nil;
  183. end;
  184. function fpc_intf_as(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_INTF_AS']; compilerproc;
  185. var
  186. tmpi: pointer; // _AddRef before _Release
  187. errObj : TObject;
  188. begin
  189. if assigned(S) then
  190. begin
  191. tmpi:=nil;
  192. if IUnknown(S).QueryInterface(iid,tmpi)<>S_OK then
  193. begin
  194. if (IUnknown(S).QueryInterface(IObjectInstance,errObj)=S_OK) then
  195. SetCastErrorInfo(errObj.ClassName,iid.AsString)
  196. else
  197. SetCastErrorInfo('External interface',iid.AsString);
  198. handleerror(219);
  199. end;
  200. // decrease reference count
  201. fpc_intf_as:=nil;
  202. pointer(fpc_intf_as):=tmpi;
  203. end
  204. else
  205. fpc_intf_as:=nil;
  206. end;
  207. function fpc_intf_as_class(const S: pointer; const aclass: tclass): pointer;[public,alias: 'FPC_INTF_AS_CLASS']; compilerproc;
  208. var
  209. tmpo: tobject;
  210. errObj : TObject;
  211. begin
  212. if assigned(S) then
  213. begin
  214. if not ((IUnknown(S).QueryInterface(IObjectInstance,tmpo)=S_OK) and tmpo.inheritsfrom(aclass)) then
  215. begin
  216. if (IUnknown(S).QueryInterface(IObjectInstance,errObj)=S_OK) then
  217. SetCastErrorInfo(errObj.ClassName,aClass.ClassName)
  218. else
  219. SetCastErrorInfo('External interface',aClass.ClassName);
  220. handleerror(219);
  221. end;
  222. fpc_intf_as_class:=tmpo;
  223. end
  224. else
  225. fpc_intf_as_class:=nil;
  226. end;
  227. function fpc_class_as_intf(const S: pointer; const iid: TGUID): IInterface;[public,alias: 'FPC_CLASS_AS_INTF']; compilerproc;
  228. var
  229. tmpi: pointer; // _AddRef before _Release
  230. tmpi2: pointer; // weak!
  231. errObj : TObject;
  232. begin
  233. if assigned(S) then
  234. begin
  235. tmpi:=nil;
  236. tmpi2:=nil;
  237. if not ((TObject(S).GetInterfaceWeak(IUnknown,tmpi2) and (IUnknown(tmpi2).QueryInterface(IID,tmpi)=S_OK)) or TObject(S).GetInterface(IID,tmpi)) then
  238. begin
  239. SetCastErrorInfo(TObject(S).ClassName,iid.AsString);
  240. handleerror(219);
  241. end;
  242. // decrease reference count
  243. fpc_class_as_intf:=nil;
  244. pointer(fpc_class_as_intf):=tmpi;
  245. end
  246. else
  247. fpc_class_as_intf:=nil;
  248. end;
  249. function fpc_class_as_corbaintf(const S: pointer; const iid: Shortstring): Pointer;[public,alias: 'FPC_CLASS_AS_CORBAINTF']; compilerproc;
  250. var
  251. tmpi: pointer; // _AddRef before _Release
  252. begin
  253. if assigned(S) then
  254. begin
  255. tmpi:=nil;
  256. if not TObject(S).GetInterface(iid,tmpi) then
  257. begin
  258. SetCastErrorInfo(TObject(S).ClassName,iid);
  259. handleerror(219);
  260. end;
  261. fpc_class_as_corbaintf:=tmpi;
  262. end
  263. else
  264. fpc_class_as_corbaintf:=nil;
  265. end;
  266. {****************************************************************************
  267. TVMT
  268. ****************************************************************************}
  269. function TVmt.GetvParent: PVmt;
  270. begin
  271. if Assigned(vParentRef) then
  272. GetvParent:=vParentRef^
  273. else
  274. GetvParent:=Nil;
  275. end;
  276. {****************************************************************************
  277. TGUID
  278. ****************************************************************************}
  279. class operator TGUID.=(const aLeft, aRight: TGUID): Boolean;
  280. var
  281. P1,P2 : ^Cardinal;
  282. begin
  283. P1:=PCardinal(@aLeft);
  284. P2:=PCardinal(@aRight);
  285. Result:=(P1[0]=P2[0]) and (P1[1]=P2[1]) and (P1[2]=P2[2]) and (P1[3]=P2[3]);
  286. end;
  287. class operator TGUID.<>(const aLeft, aRight: TGUID): Boolean;
  288. begin
  289. Result:=Not (aLeft=aRight);
  290. end;
  291. class function TGUID.Empty: TGUID; static;
  292. begin
  293. Result:=Default(TGUID);
  294. end;
  295. class function TGUID.Create(const aData; aBigEndian: Boolean = False): TGUID; overload; static;
  296. begin
  297. Result:=Create(PByte(@aData),aBigEndian);
  298. end;
  299. class function TGUID.Create(const aData : PByte; aBigEndian: Boolean = False): TGUID; overload; static;
  300. const
  301. SysBigendian = {$IFDEF FPC_LITTLE_ENDIAN} false {$ELSE} true {$ENDIF};
  302. begin
  303. Result := PGuid(aData)^;
  304. if (aBigEndian=SysBigEndian) then
  305. exit;
  306. Result.D1:=SwapEndian(Result.D1);
  307. Result.D2:=SwapEndian(Result.D2);
  308. Result.D3:=SwapEndian(Result.D3);
  309. end;
  310. class function TGUID.Create(const aData: array of Byte; aStartIndex: Cardinal; aBigEndian: Boolean = False): TGUID; overload; static;
  311. begin
  312. if ((Length(aData)-aStartIndex)<16) then
  313. Result:=Empty
  314. else
  315. Result:=Create(PByte(@aData[aStartIndex]),aBigEndian);
  316. end;
  317. function TGUID.IsEmpty: Boolean;
  318. var
  319. P : ^Cardinal;
  320. begin
  321. P:=PCardinal(@Self);
  322. Result:=(P[0]=0) and (P[1]=0) and (P[2]=0) and (P[3]=0)
  323. end;
  324. function TGUID.AsString : ShortString;
  325. begin
  326. WriteStr(Result,'{',hexstr(Longint(D1),8),
  327. '-',HexStr(D2,4),
  328. '-',HexStr(D3,4),
  329. '-',HexStr(D4[0],2), HexStr(D4[1],2),
  330. '-',HexStr(D4[2],2), HexStr(D4[3],2), HexStr(D4[4],2), HexStr(D4[5],2), HexStr(D4[6],2), HexStr(D4[7],2),
  331. '}');
  332. end;
  333. {****************************************************************************
  334. TINTERFACEENTRY
  335. ****************************************************************************}
  336. function tinterfaceentry.GetIID: pguid;
  337. begin
  338. if Assigned(IIDRef) then
  339. GetIID:=IIDRef^
  340. else
  341. GetIID:=Nil;
  342. end;
  343. function tinterfaceentry.GetIIDStr: pshortstring;
  344. begin
  345. if Assigned(IIDStrRef) then
  346. GetIIDStr:=IIDStrRef^
  347. else
  348. GetIIDStr:=Nil;
  349. end;
  350. {****************************************************************************
  351. TOBJECT
  352. ****************************************************************************}
  353. constructor TObject.Create;
  354. begin
  355. end;
  356. destructor TObject.Destroy;
  357. begin
  358. end;
  359. procedure TObject.Free;
  360. begin
  361. // the call via self avoids a warning
  362. if self<>nil then
  363. self.destroy;
  364. end;
  365. class function TObject.InstanceSize : SizeInt;
  366. begin
  367. InstanceSize := PVmt(Self)^.vInstanceSize;
  368. end;
  369. procedure InitInterfacePointers(objclass: tclass;instance : pointer);
  370. var
  371. ovmt: PVmt;
  372. i: sizeuint;
  373. intftable: pinterfacetable;
  374. Res: pinterfaceentry;
  375. begin
  376. ovmt := PVmt(objclass);
  377. while assigned(ovmt) and assigned(ovmt^.vIntfTable) do
  378. begin
  379. intftable:=ovmt^.vIntfTable;
  380. i:=intftable^.EntryCount;
  381. Res:=@intftable^.Entries[0];
  382. while i>0 do begin
  383. if Res^.IType = etStandard then
  384. ppointer(@(pbyte(instance)[Res^.IOffset]))^:=
  385. pointer(Res^.VTable);
  386. inc(Res);
  387. dec(i);
  388. end;
  389. ovmt:=ovmt^.vParent;
  390. end;
  391. end;
  392. class function TObject.InitInstance(instance : pointer) : tobject;
  393. var
  394. vmt : PVmt;
  395. inittable : pointer;
  396. Res : ^TRTTIRecordOpOffsetEntry;
  397. {$ifdef FPC_HAS_FEATURE_RTTI}
  398. mopinittable : PRTTIRecordOpOffsetTable;
  399. {$endif def FPC_HAS_FEATURE_RTTI}
  400. i : longword;
  401. begin
  402. { the size is saved at offset 0 }
  403. fillchar(instance^, InstanceSize, 0);
  404. { insert VMT pointer into the new created memory area }
  405. { (in class methods self contains the VMT!) }
  406. {$IFNDEF SYSTEM_HAS_FEATURE_MONITOR}
  407. ppointer(instance)^:=pointer(self);
  408. {$ELSE}
  409. {$IFDEF VER3_2}
  410. // In 3.2.x Compiler (used during bootstrap) still inserts VMT at offset...
  411. ppointer(PByte(instance)+SizeOf(Pointer))^:=pointer(self);
  412. {$ELSE}
  413. // As of 3.3.x compiler forces insert of VMT at first pos.
  414. ppointer(instance)^:=pointer(self);
  415. {$ENDIF}
  416. {$ENDIF}
  417. if assigned(PVmt(self)^.vIntfTable) then
  418. InitInterfacePointers(self,instance);
  419. {$ifdef FPC_HAS_FEATURE_RTTI}
  420. { for management operators like initialize call int_initialize }
  421. vmt := PVmt(self);
  422. if assigned(vmt) then
  423. begin
  424. inittable:=vmt^.vInitTable;
  425. if assigned(inittable) then
  426. begin
  427. mopinittable:=RTTIRecordMopInitTable(inittable);
  428. if assigned(mopinittable) then
  429. begin
  430. {$push}
  431. { ensure that no range check errors pop up with the [0..0] array }
  432. {$R-}
  433. i:=mopinittable^.Count;
  434. Res:=@mopinittable^.Entries[0];
  435. while i>0 do
  436. begin
  437. TRTTIRecVarOp(Res^.ManagmentOperator)(PByte(Instance)+Res^.FieldOffset);
  438. inc(Res);
  439. dec(i);
  440. end;
  441. {$pop}
  442. end;
  443. end;
  444. end;
  445. {$endif def FPC_HAS_FEATURE_RTTI}
  446. InitInstance:=TObject(Instance);
  447. end;
  448. class function TObject.ClassParent : tclass;
  449. begin
  450. { type of self is class of tobject => it points to the vmt }
  451. { the parent vmt is saved at offset vmtParent }
  452. classparent:=tclass(PVmt(Self)^.vParent);
  453. end;
  454. class function TObject.NewInstance : tobject;
  455. var
  456. p : pointer;
  457. begin
  458. getmem(p, InstanceSize);
  459. if p <> nil then
  460. InitInstance(p);
  461. NewInstance:=TObject(p);
  462. end;
  463. procedure TObject.FreeInstance;
  464. begin
  465. CleanupInstance;
  466. FreeMem(Pointer(Self));
  467. end;
  468. class function TObject.ClassType : TClass;
  469. begin
  470. ClassType:=TClass(Pointer(Self))
  471. end;
  472. type
  473. {$PUSH}
  474. {$PACKRECORDS NORMAL}
  475. tmethodnamerec =
  476. {$IFNDEF FPC_REQUIRES_PROPER_ALIGNMENT}
  477. packed
  478. {$ENDIF FPC_REQUIRES_PROPER_ALIGNMENT}
  479. record
  480. name : pshortstring;
  481. addr : codepointer;
  482. end;
  483. tmethodnametable =
  484. {$IFNDEF FPC_REQUIRES_PROPER_ALIGNMENT}
  485. packed
  486. {$ENDIF FPC_REQUIRES_PROPER_ALIGNMENT}
  487. record
  488. count : dword;
  489. entries : packed array[0..0] of tmethodnamerec;
  490. end;
  491. {$POP}
  492. pmethodnametable = ^tmethodnametable;
  493. class function TObject.MethodAddress(const name : shortstring) : codepointer;
  494. var
  495. methodtable : pmethodnametable;
  496. i : longint; // in case count=0
  497. ovmt : PVmt;
  498. begin
  499. ovmt:=PVmt(self);
  500. while assigned(ovmt) do
  501. begin
  502. methodtable:=pmethodnametable(ovmt^.vMethodTable);
  503. if assigned(methodtable) then
  504. begin
  505. for i:=0 to methodtable^.count-1 do
  506. if ShortCompareText(methodtable^.entries[i].name^, name)=0 then
  507. begin
  508. MethodAddress:=methodtable^.entries[i].addr;
  509. exit;
  510. end;
  511. end;
  512. ovmt := ovmt^.vParent;
  513. end;
  514. MethodAddress:=nil;
  515. end;
  516. class function TObject.MethodName(address : codepointer) : shortstring;
  517. var
  518. methodtable : pmethodnametable;
  519. i : longint; // in case count=0
  520. ovmt : PVmt;
  521. begin
  522. ovmt:=PVmt(self);
  523. while assigned(ovmt) do
  524. begin
  525. methodtable:=pmethodnametable(ovmt^.vMethodTable);
  526. if assigned(methodtable) then
  527. begin
  528. for i:=0 to methodtable^.count-1 do
  529. if methodtable^.entries[i].addr=address then
  530. begin
  531. MethodName:=methodtable^.entries[i].name^;
  532. exit;
  533. end;
  534. end;
  535. ovmt := ovmt^.vParent;
  536. end;
  537. MethodName:='';
  538. end;
  539. function TObject.FieldAddress(const name : shortstring) : pointer;
  540. {The following is copied to the typinfo unit. If it is changed here, change it there as well ! }
  541. type
  542. {$PUSH}
  543. {$PACKRECORDS NORMAL}
  544. PFieldInfo = ^TFieldInfo;
  545. TFieldInfo =
  546. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  547. packed
  548. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  549. record
  550. FieldOffset: SizeUInt;
  551. ClassTypeIndex: Word;
  552. Name: ShortString;
  553. end;
  554. PFieldTable = ^TFieldTable;
  555. TFieldTable =
  556. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  557. packed
  558. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  559. record
  560. FieldCount: Word;
  561. ClassTable: Pointer;
  562. { should be array[Word] of TFieldInfo; but
  563. Elements have variant size! force at least proper alignment }
  564. Fields: array[0..0] of TFieldInfo
  565. end;
  566. {$POP}
  567. var
  568. ovmt: PVmt;
  569. FieldTable: PFieldTable;
  570. FieldInfo: PFieldInfo;
  571. i: longint;
  572. begin
  573. if Length(name) > 0 then
  574. begin
  575. ovmt := PVmt(ClassType);
  576. while ovmt <> nil do
  577. begin
  578. FieldTable := PFieldTable(ovmt^.vFieldTable);
  579. if FieldTable <> nil then
  580. begin
  581. FieldInfo := @FieldTable^.Fields[0];
  582. for i := 0 to FieldTable^.FieldCount - 1 do
  583. begin
  584. if ShortCompareText(FieldInfo^.Name, name) = 0 then
  585. begin
  586. fieldaddress := Pointer(Self) + FieldInfo^.FieldOffset;
  587. exit;
  588. end;
  589. FieldInfo := PFieldInfo(PByte(@FieldInfo^.Name) + 1 + Length(FieldInfo^.Name));
  590. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  591. { align to largest field of TFieldInfo }
  592. FieldInfo := Align(FieldInfo, SizeOf(PtrUInt));
  593. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  594. end;
  595. end;
  596. { Try again with the parent class type }
  597. ovmt:=ovmt^.vParent;
  598. end;
  599. end;
  600. fieldaddress:=nil;
  601. end;
  602. function TObject.SafeCallException(exceptobject : tobject;
  603. exceptaddr : codepointer) : HResult;
  604. begin
  605. safecallexception:=E_UNEXPECTED;
  606. end;
  607. class function TObject.ClassInfo : pointer;
  608. begin
  609. ClassInfo := PVmt(Self)^.vTypeInfo;
  610. end;
  611. class function TObject.ClassName : ShortString;
  612. begin
  613. ClassName := PVmt(Self)^.vClassName^;
  614. end;
  615. class function TObject.ClassNameIs(const name : RTLString) : boolean;
  616. var
  617. SS : ShortString;
  618. begin
  619. SS:=ShortString(Name);
  620. ClassNameIs:=ShortCompareText(PVmt(Self)^.vClassName^, SS) = 0;
  621. end;
  622. class function TObject.InheritsFrom(aclass : TClass) : Boolean;
  623. var
  624. vmt: PVmt;
  625. begin
  626. if assigned(aclass) then
  627. begin
  628. vmt:=PVmt(self);
  629. while assigned(vmt) and (vmt <> PVmt(aclass)) do
  630. vmt := vmt^.vParent;
  631. InheritsFrom := (vmt = PVmt(aclass));
  632. end
  633. else
  634. inheritsFrom := False;
  635. end;
  636. class function TObject.stringmessagetable : pstringmessagetable;
  637. begin
  638. stringmessagetable:=PVmt(Self)^.vMsgStrPtr;
  639. end;
  640. type
  641. tmessagehandler = procedure(var msg) of object;
  642. procedure TObject.Dispatch(var message);
  643. type
  644. {$PUSH}
  645. {$PACKRECORDS NORMAL}
  646. PMsgIntTable = ^TMsgIntTable;
  647. TMsgIntTable = record
  648. index : dword;
  649. method : codepointer;
  650. end;
  651. PMsgInt = ^TMsgInt;
  652. TMsgInt = record
  653. count : longint;
  654. msgs : array[0..0] of TMsgIntTable;
  655. end;
  656. {$POP}
  657. var
  658. index : dword;
  659. count,i : longint;
  660. msgtable : PMsgIntTable;
  661. p : PMsgInt;
  662. ovmt : PVmt;
  663. msghandler : tmessagehandler;
  664. begin
  665. index:=dword(message);
  666. ovmt := PVmt(ClassType);
  667. while assigned(ovmt) do
  668. begin
  669. // See if we have messages at all in this class.
  670. p:=PMsgInt(ovmt^.vDynamicTable);
  671. If Assigned(p) then
  672. begin
  673. msgtable:=@p^.msgs;
  674. count:=p^.count;
  675. end
  676. else
  677. Count:=0;
  678. { later, we can implement a binary search here }
  679. for i:=0 to count-1 do
  680. begin
  681. if index=msgtable[i].index then
  682. begin
  683. TMethod(msghandler).Code:=msgtable[i].method;
  684. TMethod(msghandler).Data:=self;
  685. msghandler(message);
  686. exit;
  687. end;
  688. end;
  689. ovmt:=ovmt^.vParent;
  690. end;
  691. DefaultHandler(message);
  692. end;
  693. procedure TObject.DispatchStr(var message);
  694. var
  695. name : shortstring;
  696. count,i : longint;
  697. msgstrtable : pmsgstrtable;
  698. p: pstringmessagetable;
  699. ovmt : PVmt;
  700. msghandler : tmessagehandler;
  701. begin
  702. name:=pshortstring(@message)^;
  703. ovmt:=PVmt(ClassType);
  704. while assigned(ovmt) do
  705. begin
  706. p := ovmt^.vMsgStrPtr;
  707. if (P<>Nil) and (p^.count<>0) then
  708. begin
  709. count:=p^.count;
  710. msgstrtable:=@p^.msgstrtable;
  711. end
  712. else
  713. Count:=0;
  714. { later, we can implement a binary search here }
  715. for i:=0 to count-1 do
  716. begin
  717. if name=msgstrtable[i].name^ then
  718. begin
  719. TMethod(msghandler).Code:=msgstrtable[i].method;
  720. TMethod(msghandler).Data:=self;
  721. msghandler(message);
  722. exit;
  723. end;
  724. end;
  725. ovmt:=ovmt^.vParent;
  726. end;
  727. DefaultHandlerStr(message);
  728. end;
  729. procedure TObject.DefaultHandler(var message);
  730. begin
  731. end;
  732. procedure TObject.DefaultHandlerStr(var message);
  733. begin
  734. end;
  735. procedure TObject.CleanupInstance;
  736. var
  737. vmt : PVmt;
  738. temp : pointer;
  739. begin
  740. vmt := PVmt(ClassType);
  741. while vmt<>nil do
  742. begin
  743. Temp:= vmt^.vInitTable;
  744. {$ifdef FPC_HAS_FEATURE_RTTI}
  745. { The RTTI format matches one for records, except the type is tkClass.
  746. Since RecordRTTI does not check the type, calling it yields the desired result. }
  747. if Assigned(Temp) then
  748. RecordRTTI(Self,aligntoqword(Temp+2+PByte(Temp)[1]),@int_finalize);
  749. {$endif def FPC_HAS_FEATURE_RTTI}
  750. vmt:= vmt^.vParent;
  751. end;
  752. {$IFDEF SYSTEM_HAS_FEATURE_MONITOR}
  753. if Assigned(_MonitorData) then
  754. TMonitor.FreeMonitorData(_MonitorData);
  755. {$ENDIF}
  756. end;
  757. procedure TObject.AfterConstruction;
  758. begin
  759. end;
  760. procedure TObject.BeforeDestruction;
  761. begin
  762. end;
  763. function IsGUIDEqual(const guid1, guid2: tguid): boolean;
  764. begin
  765. IsGUIDEqual:=
  766. (guid1.D1=guid2.D1) and
  767. (PDWORD(@guid1.D2)^=PDWORD(@guid2.D2)^) and
  768. (PDWORD(@guid1.D4[0])^=PDWORD(@guid2.D4[0])^) and
  769. (PDWORD(@guid1.D4[4])^=PDWORD(@guid2.D4[4])^);
  770. end;
  771. // Use of managed types should be avoided here; implicit _Addref/_Release
  772. // will end up in unpredictable behaviour if called on CORBA interfaces.
  773. type
  774. TInterfaceGetter = procedure(out Obj) of object;
  775. TClassGetter = function: TObject of object;
  776. function GetInterfaceByEntry(Instance: pointer; IEntry: pinterfaceentry; out obj): boolean;
  777. var
  778. Getter: TMethod;
  779. begin
  780. Pointer(Obj) := nil;
  781. Getter.Data := Instance;
  782. if Assigned(IEntry) and Assigned(Instance) then
  783. begin
  784. case IEntry^.IType of
  785. etStandard:
  786. Pointer(Obj) := PByte(instance)+IEntry^.IOffset;
  787. etFieldValue, etFieldValueClass:
  788. Pointer(obj) := PPointer(PByte(Instance)+IEntry^.IOffset)^;
  789. etVirtualMethodResult:
  790. begin
  791. // IOffset is relative to the VMT, not to instance.
  792. Getter.code := PCodePointer(PByte(PPointer(Instance)^) + IEntry^.IOffset)^;
  793. TInterfaceGetter(Getter)(obj);
  794. end;
  795. etVirtualMethodClass:
  796. begin
  797. // IOffset is relative to the VMT, not to instance.
  798. Getter.code := PCodePointer(PByte(PPointer(Instance)^) + IEntry^.IOffset)^;
  799. TObject(obj) := TClassGetter(Getter)();
  800. end;
  801. etStaticMethodResult:
  802. begin
  803. Getter.code := IEntry^.IOffsetAsCodePtr;
  804. TInterfaceGetter(Getter)(obj);
  805. end;
  806. etStaticMethodClass:
  807. begin
  808. Getter.code := IEntry^.IOffsetAsCodePtr;
  809. TObject(obj) := TClassGetter(Getter)();
  810. end;
  811. end;
  812. end;
  813. result := assigned(pointer(obj));
  814. end;
  815. function TObject.GetInterface(const iid : tguid;out obj) : boolean;
  816. var
  817. IEntry: PInterfaceEntry;
  818. Instance: TObject;
  819. begin
  820. if IsGUIDEqual(IObjectInstance,iid) then
  821. begin
  822. TObject(Obj) := Self;
  823. Result := True;
  824. Exit;
  825. end;
  826. Instance := self;
  827. repeat
  828. IEntry := Instance.GetInterfaceEntry(iid);
  829. result := GetInterfaceByEntry(Instance, IEntry, obj);
  830. if (not result) or
  831. (IEntry^.IType in [etStandard, etFieldValue,
  832. etStaticMethodResult, etVirtualMethodResult]) then
  833. Break;
  834. { if interface is implemented by a class-type property or field,
  835. continue search }
  836. Instance := TObject(obj);
  837. until False;
  838. { Getter function will normally AddRef, so adding another reference here
  839. will cause memleak. }
  840. if result and (IEntry^.IType in [etStandard, etFieldValue]) then
  841. IInterface(obj)._AddRef;
  842. end;
  843. function TObject.GetInterfaceWeak(const iid : tguid; out obj) : boolean;
  844. var
  845. IEntry: PInterfaceEntry;
  846. Instance: TObject;
  847. begin
  848. if IsGUIDEqual(IObjectInstance,iid) then
  849. begin
  850. TObject(Obj) := Self;
  851. Result := True;
  852. Exit;
  853. end;
  854. Instance := self;
  855. repeat
  856. IEntry := Instance.GetInterfaceEntry(iid);
  857. result := GetInterfaceByEntry(Instance, IEntry, obj);
  858. if (not result) or
  859. (IEntry^.IType in [etStandard, etFieldValue,
  860. etStaticMethodResult, etVirtualMethodResult]) then
  861. Break;
  862. { if interface is implemented by a class-type property or field,
  863. continue search }
  864. Instance := TObject(obj);
  865. until False;
  866. { Getter function will normally AddRef, so we have to release it,
  867. else the ref is not weak. }
  868. if result and not (IEntry^.IType in [etStandard, etFieldValue]) then
  869. IInterface(obj)._Release;
  870. end;
  871. function TObject.GetInterfaceByStr(const iidstr : shortstring;out obj) : boolean;
  872. var
  873. IEntry: PInterfaceEntry;
  874. Instance: TObject;
  875. begin
  876. Instance := self;
  877. repeat
  878. IEntry := Instance.GetInterfaceEntryByStr(iidstr);
  879. result := GetInterfaceByEntry(Instance, IEntry, obj);
  880. if (not result) or
  881. (IEntry^.IType in [etStandard, etFieldValue,
  882. etStaticMethodResult, etVirtualMethodResult]) then
  883. Break;
  884. { if interface is implemented by a class-type property or field,
  885. continue search }
  886. Instance := TObject(obj);
  887. until False;
  888. { Getter function will normally AddRef, so adding another reference here
  889. will cause memleak. (com interfaces only!) }
  890. if result and Assigned(IEntry^.IID) and (IEntry^.IType in [etStandard, etFieldValue]) then
  891. IInterface(obj)._AddRef;
  892. end;
  893. function TObject.GetInterface(const iidstr : shortstring;out obj) : boolean;
  894. begin
  895. Result := GetInterfaceByStr(iidstr,obj);
  896. end;
  897. class function TObject.GetInterfaceEntry(const iid : tguid) : pinterfaceentry;
  898. var
  899. i: sizeuint;
  900. intftable: pinterfacetable;
  901. ovmt: PVmt;
  902. begin
  903. ovmt := PVmt(Self);
  904. while Assigned(ovmt) and Assigned(ovmt^.vIntftable) do
  905. begin
  906. intftable:=ovmt^.vIntfTable;
  907. i:=intftable^.EntryCount;
  908. result:=@intftable^.Entries[0];
  909. while i>0 do
  910. begin
  911. if assigned(Result^.iid) and IsGUIDEqual(Result^.iid^,iid) then
  912. Exit;
  913. inc(Result);
  914. dec(i);
  915. end;
  916. ovmt := ovmt^.vParent;
  917. end;
  918. result := nil;
  919. end;
  920. class function TObject.GetInterfaceEntryByStr(const iidstr : shortstring) : pinterfaceentry;
  921. var
  922. i: sizeuint;
  923. intftable: pinterfacetable;
  924. ovmt: PVmt;
  925. begin
  926. ovmt := PVmt(Self);
  927. while Assigned(ovmt) and Assigned(ovmt^.vIntfTable) do
  928. begin
  929. intftable:=ovmt^.vIntfTable;
  930. i:=intftable^.EntryCount;
  931. result:=@intftable^.Entries[0];
  932. while i>0 do
  933. begin
  934. if assigned(result^.iidstr) and (result^.iidstr^ = iidstr) then
  935. Exit;
  936. inc(Result);
  937. dec(i);
  938. end;
  939. ovmt := ovmt^.vParent;
  940. end;
  941. result:=nil;
  942. end;
  943. class function TObject.GetInterfaceTable : pinterfacetable;
  944. begin
  945. getinterfacetable:=PVmt(Self)^.vIntfTable;
  946. end;
  947. class procedure TObject.GetLastCastErrorInfo(out aFrom,aTo : shortstring);
  948. begin
  949. aFrom:=CastErrorFrom;
  950. aTo:=CastErrorTo;
  951. CastErrorFrom:='';
  952. CastErrorTo:='';
  953. end;
  954. class function TObject.UnitName : RTLString;
  955. {$ifdef FPC_HAS_FEATURE_RTTI}
  956. type
  957. TClassTypeInfo = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif}record
  958. Attributes: Pointer;
  959. case TTypeKind of
  960. tkClass: (
  961. ClassType: TClass;
  962. ParentInfo: Pointer;
  963. PropCount: SmallInt;
  964. UnitName: ShortString;
  965. );
  966. { include for proper alignment }
  967. tkInt64: (
  968. Dummy: Int64;
  969. );
  970. end;
  971. PClassTypeInfo = ^TClassTypeInfo;
  972. var
  973. classtypeinfo: PClassTypeInfo;
  974. begin
  975. classtypeinfo:=ClassInfo;
  976. if Assigned(classtypeinfo) then
  977. begin
  978. // offset PTypeInfo by Length(Name) + 2 (ShortString length byte + SizeOf(Kind))
  979. inc(Pointer(classtypeinfo), PByte(Pointer(classtypeinfo)+1)^ + 2);
  980. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  981. classtypeinfo:=aligntoqword(classtypeinfo);
  982. {$endif}
  983. result:=classtypeinfo^.UnitName;
  984. end
  985. else
  986. result:='';
  987. end;
  988. {$else not FPC_HAS_FEATURE_RTTI}
  989. begin
  990. result:='';
  991. end;
  992. {$endif ndef FPC_HAS_FEATURE_RTTI}
  993. class function TObject.QualifiedClassName: RTLString;
  994. var
  995. uname: RTLString;
  996. begin
  997. uname := UnitName; //TODO: change 'UnitName' to 'UnitScope' as soon as RTL implement it
  998. if uname='' then
  999. result:=ClassName
  1000. else
  1001. result:=Concat(uname, '.', ClassName);
  1002. end;
  1003. function TObject.Equals(Obj: TObject) : boolean;
  1004. begin
  1005. result:=Obj=Self;
  1006. end;
  1007. function TObject.GetHashCode: PtrInt;
  1008. begin
  1009. result:=PtrInt(Self);
  1010. end;
  1011. function TObject.ToString: RTLString;
  1012. begin
  1013. result:=ClassName;
  1014. end;
  1015. procedure TObject.DisposeOf;
  1016. begin
  1017. Free;
  1018. end;
  1019. function TObject.GetDisposed : Boolean;
  1020. begin
  1021. Result:=False;
  1022. end;
  1023. procedure TObject.CheckDisposed;
  1024. begin
  1025. // Do nothing since we have no reference count.
  1026. end;
  1027. {$IFDEF SYSTEM_HAS_FEATURE_MONITOR}
  1028. function TObject.SetMonitorData(aData,aCheckOld : Pointer) : Pointer;
  1029. begin
  1030. Result:=InterlockedCompareExchange(_MonitorData,aData,aCheckOld);
  1031. end;
  1032. function TObject.GetMonitorData: Pointer;
  1033. begin
  1034. Result:=_MonitorData;
  1035. end;
  1036. {$ENDIF}
  1037. {****************************************************************************
  1038. TINTERFACEDOBJECT
  1039. ****************************************************************************}
  1040. function TInterfacedObject.QueryInterface(
  1041. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1042. begin
  1043. if getinterface(iid,obj) then
  1044. result:=S_OK
  1045. else
  1046. result:=longint(E_NOINTERFACE);
  1047. end;
  1048. function TInterfacedObject._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1049. begin
  1050. _addref:=frefcount;
  1051. if _addref<>0 then
  1052. begin
  1053. if _addref>0 then
  1054. _addref:=interlockedincrement(frefcount);
  1055. exit;
  1056. end;
  1057. frefcount:=1; { Work non-atomically in the common case of refcount = 0 (typical state after the complete object construction). }
  1058. _addref:=1;
  1059. end;
  1060. function TInterfacedObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1061. begin
  1062. _Release:=frefcount;
  1063. if _Release<>1 then
  1064. begin
  1065. if _Release<=0 then { -1 means recursive call from destructor... 0 is impossible. }
  1066. exit;
  1067. _Release:=interlockeddecrement(frefcount);
  1068. if _Release>0 then
  1069. exit;
  1070. end
  1071. else
  1072. _Release:=0; { Work non-atomically in the common case of refcount = 1 (typical state for the last owner... which is often the only owner). }
  1073. frefcount:=-1; { Prevent recursive _Release from destroying twice (bug 32168). }
  1074. self.destroy;
  1075. end;
  1076. destructor TInterfacedObject.Destroy;
  1077. begin
  1078. // We must explicitly reset. Bug ID 32353
  1079. FRefCount:=0;
  1080. inherited Destroy;
  1081. end;
  1082. procedure TInterfacedObject.AfterConstruction;
  1083. begin
  1084. { we need to fix the refcount we forced in newinstance }
  1085. { further, it must be done in a thread safe way }
  1086. if frefcount=1 then
  1087. frefcount:=0 { Work non-atomically in the common case of refcount = 1 (usual state before AfterConstruction). }
  1088. else
  1089. declocked(frefcount);
  1090. end;
  1091. procedure TInterfacedObject.BeforeDestruction;
  1092. begin
  1093. if frefcount>0 then { Legitimate values: -1 if destroying by _Release, 0 if destroying manually. }
  1094. HandleError(204);
  1095. end;
  1096. class function TInterfacedObject.NewInstance : TObject;
  1097. begin
  1098. NewInstance:=inherited NewInstance;
  1099. if NewInstance<>nil then
  1100. TInterfacedObject(NewInstance).frefcount:=1;
  1101. end;
  1102. {****************************************************************************
  1103. TAGGREGATEDOBJECT
  1104. ****************************************************************************}
  1105. constructor TAggregatedObject.Create(const aController: IUnknown);
  1106. begin
  1107. inherited Create;
  1108. { do not keep a counted reference to the controller! }
  1109. fcontroller := Pointer(aController);
  1110. end;
  1111. function TAggregatedObject.QueryInterface(
  1112. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1113. begin
  1114. Result := IUnknown(fcontroller).QueryInterface(iid, obj);
  1115. end;
  1116. function TAggregatedObject._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1117. begin
  1118. Result := IUnknown(fcontroller)._AddRef;
  1119. end;
  1120. function TAggregatedObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1121. begin
  1122. Result := IUnknown(fcontroller)._Release;
  1123. end;
  1124. function TAggregatedObject.GetController : IUnknown;
  1125. begin
  1126. Result := IUnknown(fcontroller);
  1127. end;
  1128. {****************************************************************************
  1129. TContainedOBJECT
  1130. ****************************************************************************}
  1131. function TContainedObject.QueryInterface(
  1132. {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1133. begin
  1134. if getinterface(iid,obj) then
  1135. result:=S_OK
  1136. else
  1137. result:=longint(E_NOINTERFACE);
  1138. end;
  1139. {****************************************************************************
  1140. TNoRefCountObject
  1141. ****************************************************************************}
  1142. function TNoRefCountObject.QueryInterface( {$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1143. begin
  1144. if getinterface(iid,obj) then
  1145. result:=S_OK
  1146. else
  1147. result:=longint(E_NOINTERFACE);
  1148. end;
  1149. function TNoRefCountObject._AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1150. begin
  1151. Result:=-1;
  1152. end;
  1153. function TNoRefCountObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1154. begin
  1155. Result:=-1;
  1156. end;
  1157. {****************************************************************************
  1158. TCustomAttribute
  1159. ****************************************************************************}
  1160. constructor TCustomAttribute.Create;
  1161. begin
  1162. inherited;
  1163. end;
  1164. {****************************************************************************
  1165. TUnimplementedAttribute
  1166. ****************************************************************************}
  1167. constructor TUnimplementedAttribute.Create;
  1168. begin
  1169. inherited;
  1170. end;
  1171. {****************************************************************************
  1172. TCustomStoredAttribute
  1173. ****************************************************************************}
  1174. constructor StoredAttribute.Create;
  1175. begin
  1176. end;
  1177. constructor StoredAttribute.Create(Const aFlag : Boolean);
  1178. begin
  1179. FFlag:=aFlag;
  1180. end;
  1181. constructor StoredAttribute.Create(Const aName : shortstring);
  1182. begin
  1183. FName:=aName;
  1184. end;
  1185. {****************************************************************************
  1186. TInterfaceThunk
  1187. ****************************************************************************}
  1188. Constructor TInterfaceThunk.Create(aCallback : TThunkCallback);
  1189. begin
  1190. FCallBack:=aCallBack;
  1191. end;
  1192. Procedure TInterfaceThunk.Thunk(aMethod: Longint; aCount : Longint; aData : PArgData);
  1193. begin
  1194. if Assigned(FCallBack) then
  1195. FCallBack(Self,aMethod,aCount,aData);
  1196. end;
  1197. function TInterfaceThunk.QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  1198. begin
  1199. result:=longint(E_NOINTERFACE);
  1200. if (TMethod(FCallBack).Data<>Nil) then
  1201. // Query the object that created us, this is normally TVirtualInterface
  1202. // Take care: do not call QueryInterface, that would create a never-ending loop !!
  1203. if TObject(TMethod(FCallBack).Data).GetInterface(iid,obj) then
  1204. result:=S_OK;
  1205. if (Result<>S_OK) then
  1206. Result:=Inherited QueryInterface(iid,obj);
  1207. if (Result<>S_OK) and Assigned(OnQueryInterface) then
  1208. OnQueryInterface(iid,Result,obj);
  1209. end;
  1210. function TInterfaceThunk.InterfaceVMTOffset : word;
  1211. begin
  1212. Result:=0;
  1213. end;
  1214. {****************************************************************************
  1215. Exception Support
  1216. ****************************************************************************}
  1217. {$ifdef FPC_HAS_FEATURE_EXCEPTIONS}
  1218. {$if defined(FPC_WASM_EXNREF_EXCEPTIONS)}
  1219. {$I except_exnref.inc}
  1220. {$elseif defined(FPC_WASM_LEGACY_EXCEPTIONS)}
  1221. {$I except_legacy.inc}
  1222. {$elseif defined(FPC_WASM_BRANCHFUL_EXCEPTIONS)}
  1223. {$I except_branchful.inc}
  1224. {$else}
  1225. {$i except.inc}
  1226. {$endif}
  1227. {$endif FPC_HAS_FEATURE_EXCEPTIONS}
  1228. {****************************************************************************
  1229. Various Delphi constructs
  1230. ****************************************************************************}
  1231. class operator TMethod.=(const aLeft, aRight: TMethod): Boolean; inline;
  1232. begin
  1233. Result:=(aLeft.Data=aRight.Data) and (aLeft.Code=aRight.Code);
  1234. end;
  1235. class operator TMethod.<>(const aLeft, aRight: TMethod): Boolean; inline;
  1236. begin
  1237. Result:=(aLeft.Data<>aRight.Data) or (aLeft.Code<>aRight.Code);
  1238. end;
  1239. class operator TMethod.>(const aLeft, aRight: TMethod): Boolean; inline;
  1240. begin
  1241. Result:=(PtrUInt(aLeft.Data)>PtrUInt(aRight.Data))
  1242. or
  1243. ((aLeft.Data=aRight.Data) and (PtrUInt(aLeft.Code)>PtrUint(aRight.Code)));
  1244. end;
  1245. class operator TMethod.>=(const aLeft, aRight: TMethod): Boolean; inline;
  1246. begin
  1247. Result:=(aLeft>aRight) or (aLeft=aRight);
  1248. end;
  1249. class operator TMethod.<(const aLeft, aRight: TMethod): Boolean; inline;
  1250. begin
  1251. Result:=(PtrUInt(aLeft.Data)<PtrUInt(aRight.Data))
  1252. or
  1253. ((aLeft.Data=aRight.Data) and (PtrUInt(aLeft.Code)<PtrUint(aRight.Code)));
  1254. end;
  1255. class operator TMethod.<=(const aLeft, aRight: TMethod): Boolean; inline;
  1256. begin
  1257. Result:=(aLeft<aRight) or (aLeft=aRight);
  1258. end;
  1259. function TPtrWrapper.ToPointer: Pointer;
  1260. begin
  1261. Result:=FValue;
  1262. end;
  1263. class function TPtrWrapper.GetNilValue: TPtrWrapper;
  1264. begin
  1265. Result.FValue:=Nil;
  1266. end;
  1267. constructor TPtrWrapper.Create(AValue: PtrInt);
  1268. begin
  1269. FValue:=Pointer(aValue);
  1270. end;
  1271. constructor TPtrWrapper.Create(AValue: Pointer);
  1272. begin
  1273. FValue:=aValue;
  1274. end;
  1275. function TPtrWrapper.ToInteger: PtrInt;
  1276. begin
  1277. Result:=PtrInt(FValue);
  1278. end;
  1279. class operator TPtrWrapper.=(Left, Right: TPtrWrapper): Boolean;
  1280. begin
  1281. Result:=Left.FValue=Right.FValue;
  1282. end;
  1283. constructor TMarshal.Create;
  1284. begin
  1285. System.Error(reInvalidPtr);
  1286. end;
  1287. class function TMarshal.AllocMem(Size: SizeInt): TPtrWrapper;
  1288. begin
  1289. Result.Value := System.AllocMem(Size);
  1290. end;
  1291. class function TMarshal.ReallocMem(OldPtr: TPtrWrapper; NewSize: SizeInt): TPtrWrapper;
  1292. var
  1293. P: Pointer;
  1294. begin
  1295. P := OldPtr.Value;
  1296. Result.Value := System.ReallocMem(P, NewSize);
  1297. end;
  1298. class procedure TMarshal.FreeMem(Ptr: TPtrWrapper);
  1299. begin
  1300. System.FreeMem(Ptr.Value);
  1301. end;
  1302. class procedure TMarshal.Move(Src, Dest: TPtrWrapper; Count: SizeInt); static;
  1303. begin
  1304. System.Move(Src.Value^, Dest.Value^, Count);
  1305. end;
  1306. class function TMarshal.UnsafeAddrOf(var Value): TPtrWrapper;
  1307. begin
  1308. Result.Value := @Value;
  1309. end;
  1310. class procedure TMarshal.Copy(const Src: TUint8Array; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1311. begin
  1312. System.Move(PUInt8(Src)[StartIndex], Dest.Value^, Count * SizeOf(UInt8));
  1313. end;
  1314. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TUint8Array; StartIndex: SizeInt; Count: SizeInt);
  1315. begin
  1316. System.Move(Src.Value^, PUInt8(Dest)[StartIndex], Count * SizeOf(UInt8));
  1317. end;
  1318. class procedure TMarshal.Copy(const Src: TInt8Array; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1319. begin
  1320. System.Move(PInt8(Src)[StartIndex], Dest.Value^, Count * SizeOf(Int8));
  1321. end;
  1322. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TInt8Array ; StartIndex: SizeInt; Count: SizeInt);
  1323. begin
  1324. System.Move(Src.Value^, PInt8(Dest)[StartIndex], Count * SizeOf(Int8));
  1325. end;
  1326. class procedure TMarshal.Copy(const Src: TUInt16Array; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1327. begin
  1328. System.Move(PUInt16(Src)[StartIndex], Dest.Value^, Count * SizeOf(UInt16));
  1329. end;
  1330. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TUint16Array; StartIndex: SizeInt; Count: SizeInt);
  1331. begin
  1332. System.Move(Src.Value^, PUInt16(Dest)[StartIndex], Count * SizeOf(UInt16));
  1333. end;
  1334. class procedure TMarshal.Copy(const Src: TInt16Array; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1335. begin
  1336. System.Move(PInt16(Src)[StartIndex], Dest.Value^, Count * SizeOf(Int16));
  1337. end;
  1338. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TInt16Array; StartIndex: SizeInt; Count: SizeInt);
  1339. begin
  1340. System.Move(Src.Value^, PInt16(Dest)[StartIndex], Count * SizeOf(Int16));
  1341. end;
  1342. class procedure TMarshal.Copy(const Src: TInt32Array; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1343. begin
  1344. System.Move(PInt32(Src)[StartIndex], Dest.Value^, Count * SizeOf(Int32));
  1345. end;
  1346. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TInt32Array; StartIndex: SizeInt; Count: SizeInt);
  1347. begin
  1348. System.Move(Src.Value^, PInt32(Dest)[StartIndex], Count * SizeOf(Int32));
  1349. end;
  1350. class procedure TMarshal.Copy(const Src: TInt64Array; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1351. begin
  1352. System.Move(PInt64(Src)[StartIndex], Dest.Value^, Count * SizeOf(Int64));
  1353. end;
  1354. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TInt64Array; StartIndex: SizeInt; Count: SizeInt);
  1355. begin
  1356. System.Move(Src.Value^, PInt64(Dest)[StartIndex], Count * SizeOf(Int64));
  1357. end;
  1358. class procedure TMarshal.Copy(const Src: TPtrWrapperArray; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1359. begin
  1360. System.Move(PPointer(Src)[StartIndex], Dest.Value^, Count * SizeOf(TPtrWrapper));
  1361. end;
  1362. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TPtrWrapperArray; StartIndex: SizeInt; Count: SizeInt);
  1363. begin
  1364. System.Move(Src.Value^, PPointer(Dest)[StartIndex], Count * SizeOf(TPtrWrapper));
  1365. end;
  1366. generic class function TMarshal.FixArray<T>(const Arr: specialize TArray<T>): TPtrWrapper;
  1367. begin
  1368. Result.Value := nil;
  1369. specialize TArray<T>(Result) := Arr;
  1370. end;
  1371. generic class procedure TMarshal.UnfixArray<T>(ArrPtr: TPtrWrapper);
  1372. begin
  1373. Finalize(specialize TArray<T>(ArrPtr));
  1374. end;
  1375. class function TMarshal.ReadByte(Ptr: TPtrWrapper; Ofs: SizeInt = 0): Byte;
  1376. begin
  1377. Result := PByte(Ptr.Value + Ofs)^;
  1378. end;
  1379. class procedure TMarshal.WriteByte(Ptr: TPtrWrapper; Ofs: SizeInt; Value: Byte);
  1380. begin
  1381. PByte(Ptr.Value + Ofs)^ := Value;
  1382. end;
  1383. class procedure TMarshal.WriteByte(Ptr: TPtrWrapper; Value: Byte);
  1384. begin
  1385. PByte(Ptr.Value)^ := Value;
  1386. end;
  1387. class function TMarshal.ReadInt16(Ptr: TPtrWrapper; Ofs: SizeInt = 0): Int16;
  1388. begin
  1389. Result := PInt16(Ptr.Value + Ofs)^;
  1390. end;
  1391. class procedure TMarshal.WriteInt16(Ptr: TPtrWrapper; Ofs: SizeInt; Value: Int16);
  1392. begin
  1393. PInt16(Ptr.Value + Ofs)^ := Value;
  1394. end;
  1395. class procedure TMarshal.WriteInt16(Ptr: TPtrWrapper; Value: Int16);
  1396. begin
  1397. PInt16(Ptr.Value)^ := Value;
  1398. end;
  1399. class function TMarshal.ReadInt32(Ptr: TPtrWrapper; Ofs: SizeInt = 0): Int32;
  1400. begin
  1401. Result := PInt32(Ptr.Value + Ofs)^;
  1402. end;
  1403. class procedure TMarshal.WriteInt32(Ptr: TPtrWrapper; Ofs: SizeInt; Value: Int32);
  1404. begin
  1405. PInt32(Ptr.Value + Ofs)^ := Value;
  1406. end;
  1407. class procedure TMarshal.WriteInt32(Ptr: TPtrWrapper; Value: Int32);
  1408. begin
  1409. PInt32(Ptr.Value)^ := Value;
  1410. end;
  1411. class function TMarshal.ReadInt64(Ptr: TPtrWrapper; Ofs: SizeInt = 0): Int64;
  1412. begin
  1413. Result := PInt64(Ptr.Value + Ofs)^;
  1414. end;
  1415. class procedure TMarshal.WriteInt64(Ptr: TPtrWrapper; Ofs: SizeInt; Value: Int64);
  1416. begin
  1417. PInt64(Ptr.Value + Ofs)^ := Value;
  1418. end;
  1419. class procedure TMarshal.WriteInt64(Ptr: TPtrWrapper; Value: Int64);
  1420. begin
  1421. PInt64(Ptr.Value)^ := Value;
  1422. end;
  1423. class function TMarshal.ReadPtr(Ptr: TPtrWrapper; Ofs: SizeInt = 0): TPtrWrapper;
  1424. begin
  1425. Result.Value := PPointer(Ptr.Value + Ofs)^;
  1426. end;
  1427. class procedure TMarshal.WritePtr(Ptr: TPtrWrapper; Ofs: SizeInt; Value: TPtrWrapper);
  1428. begin
  1429. PPointer(Ptr.Value + Ofs)^ := Value.Value;
  1430. end;
  1431. class procedure TMarshal.WritePtr(Ptr, Value: TPtrWrapper);
  1432. begin
  1433. PPointer(Ptr.Value)^ := Value.Value;
  1434. end;
  1435. {$IFDEF FPC_HAS_FEATURE_UNICODESTRINGS}
  1436. class function TMarshal.AsAnsi(const S: UnicodeString): AnsiString;
  1437. begin
  1438. Result := AnsiString(S);
  1439. end;
  1440. class function TMarshal.AsAnsi(S: PUnicodeChar): AnsiString;
  1441. begin
  1442. result := AnsiString(S);
  1443. end;
  1444. class function TMarshal.InOutString(const S: UnicodeString): PUnicodeChar;
  1445. begin
  1446. Result := PUnicodeChar(S);
  1447. end;
  1448. class function TMarshal.InString(const S: UnicodeString): PUnicodeChar;
  1449. begin
  1450. Result := PUnicodeChar(S);
  1451. end;
  1452. class function TMarshal.OutString(const S: UnicodeString): PUnicodeChar;
  1453. begin
  1454. Result := PUnicodeChar(S);
  1455. end;
  1456. class function TMarshal.FixString(var Str: UnicodeString): TPtrWrapper;
  1457. begin
  1458. UniqueString(Str);
  1459. Result := UnsafeFixString(Str);
  1460. end;
  1461. class procedure TMarshal.UnfixString(Ptr: TPtrWrapper);
  1462. begin
  1463. if Ptr.Value <> PUnicodeChar('') then
  1464. Finalize(UnicodeString(Ptr));
  1465. end;
  1466. class function TMarshal.UnsafeFixString(const Str: UnicodeString): TPtrWrapper;
  1467. begin
  1468. if Length(Str) = 0 then
  1469. begin
  1470. Result.Value := PUnicodeChar('');
  1471. Exit;
  1472. end;
  1473. Result.Value := nil;
  1474. UnicodeString(Result) := Str;
  1475. end;
  1476. class function TMarshal.AllocStringAsAnsi(const Str: UnicodeString): TPtrWrapper;
  1477. begin
  1478. Result := AllocStringAsAnsi(PUnicodeChar(Pointer(Str)), Length(Str), DefaultSystemCodePage);
  1479. end;
  1480. class function TMarshal.AllocStringAsAnsi(const Str: UnicodeString; CodePage: Word): TPtrWrapper;
  1481. begin
  1482. Result := AllocStringAsAnsi(PUnicodeChar(Pointer(Str)), Length(Str), CodePage);
  1483. end;
  1484. class function TMarshal.AllocStringAsAnsi(S: PUnicodeChar): TPtrWrapper;
  1485. begin
  1486. Result := AllocStringAsAnsi(S, Length(S), DefaultSystemCodePage);
  1487. end;
  1488. class function TMarshal.AllocStringAsAnsi(S: PUnicodeChar; CodePage: Word): TPtrWrapper;
  1489. begin
  1490. Result := AllocStringAsAnsi(S, Length(S), CodePage);
  1491. end;
  1492. class function TMarshal.AllocStringAsUnicode(const Str: UnicodeString): TPtrWrapper;
  1493. var
  1494. NBytes: SizeUint;
  1495. begin
  1496. NBytes := (Length(Str) + 1) * SizeOf(UnicodeChar);
  1497. Result.Value := System.GetMem(NBytes);
  1498. System.Move(PUnicodeChar(Str)^, Result.Value^, NBytes);
  1499. end;
  1500. class function TMarshal.AllocStringAsUtf8(const Str: UnicodeString): TPtrWrapper;
  1501. begin
  1502. Result := AllocStringAsAnsi(PUnicodeChar(Pointer(Str)), Length(Str), CP_UTF8);
  1503. end;
  1504. class function TMarshal.AllocStringAsUtf8(S: PUnicodeChar): TPtrWrapper;
  1505. begin
  1506. Result := AllocStringAsAnsi(S, Length(S), CP_UTF8);
  1507. end;
  1508. class function TMarshal.AllocStringAsAnsi(S: PUnicodeChar; Len: SizeInt; CodePage: Word): TPtrWrapper;
  1509. var
  1510. U2ARes: AnsiString;
  1511. NBytes: SizeInt;
  1512. begin
  1513. U2ARes := ''; { Suppress warning. }
  1514. WideStringManager.Unicode2AnsiMoveProc(S, U2ARes, CodePage, Len);
  1515. if Length(U2ARes) = 0 then
  1516. begin
  1517. Result.Value := nil;
  1518. Exit;
  1519. end;
  1520. { Could instead avoid the second allocation, assuming U2ARes.RefCount = 1:
  1521. System.Move(Pointer(U2ARes)^, (Pointer(U2ARes) - AnsiStringHeaderSize)^, (Length(U2ARes) + 1) * SizeOf(AnsiChar));
  1522. Result.FValue := Pointer(U2ARes) - AnsiStringHeaderSize;
  1523. Pointer(U2ARes) := nil; }
  1524. NBytes := (Length(U2ARes) + 1) * SizeOf(AnsiChar);
  1525. Result.Value := System.GetMem(NBytes);
  1526. System.Move(PAnsiChar(U2ARes)^, Result.Value^, NBytes);
  1527. end;
  1528. class procedure TMarshal.Copy(const Src: TUnicodeCharArray; StartIndex: SizeInt; Dest: TPtrWrapper; Count: SizeInt);
  1529. begin
  1530. System.Move(PUnicodeChar(Src)[StartIndex], Dest.Value^, Count * SizeOf(UnicodeChar));
  1531. end;
  1532. class procedure TMarshal.Copy(Src: TPtrWrapper; var Dest: TUnicodeCharArray; StartIndex: SizeInt; Count: SizeInt);
  1533. begin
  1534. System.Move(Src.Value^, PUnicodeChar(Dest)[StartIndex], Count * SizeOf(UnicodeChar));
  1535. end;
  1536. class function TMarshal.ReadStringAsAnsi(Ptr: TPtrWrapper; Len: SizeInt = -1): UnicodeString;
  1537. begin
  1538. Result := ReadStringAsAnsi(DefaultSystemCodePage, Ptr, Len);
  1539. end;
  1540. class function TMarshal.ReadStringAsAnsi(CodePage: Word; Ptr: TPtrWrapper; Len: SizeInt = -1): UnicodeString;
  1541. begin
  1542. { Here and below, IndexByte/Word assume that, when Len >= 0, either:
  1543. - Up to Len characters are accessible in Ptr;
  1544. - IndexByte/Word cannot access invalid memory past the searched character
  1545. (e.g. i386.inc and x86_64.inc IndexByte/Word versions are specifically designed not to). }
  1546. if Len < 0 then
  1547. Len := IndexByte(Ptr.Value^, Len, 0);
  1548. Result := ''; { Suppress warning. }
  1549. WideStringManager.Ansi2UnicodeMoveProc(Ptr.Value, CodePage, Result, Len);
  1550. end;
  1551. class function TMarshal.ReadStringAsAnsiUpTo(CodePage: Word; Ptr: TPtrWrapper; MaxLen: SizeInt): UnicodeString;
  1552. var
  1553. Len: SizeInt;
  1554. begin
  1555. Len := IndexByte(Ptr.Value^, MaxLen, 0);
  1556. if Len < 0 then
  1557. Len := MaxLen;
  1558. Result := ReadStringAsAnsi(CodePage, Ptr, Len);
  1559. end;
  1560. class procedure TMarshal.WriteStringAsAnsi(Ptr: TPtrWrapper; const Value: UnicodeString; MaxCharsIncNull: SizeInt);
  1561. begin
  1562. WriteStringAsAnsi(Ptr, 0, Value, MaxCharsIncNull, DefaultSystemCodePage);
  1563. end;
  1564. class procedure TMarshal.WriteStringAsAnsi(Ptr: TPtrWrapper; const Value: UnicodeString; MaxCharsIncNull: SizeInt; CodePage: Word);
  1565. begin
  1566. WriteStringAsAnsi(Ptr, 0, Value, MaxCharsIncNull, CodePage);
  1567. end;
  1568. class procedure TMarshal.WriteStringAsAnsi(Ptr: TPtrWrapper; Ofs: SizeInt; const Value: UnicodeString; MaxCharsIncNull: SizeInt);
  1569. begin
  1570. WriteStringAsAnsi(Ptr, Ofs, Value, MaxCharsIncNull, DefaultSystemCodePage);
  1571. end;
  1572. class procedure TMarshal.WriteStringAsAnsi(Ptr: TPtrWrapper; Ofs: SizeInt; const Value: UnicodeString; MaxCharsIncNull: SizeInt; CodePage: Word);
  1573. var
  1574. U2ARes: AnsiString;
  1575. ValueLen, U2AResLen: SizeInt;
  1576. begin
  1577. U2ARes := ''; { Suppress warning. }
  1578. ValueLen := Length(Value);
  1579. { Delphi null-terminates iff MaxCharsIncNull < 0, so MaxCharsIncNull is actually just MaxChars. }
  1580. if (MaxCharsIncNull > 0) and (MaxCharsIncNull < ValueLen) then
  1581. ValueLen := MaxCharsIncNull; { UTF-16 → ANSI should never shrink element count, so limit the number of characters analyzed. }
  1582. WideStringManager.Unicode2AnsiMoveProc(PUnicodeChar(Pointer(Value)), U2ARes, CodePage, ValueLen);
  1583. U2AResLen := Length(U2ARes);
  1584. if (MaxCharsIncNull >= 0) and (MaxCharsIncNull < U2AResLen) then
  1585. U2AResLen := MaxCharsIncNull;
  1586. System.Move(PAnsiChar(Pointer(U2ARes))^, (Ptr.Value + Ofs)^, U2AResLen * SizeOf(AnsiChar));
  1587. if MaxCharsIncNull < 0 then
  1588. PAnsiChar(Ptr.Value + Ofs)[U2AResLen] := #0;
  1589. end;
  1590. class function TMarshal.ReadStringAsUnicode(Ptr: TPtrWrapper; Len: SizeInt = -1): UnicodeString;
  1591. begin
  1592. if Len < 0 then
  1593. Len := Length(PUnicodeChar(Ptr.Value));
  1594. Result := ''; { Suppress warning. }
  1595. SetLength(Result, Len);
  1596. System.Move(Ptr.Value^, Pointer(Result)^, Len * SizeOf(UnicodeChar));
  1597. end;
  1598. class function TMarshal.ReadStringAsUnicodeUpTo(Ptr: TPtrWrapper; MaxLen: SizeInt): UnicodeString;
  1599. var
  1600. Len: SizeInt;
  1601. begin
  1602. Len := IndexWord(Ptr.Value^, MaxLen, 0);
  1603. if Len < 0 then
  1604. Len := MaxLen;
  1605. Result := ReadStringAsUnicode(Ptr, Len);
  1606. end;
  1607. class procedure TMarshal.WriteStringAsUnicode(Ptr: TPtrWrapper; const Value: UnicodeString; MaxCharsIncNull: SizeInt);
  1608. begin
  1609. WriteStringAsUnicode(Ptr, 0, Value, MaxCharsIncNull);
  1610. end;
  1611. class procedure TMarshal.WriteStringAsUnicode(Ptr: TPtrWrapper; Ofs: SizeInt; const Value: UnicodeString; MaxCharsIncNull: SizeInt);
  1612. var
  1613. Len: SizeInt;
  1614. begin
  1615. { Again, Delphi null-terminates iff MaxCharsIncNull < 0, so MaxCharsIncNull is actually just MaxChars. }
  1616. Len := Length(Value);
  1617. if (MaxCharsIncNull >= 0) and (MaxCharsIncNull < Len) then
  1618. Len := MaxCharsIncNull;
  1619. System.Move(Pointer(Value)^, (Ptr.Value + Ofs)^, Len * SizeOf(UnicodeChar));
  1620. if MaxCharsIncNull < 0 then
  1621. PUnicodeChar(Ptr.Value + Ofs)[Len] := #0;
  1622. end;
  1623. class function TMarshal.ReadStringAsUtf8(Ptr: TPtrWrapper; Len: SizeInt = -1): UnicodeString;
  1624. begin
  1625. Result := ReadStringAsAnsi(CP_UTF8, Ptr, Len);
  1626. end;
  1627. class function TMarshal.ReadStringAsUtf8UpTo(Ptr: TPtrWrapper; MaxLen: SizeInt): UnicodeString;
  1628. begin
  1629. Result := ReadStringAsAnsiUpTo(CP_UTF8, Ptr, MaxLen);
  1630. end;
  1631. class procedure TMarshal.WriteStringAsUtf8(Ptr: TPtrWrapper; const Value: UnicodeString; MaxCharsIncNull: SizeInt);
  1632. begin
  1633. WriteStringAsAnsi(Ptr, Value, MaxCharsIncNull, CP_UTF8);
  1634. end;
  1635. class procedure TMarshal.WriteStringAsUtf8(Ptr: TPtrWrapper; Ofs: SizeInt; const Value: UnicodeString; MaxCharsIncNull: SizeInt);
  1636. begin
  1637. WriteStringAsAnsi(Ptr, Ofs, Value, MaxCharsIncNull, CP_UTF8);
  1638. end;
  1639. {$ENDIF}
  1640. {$IFDEF SYSTEM_HAS_FEATURE_MONITOR}
  1641. {$i monitor.inc}
  1642. {$ENDIF}