PageRenderTime 71ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/KOLadd.pas

http://github.com/rofl0r/KOL
Pascal | 3354 lines | 2461 code | 282 blank | 611 comment | 200 complexity | 64e8546006bd38acfbf63fccf873ecc9 MD5 | raw file
  1. //[START OF KOL.pas]
  2. {****************************************************************
  3. d d
  4. KKKKK KKKKK OOOOOOOOO LLLLL d d
  5. KKKKK KKKKK OOOOOOOOOOOOO LLLLL d d
  6. KKKKK KKKKK OOOOO OOOOO LLLLL aaaa d d
  7. KKKKK KKKKK OOOOO OOOOO LLLLL a d d
  8. KKKKKKKKKK OOOOO OOOOO LLLLL a d d
  9. KKKKK KKKKK OOOOO OOOOO LLLLL aaaaa dddddd dddddd
  10. KKKKK KKKKK OOOOO OOOOO LLLLL a a d d d d
  11. KKKKK KKKKK OOOOOOOOOOOOO LLLLLLLLLLLLL a a d d d d
  12. KKKKK KKKKK OOOOOOOOO LLLLLLLLLLLLL aaaaa aa dddddd dddddd
  13. Key Objects Library (C) 2000 by Kladov Vladimir.
  14. //[VERSION]
  15. ****************************************************************
  16. * VERSION 2.04
  17. ****************************************************************
  18. //[END OF VERSION]
  19. The only reason why this part of KOL separated into another unit is that
  20. Delphi has a restriction to DCU size exceeding which it is failed to debug
  21. it normally and in attempt to execute code step by step an internal error
  22. is occur which stops Delphi from working at all.
  23. Version indicated above is a version of KOL, having place when KOLadd.pas was
  24. modified last time, this is not a version of KOLadd itself.
  25. }
  26. unit KOLadd;
  27. interface
  28. {$I KOLDEF.INC}
  29. uses Windows, KOL;
  30. {------------------------------------------------------------------------------)
  31. | |
  32. | T L i s t E x |
  33. | |
  34. (------------------------------------------------------------------------------}
  35. type
  36. //[TListEx DEFINITION]
  37. {++}(*TListEx = class;*){--}
  38. PListEx = {-}^{+}TListEx;
  39. TListEx = object( TObj )
  40. {* Extended list, with Objects[ ] property. Created calling NewListEx function. }
  41. protected
  42. fList: PList;
  43. fObjects: PList;
  44. function GetEx(Idx: Integer): Pointer;
  45. procedure PutEx(Idx: Integer; const Value: Pointer);
  46. function GetCount: Integer;
  47. function GetAddBy: Integer;
  48. procedure Set_AddBy(const Value: Integer);
  49. public
  50. destructor Destroy; {-}virtual;{+}{++}(*override;*){--}
  51. {* }
  52. property AddBy: Integer read GetAddBy write Set_AddBy;
  53. {* }
  54. property Items[ Idx: Integer ]: Pointer read GetEx write PutEx;
  55. {* }
  56. property Count: Integer read GetCount;
  57. {* }
  58. procedure Clear;
  59. {* }
  60. procedure Add( Value: Pointer );
  61. {* }
  62. procedure AddObj( Value, Obj: Pointer );
  63. {* }
  64. procedure Insert( Idx: Integer; Value: Pointer );
  65. {* }
  66. procedure InsertObj( Idx: Integer; Value, Obj: Pointer );
  67. {* }
  68. procedure Delete( Idx: Integer );
  69. {* }
  70. procedure DeleteRange( Idx, Len: Integer );
  71. {* }
  72. function IndexOf( Value: Pointer ): Integer;
  73. {* }
  74. function IndexOfObj( Obj: Pointer ): Integer;
  75. {* }
  76. procedure Swap( Idx1, Idx2: Integer );
  77. {* }
  78. procedure MoveItem( OldIdx, NewIdx: Integer );
  79. {* }
  80. property ItemsList: PList read fList;
  81. {* }
  82. property ObjList: PList read fObjects;
  83. {* }
  84. function Last: Pointer;
  85. {* }
  86. function LastObj: Pointer;
  87. {* }
  88. end;
  89. //[END OF TListEx DEFINITION]
  90. //[NewListEx DECLARATION]
  91. function NewListEx: PListEx;
  92. {* Creates extended list. }
  93. {------------------------------------------------------------------------------)
  94. | |
  95. | T B i t s |
  96. | |
  97. (------------------------------------------------------------------------------}
  98. type
  99. //[TBits DEFINITION]
  100. {++}(*TBits = class;*){--}
  101. PBits = {-}^{+}TBits;
  102. TBits = object( TObj )
  103. {* Variable-length bits array object. Created using function NewBits. See also
  104. |<a href="kol_pas.htm#Small bit arrays (max 32 bits in array)">
  105. Small bit arrays (max 32 bits in array)
  106. |</a>. }
  107. protected
  108. fList: PList;
  109. fCount: Integer;
  110. function GetBit(Idx: Integer): Boolean;
  111. procedure SetBit(Idx: Integer; const Value: Boolean);
  112. function GetCapacity: Integer;
  113. function GetSize: Integer;
  114. procedure SetCapacity(const Value: Integer);
  115. public
  116. destructor Destroy; {-}virtual;{+}{++}(*override;*){--}
  117. {* }
  118. property Bits[ Idx: Integer ]: Boolean read GetBit write SetBit;
  119. {* }
  120. property Size: Integer read GetSize;
  121. {* Size in bytes of the array. To get know number of bits, use property Count. }
  122. property Count: Integer read fCount;
  123. {* Number of bits an the array. }
  124. property Capacity: Integer read GetCapacity write SetCapacity;
  125. {* Number of bytes allocated. Can be set before assigning bit values
  126. to improve performance (minimizing amount of memory allocation
  127. operations). }
  128. function Copy( From, BitsCount: Integer ): PBits;
  129. {* Use this property to get a sub-range of bits starting from given bit
  130. and of BitsCount bits count. }
  131. function IndexOf( Value: Boolean ): Integer;
  132. {* Returns index of first bit with given value (True or False). }
  133. function OpenBit: Integer;
  134. {* Returns index of the first bit not set to true. }
  135. procedure Clear;
  136. {* Clears bits array. Count, Size and Capacity become 0. }
  137. function LoadFromStream( strm: PStream ): Integer;
  138. {* Loads bits from the stream. Data should be stored in the stream
  139. earlier using SaveToStream method. While loading, previous bits
  140. data are discarded and replaced with new one totally. In part,
  141. Count of bits also is changed. Count of bytes read from the stream
  142. while loading data is returned. }
  143. function SaveToStream( strm: PStream ): Integer;
  144. {* Saves entire array of bits to the stream. First, Count of bits
  145. in the array is saved, then all bytes containing bits data. }
  146. function Range( Idx, N: Integer ): PBits;
  147. {* Creates and returns new TBits object instance containing N bits
  148. starting from index Idx. If you call this method, you are responsible
  149. for destroying returned object when it become not neccessary. }
  150. procedure AssignBits( ToIdx: Integer; FromBits: PBits; FromIdx, N: Integer );
  151. {* Assigns bits from another bits array object. N bits are assigned
  152. starting at index ToIdx. }
  153. end;
  154. //[END OF TBits DEFINITION]
  155. //[NewBits DECLARATION]
  156. function NewBits: PBits;
  157. {* Creates variable-length bits array object. }
  158. {------------------------------------------------------------------------------)
  159. | |
  160. | T F a s t S t r L i s t |
  161. | |
  162. (------------------------------------------------------------------------------}
  163. type
  164. PFastStrListEx = ^TFastStrListEx;
  165. TFastStrListEx = object( TObj )
  166. private
  167. function GetItemLen(Idx: Integer): Integer;
  168. function GetObject(Idx: Integer): DWORD;
  169. procedure SetObject(Idx: Integer; const Value: DWORD);
  170. function GetValues(AName: PChar): PChar;
  171. protected
  172. procedure Init; virtual;
  173. protected
  174. fList: PList;
  175. fCount: Integer;
  176. fCaseSensitiveSort: Boolean;
  177. fTextBuf: PChar;
  178. fTextSiz: DWORD;
  179. fUsedSiz: DWORD;
  180. protected
  181. procedure ProvideSpace( AddSize: DWORD );
  182. function Get(Idx: integer): string;
  183. function GetTextStr: string;
  184. procedure Put(Idx: integer; const Value: string);
  185. procedure SetTextStr(const Value: string);
  186. function GetPChars( Idx: Integer ): PChar;
  187. {++}(*public*){--}
  188. destructor Destroy; {-}virtual;{+}{++}(*override;*){--}
  189. public
  190. function AddAnsi( const S: String ): Integer;
  191. {* Adds Ansi String to a list. }
  192. function AddAnsiObject( const S: String; Obj: DWORD ): Integer;
  193. {* Adds Ansi String and correspondent object to a list. }
  194. function Add(S: PChar): integer;
  195. {* Adds a string to list. }
  196. function AddLen(S: PChar; Len: Integer): integer;
  197. {* Adds a string to list. The string can contain #0 characters. }
  198. public
  199. FastClear: Boolean;
  200. {* }
  201. procedure Clear;
  202. {* Makes string list empty. }
  203. procedure Delete(Idx: integer);
  204. {* Deletes string with given index (it *must* exist). }
  205. function IndexOf(const S: string): integer;
  206. {* Returns index of first string, equal to given one. }
  207. function IndexOf_NoCase(const S: string): integer;
  208. {* Returns index of first string, equal to given one (while comparing it
  209. without case sensitivity). }
  210. function IndexOfStrL_NoCase( Str: PChar; L: Integer ): integer;
  211. {* Returns index of first string, equal to given one (while comparing it
  212. without case sensitivity). }
  213. function Find(const S: String; var Index: Integer): Boolean;
  214. {* Returns Index of the first string, equal or greater to given pattern, but
  215. works only for sorted TFastStrListEx object. Returns TRUE if exact string found,
  216. otherwise nearest (greater then a pattern) string index is returned,
  217. and the result is FALSE. }
  218. procedure InsertAnsi(Idx: integer; const S: String);
  219. {* Inserts ANSI string before one with given index. }
  220. procedure InsertAnsiObject(Idx: integer; const S: String; Obj: DWORD);
  221. {* Inserts ANSI string before one with given index. }
  222. procedure Insert(Idx: integer; S: PChar);
  223. {* Inserts string before one with given index. }
  224. procedure InsertLen( Idx: Integer; S: PChar; Len: Integer );
  225. {* Inserts string from given PChar. It can contain #0 characters. }
  226. function LoadFromFile(const FileName: string): Boolean;
  227. {* Loads string list from a file. (If file does not exist, nothing
  228. happens). Very fast even for huge text files. }
  229. procedure LoadFromStream(Stream: PStream; Append2List: boolean);
  230. {* Loads string list from a stream (from current position to the end of
  231. a stream). Very fast even for huge text. }
  232. procedure MergeFromFile(const FileName: string);
  233. {* Merges string list with strings in a file. Fast. }
  234. procedure Move(CurIndex, NewIndex: integer);
  235. {* Moves string to another location. }
  236. procedure SetText(const S: string; Append2List: boolean);
  237. {* Allows to set strings of string list from given string (in which
  238. strings are separated by $0D,$0A or $0D characters). Text can
  239. contain #0 characters. Works very fast. This method is used in
  240. all others, working with text arrays (LoadFromFile, MergeFromFile,
  241. Assign, AddStrings). }
  242. function SaveToFile(const FileName: string): Boolean;
  243. {* Stores string list to a file. }
  244. procedure SaveToStream(Stream: PStream);
  245. {* Saves string list to a stream (from current position). }
  246. function AppendToFile(const FileName: string): Boolean;
  247. {* Appends strings of string list to the end of a file. }
  248. property Count: integer read fCount;
  249. {* Number of strings in a string list. }
  250. property Items[Idx: integer]: string read Get write Put; default;
  251. {* Strings array items. If item does not exist, empty string is returned.
  252. But for assign to property, string with given index *must* exist. }
  253. property ItemPtrs[ Idx: Integer ]: PChar read GetPChars;
  254. {* Fast access to item strings as PChars. }
  255. property ItemLen[ Idx: Integer ]: Integer read GetItemLen;
  256. {* Length of string item. }
  257. function Last: String;
  258. {* Last item (or '', if string list is empty). }
  259. property Text: string read GetTextStr write SetTextStr;
  260. {* Content of string list as a single string (where strings are separated
  261. by characters $0D,$0A). }
  262. procedure Swap( Idx1, Idx2 : Integer );
  263. {* Swaps to strings with given indeces. }
  264. procedure Sort( CaseSensitive: Boolean );
  265. {* Call it to sort string list. }
  266. public
  267. function AddObject( S: PChar; Obj: DWORD ): Integer;
  268. {* Adds string S (null-terminated) with associated object Obj. }
  269. function AddObjectLen( S: PChar; Len: Integer; Obj: DWORD ): Integer;
  270. {* Adds string S of length Len with associated object Obj. }
  271. procedure InsertObject( Idx: Integer; S: PChar; Obj: DWORD );
  272. {* Inserts string S (null-terminated) at position Idx in the list,
  273. associating it with object Obj. }
  274. procedure InsertObjectLen( Idx: Integer; S: PChar; Len: Integer; Obj: DWORD );
  275. {* Inserts string S of length Len at position Idx in the list,
  276. associating it with object Obj. }
  277. property Objects[ Idx: Integer ]: DWORD read GetObject write SetObject;
  278. {* Access to objects associated with strings in the list. }
  279. public
  280. procedure Append( S: PChar );
  281. {* Appends S (null-terminated) to the last string in FastStrListEx object, very fast. }
  282. procedure AppendLen( S: PChar; Len: Integer );
  283. {* Appends S of length Len to the last string in FastStrListEx object, very fast. }
  284. procedure AppendInt2Hex( N: DWORD; MinDigits: Integer );
  285. {* Converts N to hexadecimal and appends resulting string to the last
  286. string, very fast. }
  287. public
  288. property Values[ Name: PChar ]: PChar read GetValues;
  289. {* Returns a value correspondent to the Name an ini-file-like string list
  290. (having Name1=Value1 Name2=Value2 etc. in each string). }
  291. function IndexOfName( AName: PChar ): Integer;
  292. {* Searches string starting from 'AName=' in string list like ini-file. }
  293. end;
  294. function NewFastStrListEx: PFastStrListEx;
  295. {* Creates FastStrListEx object. }
  296. var Upper: array[ Char ] of Char;
  297. {* An table to convert char to uppercase very fast. First call InitUpper. }
  298. Upper_Initialized: Boolean;
  299. procedure InitUpper;
  300. {* Call this fuction ones to fill Upper[ ] table before using it. }
  301. //[TWStrList]
  302. {-}
  303. {$IFNDEF _FPC}
  304. procedure WStrCopy( Dest, Src: PWideChar );
  305. {* Copies null-terminated Unicode string (terminated null also copied). }
  306. function WStrCmp( W1, W2: PWideChar ): Integer;
  307. {* Compares two null-terminated Unicode strings. }
  308. {$ENDIF _FPC}
  309. {$IFNDEF _D2} //------------------ WideString is not supported in D2 -----------
  310. type
  311. PWStrList = ^TWstrList;
  312. {* }
  313. //[TWstrList DEFINITION]
  314. TWStrList = object( TObj )
  315. {* String list to store Unicode (null-terminated) strings. }
  316. protected
  317. function GetCount: Integer;
  318. function GetItems(Idx: Integer): WideString;
  319. procedure SetItems(Idx: Integer; const Value: WideString);
  320. function GetPtrs(Idx: Integer): PWideChar;
  321. function GetText: WideString;
  322. protected
  323. fList: PList;
  324. fText: PWideChar;
  325. fTextBufSz: Integer;
  326. fTmp1, fTmp2: WideString;
  327. procedure Init; virtual;
  328. public
  329. procedure SetText(const Value: WideString);
  330. {* See also TStrList.SetText }
  331. destructor Destroy; virtual;
  332. {* }
  333. procedure Clear;
  334. {* See also TStrList.Clear }
  335. property Items[ Idx: Integer ]: WideString read GetItems write SetItems;
  336. {* See also TStrList.Items }
  337. property ItemPtrs[ Idx: Integer ]: PWideChar read GetPtrs;
  338. {* See also TStrList.ItemPtrs }
  339. property Count: Integer read GetCount;
  340. {* See also TStrList.Count }
  341. function Add( const W: WideString ): Integer;
  342. {* See also TStrList.Add }
  343. procedure Insert( Idx: Integer; const W: WideString );
  344. {* See also TStrList.Insert }
  345. procedure Delete( Idx: Integer );
  346. {* See also TStrList.Delete }
  347. property Text: WideString read GetText write SetText;
  348. {* See also TStrList.Text }
  349. procedure AddWStrings( WL: PWStrList );
  350. {* See also TStrList.AddStrings }
  351. procedure Assign( WL: PWStrList );
  352. {* See also TStrList.Assign }
  353. function LoadFromFile( const Filename: String ): Boolean;
  354. {* See also TStrList.LoadFromFile }
  355. procedure LoadFromStream( Strm: PStream );
  356. {* See also TStrList.LoadFromStream }
  357. function MergeFromFile( const Filename: String ): Boolean;
  358. {* See also TStrList.MergeFromFile }
  359. procedure MergeFromStream( Strm: PStream );
  360. {* See also TStrList.MergeFromStream }
  361. function SaveToFile( const Filename: String ): Boolean;
  362. {* See also TStrList.SaveToFile }
  363. procedure SaveToStream( Strm: PStream );
  364. {* See also TStrList.SaveToStream }
  365. function AppendToFile( const Filename: String ): Boolean;
  366. {* See also TStrList.AppendToFile }
  367. procedure Swap( Idx1, Idx2: Integer );
  368. {* See also TStrList.Swap }
  369. procedure Sort( CaseSensitive: Boolean );
  370. {* See also TStrList.Sort }
  371. procedure Move( IdxOld, IdxNew: Integer );
  372. {* See also TStrList.Move }
  373. end;
  374. //[END OF TWStrList DEFINITION]
  375. //[TWStrListEx]
  376. PWStrListEx = ^TWStrListEx;
  377. //[TWStrListEx DEFINITION]
  378. TWStrListEx = object( TWStrList )
  379. {* Extended Unicode string list (with Objects). }
  380. protected
  381. function GetObjects(Idx: Integer): DWORD;
  382. procedure SetObjects(Idx: Integer; const Value: DWORD);
  383. procedure ProvideObjectsCapacity( NewCap: Integer );
  384. protected
  385. fObjects: PList;
  386. procedure Init; virtual;
  387. public
  388. destructor Destroy; virtual;
  389. {* }
  390. property Objects[ Idx: Integer ]: DWORD read GetObjects write SetObjects;
  391. {* }
  392. procedure AddWStrings( WL: PWStrListEx );
  393. {* }
  394. procedure Assign( WL: PWStrListEx );
  395. {* }
  396. procedure Clear;
  397. {* }
  398. procedure Delete( Idx: Integer );
  399. {* }
  400. procedure Move( IdxOld, IdxNew: Integer );
  401. {* }
  402. function AddObject( const S: WideString; Obj: DWORD ): Integer;
  403. {* Adds a string and associates given number with it. Index of the item added
  404. is returned. }
  405. procedure InsertObject( Before: Integer; const S: WideString; Obj: DWORD );
  406. {* Inserts a string together with object associated. }
  407. function IndexOfObj( Obj: Pointer ): Integer;
  408. {* Returns an index of a string associated with the object passed as a
  409. parameter. If there are no such strings, -1 is returned. }
  410. end;
  411. //[END OF TWStrListEx DEFINITION]
  412. //[NewWStrList DECLARATION]
  413. function NewWStrList: PWStrList;
  414. {* Creates new TWStrList object and returns a pointer to it. }
  415. //[NewWStrListEx DECLARATION]
  416. function NewWStrListEx: PWStrListEx;
  417. {* Creates new TWStrListEx objects and returns a pointer to it. }
  418. {$ENDIF}
  419. //[CABINET FILES OBJECT]
  420. type
  421. {++}(*TCabFile = class;*){--}
  422. PCABFile = {-}^{+}TCABFile;
  423. TOnNextCAB = function( Sender: PCABFile ): String of object;
  424. TOnCABFile = function( Sender: PCABFile; var FileName: String ): Boolean of object;
  425. { ----------------------------------------------------------------------
  426. TCabFile - windows cabinet files
  427. ----------------------------------------------------------------------- }
  428. //[TCabFile DEFINITION]
  429. TCABFile = object( TObj )
  430. {* An object to simplify extracting files from a cabinet (.CAB) files.
  431. The only what need to use this object, setupapi.dll. It is provided
  432. with all latest versions of Windows. }
  433. protected
  434. FPaths: PStrList;
  435. FNames: PStrList;
  436. FOnNextCAB: TOnNextCAB;
  437. FOnFile: TOnCABFile;
  438. FTargetPath: String;
  439. FSetupapi: THandle;
  440. function GetNames(Idx: Integer): String;
  441. function GetCount: Integer;
  442. function GetPaths(Idx: Integer): String;
  443. function GetTargetPath: String;
  444. protected
  445. FGettingNames: Boolean;
  446. FCurCAB: Integer;
  447. public
  448. destructor Destroy; {-}virtual;{+}{++}(*override;*){--}
  449. {* }
  450. property Paths[ Idx: Integer ]: String read GetPaths;
  451. {* A list of CAB-files. It is stored, when constructing function
  452. OpenCABFile called. }
  453. property Names[ Idx: Integer ]: String read GetNames;
  454. {* A list of file names, stored in a sequence of CAB files. To get know,
  455. how many files are there, check Count property. }
  456. property Count: Integer read GetCount;
  457. {* Number of files stored in a sequence of CAB files. }
  458. function Execute: Boolean;
  459. {* Call this method to extract or enumerate files in CAB. For every
  460. file, found during executing, event OnFile is alled (if assigned).
  461. If the event handler (if any) does not provide full target path for
  462. a file to extract to, property TargetPath is applyed (also if it
  463. is assigned), or file is extracted to the default directory (usually
  464. the same directory there CAB file is located, or current directory
  465. - by a decision of the system).
  466. |<br>
  467. If a sequence of CAB files is used, and not all names for CAB files
  468. are provided (absent or represented by a string '?' ), an event
  469. OnNextCAB is called to obtain the name of the next CAB file.}
  470. property CurCAB: Integer read FCurCAB;
  471. {* Index of current CAB file in a sequence of CAB files. When OnNextCAB
  472. event is called (if any), CurCAB property is already set to the
  473. index of path, what should be provided. }
  474. property OnNextCAB: TOnNextCAB read FOnNextCAB write FOnNextCAB;
  475. {* This event is called, when a series of CAB files is needed and not
  476. all CAB file names are provided (absent or represented by '?' string).
  477. If this event is not assigned, the user is prompted to browse file. }
  478. property OnFile: TOnCABFile read FOnFile write FOnFile;
  479. {* This event is called for every file found during Execute method.
  480. In an event handler (if any assigned), it is possible to return
  481. False to skip file, or to provide another full target path for
  482. file to extract it to, then default. If the event is not assigned,
  483. all files are extracted either to default directory, or to the
  484. directory TargetPath, if it is provided. }
  485. property TargetPath: String read GetTargetPath write FTargetPath;
  486. {* Optional target directory to place there extracted files. }
  487. end;
  488. //[END OF TCABFile DEFINITION]
  489. //[OpenCABFile DECLARATION]
  490. function OpenCABFile( const APaths: array of String ): PCABFile;
  491. {* This function creates TCABFile object, passing a sequence of CAB file names
  492. (fully qualified). It is possible not to provide all names here, or pass '?'
  493. string in place of some of those. For such files, either an event OnNextCAB
  494. will be called, or (and) user will be prompted to browse file during
  495. executing (i.e. Extracting). }
  496. //[DIRCHANGE]
  497. type
  498. {++}(*TDirChange = class;*){--}
  499. PDirChange = {-}^{+}TDirChange;
  500. {* }
  501. TOnDirChange = procedure (Sender: PDirChange; const Path: string) of object;
  502. {* Event type to define OnChange event for folder monitoring objects. }
  503. TFileChangeFilters = (fncFileName, fncDirName, fncAttributes, fncSize,
  504. fncLastWrite, fncLastAccess, fncCreation, fncSecurity);
  505. {* Possible change monitor filters. }
  506. TFileChangeFilter = set of TFileChangeFilters;
  507. {* Set of filters to pass to a constructor of TDirChange object. }
  508. { ----------------------------------------------------------------------
  509. TDirChange object
  510. ----------------------------------------------------------------------- }
  511. //[TDirChange DEFINITION]
  512. TDirChange = object(TObj)
  513. {* Object type to monitor changes in certain folder. }
  514. protected
  515. FOnChange: TOnDirChange;
  516. FHandle: THandle;
  517. FPath: string;
  518. FMonitor: PThread;
  519. function Execute( Sender: PThread ): Integer;
  520. procedure Changed;
  521. protected
  522. {++}(*public*){--}
  523. destructor Destroy; {-}virtual;{+}{++}(*override;*){--}
  524. {*}
  525. public
  526. property Handle: THandle read FHandle;
  527. {* Handle of file change notification object. *}
  528. property Path: String read FPath; //write SetPath;
  529. {* Path to monitored folder (to a root, if tree of folders
  530. is under monitoring). }
  531. end;
  532. //[END OF TDirChange DEFINITION]
  533. //[NewDirChangeNotifier DECLARATION]
  534. function NewDirChangeNotifier( const Path: String; Filter: TFileChangeFilter;
  535. WatchSubtree: Boolean; ChangeProc: TOnDirChange ): PDirChange;
  536. {* Creates notification object TDirChangeNotifier. If something wrong (e.g.,
  537. passed directory does not exist), nil is returned as a result. When change
  538. is notified, ChangeProc is called always in main thread context.
  539. (Please note, that ChangeProc can not be nil).
  540. If empty filter is passed, default filter is used:
  541. [fncFileName..fncLastWrite]. }
  542. //[METAFILES]
  543. type
  544. {++}(*TMetafile = class;*){--}
  545. PMetafile = {-}^{+}TMetafile;
  546. { ----------------------------------------------------------------------
  547. TMetafile - Windows metafile and Enchanced Metafile image
  548. ----------------------------------------------------------------------- }
  549. //[TMetafile DEFINITION]
  550. TMetafile = object( TObj )
  551. {* Object type to incapsulate metafile image. }
  552. protected
  553. function GetHeight: Integer;
  554. function GetWidth: Integer;
  555. procedure SetHandle(const Value: THandle);
  556. protected
  557. fHandle: THandle;
  558. fHeader: PEnhMetaHeader;
  559. procedure RetrieveHeader;
  560. public
  561. destructor Destroy; {-}virtual;{+}{++}(*override;*){--}
  562. {* }
  563. procedure Clear;
  564. {* }
  565. function Empty: Boolean;
  566. {* Returns TRUE if empty}
  567. property Handle: THandle read fHandle write SetHandle;
  568. {* Returns handle of enchanced metafile. }
  569. function LoadFromStream( Strm: PStream ): Boolean;
  570. {* Loads emf or wmf file format from stream. }
  571. function LoadFromFile( const Filename: String ): Boolean;
  572. {* Loads emf or wmf from stream. }
  573. procedure Draw( DC: HDC; X, Y: Integer );
  574. {* Draws enchanced metafile on DC. }
  575. procedure StretchDraw( DC: HDC; const R: TRect );
  576. {* Draws enchanced metafile stretched. }
  577. property Width: Integer read GetWidth;
  578. {* Native width of the metafile. }
  579. property Height: Integer read GetHeight;
  580. {* Native height of the metafile. }
  581. end;
  582. //[END OF TMetafile DEFINITION]
  583. //[NewMetafile DECLARATION]
  584. function NewMetafile: PMetafile;
  585. {* Creates metafile object. }
  586. //[Metafile CONSTANTS, STRUCTURES, ETC.]
  587. const
  588. WMFKey = Integer($9AC6CDD7);
  589. WMFWord = $CDD7;
  590. type
  591. TMetafileHeader = packed record
  592. Key: Longint;
  593. Handle: SmallInt;
  594. Box: TSmallRect;
  595. Inch: Word;
  596. Reserved: Longint;
  597. CheckSum: Word;
  598. end;
  599. function ComputeAldusChecksum(var WMF: TMetafileHeader): Word;
  600. {++}(*
  601. function SetEnhMetaFileBits(p1: UINT; p2: PChar): HENHMETAFILE; stdcall;
  602. function PlayEnhMetaFile(DC: HDC; p2: HENHMETAFILE; const p3: TRect): BOOL; stdcall;
  603. *){--}
  604. // NewActionList, TAction - by Yury Sidorov
  605. //[ACTIONS OBJECT]
  606. { ----------------------------------------------------------------------
  607. TAction and TActionList
  608. ----------------------------------------------------------------------- }
  609. type
  610. PControlRec = ^TControlRec;
  611. TOnUpdateCtrlEvent = procedure(Sender: PControlRec) of object;
  612. TCtrlKind = (ckControl, ckMenu, ckToolbar);
  613. TControlRec = record
  614. Ctrl: PObj;
  615. CtrlKind: TCtrlKind;
  616. ItemID: integer;
  617. UpdateProc: TOnUpdateCtrlEvent;
  618. end;
  619. {++}(* TAction = class;*){--}
  620. PAction = {-}^{+}TAction;
  621. {++}(* TActionList = class;*){--}
  622. PActionList = {-}^{+}TActionList;
  623. //[TAction DEFINITION]
  624. TAction = {-} object( TObj ) {+}{++}(*class*){--}
  625. {*! Use action objects, in conjunction with action lists, to centralize the response
  626. to user commands (actions).
  627. Use AddControl, AddMenuItem, AddToolbarButton methods to link controls to an action.
  628. See also TActionList.
  629. }
  630. protected
  631. FControls: PList;
  632. FCaption: string;
  633. FChecked: boolean;
  634. FVisible: boolean;
  635. FEnabled: boolean;
  636. FHelpContext: integer;
  637. FHint: string;
  638. FOnExecute: TOnEvent;
  639. FAccelerator: TMenuAccelerator;
  640. FShortCut: string;
  641. procedure DoOnMenuItem(Sender: PMenu; Item: Integer);
  642. procedure DoOnToolbarButtonClick(Sender: PControl; BtnID: Integer);
  643. procedure DoOnControlClick(Sender: PObj);
  644. procedure SetCaption(const Value: string);
  645. procedure SetChecked(const Value: boolean);
  646. procedure SetEnabled(const Value: boolean);
  647. procedure SetHelpContext(const Value: integer);
  648. procedure SetHint(const Value: string);
  649. procedure SetVisible(const Value: boolean);
  650. procedure SetAccelerator(const Value: TMenuAccelerator);
  651. procedure UpdateControls;
  652. procedure LinkCtrl(ACtrl: PObj; ACtrlKind: TCtrlKind; AItemID: integer; AUpdateProc: TOnUpdateCtrlEvent);
  653. procedure SetOnExecute(const Value: TOnEvent);
  654. procedure UpdateCtrl(Sender: PControlRec);
  655. procedure UpdateMenu(Sender: PControlRec);
  656. procedure UpdateToolbar(Sender: PControlRec);
  657. public
  658. destructor Destroy; {-}virtual;{+}{++}(*override;*){--}
  659. procedure LinkControl(Ctrl: PControl);
  660. {* Add a link to a TControl or descendant control. }
  661. procedure LinkMenuItem(Menu: PMenu; MenuItemIdx: integer);
  662. {* Add a link to a menu item. }
  663. procedure LinkToolbarButton(Toolbar: PControl; ButtonIdx: integer);
  664. {* Add a link to a toolbar button. }
  665. procedure Execute;
  666. {* Executes a OnExecute event handler. }
  667. property Caption: string read FCaption write SetCaption;
  668. {* Text caption. }
  669. property Hint: string read FHint write SetHint;
  670. {* Hint (tooltip). Currently used for toolbar buttons only. }
  671. property Checked: boolean read FChecked write SetChecked;
  672. {* Checked state. }
  673. property Enabled: boolean read FEnabled write SetEnabled;
  674. {* Enabled state. }
  675. property Visible: boolean read FVisible write SetVisible;
  676. {* Visible state. }
  677. property HelpContext: integer read FHelpContext write SetHelpContext;
  678. {* Help context. }
  679. property Accelerator: TMenuAccelerator read FAccelerator write SetAccelerator;
  680. {* Accelerator for menu items. }
  681. property OnExecute: TOnEvent read FOnExecute write SetOnExecute;
  682. {* This event is executed when user clicks on a linked object or Execute method was called. }
  683. end;
  684. //[END OF TAction DEFINITION]
  685. //[TActionList DEFINITION]
  686. TActionList = {-} object( TObj ) {+}{++}(*class*){--}
  687. {*! TActionList maintains a list of actions used with components and controls,
  688. such as menu items and buttons.
  689. Action lists are used, in conjunction with actions, to centralize the response
  690. to user commands (actions).
  691. Write an OnUpdateActions handler to update actions state.
  692. Created using function NewActionList.
  693. See also TAction.
  694. }
  695. protected
  696. FOwner: PControl;
  697. FActions: PList;
  698. FOnUpdateActions: TOnEvent;
  699. function GetActions(Idx: integer): PAction;
  700. function GetCount: integer;
  701. protected
  702. procedure DoUpdateActions(Sender: PObj);
  703. public
  704. destructor Destroy; {-}virtual;{+}{++}(*override;*){--}
  705. function Add(const ACaption, AHint: string; OnExecute: TOnEvent): PAction;
  706. {* Add a new action to the list. Returns pointer to action object. }
  707. procedure Delete(Idx: integer);
  708. {* Delete action by index from list. }
  709. procedure Clear;
  710. {* Clear all actions in the list. }
  711. property Actions[Idx: integer]: PAction read GetActions;
  712. {* Access to actions in the list. }
  713. property Count: integer read GetCount;
  714. {* Number of actions in the list.. }
  715. property OnUpdateActions: TOnEvent read FOnUpdateActions write FOnUpdateActions;
  716. {* Event handler to update actions state. This event is called each time when application
  717. goes in the idle state (no messages in the queue). }
  718. end;
  719. //[END OF TActionList DEFINITION]
  720. //[NewActionList DECLARATION]
  721. function NewActionList(AOwner: PControl): PActionList;
  722. {* Action list constructor. AOwner - owner form. }
  723. implementation
  724. type
  725. PCrackList = ^TCrackList;
  726. TCrackList = object( TList )
  727. end;
  728. {------------------------------------------------------------------------------)
  729. | |
  730. | T L i s t E x |
  731. | |
  732. (------------------------------------------------------------------------------}
  733. { TListEx }
  734. //[function NewListEx]
  735. function NewListEx: PListEx;
  736. begin
  737. {-}
  738. new( Result, Create );
  739. {+}{++}(*Result := PListEx.Create;*){--}
  740. Result.fList := NewList;
  741. Result.fObjects := NewList;
  742. end;
  743. //[END NewListEx]
  744. //[procedure TListEx.Add]
  745. procedure TListEx.Add(Value: Pointer);
  746. begin
  747. AddObj( Value, nil );
  748. end;
  749. //[procedure TListEx.AddObj]
  750. procedure TListEx.AddObj(Value, Obj: Pointer);
  751. var C: Integer;
  752. begin
  753. C := Count;
  754. fList.Add( Value );
  755. fObjects.Insert( C, Obj );
  756. end;
  757. //[procedure TListEx.Clear]
  758. procedure TListEx.Clear;
  759. begin
  760. fList.Clear;
  761. fObjects.Clear;
  762. end;
  763. //[procedure TListEx.Delete]
  764. procedure TListEx.Delete(Idx: Integer);
  765. begin
  766. DeleteRange( Idx, 1 );
  767. end;
  768. //[procedure TListEx.DeleteRange]
  769. procedure TListEx.DeleteRange(Idx, Len: Integer);
  770. begin
  771. fList.DeleteRange( Idx, Len );
  772. fObjects.DeleteRange( Idx, Len );
  773. end;
  774. //[destructor TListEx.Destroy]
  775. destructor TListEx.Destroy;
  776. begin
  777. fList.Free;
  778. fObjects.Free;
  779. inherited;
  780. end;
  781. //[function TListEx.GetAddBy]
  782. function TListEx.GetAddBy: Integer;
  783. begin
  784. Result := fList.AddBy;
  785. end;
  786. //[function TListEx.GetCount]
  787. function TListEx.GetCount: Integer;
  788. begin
  789. Result := fList.Count;
  790. end;
  791. //[function TListEx.GetEx]
  792. function TListEx.GetEx(Idx: Integer): Pointer;
  793. begin
  794. Result := fList.Items[ Idx ];
  795. end;
  796. //[function TListEx.IndexOf]
  797. function TListEx.IndexOf(Value: Pointer): Integer;
  798. begin
  799. Result := fList.IndexOf( Value );
  800. end;
  801. //[function TListEx.IndexOfObj]
  802. function TListEx.IndexOfObj(Obj: Pointer): Integer;
  803. begin
  804. Result := fObjects.IndexOf( Obj );
  805. end;
  806. //[procedure TListEx.Insert]
  807. procedure TListEx.Insert(Idx: Integer; Value: Pointer);
  808. begin
  809. InsertObj( Idx, Value, nil );
  810. end;
  811. //[procedure TListEx.InsertObj]
  812. procedure TListEx.InsertObj(Idx: Integer; Value, Obj: Pointer);
  813. begin
  814. fList.Insert( Idx, Value );
  815. fObjects.Insert( Idx, Obj );
  816. end;
  817. //[function TListEx.Last]
  818. function TListEx.Last: Pointer;
  819. begin
  820. Result := fList.Last;
  821. end;
  822. //[function TListEx.LastObj]
  823. function TListEx.LastObj: Pointer;
  824. begin
  825. Result := fObjects.Last;
  826. end;
  827. //[procedure TListEx.MoveItem]
  828. procedure TListEx.MoveItem(OldIdx, NewIdx: Integer);
  829. begin
  830. fList.MoveItem( OldIdx, NewIdx );
  831. fObjects.MoveItem( OldIdx, NewIdx );
  832. end;
  833. //[procedure TListEx.PutEx]
  834. procedure TListEx.PutEx(Idx: Integer; const Value: Pointer);
  835. begin
  836. fList.Items[ Idx ] := Value;
  837. end;
  838. //[procedure TListEx.Set_AddBy]
  839. procedure TListEx.Set_AddBy(const Value: Integer);
  840. begin
  841. fList.AddBy := Value;
  842. fObjects.AddBy := Value;
  843. end;
  844. //[procedure TListEx.Swap]
  845. procedure TListEx.Swap(Idx1, Idx2: Integer);
  846. begin
  847. fList.Swap( Idx1, Idx2 );
  848. fObjects.Swap( Idx1, Idx2 );
  849. end;
  850. {------------------------------------------------------------------------------)
  851. | |
  852. | T B i t s |
  853. | |
  854. (------------------------------------------------------------------------------}
  855. { TBits }
  856. //[function NewBits]
  857. function NewBits: PBits;
  858. begin
  859. {-}
  860. new( Result, Create );
  861. {+}{++}(*Result := PBits.Create;*){--}
  862. Result.fList := NewList;
  863. //Result.fList.fAddBy := 1;
  864. end;
  865. //[procedure TBits.AssignBits]
  866. procedure TBits.AssignBits(ToIdx: Integer; FromBits: PBits; FromIdx,
  867. N: Integer);
  868. var i: Integer;
  869. NewCount: Integer;
  870. begin
  871. if FromIdx >= FromBits.Count then Exit;
  872. if FromIdx + N > FromBits.Count then
  873. N := FromBits.Count - FromIdx;
  874. Capacity := (ToIdx + N + 8) div 8;
  875. NewCount := Max( Count, ToIdx + N - 1 );
  876. fCount := Max( NewCount, fCount );
  877. PCrackList( fList ).fCount := (Capacity + 3) div 4;
  878. while ToIdx and $1F <> 0 do
  879. begin
  880. Bits[ ToIdx ] := FromBits.Bits[ FromIdx ];
  881. Inc( ToIdx );
  882. Inc( FromIdx );
  883. Dec( N );
  884. if N = 0 then Exit;
  885. end;
  886. Move( PByte( Integer( PCrackList( FromBits.fList ).fItems ) + (FromIdx + 31) div 32 )^,
  887. PByte( Integer( PCrackList( fList ).fItems ) + ToIdx div 32 )^, (N + 31) div 32 );
  888. FromIdx := FromIdx and $1F;
  889. if FromIdx <> 0 then
  890. begin // shift data by (Idx and $1F) bits right
  891. for i := ToIdx div 32 to fList.Count-2 do
  892. fList.Items[ i ] := Pointer(
  893. (DWORD( fList.Items[ i ] ) shr FromIdx) or
  894. (DWORD( fList.Items[ i+1 ] ) shl (32 - FromIdx))
  895. );
  896. fList.Items[ fList.Count-1 ] := Pointer(
  897. DWORD( fList.Items[ fList.Count-1 ] ) shr FromIdx
  898. );
  899. end;
  900. end;
  901. //[function TBits.Copy]
  902. procedure TBits.Clear;
  903. begin
  904. fCount := 0;
  905. fList.Clear;
  906. end;
  907. function TBits.Copy(From, BitsCount: Integer): PBits;
  908. var Shift, N: Integer;
  909. FirstItemPtr: Pointer;
  910. begin
  911. Result := NewBits;
  912. if BitsCount = 0 then Exit;
  913. Result.Capacity := BitsCount + 32;
  914. Result.fCount := BitsCount;
  915. Move( PCrackList( fList ).fItems[ From shr 5 ],
  916. PCrackList( Result.fList ).fItems[ 0 ], (Count + 31) div 32 );
  917. Shift := From and $1F;
  918. if Shift <> 1 then
  919. begin
  920. N := (BitsCount + 31) div 32;
  921. FirstItemPtr := @ PCrackList( Result.fList ).fItems[ N - 1 ];
  922. asm
  923. PUSH ESI
  924. PUSH EDI
  925. MOV ESI, FirstItemPtr
  926. MOV EDI, ESI
  927. STD
  928. MOV ECX, N
  929. XOR EAX, EAX
  930. CDQ
  931. @@1:
  932. PUSH ECX
  933. LODSD
  934. MOV ECX, Shift
  935. SHRD EAX, EDX, CL
  936. STOSD
  937. SUB ECX, 32
  938. NEG ECX
  939. SHR EDX, CL
  940. POP ECX
  941. LOOP @@1
  942. CLD
  943. POP EDI
  944. POP ESI
  945. end {$IFDEF F_P} ['EAX','EDX','ECX'] {$ENDIF};
  946. end;
  947. end;
  948. //[destructor TBits.Destroy]
  949. destructor TBits.Destroy;
  950. begin
  951. fList.Free;
  952. inherited;
  953. end;
  954. //[function TBits.GetBit]
  955. {$IFDEF ASM_VERSION}
  956. function TBits.GetBit(Idx: Integer): Boolean;
  957. asm
  958. CMP EDX, [EAX].FCount
  959. JL @@1
  960. XOR EAX, EAX
  961. RET
  962. @@1:
  963. MOV EAX, [EAX].fList
  964. {TEST EAX, EAX
  965. JZ @@exit}
  966. MOV EAX, [EAX].TList.fItems
  967. BT [EAX], EDX
  968. SETC AL
  969. @@exit:
  970. end;
  971. {$ELSE}
  972. function TBits.GetBit(Idx: Integer): Boolean;
  973. begin
  974. if (Idx >= Count) {or (PCrackList( fList ).fItems = nil)} then Result := FALSE else
  975. Result := ( ( DWORD( PCrackList( fList ).fItems[ Idx shr 5 ] ) shr (Idx and $1F)) and 1 ) <> 0;
  976. end;
  977. {$ENDIF}
  978. //[function TBits.GetCapacity]
  979. function TBits.GetCapacity: Integer;
  980. begin
  981. Result := fList.Capacity * 32;
  982. end;
  983. //[function TBits.GetSize]
  984. function TBits.GetSize: Integer;
  985. begin
  986. Result := ( PCrackList( fList ).fCount + 3) div 4;
  987. end;
  988. {$IFDEF ASM_noVERSION}
  989. //[function TBits.IndexOf]
  990. function TBits.IndexOf(Value: Boolean): Integer;
  991. asm //cmd //opd
  992. PUSH EDI
  993. MOV EDI, [EAX].fList
  994. MOV ECX, [EDI].TList.fCount
  995. @@ret_1:
  996. OR EAX, -1
  997. JECXZ @@ret_EAX
  998. MOV EDI, [EDI].TList.fItems
  999. TEST DL, DL
  1000. MOV EDX, EDI
  1001. JE @@of_false
  1002. INC EAX
  1003. REPZ SCASD
  1004. JE @@ret_1
  1005. MOV EAX, [EDI-4]
  1006. NOT EAX
  1007. JMP @@calc_offset
  1008. BSF EAX, EAX
  1009. SUB EDI, EDX
  1010. SHR EDI, 2
  1011. ADD EAX, EDI
  1012. JMP @@ret_EAX
  1013. @@of_false:
  1014. REPE SCASD
  1015. JE @@ret_1
  1016. MOV EAX, [EDI-4]
  1017. @@calc_offset:
  1018. BSF EAX, EAX
  1019. DEC EAX
  1020. SUB EDI, 4
  1021. SUB EDI, EDX
  1022. SHL EDI, 3
  1023. ADD EAX, EDI
  1024. @@ret_EAX:
  1025. POP EDI
  1026. end;
  1027. {$ELSE ASM_VERSION} //Pascal
  1028. function TBits.IndexOf(Value: Boolean): Integer;
  1029. var I: Integer;
  1030. D: DWORD;
  1031. begin
  1032. Result := -1;
  1033. if Value then
  1034. begin
  1035. for I := 0 to fList.Count-1 do
  1036. begin
  1037. D := DWORD( PCrackList( fList ).fItems[ I ] );
  1038. if D <> 0 then
  1039. begin
  1040. asm
  1041. MOV EAX, D
  1042. BSF EAX, EAX
  1043. MOV D, EAX
  1044. end {$IFDEF F_P} [ 'EAX' ] {$ENDIF};
  1045. Result := I * 32 + Integer( D );
  1046. break;
  1047. end;
  1048. end;
  1049. end
  1050. else
  1051. begin
  1052. for I := 0 to PCrackList( fList ).fCount-1 do
  1053. begin
  1054. D := DWORD( PCrackList( fList ).fItems[ I ] );
  1055. if D <> $FFFFFFFF then
  1056. begin
  1057. asm
  1058. MOV EAX, D
  1059. NOT EAX
  1060. BSF EAX, EAX
  1061. MOV D, EAX
  1062. end {$IFDEF F_P} [ 'EAX' ] {$ENDIF};
  1063. Result := I * 32 + Integer( D );
  1064. break;
  1065. end;
  1066. end;
  1067. end;
  1068. end;
  1069. {$ENDIF ASM_VERSION}
  1070. //[function TBits.LoadFromStream]
  1071. function TBits.LoadFromStream(strm: PStream): Integer;
  1072. var
  1073. i: Integer;
  1074. begin
  1075. Result := strm.Read( i, 4 );
  1076. if Result < 4 then Exit;
  1077. bits[ i]:= false; //by miek
  1078. fcount:= i;
  1079. i := (i + 7) div 8;
  1080. Inc( Result, strm.Read( PCrackList( fList ).fItems^, i ) );
  1081. end;
  1082. //[function TBits.OpenBit]
  1083. function TBits.OpenBit: Integer;
  1084. begin
  1085. Result := IndexOf( FALSE );
  1086. if Result < 0 then Result := Count;
  1087. end;
  1088. //[function TBits.Range]
  1089. function TBits.Range(Idx, N: Integer): PBits;
  1090. begin
  1091. Result := NewBits;
  1092. Result.AssignBits( 0, @ Self, Idx, N );
  1093. end;
  1094. //[function TBits.SaveToStream]
  1095. function TBits.SaveToStream(strm: PStream): Integer;
  1096. begin
  1097. Result := strm.Write( fCount, 4 );
  1098. if fCount = 0 then Exit;
  1099. Inc( Result, strm.Write( PCrackList( fList ).fItems^, (fCount + 7) div 8 ) );
  1100. end;
  1101. //[procedure TBits.SetBit]
  1102. {$IFDEF ASM_VERSION}
  1103. procedure TBits.SetBit(Idx: Integer; const Value: Boolean);
  1104. asm
  1105. PUSH ECX
  1106. MOV ECX, [EAX].fList
  1107. MOV ECX, [ECX].TList.fCapacity
  1108. SHL ECX, 5
  1109. CMP EDX, ECX
  1110. JLE @@1
  1111. PUSH EDX
  1112. INC EDX
  1113. PUSH EAX
  1114. CALL SetCapacity
  1115. POP EAX
  1116. POP EDX
  1117. @@1:
  1118. CMP EDX, [EAX].FCount
  1119. JL @@2
  1120. INC EDX
  1121. MOV [EAX].fCount, EDX
  1122. DEC EDX
  1123. @@2:
  1124. POP ECX
  1125. MOV EAX, [EAX].fList
  1126. MOV EAX, [EAX].TList.fItems
  1127. SHR ECX, 1
  1128. JC @@2set
  1129. BTR [EAX], EDX
  1130. JMP @@exit
  1131. @@2set:
  1132. BTS [EAX], EDX
  1133. @@exit:
  1134. end;
  1135. {$ELSE}
  1136. procedure TBits.SetBit(Idx: Integer; const Value: Boolean);
  1137. var Msk: DWORD;
  1138. begin
  1139. if Idx >= Capacity then
  1140. Capacity := Idx + 1;
  1141. Msk := 1 shl (Idx and $1F);
  1142. if Value then
  1143. PCrackList( fList ).fItems[ Idx shr 5 ] := Pointer(
  1144. DWORD(PCrackList( fList ).fItems[ Idx shr 5 ]) or Msk)
  1145. else
  1146. PCrackList( fList ).fItems[ Idx shr 5 ] := Pointer(
  1147. DWORD(PCrackList( fList ).fItems[ Idx shr 5 ]) and not Msk);
  1148. if Idx >= fCount then
  1149. fCount := Idx + 1;
  1150. end;
  1151. {$ENDIF}
  1152. //[procedure TBits.SetCapacity]
  1153. procedure TBits.SetCapacity(const Value: Integer);
  1154. var OldCap: Integer;
  1155. begin
  1156. OldCap := fList.Capacity;
  1157. fList.Capacity := (Value + 31) div 32;
  1158. if OldCap < fList.Capacity then
  1159. FillChar( PChar( Integer( PCrackList( fList ).fItems ) + OldCap * Sizeof( Pointer ) )^,
  1160. (fList.Capacity - OldCap) * sizeof( Pointer ), 0 );
  1161. end;
  1162. {------------------------------------------------------------------------------)
  1163. | |
  1164. | T F a s t S t r L i s t |
  1165. | |
  1166. (------------------------------------------------------------------------------}
  1167. function NewFastStrListEx: PFastStrListEx;
  1168. begin
  1169. new( Result, Create );
  1170. end;
  1171. procedure InitUpper;
  1172. var c: Char;
  1173. begin
  1174. for c := #0 to #255 do
  1175. Upper[ c ] := AnsiUpperCase( c + #0 )[ 1 ];
  1176. Upper_Initialized := TRUE;
  1177. end;
  1178. { TFastStrListEx }
  1179. function TFastStrListEx.AddAnsi(const S: String): Integer;
  1180. begin
  1181. Result := AddObjectLen( PChar( S ), Length( S ), 0 );
  1182. end;
  1183. function TFastStrListEx.AddAnsiObject(const S: String; Obj: DWORD): Integer;
  1184. begin
  1185. Result := AddObjectLen( PChar( S ), Length( S ), Obj );
  1186. end;
  1187. function TFastStrListEx.Add(S: PChar): integer;
  1188. begin
  1189. Result := AddObjectLen( S, StrLen( S ), 0 )
  1190. end;
  1191. function TFastStrListEx.AddLen(S: PChar; Len: Integer): integer;
  1192. begin
  1193. Result := AddObjectLen( S, Len, 0 )
  1194. end;
  1195. function TFastStrListEx.AddObject(S: PChar; Obj: DWORD): Integer;
  1196. begin
  1197. Result := AddObjectLen( S, StrLen( S ), Obj )
  1198. end;
  1199. function TFastStrListEx.AddObjectLen(S: PChar; Len: Integer; Obj: DWORD): Integer;
  1200. var Dest: PChar;
  1201. begin
  1202. ProvideSpace( Len + 9 );
  1203. Dest := PChar( DWORD( fTextBuf ) + fUsedSiz );
  1204. Result := fCount;
  1205. Inc( fCount );
  1206. fList.Add( Pointer( DWORD(Dest)-DWORD(fTextBuf) ) );
  1207. PDWORD( Dest )^ := Obj;
  1208. Inc( Dest, 4 );
  1209. PDWORD( Dest )^ := Len;
  1210. Inc( Dest, 4 );
  1211. if S <> nil then
  1212. System.Move( S^, Dest^, Len );
  1213. Inc( Dest, Len );
  1214. Dest^ := #0;
  1215. Inc( fUsedSiz, Len+9 );
  1216. end;
  1217. function TFastStrListEx.AppendToFile(const FileName: string): Boolean;
  1218. var F: HFile;
  1219. Txt: String;
  1220. begin
  1221. Txt := Text;
  1222. F := FileCreate( FileName, ofOpenAlways or ofOpenReadWrite or ofShareDenyWrite );
  1223. if F = INVALID_HANDLE_VALUE then Result := FALSE
  1224. else begin
  1225. FileSeek( F, 0, spEnd );
  1226. Result := FileWrite( F, PChar( Txt )^, Length( Txt ) ) = DWORD( Length( Txt ) );
  1227. FileClose( F );
  1228. end;
  1229. end;
  1230. procedure TFastStrListEx.Clear;
  1231. begin
  1232. if FastClear then
  1233. begin
  1234. if fList.Count > 0 then
  1235. PCrackList(fList).FCount := 0;
  1236. end
  1237. else
  1238. begin
  1239. fList.Clear;
  1240. if fTextBuf <> nil then
  1241. FreeMem( fTextBuf );
  1242. fTextBuf := nil;
  1243. end;
  1244. fTextSiz := 0;
  1245. fUsedSiz := 0;
  1246. fCount := 0;
  1247. end;
  1248. procedure TFastStrListEx.Delete(Idx: integer);
  1249. begin
  1250. if (Idx < 0) or (Idx >= Count) then Exit;
  1251. if Idx = Count-1 then
  1252. Dec( fUsedSiz, ItemLen[ Idx ]+9 );
  1253. fList.Delete( Idx );
  1254. Dec( fCount );
  1255. end;
  1256. destructor TFastStrListEx.Destroy;
  1257. begin
  1258. FastClear := FALSE;
  1259. Clear;
  1260. fList.Free;
  1261. inherited;
  1262. end;
  1263. function TFastStrListEx.Find(const S: String; var Index: Integer): Boolean;
  1264. var i: Integer;
  1265. begin
  1266. for i := 0 to Count-1 do
  1267. if (ItemLen[ i ] = Length( S )) and
  1268. ((S = '') or CompareMem( ItemPtrs[ i ], @ S[ 1 ], Length( S ) )) then
  1269. begin
  1270. Index := i;
  1271. Result := TRUE;
  1272. Exit;
  1273. end;
  1274. Result := FALSE;
  1275. end;
  1276. function TFastStrListEx.Get(Idx: integer): string;
  1277. begin
  1278. if (Idx >= 0) and (Idx <= Count) then
  1279. SetString( Result, PChar( DWORD( fTextBuf ) + DWORD( fList.Items[ Idx ] ) + 8 ),
  1280. ItemLen[ Idx ] )
  1281. else
  1282. Result := '';
  1283. end;
  1284. function TFastStrListEx.GetItemLen(Idx: Integer): Integer;
  1285. var Src: PDWORD;
  1286. begin
  1287. if (Idx >= 0) and (Idx <= Count) then
  1288. begin
  1289. Src := PDWORD( DWORD( fTextBuf ) + DWORD( fList.Items[ Idx ] ) + 4 );
  1290. Result := Src^
  1291. end
  1292. else Result := 0;
  1293. end;
  1294. function TFastStrListEx.GetObject(Idx: Integer): DWORD;
  1295. var Src: PDWORD;
  1296. begin
  1297. if (Idx >= 0) and (Idx <= Count) then
  1298. begin
  1299. Src := PDWORD( DWORD( fTextBuf ) + DWORD( fList.Items[ Idx ] ) );
  1300. Result := Src^
  1301. end
  1302. else Result := 0;
  1303. end;
  1304. function TFastStrListEx.GetPChars(Idx: Integer): PChar;
  1305. begin
  1306. if (Idx >= 0) and (Idx <= Count) then
  1307. Result := PChar( DWORD( fTextBuf ) + DWORD( fList.Items[ Idx ] ) + 8 )
  1308. else Result := nil;
  1309. end;
  1310. function TFastStrListEx.GetTextStr: string;
  1311. var L, i: Integer;
  1312. p: PChar;
  1313. begin
  1314. L := 0;
  1315. for i := 0 to Count-1 do
  1316. Inc( L, ItemLen[ i ] + 2 );
  1317. SetLength( Result, L );
  1318. p := PChar( Result );
  1319. for i := 0 to Count-1 do
  1320. begin
  1321. L := ItemLen[ i ];
  1322. if L > 0 then
  1323. begin
  1324. System.Move( ItemPtrs[ i ]^, p^, L );
  1325. Inc( p, L );
  1326. end;
  1327. p^ := #13; Inc( p );
  1328. p^ := #10; Inc( p );
  1329. end;
  1330. end;
  1331. function TFastStrListEx.IndexOf(const S: string): integer;
  1332. begin
  1333. if not Find( S, Result ) then Result := -1;
  1334. end;
  1335. function TFastStrListEx.IndexOf_NoCase(const S: string): integer;
  1336. begin
  1337. Result := IndexOfStrL_NoCase( PChar( S ), Length( S ) );
  1338. end;
  1339. function TFastStrListEx.IndexOfStrL_NoCase(Str: PChar;
  1340. L: Integer): integer;
  1341. var i: Integer;
  1342. begin
  1343. for i := 0 to Count-1 do
  1344. if (ItemLen[ i ] = L) and
  1345. ((L = 0) or (StrLComp_NoCase( ItemPtrs[ i ], Str, L ) = 0)) then
  1346. begin
  1347. Result := i;
  1348. Exit;
  1349. end;
  1350. Result := -1;
  1351. end;
  1352. procedure TFastStrListEx.Init;
  1353. begin
  1354. fList := NewList;
  1355. FastClear := TRUE;
  1356. end;
  1357. procedure TFastStrListEx.InsertAnsi(Idx: integer; const S: String);
  1358. begin
  1359. InsertObjectLen( Idx, PChar( S ), Length( S ), 0 );
  1360. end;
  1361. procedure TFastStrListEx.InsertAnsiObject(Idx: integer; const S: String;
  1362. Obj: DWORD);
  1363. begin
  1364. InsertObjectLen( Idx, PChar( S ), Length( S ), Obj );
  1365. end;
  1366. procedure TFastStrListEx.Insert(Idx: integer; S: PChar);
  1367. begin
  1368. InsertObjectLen( Idx, S, StrLen( S ), 0 )
  1369. end;
  1370. procedure TFastStrListEx.InsertLen(Idx: Integer; S: PChar; Len: Integer);
  1371. begin
  1372. InsertObjectLen( Idx, S, Len, 0 )
  1373. end;
  1374. procedure TFastStrListEx.InsertObject(Idx: Integer; S: PChar; Obj: DWORD);
  1375. begin
  1376. InsertObjectLen( Idx, S, StrLen( S ), Obj );
  1377. end;
  1378. procedure TFastStrListEx.InsertObjectLen(Idx: Integer; S: PChar;
  1379. Len: Integer; Obj: DWORD);
  1380. var Dest: PChar;
  1381. begin
  1382. ProvideSpace( Len+9 );
  1383. Dest := PChar( DWORD( fTextBuf ) + fUsedSiz );
  1384. fList.Insert( Idx, Pointer( DWORD(Dest)-DWORD(fTextBuf) ) );
  1385. PDWORD( Dest )^ := Obj;
  1386. Inc( Dest, 4 );
  1387. PDWORD( Dest )^ := Len;
  1388. Inc( Dest, 4 );
  1389. if S <> nil then
  1390. System.Move( S^, Dest^, Len );
  1391. Inc( Dest, Len );
  1392. Dest^ := #0;
  1393. Inc( fUsedSiz, Len+9 );
  1394. Inc( fCount );
  1395. end;
  1396. function TFastStrListEx.Last: String;
  1397. begin
  1398. if Count > 0 then
  1399. Result := Items[ Count-1 ]
  1400. else
  1401. Result := '';
  1402. end;
  1403. function TFastStrListEx.LoadFromFile(const FileName: string): Boolean;
  1404. var Strm: PStream;
  1405. begin
  1406. Strm := NewReadFileStream( FileName );
  1407. TRY
  1408. Result := Strm.Handle <> INVALID_HANDLE_VALUE;
  1409. if Result then
  1410. LoadFromStream( Strm, FALSE )
  1411. else
  1412. Clear;
  1413. FINALLY
  1414. Strm.Free;
  1415. END;
  1416. end;
  1417. procedure TFastStrListEx.LoadFromStream(Stream: PStream;
  1418. Append2List: boolean);
  1419. var Txt: String;
  1420. begin
  1421. SetLength( Txt, Stream.Size - Stream.Position );
  1422. Stream.Read( Txt[ 1 ], Stream.Size - Stream.Position );
  1423. SetText( Txt, Append2List );
  1424. end;
  1425. procedure TFastStrListEx.MergeFromFile(const FileName: string);
  1426. var Strm: PStream;
  1427. begin
  1428. Strm := NewReadFileStream( FileName );
  1429. TRY
  1430. LoadFromStream( Strm, TRUE );
  1431. FINALLY
  1432. Strm.Free;
  1433. END;
  1434. end;
  1435. procedure TFastStrListEx.Move(CurIndex, NewIndex: integer);
  1436. begin
  1437. Assert( (CurIndex >= 0) and (CurIndex < Count) and (NewIndex >= 0) and
  1438. (NewIndex < Count), 'Item indexes violates TFastStrListEx range' );
  1439. fList.MoveItem( CurIndex, NewIndex );
  1440. end;
  1441. procedure TFastStrListEx.ProvideSpace(AddSize: DWORD);
  1442. var OldTextBuf: PChar;
  1443. begin
  1444. Inc( AddSize, 9 );
  1445. if AddSize > fTextSiz - fUsedSiz then
  1446. begin // увеличение размера буфера
  1447. fTextSiz := Max( 1024, (fUsedSiz + AddSize) * 2 );
  1448. OldTextBuf := fTextBuf;
  1449. GetMem( fTextBuf, fTextSiz );
  1450. if OldTextBuf <> nil then
  1451. begin
  1452. System.Move( OldTextBuf^, fTextBuf^, fUsedSiz );
  1453. FreeMem( OldTextBuf );
  1454. end;
  1455. end;
  1456. if fList.Count >= fList.Capacity then
  1457. fList.Capacity := Max( 100, fList.Count * 2 );
  1458. end;
  1459. procedure TFastStrListEx.Put(Idx: integer; const Value: string);
  1460. var Dest: PChar;
  1461. OldLen: Integer;
  1462. OldObj: DWORD;
  1463. begin
  1464. OldLen := ItemLen[ Idx ];
  1465. if Length( Value ) <= OldLen then
  1466. begin
  1467. Dest := PChar( DWORD( fTextBuf ) + DWORD( fList.Items[ Idx ] ) + 4 );
  1468. PDWORD( Dest )^ := Length( Value );
  1469. Inc( Dest, 4 );
  1470. if Value <> '' then
  1471. System.Move( Value[ 1 ], Dest^, Length( Value ) );
  1472. Inc( Dest, Length( Value ) );
  1473. Dest^ := #0;
  1474. if Idx = Count-1 then
  1475. Dec( fUsedSiz, OldLen - Length( Value ) );
  1476. end
  1477. else
  1478. begin
  1479. OldObj := 0;
  1480. while Idx > Count do
  1481. AddObjectLen( nil, 0, 0 );
  1482. if Idx = Count-1 then
  1483. begin
  1484. OldObj := Objects[ Idx ];
  1485. Delete( Idx );
  1486. end;
  1487. if Idx = Count then
  1488. AddObjectLen( PChar( Value ), Length( Value ), OldObj )
  1489. else
  1490. begin
  1491. ProvideSpace( Length( Value ) + 9 );
  1492. Dest := PChar( DWORD( fTextBuf ) + fUsedSiz );
  1493. fList.Items[ Idx ] := Pointer( DWORD(Dest)-DWORD(fTextBuf) );
  1494. Inc( Dest, 4 );
  1495. PDWORD( Dest )^ := Length( Value );
  1496. Inc( Dest, 4 );
  1497. if Value <> '' then
  1498. System.Move( Value[ 1 ], Dest^, Length( Value ) );
  1499. Inc( Dest, Length( Value ) );
  1500. Dest^ := #0;
  1501. Inc( fUsedSiz, Length( Value )+9 );
  1502. end;
  1503. end;
  1504. end;
  1505. function TFastStrListEx.SaveToFile(const FileName: string): Boolean;
  1506. var Strm: PStream;
  1507. begin
  1508. Strm := NewWriteFileStream( FileName );
  1509. TRY
  1510. if Strm.Handle <> INVALID_HANDLE_VALUE then
  1511. SaveToStream( Strm );
  1512. Result := TRUE;
  1513. FINALLY
  1514. Strm.Free;
  1515. END;
  1516. end;
  1517. procedure TFastStrListEx.SaveToStream(Stream: PStream);
  1518. var Txt: String;
  1519. begin
  1520. Txt := Text;
  1521. Stream.Write( PChar( Txt )^, Length( Txt ) );
  1522. end;
  1523. procedure TFastStrListEx.SetObject(Idx: Integer; const Value: DWORD);
  1524. var Dest: PDWORD;
  1525. begin
  1526. if Idx < 0 then Exit;
  1527. while Idx >= Count do
  1528. AddObjectLen( nil, 0, 0 );
  1529. Dest := PDWORD( DWORD( fTextBuf ) + DWORD( fList.Items[ Idx ] ) );
  1530. Dest^ := Value;
  1531. end;
  1532. procedure TFastStrListEx.SetText(const S: string; Append2List: boolean);
  1533. var Len2Add, NLines, L: Integer;
  1534. p0, p: PChar;
  1535. begin
  1536. if not Append2List then Clear;
  1537. // подсчет требуемого пространства
  1538. Len2Add := 0;
  1539. NLines := 0;
  1540. p := Pchar( S );
  1541. p0 := p;
  1542. L := Length( S );
  1543. while L > 0 do
  1544. begin
  1545. if p^ = #13 then
  1546. begin
  1547. Inc( NLines );
  1548. Inc( Len2Add, 9 + DWORD(p)-DWORD(p0) );
  1549. REPEAT Inc( p ); Dec( L );
  1550. UNTIL (p^ <> #10) or (L = 0);
  1551. p0 := p;
  1552. end
  1553. else
  1554. begin
  1555. Inc( p ); Dec( L );
  1556. end;
  1557. end;
  1558. if DWORD(p) > DWORD(p0) then
  1559. begin
  1560. Inc( NLines );
  1561. Inc( Len2Add, 9 + DWORD(p)-DWORD(p0) );
  1562. end;
  1563. if Len2Add = 0 then Exit;
  1564. // добавление
  1565. ProvideSpace( Len2Add - 9 );
  1566. if fList.Capacity <= fList.Count + NLines then
  1567. fList.Capacity := Max( (fList.Count + NLines) * 2, 100 );
  1568. p := PChar( S );
  1569. p0 := p;
  1570. L := Length( S );
  1571. while L > 0 do
  1572. begin
  1573. if p^ = #13 then
  1574. begin
  1575. AddObjectLen( p0, DWORD(p)-DWORD(p0), 0 );
  1576. REPEAT Inc( p ); Dec( L );
  1577. UNTIL (p^ <> #10) or (L = 0);
  1578. p0 := p;
  1579. end
  1580. else
  1581. begin
  1582. Inc( p ); Dec( L );
  1583. end;
  1584. end;
  1585. if DWORD(p) > DWORD(p0) then
  1586. AddObjectLen( p0, DWORD(p)-DWORD(p0), 0 );
  1587. end;
  1588. procedure TFastStrListEx.SetTextStr(const Value: string);
  1589. begin
  1590. SetText( Value, FALSE );
  1591. end;
  1592. function CompareFast(const Data: Pointer; const e1,e2 : Dword) : Integer;
  1593. var FSL: PFastStrListEx;
  1594. L1, L2: Integer;
  1595. S1, S2: PChar;
  1596. begin
  1597. FSL := Data;
  1598. S1 := FSL.ItemPtrs[ e1 ];
  1599. S2 := FSL.ItemPtrs[ e2 ];
  1600. L1 := FSL.ItemLen[ e1 ];
  1601. L2 := FSL.ItemLen[ e2 ];
  1602. if FSL.fCaseSensitiveSort then
  1603. Result := StrLComp( S1, S2, Min( L1, L2 ) )
  1604. else
  1605. Result := StrLComp_NoCase( S1, S2, Min( L1, L2 ) );
  1606. if Result = 0 then
  1607. Result := L1 - L2;
  1608. if Result = 0 then
  1609. Result := e1 - e2;
  1610. end;
  1611. procedure SwapFast(const Data : Pointer; const e1,e2 : Dword);
  1612. var FSL: PFastStrListEx;
  1613. begin
  1614. FSL := Data;
  1615. FSL.Swap( e1, e2 );
  1616. end;
  1617. procedure TFastStrListEx.Sort(CaseSensitive: Boolean);
  1618. begin
  1619. fCaseSensitiveSort := CaseSensitive;
  1620. SortData( @ Self, Count, CompareFast, SwapFast );
  1621. end;
  1622. procedure TFastStrListEx.Swap(Idx1, Idx2: Integer);
  1623. begin
  1624. Assert( (Idx1 >= 0) and (Idx1 <= Count-1) and (Idx2 >= 0) and (Idx2 <= Count-1),
  1625. 'Item indexes violates TFastStrListEx range' );
  1626. fList.Swap( Idx1, Idx2 );
  1627. end;
  1628. function TFastStrListEx.GetValues(AName: PChar): PChar;
  1629. var i: Integer;
  1630. s, n: PChar;
  1631. begin
  1632. if not Upper_Initialized then
  1633. InitUpper;
  1634. for i := 0 to Count-1 do
  1635. begin
  1636. s := ItemPtrs[ i ];
  1637. n := AName;
  1638. while (Upper[ s^ ] = Upper[ n^ ]) and (s^ <> '=') and (s^ <> #0) and (n^ <> #0) do
  1639. begin
  1640. Inc( s );
  1641. Inc( n );
  1642. end;
  1643. if (s^ = '=') and (n^ = #0) then
  1644. begin
  1645. Result := s;
  1646. Inc( Result );
  1647. Exit;
  1648. end;
  1649. end;
  1650. Result := nil;
  1651. end;
  1652. function TFastStrListEx.IndexOfName(AName: PChar): Integer;
  1653. var i: Integer;
  1654. s, n: PChar;
  1655. begin
  1656. if not Upper_Initialized then
  1657. InitUpper;
  1658. for i := 0 to Count-1 do
  1659. begin
  1660. s := ItemPtrs[ i ];
  1661. n := AName;
  1662. while (Upper[ s^ ] = Upper[ n^ ]) and (s^ <> '=') and (s^ <> #0) and (n^ <> #0) do
  1663. begin
  1664. Inc( s );
  1665. Inc( n );
  1666. end;
  1667. if (s^ = '=') and (n^ = #0) then
  1668. begin
  1669. Result := i;
  1670. Exit;
  1671. end;
  1672. end;
  1673. Result := -1;
  1674. end;
  1675. procedure TFastStrListEx.Append(S: PChar);
  1676. begin
  1677. AppendLen( S, StrLen( S ) );
  1678. end;
  1679. procedure TFastStrListEx.AppendInt2Hex(N: DWORD; MinDigits: Integer);
  1680. var Buffer: array[ 0..9 ] of Char;
  1681. Mask: DWORD;
  1682. i, Len: Integer;
  1683. B: Byte;
  1684. begin
  1685. if MinDigits > 8 then
  1686. MinDigits := 8;
  1687. if MinDigits <= 0 then
  1688. MinDigits := 1;
  1689. Mask := $F0000000;
  1690. for i := 8 downto MinDigits do
  1691. begin
  1692. if Mask and N <> 0 then
  1693. begin
  1694. MinDigits := i;
  1695. break;
  1696. end;
  1697. Mask := Mask shr 4;
  1698. end;
  1699. i := 0;
  1700. Len := MinDigits;
  1701. Mask := $F shl ((Len - 1)*4);
  1702. while MinDigits > 0 do
  1703. begin
  1704. Dec( MinDigits );
  1705. B := (N and Mask) shr (MinDigits * 4);
  1706. Mask := Mask shr 4;
  1707. if B <= 9 then
  1708. Buffer[ i ] := Char( B + Ord( '0' ) )
  1709. else
  1710. Buffer[ i ] := Char( B + Ord( 'A' ) - 10 );
  1711. Inc( i );
  1712. end;
  1713. Buffer[ i ] := #0;
  1714. AppendLen( @ Buffer[ 0 ], Len );
  1715. end;
  1716. procedure TFastStrListEx.AppendLen(S: PChar; Len: Integer);
  1717. var Dest: PChar;
  1718. begin
  1719. if Count = 0 then
  1720. AddLen( S, Len )
  1721. else
  1722. begin
  1723. ProvideSpace( Len );
  1724. Dest := PChar( DWORD( fTextBuf ) + fUsedSiz - 1 );
  1725. System.Move( S^, Dest^, Len );
  1726. Inc( Dest, Len );
  1727. Dest^ := #0;
  1728. Inc( fUsedSiz, Len );
  1729. Dest := PChar( DWORD( fTextBuf ) + DWORD( fList.Items[ Count-1 ] ) );
  1730. Inc( Dest, 4 );
  1731. PDWORD( Dest )^ := PDWORD( Dest )^ + DWORD( Len );
  1732. end;
  1733. end;
  1734. {-}
  1735. //[procedure WStrCopy]
  1736. procedure WStrCopy( Dest, Src: PWideChar );
  1737. asm
  1738. PUSH EDI
  1739. PUSH ESI
  1740. MOV ESI,EAX
  1741. MOV EDI,EDX
  1742. OR ECX, -1
  1743. XOR EAX, EAX
  1744. REPNE SCASW
  1745. NOT ECX
  1746. MOV EDI,ESI
  1747. MOV ESI,EDX
  1748. REP MOVSW
  1749. POP ESI
  1750. POP EDI
  1751. end;
  1752. //[function WStrCmp]
  1753. function WStrCmp( W1, W2: PWideChar ): Integer;
  1754. asm
  1755. PUSH ESI
  1756. PUSH EDI
  1757. XCHG ESI, EAX
  1758. MOV EDI, EDX
  1759. XOR EAX, EAX
  1760. CWDE
  1761. @@loop: LODSW
  1762. MOV DX, [EDI]
  1763. INC EDI
  1764. INC EDI
  1765. CMP EAX, EDX
  1766. JNE @@exit
  1767. TEST EAX, EAX
  1768. JNZ @@loop
  1769. @@exit: SUB EAX, EDX
  1770. POP EDI
  1771. POP ESI
  1772. end;
  1773. {------------------------------------------------------------------------------)
  1774. | |
  1775. | T W S t r L i s t |
  1776. | |
  1777. (------------------------------------------------------------------------------}
  1778. {$IFNDEF _D2}
  1779. //[function NewWStrList]
  1780. function NewWStrList: PWStrList;
  1781. begin
  1782. new( Result, Create );
  1783. end;
  1784. { TWStrList }
  1785. //[function TWStrList.Add]
  1786. function TWStrList.Add(const W: WideString): Integer;
  1787. begin
  1788. Result := Count;
  1789. Insert( Result, W );
  1790. end;
  1791. //[procedure TWStrList.AddWStrings]
  1792. procedure TWStrList.AddWStrings(WL: PWStrList);
  1793. begin
  1794. Text := Text + WL.Text;
  1795. end;
  1796. //[function TWStrList.AppendToFile]
  1797. function TWStrList.AppendToFile(const Filename: String): Boolean;
  1798. var Strm: PStream;
  1799. begin
  1800. Strm := NewReadWriteFileStream( Filename );
  1801. Result := Strm.Handle <> INVALID_HANDLE_VALUE;
  1802. if Result then
  1803. begin
  1804. Strm.Position := Strm.Size;
  1805. SaveToStream( Strm );
  1806. end;
  1807. Strm.Free;
  1808. end;
  1809. //[procedure TWStrList.Assign]
  1810. procedure TWStrList.Assign(WL: PWStrList);
  1811. begin
  1812. Text := WL.Text;
  1813. end;
  1814. //[procedure TWStrList.Clear]
  1815. procedure TWStrList.Clear;
  1816. var I: Integer;
  1817. P: Pointer;
  1818. begin
  1819. for I := 0 to Count-1 do
  1820. begin
  1821. P := fList.Items[ I ];
  1822. if P <> nil then
  1823. if not( (P >= fText) and (P <= fText + fTextBufSz) ) then
  1824. FreeMem( P );
  1825. end;
  1826. if fText <> nil then
  1827. FreeMem( fText );
  1828. fText := nil;
  1829. fTextBufSz := 0;
  1830. fList.Clear;
  1831. end;
  1832. //[procedure TWStrList.Delete]
  1833. procedure TWStrList.Delete(Idx: Integer);
  1834. var P: Pointer;
  1835. begin
  1836. P := fList.Items[ Idx ];
  1837. if P <> nil then
  1838. if not( (P >= fText) and (P <= fText + fTextBufSz) ) then
  1839. FreeMem( P );
  1840. fList.Delete( Idx );
  1841. end;
  1842. //[destructor TWStrList.Destroy]
  1843. destructor TWStrList.Destroy;
  1844. begin
  1845. Clear;
  1846. fList.Free;
  1847. inherited;
  1848. end;
  1849. //[function TWStrList.GetCount]
  1850. function TWStrList.GetCount: Integer;
  1851. begin
  1852. Result := fList.Count;
  1853. end;
  1854. //[function TWStrList.GetItems]
  1855. function TWStrList.GetItems(Idx: Integer): WideString;
  1856. begin
  1857. Result := PWideChar( fList.Items[ Idx ] );
  1858. end;
  1859. //[function TWStrList.GetPtrs]
  1860. function TWStrList.GetPtrs(Idx: Integer): PWideChar;
  1861. begin
  1862. Result := fList.Items[ Idx ];
  1863. end;
  1864. //[function TWStrList.GetText]
  1865. function TWStrList.GetText: WideString;
  1866. const
  1867. EoL: array[ 0..5 ] of Char = ( #13, #0, #10, #0, #0, #0 );
  1868. var L, I: Integer;
  1869. P, Dest: Pointer;
  1870. begin
  1871. L := 0;
  1872. for I := 0 to Count-1 do
  1873. begin
  1874. P := fList.Items[ I ];
  1875. if P <> nil then
  1876. L := L + WStrLen( P ) + 2
  1877. else
  1878. L := L + 2;
  1879. end;
  1880. SetLength( Result, L );
  1881. Dest := PWideChar( Result );
  1882. for I := 0 to Count-1 do
  1883. begin
  1884. P := fList.Items[ I ];
  1885. if P <> nil then
  1886. begin
  1887. WStrCopy( Dest, P );
  1888. Dest := Pointer( Integer( Dest ) + WStrLen( P ) * 2 );
  1889. end;
  1890. WStrCopy( Dest, Pointer( @ EoL[ 0 ] ) );
  1891. Dest := Pointer( Integer( Dest ) + 4 );
  1892. end;
  1893. end;
  1894. //[procedure TWStrList.Init]
  1895. procedure TWStrList.Init;
  1896. begin
  1897. fList := NewList;
  1898. end;
  1899. //[procedure TWStrList.Insert]
  1900. procedure TWStrList.Insert(Idx: Integer; const W: WideString);
  1901. var P: Pointer;
  1902. begin
  1903. while Idx < Count-2 do
  1904. fList.Add( nil );
  1905. GetMem( P, (Length( W ) + 1) * 2 );
  1906. fList.Insert( Idx, P );
  1907. WStrCopy( P, PWideChar( W ) );
  1908. end;
  1909. //[function TWStrList.LoadFromFile]
  1910. function TWStrList.LoadFromFile(const Filename: String): Boolean;
  1911. begin
  1912. Clear;
  1913. Result := MergeFromFile( Filename );
  1914. end;
  1915. //[procedure TWStrList.LoadFromStream]
  1916. procedure TWStrList.LoadFromStream(Strm: PStream);
  1917. begin
  1918. Clear;
  1919. MergeFromStream( Strm );
  1920. end;
  1921. //[function TWStrList.MergeFromFile]
  1922. function TWStrList.MergeFromFile(const Filename: String): Boolean;
  1923. var Strm: PStream;
  1924. begin
  1925. Strm := NewReadFileStream( Filename );
  1926. Result := Strm.Handle <> INVALID_HANDLE_VALUE;
  1927. if Result then
  1928. MergeFromStream( Strm );
  1929. Strm.Free;
  1930. end;
  1931. //[procedure TWStrList.MergeFromStream]
  1932. procedure TWStrList.MergeFromStream(Strm: PStream);
  1933. var Buf: WideString;
  1934. L: Integer;
  1935. begin
  1936. L := Strm.Size - Strm.Position;
  1937. Assert( L mod 1 = 0, 'Wide strings streams must be of even length in bytes.' );
  1938. if L = 0 then Exit;
  1939. SetLength( Buf, L div 2 );
  1940. Strm.Read( Buf[ 1 ], L );
  1941. Text := Text + Buf;
  1942. end;
  1943. //[procedure TWStrList.Move]
  1944. procedure TWStrList.Move(IdxOld, IdxNew: Integer);
  1945. begin
  1946. fList.MoveItem( IdxOld, IdxNew );
  1947. end;
  1948. //[function TWStrList.SaveToFile]
  1949. function TWStrList.SaveToFile(const Filename: String): Boolean;
  1950. var Strm: PStream;
  1951. begin
  1952. Strm := NewWriteFileStream( Filename );
  1953. Result := Strm.Handle <> INVALID_HANDLE_VALUE;
  1954. if Result then
  1955. SaveToStream( Strm );
  1956. Strm.Free;
  1957. end;
  1958. //[procedure TWStrList.SaveToStream]
  1959. procedure TWStrList.SaveToStream(Strm: PStream);
  1960. var Buf, Dest: PWideChar;
  1961. I, L, Sz: Integer;
  1962. P: Pointer;
  1963. begin
  1964. Sz := 0;
  1965. for I := 0 to Count-1 do
  1966. begin
  1967. P := fList.Items[ I ];
  1968. if P <> nil then
  1969. Sz := Sz + WStrLen( P ) * 2 + 4
  1970. else
  1971. Sz := Sz + 4;
  1972. end;
  1973. GetMem( Buf, Sz );
  1974. Dest := Buf;
  1975. for I := 0 to Count-1 do
  1976. begin
  1977. P := fList.Items[ I ];
  1978. if P <> nil then
  1979. begin
  1980. L := WStrLen( P );
  1981. System.Move( P^, Dest^, L * 2 );
  1982. Inc( Dest, L );
  1983. end;
  1984. Dest^ := #13;
  1985. Inc( Dest );
  1986. Dest^ := #10;
  1987. Inc( Dest );
  1988. end;
  1989. Strm.Write( Buf^, Sz );
  1990. FreeMem( Buf );
  1991. end;
  1992. //[procedure TWStrList.SetItems]
  1993. procedure TWStrList.SetItems(Idx: Integer; const Value: WideString);
  1994. var P: Pointer;
  1995. begin
  1996. while Idx > Count-1 do
  1997. fList.Add( nil );
  1998. if WStrLen( ItemPtrs[ Idx ] ) <= Length( Value ) then
  1999. WStrCopy( ItemPtrs[ Idx ], PWideChar( Value ) )
  2000. else
  2001. begin
  2002. P := fList.Items[ Idx ];
  2003. if P <> nil then
  2004. if not ((P >= fText) and (P <= fText + fTextBufSz)) then
  2005. FreeMem( P );
  2006. GetMem( P, (Length( Value ) + 1) * 2 );
  2007. fList.Items[ Idx ] := P;
  2008. WStrCopy( P, PWideChar( Value ) );
  2009. end;
  2010. end;
  2011. //[procedure TWStrList.SetText]
  2012. procedure TWStrList.SetText(const Value: WideString);
  2013. var L, N: Integer;
  2014. P: PWideChar;
  2015. begin
  2016. Clear;
  2017. if Value = '' then Exit;
  2018. L := (Length( Value ) + 1) * 2;
  2019. GetMem( fText, L );
  2020. System.Move( Value[ 1 ], fText^, L );
  2021. fTextBufSz := Length( Value );
  2022. N := 0;
  2023. P := fText;
  2024. while Word( P^ ) <> 0 do
  2025. begin
  2026. if (Word( P^ ) = 13) then
  2027. begin
  2028. Inc( N );
  2029. PWord( P )^ := 0;
  2030. if Word( P[ 1 ] ) = 10 then
  2031. Inc( P );
  2032. end
  2033. else
  2034. if (Word( P^ ) = 10) and ((P = fText) or (Word( P[ -1 ] ) <> 0)) then
  2035. begin
  2036. Inc( N );
  2037. PWord( P )^ := 0;
  2038. end;
  2039. Inc( P );
  2040. end;
  2041. fList.Capacity := N;
  2042. P := fText;
  2043. while P < fText + fTextBufSz do
  2044. begin
  2045. fList.Add( P );
  2046. while Word( P^ ) <> 0 do Inc( P );
  2047. Inc( P );
  2048. if Word( P^ ) = 10 then Inc( P );
  2049. end;
  2050. end;
  2051. //[function CompareWStrListItems]
  2052. function CompareWStrListItems( const Sender: Pointer; const Idx1, Idx2: DWORD ): Integer;
  2053. var WL: PWStrList;
  2054. begin
  2055. WL := Sender;
  2056. Result := WStrCmp( WL.fList.Items[ Idx1 ], WL.fList.Items[ Idx2 ] );
  2057. end;
  2058. //[function CompareWStrListItems_UpperCase]
  2059. function CompareWStrListItems_UpperCase( const Sender: Pointer; const Idx1, Idx2: DWORD ): Integer;
  2060. var WL: PWStrList;
  2061. L1, L2: Integer;
  2062. begin
  2063. WL := Sender;
  2064. L1 := WStrLen( WL.fList.Items[ Idx1 ] );
  2065. L2 := WStrLen( WL.fList.Items[ Idx2 ] );
  2066. if Length( WL.fTmp1 ) < L1 then
  2067. SetLength( WL.fTmp1, L1 + 1 );
  2068. if Length( WL.fTmp2 ) < L2 then
  2069. SetLength( WL.fTmp2, L2 + 1 );
  2070. if L1 > 0 then
  2071. Move( WL.fList.Items[ Idx1 ]^, WL.fTmp1[ 1 ], (L1 + 1) * 2 )
  2072. else
  2073. WL.fTmp1[ 1 ] := #0;
  2074. if L2 > 0 then
  2075. Move( WL.fList.Items[ Idx2 ]^, WL.fTmp2[ 1 ], (L2 + 1) * 2 )
  2076. else
  2077. WL.fTmp2[ 1 ] := #0;
  2078. CharUpperBuffW( PWideChar( WL.fTmp1 ), L1 );
  2079. CharUpperBuffW( PWideChar( WL.fTmp2 ), L2 );
  2080. Result := WStrCmp( PWideChar( WL.fTmp1 ), PWideChar( WL.fTmp2 ) );
  2081. end;
  2082. //[procedure SwapWStrListItems]
  2083. procedure SwapWStrListItems( const Sender: Pointer; const Idx1, Idx2: DWORD );
  2084. var WL: PWStrList;
  2085. begin
  2086. WL := Sender;
  2087. WL.Swap( Idx1, Idx2 );
  2088. end;
  2089. //[procedure TWStrList.Sort]
  2090. procedure TWStrList.Sort( CaseSensitive: Boolean );
  2091. begin
  2092. if CaseSensitive then
  2093. SortData( @ Self, Count, @CompareWStrListItems, @SwapWStrListItems )
  2094. else
  2095. begin
  2096. SortData( @ Self, Count, @CompareWStrListItems_UpperCase, @SwapWStrListItems );
  2097. fTmp1 := '';
  2098. fTmp2 := '';
  2099. end;
  2100. end;
  2101. //[procedure TWStrList.Swap]
  2102. procedure TWStrList.Swap(Idx1, Idx2: Integer);
  2103. begin
  2104. fList.Swap( Idx1, Idx2 );
  2105. end;
  2106. //[function NewWStrListEx]
  2107. function NewWStrListEx: PWStrListEx;
  2108. begin
  2109. new( Result, Create );
  2110. end;
  2111. { TWStrListEx }
  2112. //[function TWStrListEx.AddObject]
  2113. function TWStrListEx.AddObject(const S: WideString; Obj: DWORD): Integer;
  2114. begin
  2115. Result := Count;
  2116. InsertObject( Count, S, Obj );
  2117. end;
  2118. //[procedure TWStrListEx.AddWStrings]
  2119. procedure TWStrListEx.AddWStrings(WL: PWStrListEx);
  2120. var I: Integer;
  2121. begin
  2122. I := Count;
  2123. if WL.FObjects.Count > 0 then
  2124. ProvideObjectsCapacity( Count );
  2125. inherited AddWStrings( WL );
  2126. if WL.FObjects.Count > 0 then
  2127. begin
  2128. ProvideObjectsCapacity( I + WL.FObjects.Count );
  2129. System.Move( PCrackList( WL.FObjects ).FItems[ 0 ],
  2130. PCrackList( FObjects ).FItems[ I ],
  2131. Sizeof( Pointer ) * WL.FObjects.Count );
  2132. end;
  2133. end;
  2134. //[procedure TWStrListEx.Assign]
  2135. procedure TWStrListEx.Assign(WL: PWStrListEx);
  2136. begin
  2137. inherited Assign( WL );
  2138. FObjects.Assign( WL.FObjects );
  2139. end;
  2140. //[procedure TWStrListEx.Clear]
  2141. procedure TWStrListEx.Clear;
  2142. begin
  2143. inherited Clear;
  2144. FObjects.Clear;
  2145. end;
  2146. //[procedure TWStrListEx.Delete]
  2147. procedure TWStrListEx.Delete(Idx: Integer);
  2148. begin
  2149. inherited Delete( Idx );
  2150. if PCrackList( FObjects ).FCount >= Idx then
  2151. FObjects.Delete( Idx );
  2152. end;
  2153. //[destructor TWStrListEx.Destroy]
  2154. destructor TWStrListEx.Destroy;
  2155. begin
  2156. fObjects.Free;
  2157. inherited;
  2158. end;
  2159. //[function TWStrListEx.GetObjects]
  2160. function TWStrListEx.GetObjects(Idx: Integer): DWORD;
  2161. begin
  2162. Result := DWORD( fObjects.Items[ Idx ] );
  2163. end;
  2164. //[function TWStrListEx.IndexOfObj]
  2165. function TWStrListEx.IndexOfObj(Obj: Pointer): Integer;
  2166. begin
  2167. Result := FObjects.IndexOf( Obj );
  2168. end;
  2169. //[procedure TWStrListEx.Init]
  2170. procedure TWStrListEx.Init;
  2171. begin
  2172. inherited;
  2173. fObjects := NewList;
  2174. end;
  2175. //[procedure TWStrListEx.InsertObject]
  2176. procedure TWStrListEx.InsertObject(Before: Integer; const S: WideString;
  2177. Obj: DWORD);
  2178. begin
  2179. Insert( Before, S );
  2180. FObjects.Insert( Before, Pointer( Obj ) );
  2181. end;
  2182. //[procedure TWStrListEx.Move]
  2183. procedure TWStrListEx.Move(IdxOld, IdxNew: Integer);
  2184. begin
  2185. fList.MoveItem( IdxOld, IdxNew );
  2186. if PCrackList( FObjects ).FCount >= Min( IdxOld, IdxNew ) then
  2187. begin
  2188. ProvideObjectsCapacity( Max( IdxOld, IdxNew ) + 1 );
  2189. FObjects.MoveItem( IdxOld, IdxNew );
  2190. end;
  2191. end;
  2192. //[procedure TWStrListEx.ProvideObjectsCapacity]
  2193. procedure TWStrListEx.ProvideObjectsCapacity(NewCap: Integer);
  2194. begin
  2195. if fObjects.Capacity >= NewCap then Exit;
  2196. fObjects.Capacity := NewCap;
  2197. FillChar( PCrackList( FObjects ).FItems[ FObjects.Count ],
  2198. (FObjects.Capacity - FObjects.Count) * Sizeof( Pointer ), 0 );
  2199. PCrackList( FObjects ).FCount := NewCap;
  2200. end;
  2201. //[procedure TWStrListEx.SetObjects]
  2202. procedure TWStrListEx.SetObjects(Idx: Integer; const Value: DWORD);
  2203. begin
  2204. ProvideObjectsCapacity( Idx + 1 );
  2205. fObjects.Items[ Idx ] := Pointer( Value );
  2206. end;
  2207. {$ENDIF}
  2208. {+}
  2209. { TCABFile }
  2210. //[function OpenCABFile]
  2211. function OpenCABFile( const APaths: array of String ): PCABFile;
  2212. var I: Integer;
  2213. begin
  2214. {-}
  2215. New( Result, Create );
  2216. {+}{++}(*Result := PCABFile.Create;*){--}
  2217. Result.FSetupapi := LoadLibrary( 'setupapi.dll' );
  2218. Result.FNames := NewStrList;
  2219. Result.FPaths := NewStrList;
  2220. for I := 0 to High( APaths ) do
  2221. Result.FPaths.Add( APaths[ I ] );
  2222. end;
  2223. //[destructor TCABFile.Destroy]
  2224. destructor TCABFile.Destroy;
  2225. begin
  2226. FNames.Free;
  2227. FPaths.Free;
  2228. FTargetPath := '';
  2229. if FSetupapi <> 0 then
  2230. FreeLibrary( FSetupapi );
  2231. inherited;
  2232. end;
  2233. const
  2234. SPFILENOTIFY_FILEINCABINET = $11;
  2235. SPFILENOTIFY_NEEDNEWCABINET = $12;
  2236. type
  2237. PSP_FILE_CALLBACK = function( Context: Pointer; Notification, Param1, Param2: DWORD ): DWORD;
  2238. stdcall;
  2239. TSetupIterateCabinet = function ( CabinetFile: PChar; Reserved: DWORD;
  2240. MsgHandler: PSP_FILE_CALLBACK; Context: Pointer ): Boolean; stdcall;
  2241. //external 'setupapi.dll' name 'SetupIterateCabinetA';
  2242. TSetupPromptDisk = function (
  2243. hwndParent: HWND; // parent window of the dialog box
  2244. DialogTitle: PChar; // optional, title of the dialog box
  2245. DiskName: PChar; // optional, name of disk to insert
  2246. PathToSource: PChar;// optional, expected source path
  2247. FileSought: PChar; // name of file needed
  2248. TagFile: PChar; // optional, source media tag file
  2249. DiskPromptStyle: DWORD; // specifies dialog box behavior
  2250. PathBuffer: PChar; // receives the source location
  2251. PathBufferSize: DWORD; // size of the supplied buffer
  2252. PathRequiredSize: PDWORD // optional, buffer size needed
  2253. ): DWORD; stdcall;
  2254. //external 'setupapi.dll' name 'SetupPromptForDiskA';
  2255. type
  2256. TCabinetInfo = packed record
  2257. CabinetPath: PChar;
  2258. CabinetFile: PChar;
  2259. DiskName: PChar;
  2260. SetId: WORD;
  2261. CabinetNumber: WORD;
  2262. end;
  2263. PCabinetInfo = ^TCabinetInfo;
  2264. TFileInCabinetInfo = packed record
  2265. NameInCabinet: PChar;
  2266. FileSize: DWORD;
  2267. Win32Error: DWORD;
  2268. DosDate: WORD;
  2269. DosTime: WORD;
  2270. DosAttribs: WORD;
  2271. FullTargetName: array[0..MAX_PATH-1] of Char;
  2272. end;
  2273. PFileInCabinetInfo = ^TFileInCabinetInfo;
  2274. //[function CABCallback]
  2275. function CABCallback( Context: Pointer; Notification, Param1, Param2: DWORD ): DWORD;
  2276. stdcall;
  2277. var CAB: PCABFile;
  2278. CABPath, OldPath: String;
  2279. CABInfo: PCabinetInfo;
  2280. CABFileInfo: PFileInCabinetInfo;
  2281. hr: Integer;
  2282. SetupPromptProc: TSetupPromptDisk;
  2283. begin
  2284. Result := 0;
  2285. CAB := Context;
  2286. case Notification of
  2287. SPFILENOTIFY_NEEDNEWCABINET:
  2288. begin
  2289. OldPath := CAB.FPaths.Items[ CAB.FCurCAB ];
  2290. Inc( CAB.FCurCAB );
  2291. if CAB.FCurCAB = CAB.FPaths.Count then
  2292. CAB.FPaths.Add( '?' );
  2293. CABPath := CAB.FPaths.Items[ CAB.FCurCAB ];
  2294. if CABPath = '?' then
  2295. begin
  2296. if Assigned( CAB.FOnNextCAB ) then
  2297. CAB.FPaths.Items[CAB.FCurCAB ] := CAB.FOnNextCAB( CAB );
  2298. CABPath := CAB.FPaths.Items[ CAB.FCurCAB ];
  2299. if CABPath = '?' then
  2300. begin
  2301. SetLength( CABPath, MAX_PATH );
  2302. CABInfo := Pointer( Param1 );
  2303. if CAB.FSetupapi <> 0 then
  2304. SetupPromptProc := GetProcAddress( CAB.FSetupapi, 'SetupPromptForDiskA' )
  2305. else
  2306. SetupPromptProc := nil;
  2307. if Assigned( SetupPromptProc ) then
  2308. begin
  2309. hr := SetupPromptProc( 0, nil, nil, PChar( ExtractFilePath( OldPath ) ),
  2310. CABInfo.CabinetFile, nil, 2 {IDF_NOSKIP}, @CabPath[ 1 ], MAX_PATH, nil );
  2311. case hr of
  2312. 0: // success
  2313. begin
  2314. StrCopy( PChar( Param2 ), PChar( CABPath ) );
  2315. Result := 0;
  2316. end;
  2317. 2: // skip file
  2318. Result := 0;
  2319. else // cancel
  2320. Result := ERROR_FILE_NOT_FOUND;
  2321. end;
  2322. end;
  2323. end
  2324. else
  2325. begin
  2326. StrCopy( PChar( Param2 ), PChar( CABPath ) );
  2327. Result := 0;
  2328. end;
  2329. end;
  2330. end;
  2331. SPFILENOTIFY_FILEINCABINET:
  2332. begin
  2333. CABFileInfo := Pointer( Param1 );
  2334. if CAB.FGettingNames then
  2335. begin
  2336. CAB.FNames.Add( CABFileInfo.NameInCabinet );
  2337. Result := 2; // FILEOP_SKIP
  2338. end
  2339. else
  2340. begin
  2341. CABPath := CABFileInfo.NameInCabinet;
  2342. if Assigned( CAB.FOnFile ) then
  2343. begin
  2344. if CAB.FOnFile( CAB, CABPath ) then
  2345. begin
  2346. if ExtractFilePath( CABPath ) = '' then
  2347. if CAB.FTargetPath <> '' then
  2348. CABPath := CAB.TargetPath + CABPath;
  2349. StrCopy( @CABFileInfo.FullTargetName[ 0 ], PChar( CABPath ) );
  2350. Result := 1; // FILEOP_DOIT
  2351. end
  2352. else
  2353. Result := 2
  2354. end
  2355. else
  2356. begin
  2357. if CAB.FTargetPath <> '' then
  2358. StrCopy( @CABFileInfo.FullTargetName[ 0 ], PChar( CAB.TargetPath + CABPath ) );
  2359. Result := 1;
  2360. end;
  2361. end;
  2362. end;
  2363. end;
  2364. end;
  2365. //[function TCABFile.Execute]
  2366. function TCABFile.Execute: Boolean;
  2367. var SetupIterateProc: TSetupIterateCabinet;
  2368. begin
  2369. FCurCAB := 0;
  2370. Result := FALSE;
  2371. if FSetupapi = 0 then Exit;
  2372. SetupIterateProc := GetProcAddress( FSetupapi, 'SetupIterateCabinetA' );
  2373. if not Assigned( SetupIterateProc ) then Exit;
  2374. Result := SetupIterateProc( PChar( FPaths.Items[ 0 ] ), 0, CABCallback, @Self );
  2375. end;
  2376. //[function TCABFile.GetCount]
  2377. function TCABFile.GetCount: Integer;
  2378. begin
  2379. GetNames( 0 );
  2380. Result := FNames.Count;
  2381. end;
  2382. //[function TCABFile.GetNames]
  2383. function TCABFile.GetNames(Idx: Integer): String;
  2384. begin
  2385. if FNames.Count = 0 then
  2386. begin
  2387. FGettingNames := TRUE;
  2388. Execute;
  2389. FGettingNames := FALSE;
  2390. end;
  2391. Result := '';
  2392. if Idx < FNames.Count then
  2393. Result := FNames.Items[ Idx ];
  2394. end;
  2395. //[function TCABFile.GetPaths]
  2396. function TCABFile.GetPaths(Idx: Integer): String;
  2397. begin
  2398. Result := FPaths.Items[ Idx ];
  2399. end;
  2400. //[function TCABFile.GetTargetPath]
  2401. function TCABFile.GetTargetPath: String;
  2402. begin
  2403. Result := FTargetPath;
  2404. if Result <> '' then
  2405. if Result[ Length( Result ) ] <> '\' then
  2406. Result := Result + '\';
  2407. end;
  2408. { -- TDirChange -- }
  2409. const FilterFlags: array[ TFileChangeFilters ] of Integer = (
  2410. FILE_NOTIFY_CHANGE_FILE_NAME, FILE_NOTIFY_CHANGE_DIR_NAME,
  2411. FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_NOTIFY_CHANGE_SIZE,
  2412. FILE_NOTIFY_CHANGE_LAST_WRITE, $20 {FILE_NOTIFY_CHANGE_LAST_ACCESS},
  2413. $40 {FILE_NOTIFY_CHANGE_CREATION}, FILE_NOTIFY_CHANGE_SECURITY );
  2414. //[FUNCTION _NewDirChgNotifier]
  2415. {$IFDEF ASM_VERSION}
  2416. function _NewDirChgNotifier: PDirChange;
  2417. begin
  2418. New( Result, Create );
  2419. end;
  2420. //[function NewDirChangeNotifier]
  2421. function NewDirChangeNotifier( const Path: String; Filter: TFileChangeFilter;
  2422. WatchSubtree: Boolean; ChangeProc: TOnDirChange )
  2423. : PDirChange;
  2424. const Dflt_Flags = FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME or
  2425. FILE_NOTIFY_CHANGE_ATTRIBUTES or FILE_NOTIFY_CHANGE_SIZE or
  2426. FILE_NOTIFY_CHANGE_LAST_WRITE;
  2427. asm
  2428. PUSH EBX
  2429. PUSH ECX // [EBP-8] = WatchSubtree
  2430. PUSH EDX // [EBP-12] = Filter
  2431. PUSH EAX // [EBP-16] = Path
  2432. CALL _NewDirChgNotifier
  2433. XCHG EBX, EAX
  2434. LEA EAX, [EBX].TDirChange.FPath
  2435. POP EDX
  2436. CALL System.@LStrAsg
  2437. MOV EAX, [ChangeProc].TMethod.Code
  2438. MOV [EBX].TDirChange.FOnChange.TMethod.Code, EAX
  2439. MOV EAX, [ChangeProc].TMethod.Data
  2440. MOV [EBX].TDirChange.FOnChange.TMethod.Data, EAX
  2441. POP ECX
  2442. MOV EAX, Dflt_Flags
  2443. MOVZX ECX, CL
  2444. JECXZ @@flags_ready
  2445. PUSH ECX
  2446. MOV EAX, ESP
  2447. MOV EDX, offset[FilterFlags]
  2448. XOR ECX, ECX
  2449. MOV CL, 7
  2450. CALL MakeFlags
  2451. POP ECX
  2452. @@flags_ready: // EAX = Flags
  2453. POP EDX
  2454. MOVZX EDX, DL // EDX = WatchSubtree
  2455. PUSH EAX
  2456. PUSH EDX
  2457. PUSH [EBX].TDirChange.FPath
  2458. CALL FindFirstChangeNotification
  2459. MOV [EBX].TDirChange.FHandle, EAX
  2460. INC EAX
  2461. JZ @@fault
  2462. PUSH EBX
  2463. PUSH offset[TDirChange.Execute]
  2464. CALL NewThreadEx
  2465. MOV [EBX].TDirChange.FMonitor, EAX
  2466. JMP @@exit
  2467. @@fault:
  2468. XCHG EAX, EBX
  2469. CALL TObj.Free
  2470. @@exit:
  2471. XCHG EAX, EBX
  2472. POP EBX
  2473. end;
  2474. {$ELSE ASM_VERSION} //Pascal
  2475. function NewDirChangeNotifier( const Path: String; Filter: TFileChangeFilter;
  2476. WatchSubtree: Boolean; ChangeProc: TOnDirChange )
  2477. : PDirChange;
  2478. var Flags: DWORD;
  2479. begin
  2480. {-}
  2481. New( Result, Create );
  2482. {+}{++}(*Result := PDirChange.Create;*){--}
  2483. Result.FPath := Path;
  2484. Result.FOnChange := ChangeProc;
  2485. if Filter = [ ] then
  2486. Flags := FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME or
  2487. FILE_NOTIFY_CHANGE_ATTRIBUTES or FILE_NOTIFY_CHANGE_SIZE or
  2488. FILE_NOTIFY_CHANGE_LAST_WRITE
  2489. else
  2490. Flags := MakeFlags( @Filter, FilterFlags );
  2491. Result.FHandle := FindFirstChangeNotification(PChar(Result.FPath),
  2492. Bool( Integer( WatchSubtree ) ), Flags);
  2493. if Result.FHandle <> INVALID_HANDLE_VALUE then
  2494. Result.FMonitor := NewThreadEx( Result.Execute )
  2495. else //MsgOK( 'Can not monitor ' + Result.FPath + #13'Error ' + Int2Str( GetLastError ) );
  2496. begin
  2497. Result.Free;
  2498. Result := nil;
  2499. end;
  2500. end;
  2501. {$ENDIF ASM_VERSION}
  2502. //[END _NewDirChgNotifier]
  2503. { TDirChange }
  2504. {$IFDEF ASM_VERSION}
  2505. //[procedure TDirChange.Changed]
  2506. procedure TDirChange.Changed;
  2507. asm
  2508. MOV ECX, [EAX].FPath
  2509. XCHG EDX, EAX
  2510. MOV EAX, [EDX].FOnChange.TMethod.Data
  2511. CALL [EDX].FOnChange.TMethod.Code
  2512. end;
  2513. {$ELSE ASM_VERSION} //Pascal
  2514. procedure TDirChange.Changed;
  2515. begin
  2516. FOnChange(@Self, FPath); // must be assigned always!!!
  2517. end;
  2518. {$ENDIF ASM_VERSION}
  2519. {$IFDEF ASM_VERSION}
  2520. //[destructor TDirChange.Destroy]
  2521. destructor TDirChange.Destroy;
  2522. asm
  2523. PUSH EBX
  2524. XCHG EBX, EAX
  2525. MOV ECX, [EBX].FMonitor
  2526. JECXZ @@no_monitor
  2527. XCHG EAX, ECX
  2528. CALL TObj.Free
  2529. @@no_monitor:
  2530. MOV ECX, [EBX].FHandle
  2531. JECXZ @@exit
  2532. PUSH ECX
  2533. CALL FindCloseChangeNotification
  2534. @@exit:
  2535. LEA EAX, [EBX].FPath
  2536. CALL System.@LStrClr
  2537. XCHG EAX, EBX
  2538. CALL TObj.Destroy
  2539. POP EBX
  2540. end;
  2541. {$ELSE ASM_VERSION} //Pascal
  2542. destructor TDirChange.Destroy;
  2543. begin
  2544. if FMonitor <> nil then
  2545. FMonitor.Free;
  2546. if FHandle > 0 then // FHandle <> INVALID_HANDLE_VALUE AND FHandle <> 0
  2547. FindCloseChangeNotification(FHandle);
  2548. FPath := '';
  2549. inherited;
  2550. end;
  2551. {$ENDIF ASM_VERSION}
  2552. {$IFDEF ASM_noVERSION}
  2553. //[function TDirChange.Execute]
  2554. function TDirChange.Execute(Sender: PThread): Integer;
  2555. asm
  2556. PUSH EBX
  2557. PUSH ESI
  2558. XCHG EBX, EAX
  2559. MOV ESI, EDX
  2560. @@loo:
  2561. MOVZX ECX, [ESI].TThread.FTerminated
  2562. INC ECX
  2563. LOOP @@e_loop
  2564. MOV ECX, [EBX].FHandle
  2565. INC ECX
  2566. JZ @@e_loop
  2567. PUSH INFINITE
  2568. PUSH ECX
  2569. CALL WaitForSingleObject
  2570. OR EAX, EAX
  2571. JNZ @@loo
  2572. PUSH [EBX].FHandle
  2573. MOV EAX, [EBX].FMonitor
  2574. PUSH EBX
  2575. PUSH offset[TDirChange.Changed]
  2576. CALL TThread.Synchronize
  2577. CALL FindNextChangeNotification
  2578. JMP @@loo
  2579. @@e_loop:
  2580. POP ESI
  2581. POP EBX
  2582. XOR EAX, EAX
  2583. end;
  2584. {$ELSE ASM_VERSION} //Pascal
  2585. function TDirChange.Execute(Sender: PThread): Integer;
  2586. begin
  2587. while (not Sender.Terminated and (FHandle <> INVALID_HANDLE_VALUE)) do
  2588. if (WaitForSingleObject(FHandle, INFINITE) = WAIT_OBJECT_0) then
  2589. begin
  2590. if AppletTerminated then break;
  2591. Applet.GetWindowHandle;
  2592. FMonitor.Synchronize( Changed );
  2593. FindNextChangeNotification(FHandle);
  2594. end;
  2595. Result := 0;
  2596. end;
  2597. {$ENDIF ASM_VERSION}
  2598. ////////////////////////////////////////////////////////////////////////
  2599. //
  2600. //
  2601. // M E T A F I L E
  2602. //
  2603. //
  2604. ////////////////////////////////////////////////////////////////////////
  2605. {++}(*
  2606. //[API SetEnhMetaFileBits]
  2607. function SetEnhMetaFileBits; external gdi32 name 'SetEnhMetaFileBits';
  2608. function PlayEnhMetaFile; external gdi32 name 'PlayEnhMetaFile';
  2609. *){--}
  2610. //[function NewMetafile]
  2611. function NewMetafile: PMetafile;
  2612. begin
  2613. {-}
  2614. new( Result, Create );
  2615. {+}{++}(*Result := PMetafile.Create;*){--}
  2616. end;
  2617. //[END NewMetafile]
  2618. { TMetafile }
  2619. //[procedure TMetafile.Clear]
  2620. procedure TMetafile.Clear;
  2621. begin
  2622. if fHandle <> 0 then
  2623. DeleteEnhMetaFile( fHandle );
  2624. fHandle := 0;
  2625. end;
  2626. //[destructor TMetafile.Destroy]
  2627. destructor TMetafile.Destroy;
  2628. begin
  2629. if fHeader <> nil then
  2630. FreeMem( fHeader );
  2631. Clear;
  2632. inherited;
  2633. end;
  2634. //[procedure TMetafile.Draw]
  2635. procedure TMetafile.Draw(DC: HDC; X, Y: Integer);
  2636. begin
  2637. StretchDraw( DC, MakeRect( X, Y, X + Width, Y + Height ) );
  2638. end;
  2639. //[function TMetafile.Empty]
  2640. function TMetafile.Empty: Boolean;
  2641. begin
  2642. Result := fHandle = 0;
  2643. end;
  2644. //[function TMetafile.GetHeight]
  2645. function TMetafile.GetHeight: Integer;
  2646. begin
  2647. Result := 0;
  2648. if Empty then Exit;
  2649. RetrieveHeader;
  2650. Result := fHeader.rclBounds.Bottom - fHeader.rclBounds.Top;
  2651. end;
  2652. //[function TMetafile.GetWidth]
  2653. function TMetafile.GetWidth: Integer;
  2654. begin
  2655. Result := 0;
  2656. if Empty then Exit;
  2657. RetrieveHeader;
  2658. Result := fHeader.rclBounds.Right - fHeader.rclBounds.Left;
  2659. end;
  2660. //[function TMetafile.LoadFromFile]
  2661. function TMetafile.LoadFromFile(const Filename: String): Boolean;
  2662. var Strm: PStream;
  2663. begin
  2664. Strm := NewReadFileStream( FileName );
  2665. Result := LoadFromStream( Strm );
  2666. Strm.Free;
  2667. end;
  2668. //[function ComputeAldusChecksum]
  2669. function ComputeAldusChecksum(var WMF: TMetafileHeader): Word;
  2670. type
  2671. PWord = ^Word;
  2672. var
  2673. pW: PWord;
  2674. pEnd: PWord;
  2675. begin
  2676. Result := 0;
  2677. pW := @WMF;
  2678. pEnd := @WMF.CheckSum;
  2679. while Longint(pW) < Longint(pEnd) do
  2680. begin
  2681. Result := Result xor pW^;
  2682. Inc(Longint(pW), SizeOf(Word));
  2683. end;
  2684. end;
  2685. //[function TMetafile.LoadFromStream]
  2686. function TMetafile.LoadFromStream(Strm: PStream): Boolean;
  2687. var WMF: TMetaFileHeader;
  2688. WmfHdr: TMetaHeader;
  2689. EnhHdr: TEnhMetaHeader;
  2690. Pos, Pos1: Integer;
  2691. Sz: Integer;
  2692. MemStrm: PStream;
  2693. MFP: TMetafilePict;
  2694. begin
  2695. Result := FALSE;
  2696. Pos := Strm.Position;
  2697. if Strm.Read( WMF, Sizeof( WMF ) ) <> Sizeof( WMF ) then
  2698. begin
  2699. Strm.Position := Pos;
  2700. Exit;
  2701. end;
  2702. MemStrm := NewMemoryStream;
  2703. if WMF.Key = WMFKey then
  2704. begin // Windows metafile
  2705. if WMF.CheckSum <> ComputeAldusChecksum( WMF ) then
  2706. begin
  2707. Strm.Position := Pos;
  2708. Exit;
  2709. end;
  2710. Pos1 := Strm.Position;
  2711. if Strm.Read( WmfHdr, Sizeof( WmfHdr ) ) <> Sizeof( WmfHdr ) then
  2712. begin
  2713. Strm.Position := Pos;
  2714. Exit;
  2715. end;
  2716. Strm.Position := Pos1;
  2717. Sz := WMFHdr.mtSize * 2;
  2718. Stream2Stream( MemStrm, Strm, Sz );
  2719. FillChar( MFP, Sizeof( MFP ), 0 );
  2720. MFP.mm := MM_ANISOTROPIC;
  2721. fHandle := SetWinMetafileBits( Sz, MemStrm.Memory, 0, MFP );
  2722. end
  2723. else
  2724. begin // may be enchanced?
  2725. Strm.Position := Pos;
  2726. if Strm.Read( EnhHdr, Sizeof( EnhHdr ) ) < 8 then
  2727. begin
  2728. Strm.Position := Pos;
  2729. Exit;
  2730. end;
  2731. // yes, enchanced
  2732. Strm.Position := Pos;
  2733. Sz := EnhHdr.nBytes;
  2734. Stream2Stream( MemStrm, Strm, Sz );
  2735. fHandle := SetEnhMetaFileBits( Sz, MemStrm.Memory );
  2736. end;
  2737. MemStrm.Free;
  2738. Result := fHandle <> 0;
  2739. if not Result then
  2740. Strm.Position := Pos;
  2741. end;
  2742. //[procedure TMetafile.RetrieveHeader]
  2743. procedure TMetafile.RetrieveHeader;
  2744. var SzHdr: Integer;
  2745. begin
  2746. if fHeader <> nil then
  2747. FreeMem( fHeader );
  2748. SzHdr := GetEnhMetaFileHeader( fHandle, 0, nil );
  2749. GetMem( fHeader, SzHdr );
  2750. GetEnhMetaFileHeader( fHandle, SzHdr, fHeader );
  2751. end;
  2752. //[procedure TMetafile.SetHandle]
  2753. procedure TMetafile.SetHandle(const Value: THandle);
  2754. begin
  2755. Clear;
  2756. fHandle := Value;
  2757. end;
  2758. //[procedure TMetafile.StretchDraw]
  2759. procedure TMetafile.StretchDraw(DC: HDC; const R: TRect);
  2760. begin
  2761. if Empty then Exit;
  2762. PlayEnhMetaFile( DC, fHandle, R );
  2763. end;
  2764. { ----------------------------------------------------------------------
  2765. TAction and TActionList
  2766. ----------------------------------------------------------------------- }
  2767. //[function NewActionList]
  2768. function NewActionList(AOwner: PControl): PActionList;
  2769. begin
  2770. {-}
  2771. New( Result, Create );
  2772. {+} {++}(* Result := PActionList.Create; *){--}
  2773. with Result{-}^{+} do begin
  2774. FActions:=NewList;
  2775. FOwner:=AOwner;
  2776. RegisterIdleHandler(DoUpdateActions);
  2777. end;
  2778. end;
  2779. //[END NewActionList]
  2780. //[function NewAction]
  2781. function NewAction(const ACaption, AHint: string; AOnExecute: TOnEvent): PAction;
  2782. begin
  2783. {-}
  2784. New( Result, Create );
  2785. {+} {++}(* Result := PAction.Create; *){--}
  2786. with Result{-}^{+} do begin
  2787. FControls:=NewList;
  2788. Enabled:=True;
  2789. Visible:=True;
  2790. Caption:=ACaption;
  2791. Hint:=AHint;
  2792. OnExecute:=AOnExecute;
  2793. end;
  2794. end;
  2795. //[END NewAction]
  2796. { TAction }
  2797. //[procedure TAction.LinkCtrl]
  2798. procedure TAction.LinkCtrl(ACtrl: PObj; ACtrlKind: TCtrlKind; AItemID: integer; AUpdateProc: TOnUpdateCtrlEvent);
  2799. var
  2800. cr: PControlRec;
  2801. begin
  2802. New(cr);
  2803. with cr^ do begin
  2804. Ctrl:=ACtrl;
  2805. CtrlKind:=ACtrlKind;
  2806. ItemID:=AItemID;
  2807. UpdateProc:=AUpdateProc;
  2808. end;
  2809. FControls.Add(cr);
  2810. AUpdateProc(cr);
  2811. end;
  2812. //[procedure TAction.LinkControl]
  2813. procedure TAction.LinkControl(Ctrl: PControl);
  2814. begin
  2815. LinkCtrl(Ctrl, ckControl, 0, UpdateCtrl);
  2816. Ctrl.OnClick:=DoOnControlClick;
  2817. end;
  2818. //[procedure TAction.LinkMenuItem]
  2819. procedure TAction.LinkMenuItem(Menu: PMenu; MenuItemIdx: integer);
  2820. {$IFDEF _FPC}
  2821. var
  2822. arr1_DoOnMenuItem: array[ 0..0 ] of TOnMenuItem;
  2823. {$ENDIF _FPC}
  2824. begin
  2825. LinkCtrl(Menu, ckMenu, MenuItemIdx, UpdateMenu);
  2826. {$IFDEF _FPC}
  2827. arr1_DoOnMenuItem[ 0 ] := DoOnMenuItem;
  2828. Menu.AssignEvents(MenuItemIdx, arr1_DoOnMenuItem);
  2829. {$ELSE}
  2830. Menu.AssignEvents(MenuItemIdx, [ DoOnMenuItem ]);
  2831. {$ENDIF}
  2832. end;
  2833. //[procedure TAction.LinkToolbarButton]
  2834. procedure TAction.LinkToolbarButton(Toolbar: PControl; ButtonIdx: integer);
  2835. {$IFDEF _FPC}
  2836. var
  2837. arr1_DoOnToolbarButtonClick: array[ 0..0 ] of TOnToolbarButtonClick;
  2838. {$ENDIF _FPC}
  2839. begin
  2840. LinkCtrl(Toolbar, ckToolbar, ButtonIdx, UpdateToolbar);
  2841. {$IFDEF _FPC}
  2842. arr1_DoOnToolbarButtonClick[ 0 ] := DoOnToolbarButtonClick;
  2843. Toolbar.TBAssignEvents(ButtonIdx, arr1_DoOnToolbarButtonClick);
  2844. {$ELSE}
  2845. Toolbar.TBAssignEvents(ButtonIdx, [DoOnToolbarButtonClick]);
  2846. {$ENDIF}
  2847. end;
  2848. //[destructor TAction.Destroy]
  2849. destructor TAction.Destroy;
  2850. begin
  2851. FControls.Release;
  2852. FCaption:='';
  2853. FShortCut:='';
  2854. FHint:='';
  2855. inherited;
  2856. end;
  2857. //[procedure TAction.DoOnControlClick]
  2858. procedure TAction.DoOnControlClick(Sender: PObj);
  2859. begin
  2860. Execute;
  2861. end;
  2862. //[procedure TAction.DoOnMenuItem]
  2863. procedure TAction.DoOnMenuItem(Sender: PMenu; Item: Integer);
  2864. begin
  2865. Execute;
  2866. end;
  2867. //[procedure TAction.DoOnToolbarButtonClick]
  2868. procedure TAction.DoOnToolbarButtonClick(Sender: PControl; BtnID: Integer);
  2869. begin
  2870. Execute;
  2871. end;
  2872. //[procedure TAction.Execute]
  2873. procedure TAction.Execute;
  2874. begin
  2875. if Assigned(FOnExecute) and FEnabled then
  2876. FOnExecute(PObj( @Self ));
  2877. end;
  2878. //[procedure TAction.SetCaption]
  2879. procedure TAction.SetCaption(const Value: string);
  2880. var
  2881. i: integer;
  2882. c, ss: string;
  2883. begin
  2884. i:=Pos(#9, Value);
  2885. if i <> 0 then begin
  2886. c:=Copy(Value, 1, i - 1);
  2887. ss:=Copy(Value, i + 1, MaxInt);
  2888. end
  2889. else begin
  2890. c:=Value;
  2891. ss:='';
  2892. end;
  2893. if (FCaption = c) and (FShortCut = ss) then exit;
  2894. FCaption:=c;
  2895. FShortCut:=ss;
  2896. UpdateControls;
  2897. end;
  2898. //[procedure TAction.SetChecked]
  2899. procedure TAction.SetChecked(const Value: boolean);
  2900. begin
  2901. if FChecked = Value then exit;
  2902. FChecked := Value;
  2903. UpdateControls;
  2904. end;
  2905. //[procedure TAction.SetEnabled]
  2906. procedure TAction.SetEnabled(const Value: boolean);
  2907. begin
  2908. if FEnabled = Value then exit;
  2909. FEnabled := Value;
  2910. UpdateControls;
  2911. end;
  2912. //[procedure TAction.SetHelpContext]
  2913. procedure TAction.SetHelpContext(const Value: integer);
  2914. begin
  2915. if FHelpContext = Value then exit;
  2916. FHelpContext := Value;
  2917. UpdateControls;
  2918. end;
  2919. //[procedure TAction.SetHint]
  2920. procedure TAction.SetHint(const Value: string);
  2921. begin
  2922. if FHint = Value then exit;
  2923. FHint := Value;
  2924. UpdateControls;
  2925. end;
  2926. //[procedure TAction.SetOnExecute]
  2927. procedure TAction.SetOnExecute(const Value: TOnEvent);
  2928. begin
  2929. if @FOnExecute = @Value then exit;
  2930. FOnExecute:=Value;
  2931. UpdateControls;
  2932. end;
  2933. //[procedure TAction.SetVisible]
  2934. procedure TAction.SetVisible(const Value: boolean);
  2935. begin
  2936. if FVisible = Value then exit;
  2937. FVisible := Value;
  2938. UpdateControls;
  2939. end;
  2940. //[procedure TAction.UpdateControls]
  2941. procedure TAction.UpdateControls;
  2942. var
  2943. i: integer;
  2944. begin
  2945. with FControls{-}^{+} do
  2946. for i:=0 to Count - 1 do
  2947. PControlRec(Items[i]).UpdateProc(Items[i]);
  2948. end;
  2949. //[procedure TAction.UpdateCtrl]
  2950. procedure TAction.UpdateCtrl(Sender: PControlRec);
  2951. begin
  2952. with Sender^, PControl(Ctrl){-}^{+} do begin
  2953. if Caption <> Self.FCaption then
  2954. Caption:=Self.FCaption;
  2955. if Enabled <> Self.FEnabled then
  2956. Enabled:=Self.FEnabled;
  2957. if Checked <> Self.FChecked then
  2958. Checked:=Self.FChecked;
  2959. if Visible <> Self.FVisible then
  2960. Visible:=Self.FVisible;
  2961. end;
  2962. end;
  2963. //[procedure TAction.UpdateMenu]
  2964. procedure TAction.UpdateMenu(Sender: PControlRec);
  2965. var
  2966. s: string;
  2967. begin
  2968. with Sender^, PMenu(Ctrl).Items[ItemID]{-}^{+} do begin
  2969. s:=Self.FCaption;
  2970. if Self.FShortCut <> '' then
  2971. s:=s + #9 + Self.FShortCut;
  2972. if Caption <> s then
  2973. Caption:=s;
  2974. if Enabled <> Self.FEnabled then
  2975. Enabled:=Self.FEnabled;
  2976. if Checked <> Self.FChecked then
  2977. Checked:=Self.FChecked;
  2978. if Visible <> Self.FVisible then
  2979. Visible:=Self.FVisible;
  2980. if HelpContext <> Self.FHelpContext then
  2981. HelpContext:=Self.FHelpContext;
  2982. if Self.FAccelerator.Key <> 0 then {YS} // Добавить
  2983. Accelerator:=Self.FAccelerator;
  2984. end;
  2985. end;
  2986. //[procedure TAction.UpdateToolbar]
  2987. procedure TAction.UpdateToolbar(Sender: PControlRec);
  2988. var
  2989. i: integer;
  2990. s: string;
  2991. begin
  2992. with Sender^, PControl(Ctrl){-}^{+} do begin
  2993. i:=TBIndex2Item(ItemID);
  2994. s:=TBButtonText[i];
  2995. if (s <> '') and (s <> Self.FCaption) then
  2996. TBButtonText[i]:=Self.FCaption;
  2997. TBSetTooltips(i, [PChar(Self.FHint)]);
  2998. if TBButtonEnabled[ItemID] <> Self.FEnabled then
  2999. TBButtonEnabled[ItemID]:=Self.FEnabled;
  3000. if TBButtonVisible[ItemID] <> Self.FVisible then
  3001. TBButtonVisible[ItemID]:=Self.FVisible;
  3002. if TBButtonChecked[ItemID] <> Self.FChecked then
  3003. TBButtonChecked[ItemID]:=Self.FChecked;
  3004. end;
  3005. end;
  3006. //[procedure TAction.SetAccelerator]
  3007. procedure TAction.SetAccelerator(const Value: TMenuAccelerator);
  3008. begin
  3009. if (FAccelerator.fVirt = Value.fVirt) and (FAccelerator.Key = Value.Key) then exit;
  3010. FAccelerator := Value;
  3011. FShortCut:=GetAcceleratorText(FAccelerator); // {YS}
  3012. UpdateControls;
  3013. end;
  3014. { TActionList }
  3015. //[function TActionList.Add]
  3016. function TActionList.Add(const ACaption, AHint: string; OnExecute: TOnEvent): PAction;
  3017. begin
  3018. Result:=NewAction(ACaption, AHint, OnExecute);
  3019. FActions.Add(Result);
  3020. end;
  3021. //[procedure TActionList.Clear]
  3022. procedure TActionList.Clear;
  3023. begin
  3024. while FActions.Count > 0 do
  3025. Delete(0);
  3026. FActions.Clear;
  3027. end;
  3028. //[procedure TActionList.Delete]
  3029. procedure TActionList.Delete(Idx: integer);
  3030. begin
  3031. Actions[Idx].Free;
  3032. FActions.Delete(Idx);
  3033. end;
  3034. //[destructor TActionList.Destroy]
  3035. destructor TActionList.Destroy;
  3036. begin
  3037. UnRegisterIdleHandler(DoUpdateActions);
  3038. Clear;
  3039. FActions.Free;
  3040. inherited;
  3041. end;
  3042. //[procedure TActionList.DoUpdateActions]
  3043. procedure TActionList.DoUpdateActions(Sender: PObj);
  3044. begin
  3045. if Assigned(FOnUpdateActions) and (GetActiveWindow = FOwner.Handle) then
  3046. FOnUpdateActions(PObj( @Self ));
  3047. end;
  3048. //[function TActionList.GetActions]
  3049. function TActionList.GetActions(Idx: integer): PAction;
  3050. begin
  3051. Result:=FActions.Items[Idx];
  3052. end;
  3053. //[function TActionList.GetCount]
  3054. function TActionList.GetCount: integer;
  3055. begin
  3056. Result:=FActions.Count;
  3057. end;
  3058. end.