/jcl/source/common/JclSysUtils.pas

https://github.com/project-jedi/jcl · Pascal · 4540 lines · 3632 code · 377 blank · 531 comment · 174 complexity · 00573b12b18ba02a8212f58df1790e9a MD5 · raw file

Large files are truncated click here to view the full file

  1. {**************************************************************************************************}
  2. { }
  3. { Project JEDI Code Library (JCL) }
  4. { }
  5. { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
  6. { you may not use this file except in compliance with the License. You may obtain a copy of the }
  7. { License at http://www.mozilla.org/MPL/ }
  8. { }
  9. { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
  10. { ANY KIND, either express or implied. See the License for the specific language governing rights }
  11. { and limitations under the License. }
  12. { }
  13. { The Original Code is JclSysUtils.pas. }
  14. { }
  15. { The Initial Developer of the Original Code is Marcel van Brakel. }
  16. { Portions created by Marcel van Brakel are Copyright (C) Marcel van Brakel. All rights reserved. }
  17. { }
  18. { Contributors: }
  19. { Alexander Radchenko, }
  20. { Andreas Hausladen (ahuser) }
  21. { Anthony Steele }
  22. { Bernhard Berger }
  23. { Heri Bender }
  24. { Jean-Fabien Connault (cycocrew) }
  25. { Jens Fudickar }
  26. { Jeroen Speldekamp }
  27. { Marcel van Brakel }
  28. { Peter Friese }
  29. { Petr Vones (pvones) }
  30. { Python }
  31. { Robert Marquardt (marquardt) }
  32. { Robert R. Marsh }
  33. { Robert Rossmair (rrossmair) }
  34. { Rudy Velthuis }
  35. { Uwe Schuster (uschuster) }
  36. { Wayne Sherman }
  37. { }
  38. {**************************************************************************************************}
  39. { }
  40. { Description: Various pointer and class related routines. }
  41. { }
  42. {**************************************************************************************************}
  43. { }
  44. { Last modified: $Date:: $ }
  45. { Revision: $Rev:: $ }
  46. { Author: $Author:: $ }
  47. { }
  48. {**************************************************************************************************}
  49. unit JclSysUtils;
  50. {$I jcl.inc}
  51. interface
  52. uses
  53. {$IFDEF UNITVERSIONING}
  54. JclUnitVersioning,
  55. {$ENDIF UNITVERSIONING}
  56. {$IFDEF HAS_UNITSCOPE}
  57. {$IFDEF MSWINDOWS}
  58. Winapi.Windows,
  59. {$ENDIF MSWINDOWS}
  60. System.SysUtils, System.Classes, System.TypInfo, System.SyncObjs,
  61. {$ELSE ~HAS_UNITSCOPE}
  62. {$IFDEF MSWINDOWS}
  63. Windows,
  64. {$ENDIF MSWINDOWS}
  65. SysUtils, Classes, TypInfo, SyncObjs,
  66. {$ENDIF ~HAS_UNITSCOPE}
  67. JclBase, JclSynch;
  68. // memory initialization
  69. // first parameter is "out" to make FPC happy with uninitialized values
  70. procedure ResetMemory(out P; Size: Longint);
  71. // Pointer manipulation
  72. procedure GetAndFillMem(var P: Pointer; const Size: Integer; const Value: Byte);
  73. procedure FreeMemAndNil(var P: Pointer);
  74. function PCharOrNil(const S: string): PChar;
  75. function PAnsiCharOrNil(const S: AnsiString): PAnsiChar;
  76. {$IFDEF SUPPORTS_WIDESTRING}
  77. function PWideCharOrNil(const W: WideString): PWideChar;
  78. {$ENDIF SUPPORTS_WIDESTRING}
  79. function SizeOfMem(const APointer: Pointer): Integer;
  80. function WriteProtectedMemory(BaseAddress, Buffer: Pointer; Size: Cardinal;
  81. out WrittenBytes: Cardinal): Boolean;
  82. // Guards
  83. type
  84. ISafeGuard = interface
  85. function ReleaseItem: Pointer;
  86. function GetItem: Pointer;
  87. procedure FreeItem;
  88. property Item: Pointer read GetItem;
  89. end;
  90. IMultiSafeGuard = interface (IInterface)
  91. function AddItem(Item: Pointer): Pointer;
  92. procedure FreeItem(Index: Integer);
  93. function GetCount: Integer;
  94. function GetItem(Index: Integer): Pointer;
  95. function ReleaseItem(Index: Integer): Pointer;
  96. property Count: Integer read GetCount;
  97. property Items[Index: Integer]: Pointer read GetItem;
  98. end;
  99. TJclSafeGuard = class(TInterfacedObject, ISafeGuard)
  100. private
  101. FItem: Pointer;
  102. public
  103. constructor Create(Mem: Pointer);
  104. destructor Destroy; override;
  105. { ISafeGuard }
  106. function ReleaseItem: Pointer;
  107. function GetItem: Pointer;
  108. procedure FreeItem; virtual;
  109. property Item: Pointer read GetItem;
  110. end;
  111. TJclObjSafeGuard = class(TJclSafeGuard, ISafeGuard)
  112. public
  113. constructor Create(Obj: TObject);
  114. { ISafeGuard }
  115. procedure FreeItem; override;
  116. end;
  117. TJclMultiSafeGuard = class(TInterfacedObject, IMultiSafeGuard)
  118. private
  119. FItems: TList;
  120. public
  121. constructor Create;
  122. destructor Destroy; override;
  123. { IMultiSafeGuard }
  124. function AddItem(Item: Pointer): Pointer;
  125. procedure FreeItem(Index: Integer); virtual;
  126. function GetCount: Integer;
  127. function GetItem(Index: Integer): Pointer;
  128. function ReleaseItem(Index: Integer): Pointer;
  129. property Count: Integer read GetCount;
  130. property Items[Index: Integer]: Pointer read GetItem;
  131. end;
  132. TJclObjMultiSafeGuard = class(TJclMultiSafeGuard, IMultiSafeGuard)
  133. public
  134. { IMultiSafeGuard }
  135. procedure FreeItem(Index: Integer); override;
  136. end;
  137. function Guard(Mem: Pointer; out SafeGuard: ISafeGuard): Pointer; overload;
  138. function Guard(Obj: TObject; out SafeGuard: ISafeGuard): TObject; overload;
  139. function Guard(Mem: Pointer; var SafeGuard: IMultiSafeGuard): Pointer; overload;
  140. function Guard(Obj: TObject; var SafeGuard: IMultiSafeGuard): TObject; overload;
  141. function GuardGetMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;
  142. function GuardAllocMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;
  143. (*
  144. {$IFDEF SUPPORTS_GENERICS}
  145. type
  146. ISafeGuard<T: class> = interface
  147. function ReleaseItem: T;
  148. function GetItem: T;
  149. procedure FreeItem;
  150. property Item: T read GetItem;
  151. end;
  152. TSafeGuard<T: class> = class(TObject, ISafeGuard<T>)
  153. private
  154. FItem: T;
  155. function ReleaseItem: T;
  156. function GetItem: T;
  157. procedure FreeItem;
  158. constructor Create(Instance: T);
  159. destructor Destroy; override;
  160. public
  161. class function New(Instance: T): ISafeGuard<T>; static;
  162. end;
  163. {$ENDIF SUPPORTS_GENERICS}
  164. *)
  165. { Shared memory between processes functions }
  166. // Functions for the shared memory owner
  167. type
  168. ESharedMemError = class(EJclError);
  169. {$IFDEF MSWINDOWS}
  170. { SharedGetMem return ERROR_ALREADY_EXISTS if the shared memory is already
  171. allocated, otherwise it returns 0.
  172. Throws ESharedMemError if the Name is invalid. }
  173. function SharedGetMem(var P{: Pointer}; const Name: string; Size: Cardinal;
  174. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Integer;
  175. { SharedAllocMem calls SharedGetMem and then fills the memory with zero if
  176. it was not already allocated.
  177. Throws ESharedMemError if the Name is invalid. }
  178. function SharedAllocMem(const Name: string; Size: Cardinal;
  179. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer;
  180. { SharedFreeMem releases the shared memory if it was the last reference. }
  181. function SharedFreeMem(var P{: Pointer}): Boolean;
  182. // Functions for the shared memory user
  183. { SharedOpenMem returns True if the shared memory was already allocated by
  184. SharedGetMem or SharedAllocMem. Otherwise it returns False.
  185. Throws ESharedMemError if the Name is invalid. }
  186. function SharedOpenMem(var P{: Pointer}; const Name: string;
  187. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Boolean; overload;
  188. { SharedOpenMem return nil if the shared memory was not already allocated
  189. by SharedGetMem or SharedAllocMem.
  190. Throws ESharedMemError if the Name is invalid. }
  191. function SharedOpenMem(const Name: string;
  192. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer; overload;
  193. { SharedCloseMem releases the shared memory if it was the last reference. }
  194. function SharedCloseMem(var P{: Pointer}): Boolean;
  195. {$ENDIF MSWINDOWS}
  196. // Binary search
  197. function SearchSortedList(List: TList; SortFunc: TListSortCompare; Item: Pointer;
  198. Nearest: Boolean = False): Integer;
  199. type
  200. TUntypedSearchCompare = function(Param: Pointer; ItemIndex: Integer; const Value): Integer;
  201. function SearchSortedUntyped(Param: Pointer; ItemCount: Integer; SearchFunc: TUntypedSearchCompare;
  202. const Value; Nearest: Boolean = False): Integer;
  203. // Dynamic array sort and search routines
  204. type
  205. TDynArraySortCompare = function (Item1, Item2: Pointer): Integer;
  206. procedure SortDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare);
  207. // Usage: SortDynArray(Array, SizeOf(Array[0]), SortFunction);
  208. function SearchDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare;
  209. ValuePtr: Pointer; Nearest: Boolean = False): SizeInt;
  210. // Usage: SearchDynArray(Array, SizeOf(Array[0]), SortFunction, @SearchedValue);
  211. { Various compare functions for basic types }
  212. function DynArrayCompareByte(Item1, Item2: Pointer): Integer;
  213. function DynArrayCompareShortInt(Item1, Item2: Pointer): Integer;
  214. function DynArrayCompareWord(Item1, Item2: Pointer): Integer;
  215. function DynArrayCompareSmallInt(Item1, Item2: Pointer): Integer;
  216. function DynArrayCompareInteger(Item1, Item2: Pointer): Integer;
  217. function DynArrayCompareCardinal(Item1, Item2: Pointer): Integer;
  218. function DynArrayCompareInt64(Item1, Item2: Pointer): Integer;
  219. function DynArrayCompareSingle(Item1, Item2: Pointer): Integer;
  220. function DynArrayCompareDouble(Item1, Item2: Pointer): Integer;
  221. function DynArrayCompareExtended(Item1, Item2: Pointer): Integer;
  222. function DynArrayCompareFloat(Item1, Item2: Pointer): Integer;
  223. function DynArrayCompareAnsiString(Item1, Item2: Pointer): Integer;
  224. function DynArrayCompareAnsiText(Item1, Item2: Pointer): Integer;
  225. function DynArrayCompareWideString(Item1, Item2: Pointer): Integer;
  226. function DynArrayCompareWideText(Item1, Item2: Pointer): Integer;
  227. function DynArrayCompareString(Item1, Item2: Pointer): Integer;
  228. function DynArrayCompareText(Item1, Item2: Pointer): Integer;
  229. // Object lists
  230. procedure ClearObjectList(List: TList);
  231. procedure FreeObjectList(var List: TList);
  232. // Reference memory stream
  233. type
  234. TJclReferenceMemoryStream = class(TCustomMemoryStream)
  235. public
  236. constructor Create(const Ptr: Pointer; Size: Longint);
  237. function Write(const Buffer; Count: Longint): Longint; override;
  238. end;
  239. // AutoPtr
  240. type
  241. IAutoPtr = interface
  242. { Returns the object as pointer, so it is easier to assign it to a variable }
  243. function AsPointer: Pointer;
  244. { Returns the AutoPtr handled object }
  245. function AsObject: TObject;
  246. { Releases the object from the AutoPtr. The AutoPtr looses the control over
  247. the object. }
  248. function ReleaseObject: TObject;
  249. end;
  250. TJclAutoPtr = class(TInterfacedObject, IAutoPtr)
  251. private
  252. FValue: TObject;
  253. public
  254. constructor Create(AValue: TObject);
  255. destructor Destroy; override;
  256. { IAutoPtr }
  257. function AsPointer: Pointer;
  258. function AsObject: TObject;
  259. function ReleaseObject: TObject;
  260. end;
  261. function CreateAutoPtr(Value: TObject): IAutoPtr;
  262. // Replacement for the C ternary conditional operator ? :
  263. function Iff(const Condition: Boolean; const TruePart, FalsePart: string): string; overload;
  264. function Iff(const Condition: Boolean; const TruePart, FalsePart: Char): Char; overload;
  265. function Iff(const Condition: Boolean; const TruePart, FalsePart: Byte): Byte; overload;
  266. function Iff(const Condition: Boolean; const TruePart, FalsePart: Integer): Integer; overload;
  267. function Iff(const Condition: Boolean; const TruePart, FalsePart: Cardinal): Cardinal; overload;
  268. function Iff(const Condition: Boolean; const TruePart, FalsePart: Float): Float; overload;
  269. function Iff(const Condition: Boolean; const TruePart, FalsePart: Boolean): Boolean; overload;
  270. function Iff(const Condition: Boolean; const TruePart, FalsePart: Pointer): Pointer; overload;
  271. function Iff(const Condition: Boolean; const TruePart, FalsePart: Int64): Int64; overload;
  272. {$IFDEF SUPPORTS_VARIANT}
  273. function Iff(const Condition: Boolean; const TruePart, FalsePart: Variant): Variant; overload;
  274. {$ENDIF SUPPORTS_VARIANT}
  275. // Classes information and manipulation
  276. type
  277. EJclVMTError = class(EJclError);
  278. // Virtual Methods
  279. {$IFNDEF FPC}
  280. function GetVirtualMethodCount(AClass: TClass): Integer;
  281. {$ENDIF ~FPC}
  282. function GetVirtualMethod(AClass: TClass; const Index: Integer): Pointer;
  283. procedure SetVirtualMethod(AClass: TClass; const Index: Integer; const Method: Pointer);
  284. // Dynamic Methods
  285. type
  286. TDynamicIndexList = array [0..MaxInt div 16] of Word;
  287. PDynamicIndexList = ^TDynamicIndexList;
  288. TDynamicAddressList = array [0..MaxInt div 16] of Pointer;
  289. PDynamicAddressList = ^TDynamicAddressList;
  290. function GetDynamicMethodCount(AClass: TClass): Integer;
  291. function GetDynamicIndexList(AClass: TClass): PDynamicIndexList;
  292. function GetDynamicAddressList(AClass: TClass): PDynamicAddressList;
  293. function HasDynamicMethod(AClass: TClass; Index: Integer): Boolean;
  294. {$IFNDEF FPC}
  295. function GetDynamicMethod(AClass: TClass; Index: Integer): Pointer;
  296. {$ENDIF ~FPC}
  297. { init table methods }
  298. function GetInitTable(AClass: TClass): PTypeInfo;
  299. { field table methods }
  300. type
  301. PFieldEntry = ^TFieldEntry;
  302. TFieldEntry = packed record
  303. OffSet: Integer;
  304. IDX: Word;
  305. Name: ShortString;
  306. end;
  307. PFieldClassTable = ^TFieldClassTable;
  308. TFieldClassTable = packed record
  309. Count: Smallint;
  310. Classes: array [0..8191] of ^TPersistentClass;
  311. end;
  312. PFieldTable = ^TFieldTable;
  313. TFieldTable = packed record
  314. EntryCount: Word;
  315. FieldClassTable: PFieldClassTable;
  316. FirstEntry: TFieldEntry;
  317. {Entries: array [1..65534] of TFieldEntry;}
  318. end;
  319. function GetFieldTable(AClass: TClass): PFieldTable;
  320. { method table }
  321. type
  322. PMethodEntry = ^TMethodEntry;
  323. TMethodEntry = packed record
  324. EntrySize: Word;
  325. Address: Pointer;
  326. Name: ShortString;
  327. end;
  328. PMethodTable = ^TMethodTable;
  329. TMethodTable = packed record
  330. Count: Word;
  331. FirstEntry: TMethodEntry;
  332. {Entries: array [1..65534] of TMethodEntry;}
  333. end;
  334. function GetMethodTable(AClass: TClass): PMethodTable;
  335. function GetMethodEntry(MethodTable: PMethodTable; Index: Integer): PMethodEntry;
  336. // Function to compare if two methods/event handlers are equal
  337. function MethodEquals(aMethod1, aMethod2: TMethod): boolean;
  338. function NotifyEventEquals(aMethod1, aMethod2: TNotifyEvent): boolean;
  339. // Class Parent
  340. procedure SetClassParent(AClass: TClass; NewClassParent: TClass);
  341. function GetClassParent(AClass: TClass): TClass;
  342. {$IFNDEF FPC}
  343. function IsClass(Address: Pointer): Boolean;
  344. function IsObject(Address: Pointer): Boolean;
  345. {$ENDIF ~FPC}
  346. function InheritsFromByName(AClass: TClass; const AClassName: string): Boolean;
  347. // Interface information
  348. function GetImplementorOfInterface(const I: IInterface): TObject;
  349. // interfaced persistent
  350. type
  351. TJclInterfacedPersistent = class(TInterfacedPersistent, IInterface)
  352. protected
  353. FOwnerInterface: IInterface;
  354. FRefCount: Integer;
  355. public
  356. procedure AfterConstruction; override;
  357. { IInterface }
  358. // function QueryInterface(const IID: TGUID; out Obj): HRESULT; virtual; stdcall;
  359. function _AddRef: Integer; stdcall;
  360. function _Release: Integer; stdcall;
  361. end;
  362. // Numeric formatting routines
  363. type
  364. TDigitCount = 0..255;
  365. TDigitValue = -1..35; // invalid, '0'..'9', 'A'..'Z'
  366. TNumericSystemBase = 2..Succ(High(TDigitValue));
  367. TJclNumericFormat = class(TObject)
  368. private
  369. FWantedPrecision: TDigitCount;
  370. FPrecision: TDigitCount;
  371. FNumberOfFractionalDigits: TDigitCount;
  372. FExpDivision: Integer;
  373. FDigitBlockSize: TDigitCount;
  374. FWidth: TDigitCount;
  375. FSignChars: array [Boolean] of Char;
  376. FBase: TNumericSystemBase;
  377. FFractionalPartSeparator: Char;
  378. FDigitBlockSeparator: Char;
  379. FShowPositiveSign: Boolean;
  380. FPaddingChar: Char;
  381. FMultiplier: string;
  382. function GetDigitValue(Digit: Char): Integer;
  383. function GetNegativeSign: Char;
  384. function GetPositiveSign: Char;
  385. procedure InvalidDigit(Digit: Char);
  386. procedure SetPrecision(const Value: TDigitCount);
  387. procedure SetBase(const Value: TNumericSystemBase);
  388. procedure SetNegativeSign(const Value: Char);
  389. procedure SetPositiveSign(const Value: Char);
  390. procedure SetExpDivision(const Value: Integer);
  391. protected
  392. function IntToStr(const Value: Int64; out FirstDigitPos: Integer): string; overload;
  393. function ShowSign(const Value: Float): Boolean; overload;
  394. function ShowSign(const Value: Int64): Boolean; overload;
  395. function SignChar(const Value: Float): Char; overload;
  396. function SignChar(const Value: Int64): Char; overload;
  397. property WantedPrecision: TDigitCount read FWantedPrecision;
  398. public
  399. constructor Create;
  400. function Digit(DigitValue: TDigitValue): Char;
  401. function DigitValue(Digit: Char): TDigitValue;
  402. function IsDigit(Value: Char): Boolean;
  403. function Sign(Value: Char): Integer;
  404. procedure GetMantissaExp(const Value: Float; out Mantissa: string; out Exponent: Integer);
  405. function FloatToHTML(const Value: Float): string;
  406. function IntToStr(const Value: Int64): string; overload;
  407. function FloatToStr(const Value: Float): string; overload;
  408. function StrToInt(const Value: string): Int64;
  409. property Base: TNumericSystemBase read FBase write SetBase;
  410. property Precision: TDigitCount read FPrecision write SetPrecision;
  411. property NumberOfFractionalDigits: TDigitCount read FNumberOfFractionalDigits write FNumberOfFractionalDigits;
  412. property ExponentDivision: Integer read FExpDivision write SetExpDivision;
  413. property DigitBlockSize: TDigitCount read FDigitBlockSize write FDigitBlockSize;
  414. property DigitBlockSeparator: Char read FDigitBlockSeparator write FDigitBlockSeparator;
  415. property FractionalPartSeparator: Char read FFractionalPartSeparator write FFractionalPartSeparator;
  416. property Multiplier: string read FMultiplier write FMultiplier;
  417. property PaddingChar: Char read FPaddingChar write FPaddingChar;
  418. property ShowPositiveSign: Boolean read FShowPositiveSign write FShowPositiveSign;
  419. property Width: TDigitCount read FWidth write FWidth;
  420. property NegativeSign: Char read GetNegativeSign write SetNegativeSign;
  421. property PositiveSign: Char read GetPositiveSign write SetPositiveSign;
  422. end;
  423. function IntToStrZeroPad(Value, Count: Integer): string;
  424. // Child processes
  425. type
  426. // e.g. TStrings.Append
  427. TTextHandler = procedure(const Text: string) of object;
  428. TJclProcessPriority = (ppIdle, ppNormal, ppHigh, ppRealTime, ppBelowNormal, ppAboveNormal);
  429. const
  430. ABORT_EXIT_CODE = {$IFDEF MSWINDOWS} ERROR_CANCELLED {$ELSE} 1223 {$ENDIF};
  431. function Execute(const CommandLine: string; OutputLineCallback: TTextHandler; RawOutput: Boolean = False;
  432. AbortPtr: PBoolean = nil; ProcessPriority: TJclProcessPriority = ppNormal;
  433. AutoConvertOem: Boolean = False): Cardinal; overload;
  434. function Execute(const CommandLine: string; AbortEvent: TJclEvent;
  435. OutputLineCallback: TTextHandler; RawOutput: Boolean = False; ProcessPriority: TJclProcessPriority = ppNormal;
  436. AutoConvertOem: Boolean = False): Cardinal; overload;
  437. function Execute(const CommandLine: string; var Output: string; RawOutput: Boolean = False;
  438. AbortPtr: PBoolean = nil; ProcessPriority: TJclProcessPriority = ppNormal;
  439. AutoConvertOem: Boolean = False): Cardinal; overload;
  440. function Execute(const CommandLine: string; AbortEvent: TJclEvent;
  441. var Output: string; RawOutput: Boolean = False; ProcessPriority: TJclProcessPriority = ppNormal;
  442. AutoConvertOem: Boolean = False): Cardinal; overload;
  443. function Execute(const CommandLine: string; OutputLineCallback, ErrorLineCallback: TTextHandler;
  444. RawOutput: Boolean = False; RawError: Boolean = False; AbortPtr: PBoolean = nil;
  445. ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;
  446. function Execute(const CommandLine: string; AbortEvent: TJclEvent;
  447. OutputLineCallback, ErrorLineCallback: TTextHandler; RawOutput: Boolean = False; RawError: Boolean = False;
  448. ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;
  449. function Execute(const CommandLine: string; var Output, Error: string;
  450. RawOutput: Boolean = False; RawError: Boolean = False; AbortPtr: PBoolean = nil;
  451. ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;
  452. function Execute(const CommandLine: string; AbortEvent: TJclEvent;
  453. var Output, Error: string; RawOutput: Boolean = False; RawError: Boolean = False;
  454. ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;
  455. type
  456. {$IFDEF MSWINDOWS}
  457. TJclExecuteCmdProcessOptionBeforeResumeEvent = procedure(const ProcessInfo: TProcessInformation) of object;
  458. TStartupVisibility = (svHide, svShow, svNotSet);
  459. {$ENDIF MSWINDOWS}
  460. TJclExecuteCmdProcessOptions = {record} class(TObject)
  461. private
  462. FCommandLine: string;
  463. FAbortPtr: PBoolean;
  464. FAbortEvent: TJclEvent;
  465. FOutputLineCallback: TTextHandler;
  466. FRawOutput: Boolean;
  467. FMergeError: Boolean;
  468. FErrorLineCallback: TTextHandler;
  469. FRawError: Boolean;
  470. FProcessPriority: TJclProcessPriority;
  471. FAutoConvertOem: Boolean;
  472. {$IFDEF MSWINDOWS}
  473. FCreateProcessFlags: DWORD;
  474. FStartupVisibility: TStartupVisibility;
  475. FBeforeResume: TJclExecuteCmdProcessOptionBeforeResumeEvent;
  476. {$ENDIF MSWINDOWS}
  477. FExitCode: Cardinal;
  478. FOutput: string;
  479. FError: string;
  480. public
  481. // in:
  482. property CommandLine: string read FCommandLine write FCommandLine;
  483. property AbortPtr: PBoolean read FAbortPtr write FAbortPtr;
  484. property AbortEvent: TJclEvent read FAbortEvent write FAbortEvent;
  485. property OutputLineCallback: TTextHandler read FOutputLineCallback write FOutputLineCallback;
  486. property RawOutput: Boolean read FRawOutput write FRawOutput default False;
  487. property MergeError: Boolean read FMergeError write FMergeError default False;
  488. property ErrorLineCallback: TTextHandler read FErrorLineCallback write FErrorLineCallback;
  489. property RawError: Boolean read FRawError write FRawError default False;
  490. property ProcessPriority: TJclProcessPriority read FProcessPriority write FProcessPriority default ppNormal;
  491. // AutoConvertOem assumes the process outputs OEM encoded strings and converts them to the
  492. // default string encoding.
  493. property AutoConvertOem: Boolean read FAutoConvertOem write FAutoConvertOem default True;
  494. {$IFDEF MSWINDOWS}
  495. property CreateProcessFlags: DWORD read FCreateProcessFlags write FCreateProcessFlags;
  496. property StartupVisibility: TStartupVisibility read FStartupVisibility write FStartupVisibility;
  497. property BeforeResume: TJclExecuteCmdProcessOptionBeforeResumeEvent read FBeforeResume write FBeforeResume;
  498. {$ENDIF MSWINDOWS}
  499. // out:
  500. property ExitCode: Cardinal read FExitCode;
  501. property Output: string read FOutput;
  502. property Error: string read FError;
  503. public
  504. constructor Create(const ACommandLine: string);
  505. end;
  506. function ExecuteCmdProcess(Options: TJclExecuteCmdProcessOptions): Boolean;
  507. type
  508. {$HPPEMIT 'namespace Jclsysutils'}
  509. {$HPPEMIT '{'}
  510. {$HPPEMIT ' // For some reason, the generator puts this interface after its first'}
  511. {$HPPEMIT ' // usage, resulting in an unusable header file. We fix this by forward'}
  512. {$HPPEMIT ' // declaring the interface.'}
  513. {$HPPEMIT ' __interface IJclCommandLineTool;'}
  514. (*$HPPEMIT '}'*)
  515. IJclCommandLineTool = interface
  516. ['{A0034B09-A074-D811-847D-0030849E4592}']
  517. function GetExeName: string;
  518. function GetOptions: TStrings;
  519. function GetOutput: string;
  520. function GetOutputCallback: TTextHandler;
  521. procedure AddPathOption(const Option, Path: string);
  522. function Execute(const CommandLine: string): Boolean;
  523. procedure SetOutputCallback(const CallbackMethod: TTextHandler);
  524. property ExeName: string read GetExeName;
  525. property Options: TStrings read GetOptions;
  526. property OutputCallback: TTextHandler read GetOutputCallback write SetOutputCallback;
  527. property Output: string read GetOutput;
  528. end;
  529. EJclCommandLineToolError = class(EJclError);
  530. TJclCommandLineTool = class(TInterfacedObject, IJclCommandLineTool)
  531. private
  532. FExeName: string;
  533. FOptions: TStringList;
  534. FOutput: string;
  535. FOutputCallback: TTextHandler;
  536. public
  537. constructor Create(const AExeName: string);
  538. destructor Destroy; override;
  539. { IJclCommandLineTool }
  540. function GetExeName: string;
  541. function GetOptions: TStrings;
  542. function GetOutput: string;
  543. function GetOutputCallback: TTextHandler;
  544. procedure AddPathOption(const Option, Path: string);
  545. function Execute(const CommandLine: string): Boolean;
  546. procedure SetOutputCallback(const CallbackMethod: TTextHandler);
  547. property ExeName: string read GetExeName;
  548. property Options: TStrings read GetOptions;
  549. property OutputCallback: TTextHandler read GetOutputCallback write SetOutputCallback;
  550. property Output: string read GetOutput;
  551. end;
  552. // Console Utilities
  553. function ReadKey: Char;
  554. // Loading of modules (DLLs)
  555. type
  556. {$IFDEF MSWINDOWS}
  557. TModuleHandle = HINST;
  558. {$ENDIF MSWINDOWS}
  559. {$IFDEF LINUX}
  560. TModuleHandle = Pointer;
  561. {$ENDIF LINUX}
  562. const
  563. INVALID_MODULEHANDLE_VALUE = TModuleHandle(0);
  564. function LoadModule(var Module: TModuleHandle; FileName: string): Boolean;
  565. function LoadModuleEx(var Module: TModuleHandle; FileName: string; Flags: Cardinal): Boolean;
  566. procedure UnloadModule(var Module: TModuleHandle);
  567. function GetModuleSymbol(Module: TModuleHandle; SymbolName: string): Pointer;
  568. function GetModuleSymbolEx(Module: TModuleHandle; SymbolName: string; var Accu: Boolean): Pointer;
  569. function ReadModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;
  570. function WriteModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;
  571. // Conversion Utilities
  572. type
  573. EJclConversionError = class(EJclError);
  574. function StrToBoolean(const S: string): Boolean;
  575. function BooleanToStr(B: Boolean): string;
  576. function IntToBool(I: Integer): Boolean;
  577. function BoolToInt(B: Boolean): Integer;
  578. function TryStrToUInt(const Value: string; out Res: Cardinal): Boolean;
  579. function StrToUIntDef(const Value: string; const Default: Cardinal): Cardinal;
  580. function StrToUInt(const Value: string): Cardinal;
  581. const
  582. {$IFDEF MSWINDOWS}
  583. ListSeparator = ';';
  584. {$ENDIF MSWINDOWS}
  585. {$IFDEF LINUX}
  586. ListSeparator = ':';
  587. {$ENDIF LINUX}
  588. // functions to handle items in a separated list of items
  589. // add items at the end
  590. procedure ListAddItems(var List: string; const Separator, Items: string);
  591. // add items at the end if they are not present
  592. procedure ListIncludeItems(var List: string; const Separator, Items: string);
  593. // delete multiple items
  594. procedure ListRemoveItems(var List: string; const Separator, Items: string);
  595. // delete one item
  596. procedure ListDelItem(var List: string; const Separator: string;
  597. const Index: Integer);
  598. // return the number of item
  599. function ListItemCount(const List, Separator: string): Integer;
  600. // return the Nth item
  601. function ListGetItem(const List, Separator: string;
  602. const Index: Integer): string;
  603. // set the Nth item
  604. procedure ListSetItem(var List: string; const Separator: string;
  605. const Index: Integer; const Value: string);
  606. // return the index of an item
  607. function ListItemIndex(const List, Separator, Item: string): Integer;
  608. // RTL package information
  609. function SystemTObjectInstance: TJclAddr;
  610. function IsCompiledWithPackages: Boolean;
  611. // GUID
  612. function JclGUIDToString(const GUID: TGUID): string;
  613. function JclStringToGUID(const S: string): TGUID;
  614. function GUIDEquals(const GUID1, GUID2: TGUID): Boolean;
  615. // thread safe support
  616. type
  617. TJclIntfCriticalSection = class(TInterfacedObject, IInterface)
  618. private
  619. FCriticalSection: TCriticalSection;
  620. public
  621. constructor Create;
  622. destructor Destroy; override;
  623. { IInterface }
  624. // function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
  625. function _AddRef: Integer; stdcall;
  626. function _Release: Integer; stdcall;
  627. end;
  628. type
  629. {$IFDEF BORLAND}
  630. {$IFDEF COMPILER16_UP}
  631. TFileHandle = THandle;
  632. {$ELSE ~COMPILER16_UP}
  633. TFileHandle = Integer;
  634. {$ENDIF ~COMPILER16_UP}
  635. {$ELSE ~BORLAND}
  636. TFileHandle = THandle;
  637. {$ENDIF ~BORLAND}
  638. TJclSimpleLog = class (TObject)
  639. private
  640. FDateTimeFormatStr: String;
  641. FLogFileHandle: TFileHandle;
  642. FLogFileName: string;
  643. FLoggingActive: Boolean;
  644. FLogWasEmpty: Boolean;
  645. function GetLogOpen: Boolean;
  646. protected
  647. function CreateDefaultFileName: string;
  648. public
  649. constructor Create(const ALogFileName: string = '');
  650. destructor Destroy; override;
  651. procedure ClearLog;
  652. procedure CloseLog;
  653. procedure OpenLog;
  654. procedure Write(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true); overload;
  655. procedure Write(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true); overload;
  656. //Writes a line to the log file. The current timestamp is written before the line.
  657. procedure TimeWrite(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true); overload;
  658. procedure TimeWrite(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true); overload;
  659. procedure WriteStamp(SeparatorLen: Integer = 0; KeepOpen: Boolean = true);
  660. // DateTimeFormatStr property assumes the values described in "FormatDateTime Function" in Delphi Help
  661. property DateTimeFormatStr: String read FDateTimeFormatStr write FDateTimeFormatStr;
  662. property LogFileName: string read FLogFileName;
  663. //1 Property to activate / deactivate the logging
  664. property LoggingActive: Boolean read FLoggingActive write FLoggingActive default True;
  665. property LogOpen: Boolean read GetLogOpen;
  666. end;
  667. type
  668. TJclFormatSettings = class
  669. private
  670. function GetCurrencyDecimals: Byte; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  671. function GetCurrencyFormat: Byte; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  672. function GetCurrencyString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  673. function GetDateSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  674. function GetDayNamesHighIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  675. function GetDayNamesLowIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  676. function GetDecimalSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  677. function GetListSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  678. function GetLongDateFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  679. function GetLongDayNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  680. function GetLongMonthNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  681. function GetLongTimeFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  682. function GetMonthNamesHighIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  683. function GetMonthNamesLowIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  684. function GetNegCurrFormat: Byte; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  685. function GetShortDateFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  686. function GetShortDayNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  687. function GetShortMonthNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  688. function GetShortTimeFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  689. function GetThousandSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  690. function GetTimeAMString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  691. function GetTimePMString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  692. function GetTimeSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  693. function GetTwoDigitYearCenturyWindow: Word; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  694. procedure SetCurrencyDecimals(AValue: Byte); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  695. procedure SetCurrencyFormat(const AValue: Byte); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  696. procedure SetCurrencyString(AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  697. procedure SetDateSeparator(const AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  698. procedure SetDecimalSeparator(AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  699. procedure SetListSeparator(const AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  700. procedure SetLongDateFormat(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  701. procedure SetLongTimeFormat(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  702. procedure SetNegCurrFormat(const AValue: Byte); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  703. procedure SetShortDateFormat(AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  704. procedure SetShortTimeFormat(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  705. procedure SetThousandSeparator(AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  706. procedure SetTimeAMString(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  707. procedure SetTimePMString(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  708. procedure SetTimeSeparator(const AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  709. procedure SetTwoDigitYearCenturyWindow(const AValue: Word); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
  710. public
  711. property CurrencyDecimals: Byte read GetCurrencyDecimals write SetCurrencyDecimals;
  712. property CurrencyFormat: Byte read GetCurrencyFormat write SetCurrencyFormat;
  713. property CurrencyString: string read GetCurrencyString write SetCurrencyString;
  714. property DateSeparator: Char read GetDateSeparator write SetDateSeparator;
  715. property DayNamesHighIndex: Integer read GetDayNamesHighIndex;
  716. property DayNamesLowIndex: Integer read GetDayNamesLowIndex;
  717. property DecimalSeparator: Char read GetDecimalSeparator write SetDecimalSeparator;
  718. property ListSeparator: Char read GetListSeparator write SetListSeparator;
  719. property LongDateFormat: string read GetLongDateFormat write SetLongDateFormat;
  720. property LongDayNames[AIndex: Integer]: string read GetLongDayNames;
  721. property LongMonthNames[AIndex: Integer]: string read GetLongMonthNames;
  722. property LongTimeFormat: string read GetLongTimeFormat write SetLongTimeFormat;
  723. property MonthNamesHighIndex: Integer read GetMonthNamesHighIndex;
  724. property MonthNamesLowIndex: Integer read GetMonthNamesLowIndex;
  725. property NegCurrFormat: Byte read GetNegCurrFormat write SetNegCurrFormat;
  726. property ShortDateFormat: string read GetShortDateFormat write SetShortDateFormat;
  727. property ShortDayNames[AIndex: Integer]: string read GetShortDayNames;
  728. property ShortMonthNames[AIndex: Integer]: string read GetShortMonthNames;
  729. property ShortTimeFormat: string read GetShortTimeFormat write SetShortTimeFormat;
  730. property ThousandSeparator: Char read GetThousandSeparator write SetThousandSeparator;
  731. property TimeAMString: string read GetTimeAMString write SetTimeAMString;
  732. property TimePMString: string read GetTimePMString write SetTimePMString;
  733. property TimeSeparator: Char read GetTimeSeparator write SetTimeSeparator;
  734. property TwoDigitYearCenturyWindow: Word read GetTwoDigitYearCenturyWindow write SetTwoDigitYearCenturyWindow;
  735. end;
  736. var
  737. JclFormatSettings: TJclFormatSettings;
  738. // Procedure to initialize the SimpleLog Variable
  739. procedure InitSimpleLog(const ALogFileName: string = ''; AOpenLog: Boolean = true);
  740. // Global Variable to make it easier for an application wide log handling.
  741. // Must be initialized with InitSimpleLog before using
  742. var
  743. SimpleLog : TJclSimpleLog;
  744. // Validates if then variant value is null or is empty
  745. function VarIsNullEmpty(const V: Variant): Boolean;
  746. // Validates if then variant value is null or is empty or VarToStr is a blank string
  747. function VarIsNullEmptyBlank(const V: Variant): Boolean;
  748. {$IFDEF UNITVERSIONING}
  749. const
  750. UnitVersioning: TUnitVersionInfo = (
  751. RCSfile: '$URL$';
  752. Revision: '$Revision$';
  753. Date: '$Date$';
  754. LogPath: 'JCL\source\common';
  755. Extra: '';
  756. Data: nil
  757. );
  758. {$ENDIF UNITVERSIONING}
  759. implementation
  760. uses
  761. {$IFDEF HAS_UNIT_LIBC}
  762. Libc,
  763. {$ENDIF HAS_UNIT_LIBC}
  764. {$IFDEF MSWINDOWS}
  765. JclConsole,
  766. {$ENDIF MSWINDOWS}
  767. {$IFDEF HAS_UNITSCOPE}
  768. System.Variants, System.Types, System.Contnrs,
  769. {$IFDEF HAS_UNIT_ANSISTRINGS}
  770. System.AnsiStrings,
  771. {$ENDIF HAS_UNIT_ANSISTRINGS}
  772. {$ELSE ~HAS_UNITSCOPE}
  773. Variants, Types, Contnrs,
  774. {$IFDEF HAS_UNIT_ANSISTRINGS}
  775. AnsiStrings,
  776. {$ENDIF HAS_UNIT_ANSISTRINGS}
  777. {$ENDIF ~HAS_UNITSCOPE}
  778. JclFileUtils, JclMath, JclResources, JclStrings,
  779. JclStringConversions, JclSysInfo, JclWin32;
  780. // memory initialization
  781. procedure ResetMemory(out P; Size: Longint);
  782. begin
  783. if Size > 0 then
  784. begin
  785. Byte(P) := 0;
  786. FillChar(P, Size, 0);
  787. end;
  788. end;
  789. // Pointer manipulation
  790. procedure GetAndFillMem(var P: Pointer; const Size: Integer; const Value: Byte);
  791. begin
  792. GetMem(P, Size);
  793. FillChar(P^, Size, Value);
  794. end;
  795. procedure FreeMemAndNil(var P: Pointer);
  796. var
  797. Q: Pointer;
  798. begin
  799. Q := P;
  800. P := nil;
  801. FreeMem(Q);
  802. end;
  803. function PCharOrNil(const S: string): PChar;
  804. begin
  805. Result := Pointer(S);
  806. end;
  807. function PAnsiCharOrNil(const S: AnsiString): PAnsiChar;
  808. begin
  809. Result := Pointer(S);
  810. end;
  811. {$IFDEF SUPPORTS_WIDESTRING}
  812. function PWideCharOrNil(const W: WideString): PWideChar;
  813. begin
  814. Result := Pointer(W);
  815. end;
  816. {$ENDIF SUPPORTS_WIDESTRING}
  817. {$IFDEF MSWINDOWS}
  818. type
  819. PUsed = ^TUsed;
  820. TUsed = record
  821. SizeFlags: Integer;
  822. end;
  823. const
  824. cThisUsedFlag = 2;
  825. cPrevFreeFlag = 1;
  826. cFillerFlag = Integer($80000000);
  827. cFlags = cThisUsedFlag or cPrevFreeFlag or cFillerFlag;
  828. function SizeOfMem(const APointer: Pointer): Integer;
  829. var
  830. U: PUsed;
  831. begin
  832. if IsMemoryManagerSet then
  833. Result:= -1
  834. else
  835. begin
  836. Result := 0;
  837. if APointer <> nil then
  838. begin
  839. U := APointer;
  840. U := PUsed(TJclAddr(U) - SizeOf(TUsed));
  841. if (U.SizeFlags and cThisUsedFlag) <> 0 then
  842. Result := (U.SizeFlags) and (not cFlags - SizeOf(TUsed));
  843. end;
  844. end;
  845. end;
  846. {$ENDIF MSWINDOWS}
  847. {$IFDEF LINUX}
  848. function SizeOfMem(const APointer: Pointer): Integer;
  849. begin
  850. if IsMemoryManagerSet then
  851. Result:= -1
  852. else
  853. begin
  854. if APointer <> nil then
  855. Result := malloc_usable_size(APointer)
  856. else
  857. Result := 0;
  858. end;
  859. end;
  860. {$ENDIF LINUX}
  861. function WriteProtectedMemory(BaseAddress, Buffer: Pointer;
  862. Size: Cardinal; out WrittenBytes: Cardinal): Boolean;
  863. {$IFDEF MSWINDOWS}
  864. var
  865. OldProtect, Dummy: Cardinal;
  866. begin
  867. WrittenBytes := 0;
  868. if Size > 0 then
  869. begin
  870. // (outchy) VirtualProtect for DEP issues
  871. OldProtect := 0;
  872. Result := VirtualProtect(BaseAddress, Size, PAGE_EXECUTE_READWRITE, OldProtect);
  873. if Result then
  874. try
  875. Move(Buffer^, BaseAddress^, Size);
  876. WrittenBytes := Size;
  877. if OldProtect in [PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY] then
  878. FlushInstructionCache(GetCurrentProcess, BaseAddress, Size);
  879. finally
  880. Dummy := 0;
  881. VirtualProtect(BaseAddress, Size, OldProtect, Dummy);
  882. end;
  883. end;
  884. Result := WrittenBytes = Size;
  885. end;
  886. {$ENDIF MSWINDOWS}
  887. {$IFDEF LINUX}
  888. { TODO -cHelp : Author: Andreas Hausladen }
  889. { TODO : Works so far, but causes app to hang on termination }
  890. var
  891. AlignedAddress: Cardinal;
  892. PageSize, ProtectSize: Cardinal;
  893. begin
  894. Result := False;
  895. WrittenBytes := 0;
  896. PageSize := Cardinal(getpagesize);
  897. AlignedAddress := Cardinal(BaseAddress) and not (PageSize - 1); // start memory page
  898. // get the number of needed memory pages
  899. ProtectSize := PageSize;
  900. while Cardinal(BaseAddress) + Size > AlignedAddress + ProtectSize do
  901. Inc(ProtectSize, PageSize);
  902. if mprotect(Pointer(AlignedAddress), ProtectSize,
  903. PROT_READ or PROT_WRITE or PROT_EXEC) = 0 then // obtain write access
  904. begin
  905. try
  906. Move(Buffer^, BaseAddress^, Size); // replace code
  907. Result := True;
  908. WrittenBytes := Size;
  909. finally
  910. // Is there any function that returns the current page protection?
  911. // mprotect(p, ProtectSize, PROT_READ or PROT_EXEC); // lock memory page
  912. end;
  913. end;
  914. end;
  915. procedure FlushInstructionCache;
  916. { TODO -cHelp : Author: Andreas Hausladen }
  917. begin
  918. // do nothing
  919. end;
  920. {$ENDIF LINUX}
  921. // Guards
  922. //=== { TJclSafeGuard } ======================================================
  923. constructor TJclSafeGuard.Create(Mem: Pointer);
  924. begin
  925. inherited Create;
  926. FItem := Mem;
  927. end;
  928. destructor TJclSafeGuard.Destroy;
  929. begin
  930. FreeItem;
  931. inherited Destroy;
  932. end;
  933. function TJclSafeGuard.ReleaseItem: Pointer;
  934. begin
  935. Result := FItem;
  936. FItem := nil;
  937. end;
  938. function TJclSafeGuard.GetItem: Pointer;
  939. begin
  940. Result := FItem;
  941. end;
  942. procedure TJclSafeGuard.FreeItem;
  943. begin
  944. if FItem <> nil then
  945. FreeMem(FItem);
  946. FItem := nil;
  947. end;
  948. //=== { TJclObjSafeGuard } ===================================================
  949. constructor TJclObjSafeGuard.Create(Obj: TObject);
  950. begin
  951. inherited Create(Pointer(Obj));
  952. end;
  953. procedure TJclObjSafeGuard.FreeItem;
  954. begin
  955. if FItem <> nil then
  956. begin
  957. TObject(FItem).Free;
  958. FItem := nil;
  959. end;
  960. end;
  961. //=== { TJclMultiSafeGuard } =================================================
  962. constructor TJclMultiSafeGuard.Create;
  963. begin
  964. inherited Create;
  965. FItems := TList.Create;
  966. end;
  967. destructor TJclMultiSafeGuard.Destroy;
  968. var
  969. I: Integer;
  970. begin
  971. for I := FItems.Count - 1 downto 0 do
  972. FreeItem(I);
  973. FItems.Free;
  974. inherited Destroy;
  975. end;
  976. function TJclMultiSafeGuard.AddItem(Item: Pointer): Pointer;
  977. begin
  978. Result := Item;
  979. FItems.Add(Item);
  980. end;
  981. procedure TJclMultiSafeGuard.FreeItem(Index: Integer);
  982. begin
  983. FreeMem(FItems[Index]);
  984. FItems.Delete(Index);
  985. end;
  986. function TJclMultiSafeGuard.GetCount: Integer;
  987. begin
  988. Result := FItems.Count;
  989. end;
  990. function TJclMultiSafeGuard.GetItem(Index: Integer): Pointer;
  991. begin
  992. Result := FItems[Index];
  993. end;
  994. function TJclMultiSafeGuard.ReleaseItem(Index: Integer): Pointer;
  995. begin
  996. Result := FItems[Index];
  997. FItems.Delete(Index);
  998. end;
  999. function Guard(Mem: Pointer; var SafeGuard: IMultiSafeGuard): Pointer; overload;
  1000. begin
  1001. if SafeGuard = nil then
  1002. SafeGuard := TJclMultiSafeGuard.Create;
  1003. Result := SafeGuard.AddItem(Mem);
  1004. end;
  1005. //=== { TJclObjMultiSafeGuard } ==============================================
  1006. procedure TJclObjMultiSafeGuard.FreeItem(Index: Integer);
  1007. begin
  1008. TObject(FItems[Index]).Free;
  1009. FItems.Delete(Index);
  1010. end;
  1011. function Guard(Obj: TObject; var SafeGuard: IMultiSafeGuard): TObject; overload;
  1012. begin
  1013. if SafeGuard = nil then
  1014. SafeGuard := TJclObjMultiSafeGuard.Create;
  1015. Result := SafeGuard.AddItem(Obj);
  1016. end;
  1017. function Guard(Mem: Pointer; out SafeGuard: ISafeGuard): Pointer; overload;
  1018. begin
  1019. Result := Mem;
  1020. SafeGuard := TJclSafeGuard.Create(Mem);
  1021. end;
  1022. function Guard(Obj: TObject; out SafeGuard: ISafeGuard): TObject; overload;
  1023. begin
  1024. Result := Obj;
  1025. SafeGuard := TJclObjSafeGuard.Create(Obj);
  1026. end;
  1027. function GuardGetMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;
  1028. begin
  1029. GetMem(Result, Size);
  1030. Guard(Result, SafeGuard);
  1031. end;
  1032. function GuardAllocMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;
  1033. begin
  1034. Result := AllocMem(Size);
  1035. Guard(Result, SafeGuard);
  1036. end;
  1037. {$IFDEF SUPPORTS_GENERICS_}
  1038. //=== { TSafeGuard<T> } ======================================================
  1039. constructor TSafeGuard<T>.Create(Instance: T);
  1040. begin
  1041. inherited Create;
  1042. FItem := Instance;
  1043. end;
  1044. destructor TSafeGuard<T>.Destroy;
  1045. begin
  1046. FreeItem;
  1047. inherited Destroy;
  1048. end;
  1049. function TSafeGuard<T>.ReleaseItem: T;
  1050. begin
  1051. Result := FItem;
  1052. FItem := nil;
  1053. end;
  1054. function TSafeGuard<T>.GetItem: T;
  1055. begin
  1056. Result := FItem;
  1057. end;
  1058. procedure TSafeGuard<T>.FreeItem;
  1059. begin
  1060. if FItem <> nil then
  1061. FItem.Free;
  1062. FItem := nil;
  1063. end;
  1064. {$ENDIF SUPPORTS_GENERICS_}
  1065. //=== Shared memory functions ================================================
  1066. type
  1067. PMMFHandleListItem = ^TMMFHandleListItem;
  1068. TMMFHandleListItem = record
  1069. Next: PMMFHandleListItem;
  1070. Memory: Pointer;
  1071. Handle: THandle;
  1072. Name: string;
  1073. References: Integer;
  1074. end;
  1075. PMMFHandleList = PMMFHandleListItem;
  1076. var
  1077. MMFHandleList: PMMFHandleList = nil;
  1078. {$IFDEF THREADSAFE}
  1079. MMFFinalized: Boolean = False;
  1080. GlobalMMFHandleListCS: TJclIntfCriticalSection = nil;
  1081. {$ENDIF THREADSAFE}
  1082. {$IFDEF THREADSAFE}
  1083. function GetAccessToHandleList: IInterface;
  1084. var
  1085. OldValue: Pointer;
  1086. CS: TJclIntfCriticalSection;
  1087. begin
  1088. if not Assigned(GlobalMMFHandleListCS) and not MMFFinalized then
  1089. begin
  1090. CS := TJclIntfCriticalSection.Create;
  1091. {$IFDEF RTL200_UP} // Delphi 2009+
  1092. OldValue := InterlockedCompareExchangePointer(Pointer(GlobalMMFHandleListCS), Pointer(CS), nil);
  1093. {$ELSE}
  1094. {$IFDEF RTL160_UP} // Delphi 7-2007
  1095. OldValue := Pointer(InterlockedCompareExchange(Longint(GlobalMMFHandleListCS), Longint(CS), 0));
  1096. {$ELSE} // Delphi 5, 6
  1097. OldValue := InterlockedCompareExchange(Pointer(GlobalMMFHandleListCS), Pointer(CS), nil);
  1098. {$ENDIF RTL180_UP}
  1099. {$ENDIF RTL185_UP}
  1100. if OldValue <> nil then
  1101. CS.Free;
  1102. end;
  1103. Result := GlobalMMFHandleListCS;
  1104. end;
  1105. {$ENDIF THREADSAFE}
  1106. {$IFDEF MSWINDOWS}
  1107. function SharedGetMem(var P{: Pointer}; const Name: string; Size: Cardinal;
  1108. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Integer;
  1109. var
  1110. FileMappingHandle: THandle;
  1111. Iterate, NewListItem: PMMFHandleListItem;
  1112. Protect: Cardinal;
  1113. {$IFDEF THREADSAFE}
  1114. HandleListAccess: IInterface;
  1115. {$ENDIF THREADSAFE}
  1116. begin
  1117. Result := 0;
  1118. Pointer(P) := nil;
  1119. if not JclCheckWinVersion(5, 0) and ((Name = '') or (Pos('\', Name) > 0)) then
  1120. raise ESharedMemError.CreateResFmt(@RsInvalidMMFName, [Name]);
  1121. {$IFDEF THREADSAFE}
  1122. HandleListAccess := GetAccessToHandleList;
  1123. {$ENDIF THREADSAFE}
  1124. // search for same name
  1125. Iterate := MMFHandleList;
  1126. while Iterate <> nil do
  1127. begin
  1128. if CompareText(Iterate^.Name, Name) = 0 then
  1129. begin
  1130. Inc(Iterate^.References);
  1131. Pointer(P) := Iterate^.Memory;
  1132. Result := ERROR_ALREADY_EXISTS;
  1133. Exit;
  1134. end;
  1135. Iterate := Iterate^.Next;
  1136. end;
  1137. // open file mapping
  1138. FileMappingHandle := OpenFileMapping(DesiredAccess, False, PChar(Name));
  1139. if FileMappingHandle = 0 then
  1140. begin
  1141. if Size = 0 then
  1142. raise ESharedMemError.CreateResFmt(@RsInvalidMMFEmpty, [Name]);
  1143. Protect := PAGE_READWRITE;
  1144. if (Win32Platform = VER_PLATFORM_WIN32_WINDOWS) and (DesiredAccess = FILE_MAP_COPY) then
  1145. Protect := PAGE_WRITECOPY;
  1146. FileMappingHandle := CreateFileMapping(INVALID_HANDLE_VALUE, nil, Protect,
  1147. 0, Size, PChar(Name));
  1148. end
  1149. else
  1150. Result := ERROR_ALREADY_EXISTS;
  1151. if GetLastError = ERROR_ALREADY_EXISTS then
  1152. Result := ERROR_ALREADY_EXISTS
  1153. else
  1154. begin
  1155. if FileMappingHandle = 0 then
  1156. RaiseLastOSError;
  1157. end;
  1158. // map view
  1159. Pointer(P) := MapViewOfFile(FileMappingHandle, DesiredAccess, 0, 0, Size);
  1160. if Pointer(P) = nil then
  1161. begin
  1162. try
  1163. RaiseLastOSError;
  1164. except
  1165. CloseHandle(FileMappingHandle);
  1166. raise;
  1167. end;
  1168. end;
  1169. // add list item to MMFHandleList
  1170. New(NewListItem);
  1171. NewListItem^.Name := Name;
  1172. NewListItem^.Handle := FileMappingHandle;
  1173. NewListItem^.Memory := Pointer(P);
  1174. NewListItem^.References := 1;
  1175. NewListItem^.Next := MMFHandleList;
  1176. MMFHandleList := NewListItem;
  1177. end;
  1178. function SharedAllocMem(const Name: string; Size: Cardinal;
  1179. DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer;
  1180. begin
  1181. Result := nil;
  1182. if (SharedGetMem(Result, Name, Size, DesiredAccess) <> ERROR_ALREADY_EXISTS) and
  1183. ((DesiredAccess and (FILE_MAP_WRITE or FILE_MAP_COPY)) <> 0) and
  1184. (Size > 0) and (Result <> nil) then
  1185. ResetMemory(Pointer(Result)^, Size);
  1186. end;
  1187. function SharedFreeMem(var P{: Pointer}): Boolean;
  1188. var
  1189. N, Iterate: PMMFHa