source: trunk/Packages/Common/Common.pas

Last change on this file was 75, checked in by chronos, 6 months ago
  • Modified: Removed U prefix from unit names.
  • Modified: Updated Common package.
File size: 18.9 KB
Line 
1unit Common;
2
3interface
4
5uses
6 {$IFDEF WINDOWS}Windows,{$ENDIF}
7 {$IFDEF UNIX}baseunix,{$ENDIF}
8 Classes, SysUtils, StrUtils, Dialogs, Process, LCLIntf, Graphics,
9 FileUtil, Generics.Collections; //, ShFolder, ShellAPI;
10
11type
12 TArrayOfByte = array of Byte;
13 TExceptionEvent = procedure(Sender: TObject; E: Exception) of object;
14
15 TUserNameFormat = (
16 unfNameUnknown = 0, // Unknown name type.
17 unfNameFullyQualifiedDN = 1, // Fully qualified distinguished name
18 unfNameSamCompatible = 2, // Windows NT® 4.0 account name
19 unfNameDisplay = 3, // A "friendly" display name
20 unfNameUniqueId = 6, // GUID string that the IIDFromString function returns
21 unfNameCanonical = 7, // Complete canonical name
22 unfNameUserPrincipal = 8, // User principal name
23 unfNameCanonicalEx = 9,
24 unfNameServicePrincipal = 10, // Generalized service principal name
25 unfDNSDomainName = 11);
26
27 TFilterMethod = function (FileName: string): Boolean of object;
28 TFileNameMethod = procedure (FileName: string) of object;
29
30var
31 ExceptionHandler: TExceptionEvent;
32 DLLHandle1: HModule;
33
34 {$IFDEF WINDOWS}
35 GetUserNameEx: procedure (NameFormat: DWORD;
36 lpNameBuffer: LPSTR; nSize: PULONG); stdcall;
37 {$ENDIF}
38
39const
40 clLightBlue = TColor($FF8080);
41 clLightGreen = TColor($80FF80);
42 clLightRed = TColor($8080FF);
43
44function AddLeadingZeroes(const aNumber, Length : integer) : string;
45function BinToInt(BinStr: string): Int64;
46function BinToHexString(Source: AnsiString): string;
47//function DelTree(DirName : string): Boolean;
48//function GetSpecialFolderPath(Folder: Integer): string;
49function BCDToInt(Value: Byte): Byte;
50function CompareByteArray(Data1, Data2: TArrayOfByte): Boolean;
51procedure CopyStringArray(Dest: TStringArray; Source: array of string);
52function CombinePaths(Path1, Path2: string): string;
53function ComputerName: string;
54procedure DeleteFiles(APath, AFileSpec: string);
55function Explode(Separator: Char; Data: string): TStringArray;
56procedure ExecuteProgram(Executable: string; Parameters: array of string);
57procedure FileDialogUpdateFilterFileType(FileDialog: TOpenDialog);
58procedure FreeThenNil(var Obj);
59function GetDirCount(Dir: string): Integer;
60function GetUserName: string;
61function GetBitCount(Variable: QWord; MaxIndex: Integer): Integer;
62function GetBit(Variable: QWord; Index: Byte): Boolean;
63function GetStringPart(var Text: string; Separator: string): string;
64function GenerateNewName(OldName: string): string;
65function GetFileFilterItemExt(Filter: string; Index: Integer): string;
66function IntToBin(Data: Int64; Count: Byte): string;
67function Implode(Separator: string; List: TList<string>): string;
68function Implode(Separator: string; List: TStringList; Around: string = ''): string;
69function LastPos(const SubStr: String; const S: String): Integer;
70function LoadFileToStr(const FileName: TFileName): AnsiString;
71function LoggedOnUserNameEx(Format: TUserNameFormat): string;
72function MergeArray(A, B: array of string): TStringArray;
73function OccurenceOfChar(What: Char; Where: string): Integer;
74procedure OpenWebPage(URL: string);
75procedure OpenEmail(Email: string);
76procedure OpenFileInShell(FileName: string);
77function PosFromIndex(SubStr: string; Text: string;
78 StartIndex: Integer): Integer;
79function PosFromIndexReverse(SubStr: string; Text: string;
80 StartIndex: Integer): Integer;
81function RemoveQuotes(Text: string): string;
82procedure SaveStringToFile(S, FileName: string);
83procedure SetBit(var Variable: Int64; Index: Byte; State: Boolean); overload;
84procedure SetBit(var Variable: QWord; Index: Byte; State: Boolean); overload;
85procedure SetBit(var Variable: Cardinal; Index: Byte; State: Boolean); overload;
86procedure SetBit(var Variable: Word; Index: Byte; State: Boolean); overload;
87procedure SearchFiles(AList: TStrings; Dir: string;
88 FilterMethod: TFilterMethod = nil; FileNameMethod: TFileNameMethod = nil);
89function SplitString(var Text: string; Count: Word): string;
90function StripTags(const S: string): string;
91function TryHexToInt(Data: string; out Value: Integer): Boolean;
92function TryBinToInt(Data: string; out Value: Integer): Boolean;
93procedure SortStrings(Strings: TStrings);
94
95
96implementation
97
98function BinToInt(BinStr : string) : Int64;
99var
100 i : byte;
101 RetVar : Int64;
102begin
103 BinStr := UpperCase(BinStr);
104 if BinStr[length(BinStr)] = 'B' then Delete(BinStr,length(BinStr),1);
105 RetVar := 0;
106 for i := 1 to length(BinStr) do begin
107 if not (BinStr[i] in ['0','1']) then begin
108 RetVar := 0;
109 Break;
110 end;
111 RetVar := (RetVar shl 1) + (byte(BinStr[i]) and 1) ;
112 end;
113
114 Result := RetVar;
115end;
116
117function BinToHexString(Source: AnsiString): string;
118var
119 I: Integer;
120begin
121 Result := '';
122 for I := 1 to Length(Source) do begin
123 Result := Result + LowerCase(IntToHex(Ord(Source[I]), 2));
124 end;
125end;
126
127
128procedure DeleteFiles(APath, AFileSpec: string);
129var
130 SearchRec: TSearchRec;
131 Find: Integer;
132 Path: string;
133begin
134 Path := IncludeTrailingPathDelimiter(APath);
135
136 Find := FindFirst(Path + AFileSpec, faAnyFile xor faDirectory, SearchRec);
137 while Find = 0 do begin
138 DeleteFile(Path + SearchRec.Name);
139
140 Find := SysUtils.FindNext(SearchRec);
141 end;
142 FindClose(SearchRec);
143end;
144
145
146function GetFileFilterItemExt(Filter: string; Index: Integer): string;
147var
148 List: TStringList;
149begin
150 try
151 List := TStringList.Create;
152 List.Text := StringReplace(Filter, '|', #10, [rfReplaceAll]);
153 Result := List[Index * 2 + 1];
154 finally
155 List.Free;
156 end;
157end;
158
159procedure FileDialogUpdateFilterFileType(FileDialog: TOpenDialog);
160var
161 FileExt: string;
162begin
163 FileExt := GetFileFilterItemExt(FileDialog.Filter, FileDialog.FilterIndex - 1);
164 Delete(FileExt, 1, 1); // Remove symbol '*'
165 if FileExt <> '.*' then
166 FileDialog.FileName := ChangeFileExt(FileDialog.FileName, FileExt)
167end;
168
169function GenerateNewName(OldName: string): string;
170var
171 I: Integer;
172 Number: Integer;
173begin
174 Number := 1;
175 // Find number on end
176 if Length(OldName) > 0 then begin
177 I := Length(OldName);
178 while (I > 1) and ((OldName[I] >= '0') and (OldName[I] <= '9')) do Dec(I);
179 TryStrToInt(Copy(OldName, I + 1, Length(OldName) - I), Number);
180 Inc(Number)
181 end;
182 Result := Copy(OldName, 1, I) + IntToStr(Number);
183end;
184
185(*function DelTree(DirName : string): Boolean;
186var
187 SHFileOpStruct : TSHFileOpStruct;
188 DirBuf : array [0..255] of char;
189begin
190 DirName := UTF8Decode(DirName);
191 try
192 Fillchar(SHFileOpStruct,Sizeof(SHFileOpStruct),0) ;
193 FillChar(DirBuf, Sizeof(DirBuf), 0 ) ;
194 StrPCopy(DirBuf, DirName) ;
195 with SHFileOpStruct do begin
196 Wnd := 0;
197 pFrom := @DirBuf;
198 wFunc := FO_DELETE;
199 fFlags := FOF_ALLOWUNDO;
200 fFlags := fFlags or FOF_NOCONFIRMATION;
201 fFlags := fFlags or FOF_SILENT;
202 end;
203 Result := (SHFileOperation(SHFileOpStruct) = 0) ;
204 except
205 Result := False;
206 end;
207end;*)
208
209function Implode(Separator: string; List: TStringList; Around: string = ''): string;
210var
211 I: Integer;
212begin
213 Result := '';
214 for I := 0 to List.Count - 1 do begin
215 Result := Result + Around + List[I] + Around;
216 if I < List.Count - 1 then Result := Result + Separator;
217 end;
218end;
219
220function LastPos(const SubStr: String; const S: String): Integer;
221begin
222 Result := Pos(ReverseString(SubStr), ReverseString(S));
223 if (Result <> 0) then
224 Result := ((Length(S) - Length(SubStr)) + 1) - Result + 1;
225end;
226
227function BCDToInt(Value: Byte): Byte;
228begin
229 Result := (Value shr 4) * 10 + (Value and 15);
230end;
231
232(*function GetSpecialFolderPath(Folder: Integer): string;
233const
234 SHGFP_TYPE_CURRENT = 0;
235var
236 Path: array[0..MAX_PATH] of Char;
237begin
238 Result := 'C:\Test';
239 if SUCCEEDED(SHGetFolderPath(0, Folder, 0, SHGFP_TYPE_CURRENT, @path[0])) then
240 Result := path
241 else
242 Result := '';
243end;*)
244
245function IntToBin(Data: Int64; Count: Byte): string;
246var
247 I: Integer;
248begin
249 Result := '';
250 for I := 0 to Count - 1 do
251 Result := IntToStr((Data shr I) and 1) + Result;
252end;
253
254function IntToHex(Data: Cardinal; Count: Byte): string;
255const
256 Chars: array[0..15] of Char = '0123456789ABCDEF';
257var
258 I: Integer;
259begin
260 Result := '';
261 for I := 0 to Count - 1 do
262 Result := Result + Chars[(Data shr (I * 4)) and 15];
263end;
264
265function TryHexToInt(Data: string; out Value: Integer): Boolean;
266var
267 I: Integer;
268begin
269 Data := UpperCase(Data);
270 Result := True;
271 Value := 0;
272 for I := 0 to Length(Data) - 1 do begin
273 if (Data[I + 1] >= '0') and (Data[I + 1] <= '9') then
274 Value := Value or (Ord(Data[I + 1]) - Ord('0')) shl ((Length(Data) - I - 1) * 4)
275 else if (Data[I + 1] >= 'A') and (Data[I + 1] <= 'F') then
276 Value := Value or (Ord(Data[I + 1]) - Ord('A') + 10) shl ((Length(Data) - I - 1) * 4)
277 else Result := False;
278 end;
279end;
280
281function TryBinToInt(Data: string; out Value: Integer): Boolean;
282var
283 I: Integer;
284begin
285 Result := True;
286 Value := 0;
287 for I := 0 to Length(Data) - 1 do begin
288 if (Data[I + 1] >= '0') and (Data[I + 1] <= '1') then
289 Value := Value or (Ord(Data[I + 1]) - Ord('0')) shl ((Length(Data) - I - 1))
290 else Result := False;
291 end;
292end;
293
294function CompareByteArray(Data1, Data2: TArrayOfByte): Boolean;
295var
296 I: Integer;
297begin
298 if Length(Data1) = Length(Data2) then begin
299 Result := True;
300 for I := 0 to Length(Data1) - 1 do begin
301 if Data1[I] <> Data2[I] then begin
302 Result := False;
303 Break;
304 end
305 end;
306 end else Result := False;
307end;
308
309function Explode(Separator: Char; Data: string): TStringArray;
310var
311 Index: Integer;
312begin
313 Result := Default(TStringArray);
314 repeat
315 Index := Pos(Separator, Data);
316 if Index > 0 then begin
317 SetLength(Result, Length(Result) + 1);
318 Result[High(Result)] := Copy(Data, 1, Index - 1);
319 Delete(Data, 1, Index);
320 end else Break;
321 until False;
322 if Data <> '' then begin
323 SetLength(Result, Length(Result) + 1);
324 Result[High(Result)] := Data;
325 end;
326end;
327
328function Implode(Separator: string; List: TList<string>): string;
329var
330 I: Integer;
331begin
332 Result := '';
333 for I := 0 to List.Count - 1 do begin
334 Result := Result + List[I];
335 if I < List.Count - 1 then Result := Result + Separator;
336 end;
337end;
338
339{$IFDEF WINDOWS}
340function GetUserName: string;
341const
342 MAX_USERNAME_LENGTH = 256;
343var
344 L: LongWord;
345begin
346 L := MAX_USERNAME_LENGTH + 2;
347 Result := Default(string);
348 SetLength(Result, L);
349 if Windows.GetUserName(PChar(Result), L) and (L > 0) then begin
350 SetLength(Result, StrLen(PChar(Result)));
351 Result := UTF8Encode(Result);
352 end else Result := '';
353end;
354
355function GetVersionInfo: TOSVersionInfo;
356begin
357 Result.dwOSVersionInfoSize := SizeOf(Result);
358 if GetVersionEx(Result) then begin
359 end;
360end;
361{$ENDIF}
362
363function ComputerName: string;
364{$IFDEF WINDOWS}
365const
366 INFO_BUFFER_SIZE = 32767;
367var
368 Buffer : array[0..INFO_BUFFER_SIZE] of WideChar;
369 Ret : DWORD;
370begin
371 Ret := INFO_BUFFER_SIZE;
372 If (GetComputerNameW(@Buffer[0],Ret)) then begin
373 Result := UTF8Encode(WideString(Buffer));
374 end
375 else begin
376 Result := 'ERROR_NO_COMPUTERNAME_RETURNED';
377 end;
378end;
379{$ENDIF}
380{$IFDEF UNIX}
381var
382 Name: UtsName;
383begin
384 Name := Default(UtsName);
385 fpuname(Name);
386 Result := Name.Nodename;
387end;
388{$ENDIF}
389
390{$IFDEF WINDOWS}
391function LoggedOnUserNameEx(Format: TUserNameFormat): string;
392const
393 MaxLength = 1000;
394var
395 UserName: array[0..MaxLength] of Char;
396 VersionInfo: TOSVersionInfo;
397 Size: DWORD;
398begin
399 VersionInfo := GetVersionInfo;
400 if VersionInfo.dwPlatformId = VER_PLATFORM_WIN32_NT then begin
401 Size := MaxLength;
402 GetUserNameEx(Integer(Format), @UserName, @Size);
403 //ShowMessage(SysErrorMessage(GetLastError));
404 if GetLastError = 0 then Result := UTF8Encode(UserName)
405 else Result := GetUserName;
406 end else Result := GetUserName;
407end;
408{$ELSE}
409function GetUserName: string;
410begin
411 Result := '';
412end;
413
414function LoggedOnUserNameEx(Format: TUserNameFormat): string;
415begin
416 Result := '';
417end;
418
419{$ENDIF}
420
421function SplitString(var Text: string; Count: Word): string;
422begin
423 Result := Copy(Text, 1, Count);
424 Delete(Text, 1, Count);
425end;
426
427function GetBitCount(Variable: QWord; MaxIndex: Integer): Integer;
428var
429 I: Integer;
430begin
431 Result := 0;
432 for I := 0 to MaxIndex - 1 do
433 if ((Variable shr I) and 1) = 1 then Inc(Result);
434end;
435
436function GetBit(Variable:QWord;Index:Byte):Boolean;
437begin
438 Result := ((Variable shr Index) and 1) = 1;
439end;
440
441procedure SetBit(var Variable: Int64; Index: Byte; State: Boolean);
442begin
443 Variable := (Variable and ((1 shl Index) xor High(QWord))) or (Int64(State) shl Index);
444end;
445
446procedure SetBit(var Variable:QWord;Index:Byte;State:Boolean); overload;
447begin
448 Variable := (Variable and ((1 shl Index) xor High(QWord))) or (QWord(State) shl Index);
449end;
450
451procedure SetBit(var Variable:Cardinal;Index:Byte;State:Boolean); overload;
452begin
453 Variable := (Variable and ((1 shl Index) xor High(Cardinal))) or (Cardinal(State) shl Index);
454end;
455
456procedure SetBit(var Variable:Word;Index:Byte;State:Boolean); overload;
457begin
458 Variable := (Variable and ((1 shl Index) xor High(Word))) or (Word(State) shl Index);
459end;
460
461function AddLeadingZeroes(const aNumber, Length : integer) : string;
462begin
463 Result := SysUtils.Format('%.*d', [Length, aNumber]) ;
464end;
465
466procedure LoadLibraries;
467begin
468 {$IFDEF WINDOWS}
469 DLLHandle1 := LoadLibrary('secur32.dll');
470 if DLLHandle1 <> 0 then
471 begin
472 @GetUserNameEx := GetProcAddress(DLLHandle1, 'GetUserNameExA');
473 end;
474 {$ENDIF}
475end;
476
477procedure FreeLibraries;
478begin
479 {$IFDEF WINDOWS}
480 if DLLHandle1 <> 0 then FreeLibrary(DLLHandle1);
481 {$ENDIF}
482end;
483
484procedure ExecuteProgram(Executable: string; Parameters: array of string);
485var
486 Process: TProcess;
487 I: Integer;
488begin
489 try
490 Process := TProcess.Create(nil);
491 Process.Executable := Executable;
492 for I := 0 to Length(Parameters) - 1 do
493 Process.Parameters.Add(Parameters[I]);
494 Process.Options := [poNoConsole];
495 Process.Execute;
496 finally
497 Process.Free;
498 end;
499end;
500
501procedure FreeThenNil(var Obj);
502begin
503 TObject(Obj).Free;
504 TObject(Obj) := nil;
505end;
506
507procedure OpenWebPage(URL: string);
508begin
509 OpenURL(URL);
510end;
511
512procedure OpenEmail(Email: string);
513begin
514 OpenURL('mailto:' + Email);
515end;
516
517procedure OpenFileInShell(FileName: string);
518begin
519 ExecuteProgram('cmd.exe', ['/c', 'start', FileName]);
520end;
521
522function RemoveQuotes(Text: string): string;
523begin
524 Result := Text;
525 if (Pos('"', Text) = 1) and (Text[Length(Text)] = '"') then
526 Result := Copy(Text, 2, Length(Text) - 2);
527end;
528
529function OccurenceOfChar(What: Char; Where: string): Integer;
530var
531 I: Integer;
532begin
533 Result := 0;
534 for I := 1 to Length(Where) do
535 if Where[I] = What then Inc(Result);
536end;
537
538function GetDirCount(Dir: string): Integer;
539begin
540 Result := OccurenceOfChar(DirectorySeparator, Dir);
541 if Copy(Dir, Length(Dir), 1) = DirectorySeparator then
542 Dec(Result);
543end;
544
545function MergeArray(A, B: array of string): TStringArray;
546var
547 I: Integer;
548begin
549 Result := Default(TStringArray);
550 SetLength(Result, Length(A) + Length(B));
551 for I := 0 to Length(A) - 1 do
552 Result[I] := A[I];
553 for I := 0 to Length(B) - 1 do
554 Result[Length(A) + I] := B[I];
555end;
556
557function LoadFileToStr(const FileName: TFileName): AnsiString;
558var
559 FileStream: TFileStream;
560 Read: Integer;
561begin
562 Result := '';
563 FileStream := TFileStream.Create(FileName, fmOpenRead);
564 try
565 if FileStream.Size > 0 then begin
566 SetLength(Result, FileStream.Size);
567 Read := FileStream.Read(Pointer(Result)^, FileStream.Size);
568 SetLength(Result, Read);
569 end;
570 finally
571 FileStream.Free;
572 end;
573end;
574
575function DefaultSearchFilter(const FileName: string): Boolean;
576begin
577 Result := True;
578end;
579
580procedure SaveStringToFile(S, FileName: string);
581var
582 F: TextFile;
583begin
584 AssignFile(F, FileName);
585 try
586 ReWrite(F);
587 Write(F, S);
588 finally
589 CloseFile(F);
590 end;
591end;
592
593procedure SearchFiles(AList: TStrings; Dir: string;
594 FilterMethod: TFilterMethod = nil; FileNameMethod: TFileNameMethod = nil);
595var
596 SR: TSearchRec;
597begin
598 Dir := IncludeTrailingPathDelimiter(Dir);
599 if FindFirst(Dir + '*', faAnyFile, SR) = 0 then
600 try
601 repeat
602 if (SR.Name = '.') or (SR.Name = '..') or (Assigned(FilterMethod) and (not FilterMethod(SR.Name) or
603 not FilterMethod(Copy(Dir, 3, Length(Dir)) + SR.Name))) then Continue;
604 if Assigned(FileNameMethod) then
605 FileNameMethod(Dir + SR.Name);
606 AList.Add(Dir + SR.Name);
607 if (SR.Attr and faDirectory) <> 0 then
608 SearchFiles(AList, Dir + SR.Name, FilterMethod);
609 until FindNext(SR) <> 0;
610 finally
611 FindClose(SR);
612 end;
613end;
614
615function GetStringPart(var Text: string; Separator: string): string;
616var
617 P: Integer;
618begin
619 P := Pos(Separator, Text);
620 if P > 0 then begin
621 Result := Copy(Text, 1, P - 1);
622 Delete(Text, 1, P - 1 + Length(Separator));
623 end else begin
624 Result := Text;
625 Text := '';
626 end;
627 Result := Trim(Result);
628 Text := Trim(Text);
629end;
630
631function StripTags(const S: string): string;
632var
633 Len: Integer;
634
635 function ReadUntil(const ReadFrom: Integer; const C: Char): Integer;
636 var
637 J: Integer;
638 begin
639 for J := ReadFrom to Len do
640 if (S[j] = C) then
641 begin
642 Result := J;
643 Exit;
644 end;
645 Result := Len + 1;
646 end;
647
648var
649 I, APos: Integer;
650begin
651 Len := Length(S);
652 I := 0;
653 Result := '';
654 while (I <= Len) do begin
655 Inc(I);
656 APos := ReadUntil(I, '<');
657 Result := Result + Copy(S, I, APos - i);
658 I := ReadUntil(APos + 1, '>');
659 end;
660end;
661
662function PosFromIndex(SubStr: string; Text: string;
663 StartIndex: Integer): Integer;
664var
665 I, MaxLen: SizeInt;
666 Ptr: PAnsiChar;
667begin
668 Result := 0;
669 if (StartIndex < 1) or (StartIndex > Length(Text) - Length(SubStr)) then Exit;
670 if Length(SubStr) > 0 then begin
671 MaxLen := Length(Text) - Length(SubStr) + 1;
672 I := StartIndex;
673 Ptr := @Text[StartIndex];
674 while (I <= MaxLen) do begin
675 if (SubStr[1] = Ptr^) and (CompareByte(Substr[1], Ptr^, Length(SubStr)) = 0) then begin
676 Result := I;
677 Exit;
678 end;
679 Inc(I);
680 Inc(Ptr);
681 end;
682 end;
683end;
684
685function PosFromIndexReverse(SubStr: string; Text: string;
686 StartIndex: Integer): Integer;
687var
688 I: SizeInt;
689 Ptr: PAnsiChar;
690begin
691 Result := 0;
692 if (StartIndex < 1) or (StartIndex > Length(Text)) then Exit;
693 if Length(SubStr) > 0 then begin
694 I := StartIndex;
695 Ptr := @Text[StartIndex];
696 while (I > 0) do begin
697 if (SubStr[1] = Ptr^) and (CompareByte(Substr[1], Ptr^, Length(SubStr)) = 0) then begin
698 Result := I;
699 Exit;
700 end;
701 Dec(I);
702 Dec(Ptr);
703 end;
704 end;
705end;
706
707procedure CopyStringArray(Dest: TStringArray; Source: array of string);
708var
709 I: Integer;
710begin
711 SetLength(Dest, Length(Source));
712 for I := 0 to Length(Dest) - 1 do
713 Dest[I] := Source[I];
714end;
715
716function CombinePaths(Path1, Path2: string): string;
717begin
718 Result := Path1;
719 if Result <> '' then Result := Result + DirectorySeparator + Path2
720 else Result := Path2;
721end;
722
723procedure SortStrings(Strings: TStrings);
724var
725 Tmp: TStringList;
726begin
727 Strings.BeginUpdate;
728 try
729 if Strings is TStringList then begin
730 TStringList(Strings).Sort;
731 end else begin
732 Tmp := TStringList.Create;
733 try
734 Tmp.Assign(Strings);
735 Tmp.Sort;
736 Strings.Assign(Tmp);
737 finally
738 Tmp.Free;
739 end;
740 end;
741 finally
742 Strings.EndUpdate;
743 end;
744end;
745
746
747initialization
748
749LoadLibraries;
750
751
752finalization
753
754FreeLibraries;
755
756end.
Note: See TracBrowser for help on using the repository browser.