{----------------------------------------------------------------------------- The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: JvUtils.PAS, released on 2002-07-04. The Initial Developers of the Original Code are: Andrei Prygounkov Roman Tkachev Copyright (c) 1999, 2002 Andrei Prygounkov, Roman Tkachev All Rights Reserved. Contributor(s): Last Modified: 2002-07-04 You may retrieve the latest version of this file at the Project JEDI's JVCL home page, located at http://jvcl.sourceforge.net Description : common routines Known Issues: * Some functions are also in JvStrUtil * Some russian comments were translated to english; these comments are marked with [translated] -----------------------------------------------------------------------------} {$I JVCL.INC} {$I WINDOWSONLY.INC} unit JvUtils; interface {$DEFINE INCLUDE_RAUTILSW} uses Windows, Forms, Controls, Graphics, SysUtils, Classes, StdCtrls, ExtCtrls, Dialogs, Menus, Clipbrd, {$IFDEF COMPILER3_UP} ShlObj, {$ENDIF} {$IFDEF COMPILER3_UP} ActiveX, {$ELSE} Ole2, {$ENDIF} {$IFDEF COMPILER6_UP} Variants, {$ENDIF} TypInfo; {$IFNDEF COMPILER4_UP} type Longword = Integer; {$ENDIF} type TTickCount = Cardinal; {**** string handling routines} const Separators: set of Char = [#00, ' ', '-', #13, #10, '.', ',', '/', '\', '#', '"', '''', ':', '+', '%', '*', '(', ')', ';', '=', '{', '}', '[', ']', '{', '}', '<', '>']; {const Separators is used in GetWordOnPos, JvUtils.ReplaceStrings and SubWord} {$IFDEF DELPHI} type TSetOfChar = set of Char; {$ENDIF DELPHI} {$IFDEF BCB} type TSetOfChar = string; {$ENDIF BCB} { GetWordOnPos returns Word from string, S, on the cursor position, P} function GetWordOnPos(const S: string; const P: Integer): string; { GetWordOnPosEx working like GetWordOnPos function, but also returns Word position in iBeg, iEnd variables } function GetWordOnPosEx(const S: string; const P: Integer; var iBeg, iEnd: Integer): string; { SubStr returns substring from string, S, separated with Separator string} function SubStr(const S: string; const Index: Integer; const Separator: string): string; { SubStrEnd same to previous function but Index numerated from the end of string } function SubStrEnd(const S: string; const Index: Integer; const Separator: string): string; { SubWord returns next Word from string, P, and offsets Pointer to the end of Word, P2 } function SubWord(P: PChar; var P2: PChar): string; { NumberByWord returns the text representation of the number, N, in normal russian language. Was typed from Monitor magazine } function NumberByWord(const N: Longint): string; // function CurrencyByWord(Value : Currency) : string; { GetLineByPos returns the Line number, there the symbol Pos is pointed. Lines separated with #13 symbol } function GetLineByPos(const S: string; const Pos: Integer): Integer; { GetXYByPos is same to previous function, but returns X position in line too} procedure GetXYByPos(const S: string; const Pos: Integer; var X, Y: Integer); { ReplaceString searches for all substrings, OldPattern, in a string, S, and replaces them with NewPattern } function ReplaceString(S: string; const OldPattern, NewPattern: string): string; { ConcatSep concatenate S and S2 strings with Separator. if S = '', separator don't included } function ConcatSep(const S, S2, Separator: string): string; { ConcatLeftSep is same to previous function, but strings concatenate right to left } function ConcatLeftSep(const S, S2, Separator: string): string; { MinimizeString trunactes long string, S, and appends '...' symbols, if Length of S is more than MaxLen } function MinimizeString(const S: string; const MaxLen: Integer): string; { Next 4 function for russian chars transliterating. This functions are needed because Oem2Ansi and Ansi2Oem functions sometimes works sucks } procedure Dos2Win(var S: string); procedure Win2Dos(var S: string); function Dos2WinRes(const S: string): string; function Win2DosRes(const S: string): string; function Win2Koi(const S: string): string; { Spaces returns string consists on N space chars } function Spaces(const N: Integer): string; { AddSpaces add spaces to string, S, if it Length is smaller than N } function AddSpaces(const S: string; const N: Integer): string; { function LastDate for russian users only } // { returns date relative to current date: 'äâà äíÿ íàçàä' } function LastDate(const Dat: TDateTime): string; { CurrencyToStr format currency, Cur, using ffCurrency float format} function CurrencyToStr(const Cur: currency): string; { Cmp compares two strings and returns True if they are equal. Case-insensitive.} function Cmp(const S1, S2: string): Boolean; { StringCat add S2 string to S1 and returns this string } function StringCat(var S1: string; S2: string): string; { HasChar returns True, if Char, Ch, contains in string, S } function HasChar(const Ch: Char; const S: string): Boolean; function HasAnyChar(const Chars: string; const S: string): Boolean; function CharInSet(const Ch: Char; const SetOfChar: TSetOfChar): Boolean; function CountOfChar(const Ch: Char; const S: string): Integer; function DefStr(const S: string; Default: string): string; {**** files routines} { GetWinDir returns Windows folder name } function GetWinDir: TFileName; { GetTempDir returns Windows temporary folder name } function GetTempDir: string; { GenTempFileName returns temporary file name on drive, there FileName is placed } function GenTempFileName(FileName: string): string; { GenTempFileNameExt same to previous function, but returning filename has given extension, FileExt } function GenTempFileNameExt(FileName: string; const FileExt: string): string; { ClearDir clears folder Dir } function ClearDir(const Dir: string): Boolean; { DeleteDir clears and than delete folder Dir } function DeleteDir(const Dir: string): Boolean; { FileEquMask returns True if file, FileName, is compatible with given dos file mask, Mask } function FileEquMask(FileName, Mask: TFileName): Boolean; { FileEquMasks returns True if file, FileName, is compatible with given Masks. Masks must be separated with comma (';') } function FileEquMasks(FileName, Masks: TFileName): Boolean; procedure DeleteFiles(const Folder: TFileName; const Masks: string); { LZFileExpand expand file, FileSource, into FileDest. Given file must be compressed, using MS Compress program } function LZFileExpand(const FileSource, FileDest: string): Boolean; { FileGetInfo fills SearchRec record for specified file attributes} function FileGetInfo(FileName: TFileName; var SearchRec: TSearchRec): Boolean; { HasSubFolder returns True, if folder APath contains other folders } function HasSubFolder(APath: TFileName): Boolean; { IsEmptyFolder returns True, if there are no files or folders in given folder, APath} function IsEmptyFolder(APath: TFileName): Boolean; { AddSlash add slash Char to Dir parameter, if needed } procedure AddSlash(var Dir: TFileName); { AddSlash returns string with added slash Char to Dir parameter, if needed } function AddSlash2(const Dir: TFileName): string; { AddPath returns FileName with Path, if FileName not contain any path } function AddPath(const FileName, Path: TFileName): TFileName; function AddPaths(const PathList, Path: string): string; function ParentPath(const Path: TFileName): TFileName; function FindInPath(const FileName, PathList: string): TFileName; {$IFNDEF BCB1} { BrowseForFolder displays Browse For Folder dialog } function BrowseForFolder(const Handle: HWND; const Title: string; var Folder: string): Boolean; {$ENDIF BCB1} { DeleteReadOnlyFile clears R/O file attribute and delete file } function DeleteReadOnlyFile(const FileName: TFileName): Boolean; { HasParam returns True, if program running with specified parameter, Param } function HasParam(const Param: string): Boolean; function HasSwitch(const Param: string): Boolean; function Switch(const Param: string): string; { ExePath returns ExtractFilePath(ParamStr(0)) } function ExePath: TFileName; function CopyDir(const SourceDir, DestDir: TFileName): Boolean; function FileTimeToDateTime(const FT: TFileTime): TDateTime; function MakeValidFileName(const FileName: TFileName; const ReplaceBadChar: Char): TFileName; {**** Graphic routines } { TTFontSelected returns True, if True Type font is selected in specified device context } function TTFontSelected(const DC: HDC): Boolean; { TrueInflateRect inflates rect in other method, than InflateRect API function } function TrueInflateRect(const R: TRect; const I: Integer): TRect; {**** Windows routines } { SetWindowTop put window to top without recreating window } procedure SetWindowTop(const Handle: HWND; const Top: Boolean); {**** other routines } { KeyPressed returns True, if Key VK is now pressed } function KeyPressed(VK: Integer): Boolean; procedure SwapInt(var Int1, Int2: Integer); function IntPower(Base, Exponent: Integer): Integer; function ChangeTopException(E: TObject): TObject; function StrToBool(const S: string): Boolean; {$IFNDEF COMPILER3_UP} { AnsiStrLIComp compares S1 to S2, without case-sensitivity, up to a maximum Length of MaxLen bytes. The compare operation is controlled by the current Windows locale. The return value is the same as for CompareStr. } function AnsiStrLIComp(S1, S2: PChar; MaxLen: Cardinal): Integer; function AnsiStrIComp(S1, S2: PChar): Integer; {$ENDIF} function Var2Type(V: Variant; const VarType: Integer): Variant; function VarToInt(V: Variant): Integer; function VarToFloat(V: Variant): Double; { following functions are not documented because they are don't work properly sometimes, so don't use them } function ReplaceStrings1(S: string; const Word, Frase: string): string; { ReplaceStrings1 is full equal to ReplaceString function - only for compatibility - don't use } { GetSubStr is full equal to SubStr function - only for compatibility - don't use } function GetSubStr(const S: string; const Index: Integer; const Separator: Char): string; function GetParameter: string; function GetLongFileName(FileName: string): string; {* from unit FileCtrl} function DirectoryExists(const Name: string): Boolean; procedure ForceDirectories(Dir: string); {# from unit FileCtrl} function FileNewExt(const FileName, NewExt: TFileName): TFileName; function GetComputerID: string; function GetComputerName: string; {**** string routines } { ReplaceAllStrings searches for all substrings, Words, in a string, S, and replaces them with Frases with the same Index. Also see RAUtilsW.ReplaceStrings1 function } function ReplaceAllStrings(S: string; Words, Frases: TStrings): string; { ReplaceStrings searches the Word in a string, S, on PosBeg position, in the list, Words, and if founds, replaces this Word with string from another list, Frases, with the same Index, and then update NewSelStart variable } function ReplaceStrings(S: string; PosBeg, Len: Integer; Words, Frases: TStrings; var NewSelStart: Integer): string; { CountOfLines calculates the lines count in a string, S, each line must be separated from another with CrLf sequence } function CountOfLines(const S: string): Integer; { DeleteEmptyLines deletes all empty lines from strings, Ss. Lines contained only spaces also deletes. } procedure DeleteEmptyLines(Ss: TStrings); { SQLAddWhere addes or modifies existing where-statement, where, to the strings, SQL. Note: If strings SQL allready contains where-statement, it must be started on the begining of any line } procedure SQLAddWhere(SQL: TStrings; const Where: string); {**** files routines - } { ResSaveToFile save resource named as Name with Typ type into file FileName. Resource can be compressed using MS Compress program} function ResSaveToFile(const Typ, Name: string; const Compressed: Boolean; const FileName: string): Boolean; function ResSaveToFileEx(Instance: HINST; Typ, Name: PChar; const Compressed: Boolean; const FileName: string): Boolean; function ResSaveToString(Instance: HINST; const Typ, Name: string; var S: string): Boolean; { Execute executes other program and waiting for it terminating, then return its Exit Code } function Execute(const CommandLine, WorkingDirectory: string): Integer; { IniReadSection read section, Section, from ini-file, IniFileName, into strings, Ss. This function reads ALL strings from specified section. Note: TIninFile.ReadSection function reads only strings with '=' symbol.} function IniReadSection(const IniFileName: TFileName; const Section: string; Ss: TStrings): Boolean; { LoadTextFile load text file, FileName, into string } function LoadTextFile(const FileName: TFileName): string; procedure SaveTextFile(const FileName: TFileName; const Source: string); { ReadFolder reads files list from disk folder, Folder, that are equal to mask, Mask, into strings, FileList} function ReadFolder(const Folder, Mask: TFileName; FileList: TStrings): Integer; function ReadFolders(const Folder: TFileName; FolderList: TStrings): Integer; {$IFDEF COMPILER3_UP} { TargetFileName - if FileName is ShortCut returns filename ShortCut linked to } function TargetFileName(const FileName: TFileName): TFileName; { return filename ShortCut linked to } function ResolveLink(const hWnd: HWND; const LinkFile: TFileName; var FileName: TFileName): HRESULT; {$ENDIF COMPILER3_UP} {**** Graphic routines - } { LoadIcoToImage loads two icons from resource named NameRes, into two image lists ALarge and ASmall} procedure LoadIcoToImage(ALarge, ASmall: TImageList; const NameRes: string); { RATextOut same with TCanvas.TextOut procedure, but can clipping drawing with rectangle, RClip. } procedure RATextOut(Canvas: TCanvas; const R, RClip: TRect; const S: string); { RATextOutEx same with RATextOut function, but can calculate needed height for correct output } function RATextOutEx(Canvas: TCanvas; const R, RClip: TRect; const S: string; const CalcHeight: Boolean): Integer; { RATextCalcHeight calculate needed height for correct output, using RATextOut or RATextOutEx functions } function RATextCalcHeight(Canvas: TCanvas; const R: TRect; const S: string): Integer; { Cinema draws some visual effect } procedure Cinema(Canvas: TCanvas; rS {Source}, rD {Dest}: TRect); { Roughed fills rect with special 3D pattern } procedure Roughed(ACanvas: TCanvas; const ARect: TRect; const AVert: Boolean); { BitmapFromBitmap creates new small bitmap from part of source bitmap, SrcBitmap, with specified width and height, AWidth, AHeight and placed on a specified Index, Index in the source bitmap } function BitmapFromBitmap(SrcBitmap: TBitmap; const AWidth, AHeight, Index: Integer): TBitmap; { TextWidth calculate text with for writing using standard desktop font } function TextWidth(AStr: string): Integer; { DefineCursor load cursor from resource, and return available cursor number, assigned to it } function DefineCursor(Identifier: PChar): TCursor; {**** other routines - } { FindFormByClass returns first form with specified class, FormClass, owned by Application global variable } function FindFormByClass(FormClass: TFormClass): TForm; function FindFormByClassName(FormClassName: string): TForm; { FindByTag returns the control with specified class, ComponentClass, from WinContol.Controls property, having Tag property value, equaled to Tag parameter } function FindByTag(WinControl: TWinControl; ComponentClass: TComponentClass; const Tag: Integer): TComponent; { ControlAtPos2 equal to TWinControl.ControlAtPos function, but works better } function ControlAtPos2(Parent: TWinControl; X, Y: Integer): TControl; { RBTag searches WinControl.Controls for checked RadioButton and returns its Tag property value } function RBTag(Parent: TWinControl): Integer; { AppMinimized returns True, if Application is minimized } function AppMinimized: Boolean; { MessageBox is Application.MessageBox with string (not PChar) parameters. if Caption parameter = '', it replaced with Application.Title } function MessageBox(const Msg: string; Caption: string; const Flags: Integer): Integer; function MsgDlg2(const Msg, ACaption: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpContext: Integer; Control: TWinControl): Integer; function MsgDlgDef(const Msg, ACaption: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; DefButton: TMsgDlgBtn; HelpContext: Integer; Control: TWinControl): Integer; { Delay stop program execution to MSec msec } procedure Delay(MSec: Longword); procedure CenterHor(Parent: TControl; MinLeft: Integer; Controls: array of TControl); procedure EnableControls(Control: TWinControl; const Enable: Boolean); procedure EnableMenuItems(MenuItem: TMenuItem; const Tag: Integer; const Enable: Boolean); procedure ExpandWidth(Parent: TControl; MinWidth: Integer; Controls: array of TControl); function PanelBorder(Panel: TCustomPanel): Integer; function Pixels(Control: TControl; APixels: Integer): Integer; procedure SetChildPropOrd(Owner: TComponent; PropName: string; Value: Longint); procedure Error(const Msg: string); procedure ItemHtDrawEx(Canvas: TCanvas; Rect: TRect; const State: TOwnerDrawState; const Text: string; const HideSelColor: Boolean; var PlainItem: string; var Width: Integer; CalcWidth: Boolean); { example for Text parameter : 'Item 1 bold italic ITALIC red green blue ' } function ItemHtDraw(Canvas: TCanvas; Rect: TRect; const State: TOwnerDrawState; const Text: string; const HideSelColor: Boolean): string; function ItemHtWidth(Canvas: TCanvas; Rect: TRect; const State: TOwnerDrawState; const Text: string; const HideSelColor: Boolean): Integer; function ItemHtPlain(const Text: string): string; { ClearList - clears list of TObject } procedure ClearList(List: TList); procedure MemStreamToClipBoard(MemStream: TMemoryStream; const Format: Word); procedure ClipBoardToMemStream(MemStream: TMemoryStream; const Format: Word); { RTTI support } function GetPropType(Obj: TObject; const PropName: string): TTypeKind; function GetPropStr(Obj: TObject; const PropName: string): string; function GetPropOrd(Obj: TObject; const PropName: string): Integer; function GetPropMethod(Obj: TObject; const PropName: string): TMethod; procedure PrepareIniSection(SS: TStrings); { following functions are not documented because they are don't work properly, so don't use them } {$IFDEF COMPILER2} function CompareMem(P1, P2: Pointer; Length: Integer): Boolean; assembler; {$ENDIF} type TMenuAnimation = (maNone, maRandom, maUnfold, maSlide); procedure ShowMenu(Form: TForm; MenuAni: TMenuAnimation); type TProcObj = procedure of object; procedure ExecAfterPause(Proc: TProcObj; Pause: Integer); const NoHelp = 0; { for MsgDlg2 } MsgDlgCharSet: Integer = DEFAULT_CHARSET; // (rom) from JvBandWindows to make it obsolete function PointL(const X, Y: Longint): TPointL; // (rom) from JvBandUtils to make it obsolete function iif(const Test: Boolean; const ATrue, AFalse: Variant): Variant; implementation uses Math, JvCtlConst; function GetLineByPos(const S: string; const Pos: Integer): Integer; var I: Integer; begin if Length(S) < Pos then Result := -1 else begin I := 1; Result := 0; while I <= Pos do begin if S[I] = #13 then Inc(Result); Inc(I); end; end; end; procedure GetXYByPos(const S: string; const Pos: Integer; var X, Y: Integer); var I, iB: Integer; begin X := -1; Y := -1; iB := 0; if (Length(S) >= Pos) and (Pos >= 0) then begin I := 1; Y := 0; while I <= Pos do begin if S[I] = #13 then begin Inc(Y); iB := I + 1; end; Inc(I); end; X := Pos - iB; end; end; function GetWordOnPos(const S: string; const P: Integer): string; var I, Beg: Integer; begin Result := ''; if (P > Length(S)) or (P < 1) then Exit; for I := P downto 1 do if S[I] in Separators then Break; Beg := I + 1; for I := P to Length(S) do if S[I] in Separators then Break; if I > Beg then Result := Copy(S, Beg, I - Beg) else Result := S[P]; end; function GetWordOnPosEx(const S: string; const P: Integer; var iBeg, iEnd: Integer): string; begin Result := ''; if (P > Length(S)) or (P < 1) then Exit; iBeg := P; if P > 1 then if S[P] in Separators then if (P < 1) or ((P - 1 > 0) and (S[P - 1] in Separators)) then Inc(iBeg) else if not ((P - 1 > 0) and (S[P - 1] in Separators)) then Dec(iBeg); while iBeg >= 1 do if S[iBeg] in Separators then Break else Dec(iBeg); Inc(iBeg); iEnd := P; while iEnd <= Length(S) do if S[iEnd] in Separators then Break else Inc(iEnd); if iEnd > iBeg then Result := Copy(S, iBeg, iEnd - iBeg) else Result := S[P]; end; function GetWinDir: TFileName; var WinDir: array [0..MAX_PATH] of Char; begin WinDir[GetWindowsDirectory(WinDir, MAX_PATH)] := #0; Result := WinDir; end; function GenTempFileName(FileName: string): string; var TempDir: array [0..MAX_PATH] of Char; TempFile: array [0..MAX_PATH] of Char; STempDir: TFileName; Res: Integer; begin TempDir[GetTempPath(260, TempDir)] := #0; if FileName <> '' then begin if Length(FileName) < 4 then FileName := ExpandFileName(FileName); if (Length(FileName) > 4) and (FileName[2] = ':') and (StrLen(@TempDir[0]) > 4) and (AnsiCompareText(TempDir[0], FileName[1]) <> 0) then begin STempDir := ExtractFilePath(FileName); Move(STempDir[1], TempDir, Length(STempDir) + 1); end; end; Res := GetTempFileName( TempDir, { address of directory name for temporary file} '~RA', { address of filename prefix} 0, { number used to create temporary filename} TempFile); { address of buffer that receives the new filename} if Res <> 0 then Result := TempFile else Result := '~JVCLTemp.tmp'; DeleteFile(Result); end; function GenTempFileNameExt(FileName: string; const FileExt: string): string; begin Result := ChangeFileExt(GenTempFileName(FileName), FileExt); end; function GetTempDir: string; var TempDir: array [0..MAX_PATH] of Char; begin TempDir[GetTempPath(260, TempDir)] := #0; Result := TempDir; end; function ClearDir(const Dir: string): Boolean; var SearchRec: TSearchRec; DosError: Integer; Path: TFileName; begin Result := True; Path := Dir; AddSlash(Path); DosError := FindFirst(Path + '*.*', faAnyFile, SearchRec); while DosError = 0 do begin if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then begin if (SearchRec.Attr and faDirectory) = faDirectory then Result := Result and DeleteDir(Path + SearchRec.Name) else Result := Result and DeleteFile(Path + SearchRec.Name); // if not Result then Exit; end; DosError := FindNext(SearchRec); end; FindClose(SearchRec); end; function DeleteDir(const Dir: string): Boolean; begin ClearDir(Dir); { if Dir[Length(Dir)] = '\' then Dir[Length(Dir)] := #0;} Result := RemoveDir(Dir); end; procedure DeleteFiles(const Folder: TFileName; const Masks: string); var SearchRec: TSearchRec; DosError: Integer; Path: TFileName; begin Path := AddSlash2(Folder); DosError := FindFirst(Path + '*.*', faAnyFile and not faDirectory, SearchRec); while DosError = 0 do begin if FileEquMasks(Path + SearchRec.Name, Masks) then DeleteFile(Path + SearchRec.Name); DosError := FindNext(SearchRec); end; FindClose(SearchRec); end; function GetParameter: string; var FN, FN1: PChar; begin if ParamCount = 0 then begin Result := ''; Exit end; FN := cmdLine; if FN[0] = '"' then begin FN := StrScan(FN + 1, '"'); if (FN[0] = #00) or (FN[1] = #00) then Result := '' else begin Inc(FN, 2); if FN[0] = '"' then begin Inc(FN, 1); FN1 := StrScan(FN + 1, '"'); if FN1[0] <> #00 then FN1[0] := #00; end; Result := FN; end; end else Result := Copy(CmdLine, Length(ParamStr(0)) + 1, 260); while (Length(Result) > 0) and (Result[1] = ' ') do Delete(Result, 1, 1); Result := ReplaceString(Result, '"', ''); if FileExists(Result) then Result := GetLongFileName(Result); end; function GetLongFileName(FileName: string): string; var SearchRec: TSearchRec; begin if FileGetInfo(FileName, SearchRec) then Result := ExtractFilePath(ExpandFileName(FileName)) + SearchRec.FindData.cFileName else Result := FileName; end; function FileEquMask(FileName, Mask: TFileName): Boolean; var I: Integer; C: Char; P: PChar; begin FileName := AnsiUpperCase(ExtractFileName(FileName)); Mask := AnsiUpperCase(Mask); Result := False; if Pos('.', FileName) = 0 then FileName := FileName + '.'; I := 1; P := PChar(FileName); while I <= Length(Mask) do begin C := Mask[I]; if (P[0] = #0) and (C <> '*') then Exit; case C of '*': if I = Length(Mask) then begin Result := True; Exit; end else begin P := StrScan(P, Mask[I + 1]); if P = nil then Exit; end; '?': Inc(P); else if C = P[0] then Inc(P) else Exit; end; Inc(I); end; if P[0] = #0 then Result := True; end; function FileEquMasks(FileName, Masks: TFileName): Boolean; var I: Integer; Mask: string; begin Result := False; I := 0; Mask := Trim(GetSubStr(Masks, I, ';')); while Length(Mask) <> 0 do if FileEquMask(FileName, Mask) then begin Result := True; Break; end else begin Inc(I); Mask := Trim(GetSubStr(Masks, I, ';')); end; end; function NumberByWord(const N: Longint): string; const Ten: array [0..9] of string = ('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'); Hun: array [1..9] of string = ('onehundred', 'twohundred', 'threehundred', 'fourhundred', 'fivehundred', 'sixhundred', 'sevenhundred', 'eighthundred', 'ninehundred'); OnTen: array [10..19] of string = ('ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'); HunIn: array [2..9] of string = ('twothousand', 'threethousand', 'fourthousand', 'fivethousand', 'sixthousand', 'seventhousand', 'eightthousand', 'ninethousand'); var StrVsp: string; NumStr: string; StrVsp2: string; I: Byte; function IndNumber(Stri: string; Place: Byte): Byte; begin IndNumber := Ord(Stri[Place]) - 48; end; function Back(Stri: string): Longint; var Code: Integer; LI: Longint; begin Result := 0; Val(Stri, LI, Code); if Code = 0 then Result := LI; end; begin NumStr := IntToStr(N); if Length(NumStr) > 9 then begin Result := '*****'; Exit; end; case Length(NumStr) of 1: StrVsp := Ten[N]; 2: case NumStr[1] of '1': StrVsp := OnTen[N]; '0': StrVsp := NumberByWord(IndNumber(NumStr, 2)); '2'..'9': begin StrVsp := HunIn[IndNumber(NumStr, 1)]; if NumStr[2] <> '0' then StrVsp := StrVsp + ' ' + NumberByWord(IndNumber(NumStr, 2)); end; end; 3: begin StrVsp := Hun[IndNumber(NumStr, 1)]; StrVsp := StrVsp + ' ' + NumberByWord(Back(Copy(NumStr, 2, 2))); end; 4: begin StrVsp := Ten[IndNumber(NumStr, 1)]; // (rom) needs translation case NumStr[1] of '1': StrVsp := 'îäíà òûñÿ÷à'; '2': StrVsp := 'äâå òûñÿ÷è'; '3', '4': StrVsp := StrVsp + ' òûñÿ÷è'; '5'..'9': StrVsp := StrVsp + ' òûñÿ÷'; end; StrVsp := StrVsp + ' ' + NumberByWord(Back(Copy(NumStr, 2, 3))); end; 5: begin StrVsp2 := NumberByWord(Back(Copy(NumStr, 1, 2))); I := Pos(' äâà', StrVsp2); if Pos(' äâà', StrVsp2) = I then I := 0; if I <> 0 then StrVsp2[I + 3] := 'e'; I := Pos(' îäèí', StrVsp2); if Pos(' îäèíí', StrVsp2) = I then I := 0; if I <> 0 then begin StrVsp2[I + 3] := 'í'; StrVsp2[I + 4] := 'à'; end; if NumStr[1] <> '1' then case NumStr[2] of '1': StrVsp := ' òûñÿ÷à '; '2'..'4': StrVsp := ' òûñÿ÷è '; '5'..'9': StrVsp := ' òûñÿ÷ '; end else StrVsp := ' òûñÿ÷ '; StrVsp := StrVsp2 + StrVsp + NumberByWord(Back(Copy(NumStr, 3, 3))); end; 6: begin StrVsp2 := NumberByWord(Back(Copy(NumStr, 1, 3))); I := Pos(' äâà', StrVsp2); if Pos(' äâàä', StrVsp2) = I then I := 0; if I <> 0 then StrVsp2[I + 3] := 'å'; I := Pos(' îäèí', Strvsp2); if Pos(' îäèíí', StrVsp2) = I then I := 0; if I <> 0 then begin StrVsp2[I + 3] := 'í'; StrVsp2[I + 4] := 'à'; end; if NumStr[2] <> '1' then case NumStr[3] of '1': StrVsp := ' òûñÿ÷à '; '2'..'4': StrVsp := ' òûñÿ÷è '; '5'..'9': StrVsp := ' òûñÿ÷ '; end else StrVsp := ' òûñÿ÷ '; StrVsp := StrVsp2 + StrVsp + NumberByWord(Back(Copy(NumStr, 4, 3))); end; 7: begin StrVsp := Ten[IndNumber(NumStr, 1)]; case NumStr[1] of '1': StrVsp := 'îäèí ìèëëèîí'; '2'..'4': StrVsp := StrVsp + ' ìèëëèîíà'; '5'..'9': StrVsp := StrVsp + ' ìèëëèîíîâ'; end; StrVsp := StrVsp + ' ' + NumberByWord(Back(Copy(NumStr, 2, 6))); end; 8: begin StrVsp := NumberByWord(Back(Copy(NumStr, 1, 2))); StrVsp := StrVsp + ' ìèëëèîí'; if NumStr[1] <> '1' then case NumStr[2] of '2'..'4': StrVsp := StrVsp + 'à'; '0', '5'..'9': StrVsp := StrVsp + 'îâ'; end else StrVsp := StrVsp + 'îâ'; StrVsp := StrVsp + ' ' + NumberByWord(Back(Copy(NumStr, 3, 6))); end; 9: begin StrVsp := NumberByWord(Back(Copy(Numstr, 1, 3))); StrVsp := StrVsp + ' ìèëëèîí'; if NumStr[2] <> '1' then case NumStr[3] of '2'..'4': StrVsp := StrVsp + 'à'; '0', '5'..'9': StrVsp := StrVsp + 'îâ'; end else StrVsp := StrVsp + 'îâ'; StrVsp := StrVsp + ' ' + NumberByWord(Back(Copy(NumStr, 4, 6))); end; end; if (Length(StrVsp) > 4) and (Copy(StrVsp, Length(StrVsp) - 3, 4) = Ten[0]) then StrVsp := Copy(StrVsp, 1, Length(StrVsp) - 4); Result := StrVsp; end; function GetSubStr(const S: string; const Index: Integer; const Separator: Char): string; begin Result := SubStr(S, Index, Separator); end; function SubStr(const S: string; const Index: Integer; const Separator: string): string; { Returns a substring. Substrings are divided by Sep character [translated] } var I: Integer; pB, pE: PChar; begin Result := ''; if ((Index < 0) or ((Index = 0) and (Length(S) > 0) and (S[1] = Separator))) or (Length(S) = 0) then Exit; pB := PChar(S); for I := 1 to Index do begin pB := StrPos(pB, PChar(Separator)); if pB = nil then Exit; pB := pB + Length(Separator); if pB[0] = #0 then Exit; end; pE := StrPos(pB + 1, PChar(Separator)); if pE = nil then pE := PChar(S) + Length(S); if not (AnsiStrLIComp(pB, PChar(Separator), Length(Separator)) = 0) then SetString(Result, pB, pE - pB); end; function SubStrEnd(const S: string; const Index: Integer; const Separator: string): string; { The same as SubStr, but substrings are numbered from the end [translated]} var MaxIndex: Integer; pB: PChar; begin { Not optimal implementation [translated] } MaxIndex := 0; pB := StrPos(PChar(S), PChar(Separator)); while pB <> nil do begin Inc(MaxIndex); pB := StrPos(pB + Length(Separator), PChar(Separator)); end; Result := SubStr(S, MaxIndex - Index, Separator); end; function FileGetInfo(FileName: TFileName; var SearchRec: TSearchRec): Boolean; var DosError: Integer; Path: TFileName; begin Result := False; Path := ExtractFilePath(ExpandFileName(FileName)) + '*.*'; FileName := AnsiUpperCase(ExtractFileName(FileName)); DosError := FindFirst(Path, faAnyFile, SearchRec); while DosError = 0 do begin if (AnsiCompareText(SearchRec.FindData.cFileName, FileName) = 0) or (AnsiCompareText(SearchRec.FindData.cAlternateFileName, FileName) = 0) then begin Result := True; Break; end; DosError := FindNext(SearchRec); end; FindClose(SearchRec); end; function HasSubFolder(APath: TFileName): Boolean; var SearchRec: TSearchRec; DosError: Integer; begin Result := False; AddSlash(APath); APath := Concat(APath, '*.*'); DosError := FindFirst(APath, faDirectory, SearchRec); while DosError = 0 do begin if (SearchRec.Attr and faDirectory = faDirectory) and (SearchRec.Name[1] <> '.') then begin Result := True; Break; end; DosError := FindNext(SearchRec); end; FindClose(SearchRec); end; function IsEmptyFolder(APath: TFileName): Boolean; var SearchRec: TSearchRec; DosError: Integer; begin Result := True; AddSlash(APath); APath := Concat(APath, '*.*'); DosError := FindFirst(APath, faDirectory, SearchRec); while DosError = 0 do begin if SearchRec.Name[1] <> '.' then begin Result := False; Break; end; DosError := FindNext(SearchRec); end; FindClose(SearchRec); end; function TTFontSelected(const DC: HDC): Boolean; var TM: TTEXTMETRIC; begin GetTextMetrics(DC, TM); Result := TM.tmPitchAndFamily and TMPF_TRUETYPE <> 0; end; function SubWord(P: PChar; var P2: PChar): string; var I: Integer; begin I := 0; while not (P[I] in Separators) do Inc(I); SetString(Result, P, I); P2 := P + I; end; function ReplaceString(S: string; const OldPattern, NewPattern: string): string; var LW: Integer; P: PChar; Sm: Integer; begin LW := Length(OldPattern); P := StrPos(PChar(S), PChar(OldPattern)); while P <> nil do begin Sm := P - PChar(S); S := Copy(S, 1, Sm) + NewPattern + Copy(S, Sm + LW + 1, Length(S)); P := StrPos(PChar(S) + Sm + Length(NewPattern), PChar(OldPattern)); end; Result := S; end; function ReplaceStrings1(S: string; const Word, Frase: string): string; begin Result := ReplaceString(S, Word, Frase); end; function ConcatSep(const S, S2, Separator: string): string; begin Result := S; if Result <> '' then Result := Result + Separator; Result := Result + S2; end; function ConcatLeftSep(const S, S2, Separator: string): string; begin Result := S; if Result <> '' then Result := Separator + Result; Result := S2 + Result; end; function MinimizeString(const S: string; const MaxLen: Integer): string; begin if Length(S) > MaxLen then if MaxLen < 3 then Result := Copy(S, 1, MaxLen) else Result := Copy(S, 1, MaxLen - 3) + '...' else Result := S; end; function TrueInflateRect(const R: TRect; const I: Integer): TRect; begin with R do SetRect(Result, Left - I, Top - I, Right + I, Bottom + I); end; procedure SetWindowTop(const Handle: HWND; const Top: Boolean); const TopFlag: array [Boolean] of Longword = (HWND_NOTOPMOST, HWND_TOPMOST); begin SetWindowPos(Handle, TopFlag[Top], 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE); end; {* from unit FileCtrl} function DirectoryExists(const Name: string): Boolean; var Code: Integer; begin Code := Integer(GetFileAttributes(PChar(Name))); Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0); end; procedure ForceDirectories(Dir: string); begin if Dir[Length(Dir)] = '\' then Delete(Dir, Length(Dir), 1); if (Length(Dir) < 3) or DirectoryExists(Dir) or (ExtractFilePath(Dir) = Dir) then Exit; { avoid 'xyz:\' problem.} ForceDirectories(ExtractFilePath(Dir)); CreateDir(Dir); end; {# from unit FileCtrl} function LZFileExpand(const FileSource, FileDest: string): Boolean; type TLZCopy = function(Source, Dest: Integer): Longint; stdcall; TLZOpenFile = function(Filename: PChar; var ReOpenBuff: TOFStruct; Style: Word): Integer; stdcall; TLZClose = procedure(hFile: Integer); stdcall; var Source, Dest: Integer; OSSource, OSDest: TOFSTRUCT; Res: Integer; Ins: Integer; LZCopy: TLZCopy; LZOpenFile: TLZOpenFile; LZClose: TLZClose; begin Result := False; Ins := LoadLibrary('LZ32.dll'); try LZCopy := GetProcAddress(Ins, 'LZCopy'); LZOpenFile := GetProcAddress(Ins, 'LZOpenFileA'); LZClose := GetProcAddress(Ins, 'LZClose'); OSSource.cBytes := SizeOf(TOFSTRUCT); OSDest.cBytes := SizeOf(TOFSTRUCT); Source := LZOpenFile( PChar(FileSource), // address of name of file to be opened OSSource, // address of open file structure OF_READ or OF_SHARE_DENY_NONE);// action to take if Source < 0 then begin DeleteFile(FileDest); Dest := LZOpenFile( PChar(FileDest), // address of name of file to be opened OSDest, // address of open file structure OF_CREATE or OF_WRITE or OF_SHARE_EXCLUSIVE); // action to take if Dest >= 0 then begin Res := LZCopy(Source, Dest); if Res >= 0 then Result := True; end; LZClose(Source); LZClose(Dest); end; finally FreeLibrary(Ins); end; end; procedure Dos2Win(var S: string); var I: Integer; begin for I := 1 to Length(S) do case S[I] of #$80..#$AF: S[I] := Char(Byte(S[I]) + (192 - $80)); #$E0..#$EF: S[I] := Char(Byte(S[I]) + (240 - $E0)); end; end; procedure Win2Dos(var S: string); var I: Integer; begin for I := 1 to Length(S) do case S[I] of #$C0..#$EF: S[I] := Char(Byte(S[I]) - (192 - $80)); #$F0..#$FF: S[I] := Char(Byte(S[I]) - (240 - $E0)); end; end; function Dos2WinRes(const S: string): string; begin Result := S; Dos2Win(Result); end; function Win2DosRes(const S: string): string; begin Result := S; Win2Dos(Result); end; function Win2Koi(const S: string): string; const W = 'àáâãä叿çèéêëìíîïðñòóôõ÷öøùüûúýþÿÀÁÂÃÄŨÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕ×ÖØÙÜÛÚÝÞß'; K = 'ÁÂ×ÇÄÅ£ÖÚÉÊËÌÍÎÏÐÒÓÔÕÆÈÞÃÛÝØÙßÜÀÑáâ÷çäå³öúéêëìíîïðòóôõæèþãûýøùÿüàñ'; var I, J: Integer; begin Result := S; for I := 1 to Length(Result) do begin J := Pos(Result[I], W); if J > 0 then Result[I] := K[J]; end; end; function Spaces(const N: Integer): string; begin // (rom) reimplemented Result := AddSpaces('', N); end; function AddSpaces(const S: string; const N: Integer): string; begin // (rom) SLOOOOW implementation Result := S; while Length(Result) < N do Result := Result + ' '; end; function KeyPressed(VK: Integer): Boolean; begin Result := GetKeyState(VK) and $8000 = $8000; end; {$IFNDEF BCB1} function BrowseForFolder(const Handle: HWND; const Title: string; var Folder: string): Boolean; {$IFDEF COMPILER2} type TSHItemID = packed record { mkid } cb: Word; { Size of the ID (including cb itself) } abID: array [0..0] of Byte; { The item ID (variable Length) } end; PItemIDList = ^TItemIDList; TItemIDList = packed record { idl } mkid: TSHItemID; end; TFNBFFCallBack = function(Wnd: HWND; uMsg: UINT; lParam, lpData: LPARAM): Integer stdcall; TBrowseInfo = packed record hwndOwner: HWND; pidlRoot: PItemIDList; pszDisplayName: PAnsiChar; { Return display name of item selected. } lpszTitle: PAnsiChar; { text to go in the banner over the tree. } ulFlags: UINT; { Flags that control the return stuff } lpfn: TFNBFFCallBack; lParam: LPARAM; { extra info that's passed back in callbacks } iImage: Integer; { output var: where to return the Image Index. } end; function SHBrowseForFolder(var lpbi: TBrowseInfo): PItemIDList; stdcall; external 'shell32.dll' name 'SHBrowseForFolderA'; function SHGetPathFromIDList(pidl: PItemIDList; pszPath: PChar): BOOL; stdcall external 'shell32.dll' name 'SHGetPathFromIDListA'; {$ENDIF} var BrowseInfo: TBrowseInfo; Id: PItemIDList; FN: array [0..MAX_PATH] of Char; begin with BrowseInfo do begin hwndOwner := Handle; pidlRoot := nil; pszDisplayName := FN; lpszTitle := PChar(Title); ulFlags := 0; lpfn := nil; end; Id := SHBrowseForFolder(BrowseInfo); Result := Id <> nil; if Result then begin SHGetPathFromIDList(Id, FN); Folder := FN; end; end; {$ENDIF BCB1} function LastDate(const Dat: TDateTime): string; const D2D: array [0..9] of 1..3 = (3, 1, 2, 2, 2, 3, 3, 3, 3, 3); Day: array [1..3] of string = ('äåíü', 'äíÿ', 'äíåé'); Month: array [1..3] of string = ('ìåñÿö', 'ìåñÿöà', 'ìåñÿöåâ'); Year: array [1..3] of string = ('ãîä', 'ãîäà', 'ëåò'); Week: array [1..4] of string = ('íåäåëþ', '2 íåäåëè', '3 íåäåëè', 'ìåñÿö'); var Y, M, D: Integer; begin if Date = Dat then Result := 'ñåãîäíÿ' else if Dat = Date - 1 then Result := 'â÷åðà' else if Dat = Date - 2 then Result := 'ïîçàâ÷åðà' else if Dat > Date then Result := 'â áóäóùåì' else begin D := Trunc(Date - Dat); Y := Round(D / 365); M := Round(D / 30); if Y > 0 then Result := IntToStr(Y) + ' ' + Year[D2D[StrToInt(IntToStr(Y)[Length(IntToStr(Y))])]] + ' íàçàä' else if M > 0 then Result := IntToStr(M) + ' ' + Month[D2D[StrToInt(IntToStr(M)[Length(IntToStr(M))])]] + ' íàçàä' else if D > 6 then Result := Week[D div 7] + ' íàçàä' else if D > 0 then Result := IntToStr(D) + ' ' + Day[D2D[StrToInt(IntToStr(D)[Length(IntToStr(D))])]] + ' íàçàä' end; end; procedure AddSlash(var Dir: TFileName); begin if (Length(Dir) > 0) and (Dir[Length(Dir)] <> '\') then Dir := Dir + '\'; end; function AddSlash2(const Dir: TFileName): string; begin Result := Dir; if (Length(Dir) > 0) and (Dir[Length(Dir)] <> '\') then Result := Dir + '\'; end; function AddPath(const FileName, Path: TFileName): TFileName; begin if ExtractFileDrive(FileName) = '' then Result := AddSlash2(Path) + FileName else Result := FileName; end; function AddPaths(const PathList, Path: string): string; var I: Integer; S: string; begin Result := ''; I := 0; S := SubStr(PathList, I, ';'); while S <> '' do begin Result := ConcatSep(Result, AddPath(S, Path), ';'); Inc(I); S := SubStr(PathList, I, ';'); end; end; function ParentPath(const Path: TFileName): TFileName; begin Result := Path; if (Length(Result) > 0) and (Result[Length(Result)] = '\') then Delete(Result, Length(Result), 1); Result := ExtractFilePath(Result); end; function FindInPath(const FileName, PathList: string): TFileName; var I: Integer; S: string; begin I := 0; S := SubStr(PathList, I, ';'); while S <> '' do begin Result := AddSlash2(S) + FileName; if FileExists(Result) then Exit; Inc(I); S := SubStr(PathList, I, ';'); end; Result := ''; end; function GetComputerID: string; var SN: DWORD; Nul: DWORD; WinDir: array [0..MAX_PATH] of Char; begin GetWindowsDirectory(WinDir, MAX_PATH); WinDir[3] := #0; if GetVolumeInformation( WinDir, // address of root directory of the file system nil, // address of name of the volume 0, // Length of lpVolumeNameBuffer @SN, // address of volume serial number Nul, // address of system's maximum filename Length Nul, // address of file system flags nil, // address of name of file system 0) // Length of lpFileSystemNameBuffer then Result := IntToHex(SN, 8) else Result := 'None'; end; function CurrencyToStr(const Cur: currency): string; begin Result := CurrToStrF(Cur, ffCurrency, CurrencyDecimals) end; function Cmp(const S1, S2: string): Boolean; begin //Result := AnsiCompareText(S1, S2) = 0; Result := AnsiStrIComp(PChar(S1), PChar(S2)) = 0; end; function StringCat(var S1: string; S2: string): string; begin S1 := S1 + S2; Result := S1; end; function HasChar(const Ch: Char; const S: string): Boolean; begin Result := Pos(Ch, S) > 0; end; function HasAnyChar(const Chars: string; const S: string): Boolean; var I: Integer; begin for I := 1 to Length(Chars) do if HasChar(Chars[I], S) then begin Result := True; Exit; end; Result := False; end; function CountOfChar(const Ch: Char; const S: string): Integer; var I: Integer; begin Result := 0; for I := 1 to Length(S) do if S[I] = Ch then Inc(Result); end; procedure SwapInt(var Int1, Int2: Integer); var Tmp: Integer; begin Tmp := Int1; Int1 := Int2; Int2 := Tmp; end; function DeleteReadOnlyFile(const FileName: TFileName): Boolean; begin FileSetAttr(FileName, 0); {clear Read Only Flag} Result := DeleteFile(FileName); end; function HasParam(const Param: string): Boolean; var I: Integer; begin Result := False; for I := 1 to ParamCount do begin Result := Cmp(ParamStr(I), Param); if Result then Exit; end; end; function HasSwitch(const Param: string): Boolean; var I: Integer; begin Result := False; for I := 1 to ParamCount do if HasChar(ParamStr(I)[1], '-/') then begin Result := Cmp(Copy(ParamStr(I), 2, Length(Param)), Param); if Result then Exit; end; end; function Switch(const Param: string): string; var I: Integer; begin Result := ''; for I := 1 to ParamCount do if HasChar(ParamStr(I)[1], '-/\') and Cmp(Copy(ParamStr(I), 2, Length(Param)), Param) then begin Result := Copy(ParamStr(I), 2 + Length(Param), 260); Exit; end; end; function ExePath: TFileName; begin Result := ExtractFilePath(ParamStr(0)); end; function FileNewExt(const FileName, NewExt: TFileName): TFileName; begin Result := Copy(FileName, 1, Length(FileName) - Length(ExtractFileExt(FileName))) + NewExt; end; {$IFNDEF COMPILER3_UP} function AnsiStrLIComp(S1, S2: PChar; MaxLen: Cardinal): Integer; begin Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, S1, MaxLen, S2, MaxLen) - 2; end; function AnsiStrIComp(S1, S2: PChar): Integer; begin Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, S1, -1, S2, -1) - 2; end; {$ENDIF} function CharInSet(const Ch: Char; const SetOfChar: TSetOfChar): Boolean; begin {$IFDEF DELPHI} Result := Ch in SetOfChar; {$ENDIF DELPHI} {$IFDEF BCB} Result := Pos(Ch, SetOfChar) > 0; {$ENDIF BCB} end; function IntPower(Base, Exponent: Integer): Integer; begin if Exponent > 0 then begin Result := Base; Dec(Exponent); while Exponent > 0 do begin Result := Result * Base; Dec(Exponent); end; end else if Exponent < 0 then begin Result := 1; Inc(Exponent); while Exponent < 0 do begin Result := Result div Base; Inc(Exponent); end; end else Result := Base; end; function ChangeTopException(E: TObject): TObject; type PRaiseFrame = ^TRaiseFrame; TRaiseFrame = record NextRaise: PRaiseFrame; ExceptAddr: Pointer; ExceptObject: TObject; ExceptionRecord: PExceptionRecord; end; begin { CBuilder 3 Warning !} { if linker error occured with message "unresolved external 'System::RaiseList'" try comment this function implementation, compile, then uncomment and compile again. } {$IFDEF COMPILER6_UP} {$WARN SYMBOL_DEPRECATED OFF} {$ENDIF} if RaiseList <> nil then begin Result := PRaiseFrame(RaiseList)^.ExceptObject; PRaiseFrame(RaiseList)^.ExceptObject := E end else Result := nil; // raise Exception.Create('Not in exception'); end; function MakeValidFileName(const FileName: TFileName; const ReplaceBadChar: Char): TFileName; var I: Integer; begin Result := FileName; for I := 1 to Length(Result) do if HasChar(Result[I], '''":?*\/') then Result[I] := ReplaceBadChar; end; function Var2Type(V: Variant; const VarType: Integer): Variant; begin if TVarData(V).VType in [varEmpty, varNull] then begin case VarType of varString, varOleStr: Result := ''; varInteger, varSmallint, varByte: Result := 0; varBoolean: Result := False; varSingle, varDouble, varCurrency, varDate: Result := 0.0; varVariant: Result := Null; else Result := VarAsType(V, VarType); end; end else Result := VarAsType(V, VarType); if (VarType = varInteger) and (TVarData(V).VType = varBoolean) then Result := Integer(V = True); end; function VarToInt(V: Variant): Integer; begin Result := Var2Type(V, varInteger); end; function VarToFloat(V: Variant): Double; begin Result := Var2Type(V, varDouble); end; function CopyDir(const SourceDir, DestDir: TFileName): Boolean; var SearchRec: TSearchRec; DosError: Integer; Path, DestPath: TFileName; begin Result := False; if not CreateDir(DestDir) then Exit; Path := SourceDir; DestPath := AddSlash2(DestDir); AddSlash(Path); DosError := FindFirst(Path + '*.*', faAnyFile, SearchRec); while DosError = 0 do begin if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then begin if (SearchRec.Attr and faDirectory) = faDirectory then Result := CopyDir(Path + SearchRec.Name, AddSlash2(DestDir) + SearchRec.Name) else Result := CopyFile(PChar(Path + SearchRec.Name), PChar(DestPath + SearchRec.Name), True); if not Result then Exit; end; DosError := FindNext(SearchRec); end; FindClose(SearchRec); Result := True; end; function FileTimeToDateTime(const FT: TFileTime): TDateTime; var LocalFileTime: TFileTime; FileDate: Integer; begin FileTimeToLocalFileTime(FT, LocalFileTime); FileTimeToDosDateTime(LocalFileTime, LongRec(FileDate).Hi, LongRec(FileDate).Lo); Result := FileDateToDateTime(FileDate); end; function DefStr(const S: string; Default: string): string; begin if S <> '' then Result := S else Result := Default; end; function GetComputerName: string; var nSize: DWORD; begin nSize := MAX_COMPUTERNAME_LENGTH + 1; SetLength(Result, nSize); if Windows.GetComputerName( PChar(Result), // address of name buffer nSize) then // address of size of name buffer SetLength(Result, nSize) else Result := ''; end; function StrToBool(const S: string): Boolean; begin Result := (S = '1') or Cmp(S, 'True') or Cmp(S, 'yes'); end; procedure LoadIcoToImage(ALarge, ASmall: TImageList; const NameRes: string); var Ico: TIcon; begin Ico := TIcon.Create; if ALarge <> nil then begin Ico.Handle := LoadImage(hInstance, PChar(NameRes), IMAGE_ICON, 32, 32, 0); ALarge.AddIcon(Ico); end; if ASmall <> nil then begin Ico.Handle := LoadImage(hInstance, PChar(NameRes), IMAGE_ICON, 16, 16, 0); ASmall.AddIcon(Ico); end; Ico.Free; end; procedure WordBreak(Canvas: TCanvas; const S: string; Ss: TStrings); begin Ss.Text := S; end; procedure RATextOut(Canvas: TCanvas; const R, RClip: TRect; const S: string); begin RATextOutEx(Canvas, R, RClip, S, False); end; function RATextCalcHeight(Canvas: TCanvas; const R: TRect; const S: string): Integer; begin Result := RATextOutEx(Canvas, R, R, S, True); end; function RATextOutEx(Canvas: TCanvas; const R, RClip: TRect; const S: string; const CalcHeight: Boolean): Integer; var Ss: TStrings; I: Integer; H: Integer; begin Ss := TStringList.Create; try WordBreak(Canvas, S, Ss); H := Canvas.TextHeight('A'); Result := H * Ss.Count; if not CalcHeight then for I := 0 to Ss.Count - 1 do ExtTextOut( Canvas.Handle, // handle of device context R.Left, // X-coordinate of reference point R.Top + H * I, // Y-coordinate of reference point ETO_CLIPPED, // text-output options @RClip, // optional clipping and/or opaquing rectangle PChar(Ss[I]), Length(Ss[I]), // number of characters in string nil); // address of array of intercharacter spacing values finally Ss.Free; end; end; procedure Cinema(Canvas: TCanvas; rS, rD: TRect); const Pause = 30; {milliseconds} Steps = 7; Width = 1; var R: TRect; I: Integer; PenOld: TPen; procedure FrameR(R: TRect); begin with Canvas do begin MoveTo(R.Left, R.Top); LineTo(R.Left, R.Bottom); LineTo(R.Right, R.Bottom); LineTo(R.Right, R.Top); LineTo(R.Left, R.Top); end; end; procedure Frame; begin FrameR(R); with Canvas do begin MoveTo(rS.Left, rS.Top); LineTo(R.Left, R.Top); if R.Top <> rS.Top then begin MoveTo(rS.Right, rS.Top); LineTo(R.Right, R.Top); end; if R.Left <> rS.Left then begin MoveTo(rS.Left, rS.Bottom); LineTo(R.Left, R.Bottom); end; if (R.Bottom <> rS.Bottom) and (R.Right <> rS.Right) then begin MoveTo(rS.Right, rS.Bottom); LineTo(R.Right, R.Bottom); end; end; end; begin PenOld := TPen.Create; PenOld.Assign(Canvas.Pen); Canvas.Pen.Mode := pmNot; Canvas.Pen.Width := Width; Canvas.Pen.Style := psDot; FrameR(rS); R := rS; for I := 1 to Steps do begin R.Left := rS.Left + (rD.Left - rS.Left) div Steps * I; R.Top := rS.Top + (rD.Top - rS.Top) div Steps * I; R.Bottom := rS.Bottom + (rD.Bottom - rS.Bottom) div Steps * I; R.Right := rS.Right + (rD.Right - rS.Right) div Steps * I; Frame; Sleep(Pause); Frame; end; FrameR(rS); Canvas.Pen.Assign(PenOld); end; function FindFormByClass(FormClass: TFormClass): TForm; var I: Integer; begin Result := nil; for I := 0 to Application.ComponentCount - 1 do if Application.Components[I].ClassName = FormClass.ClassName then begin Result := Application.Components[I] as TForm; Break; end; end; function FindFormByClassName(FormClassName: string): TForm; var I: Integer; begin Result := nil; for I := 0 to Application.ComponentCount - 1 do if Application.Components[I].ClassName = FormClassName then begin Result := Application.Components[I] as TForm; Break; end; end; function FindByTag(WinControl: TWinControl; ComponentClass: TComponentClass; const Tag: Integer): TComponent; var I: Integer; begin for I := 0 to WinControl.ControlCount - 1 do begin Result := WinControl.Controls[I]; if (Result is ComponentClass) and (Result.Tag = Tag) then Exit; end; Result := nil; end; function ControlAtPos2(Parent: TWinControl; X, Y: Integer): TControl; var I: Integer; P: TPoint; begin P := Point(X, Y); for I := Parent.ControlCount - 1 downto 0 do begin Result := Parent.Controls[I]; with Result do if PtInRect(BoundsRect, P) then Exit; end; Result := nil; end; function RBTag(Parent: TWinControl): Integer; var RB: TRadioButton; I: Integer; begin RB := nil; with Parent do for I := 0 to ControlCount - 1 do if (Controls[I] is TRadioButton) and (Controls[I] as TRadioButton).Checked then begin RB := Controls[I] as TRadioButton; Break; end; if RB <> nil then Result := RB.Tag else Result := 0; end; function IniReadSection(const IniFileName: TFileName; const Section: string; Ss: TStrings): Boolean; var F: Integer; S: string; begin with TStringList.Create do try LoadFromFile(IniFileName); F := IndexOf('[' + Section + ']'); Result := F > -1; if Result then begin Ss.Clear; Inc(F); while F < Count do begin S := Strings[F]; if (Length(S) > 0) and (Trim(S[1]) = '[') then Break; Ss.Add(S); Inc(F); end; end; finally Free; end; end; procedure SaveTextFile(const FileName: TFileName; const Source: string); begin with TStringList.Create do try Text := Source; SaveToFile(FileName); finally Free; end; end; function LoadTextFile(const FileName: TFileName): string; begin with TStringList.Create do try LoadFromFile(FileName); Result := Text; finally Free; end; end; function ReadFolder(const Folder, Mask: TFileName; FileList: TStrings): Integer; var SearchRec: TSearchRec; DosError: Integer; begin FileList.Clear; Result := FindFirst(AddSlash2(Folder) + Mask, faAnyFile, SearchRec); DosError := Result; while DosError = 0 do begin if not ((SearchRec.Attr and faDirectory) = faDirectory) then FileList.Add(SearchRec.Name); DosError := FindNext(SearchRec); end; FindClose(SearchRec); end; function ReadFolders(const Folder: TFileName; FolderList: TStrings): Integer; var SearchRec: TSearchRec; DosError: Integer; begin FolderList.Clear; Result := FindFirst(AddSlash2(Folder) + '*.*', faAnyFile, SearchRec); DosError := Result; while DosError = 0 do begin if ((SearchRec.Attr and faDirectory) = faDirectory) and (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then FolderList.Add(SearchRec.Name); DosError := FindNext(SearchRec); end; FindClose(SearchRec); end; {$IFDEF COMPILER3_UP} function TargetFileName(const FileName: TFileName): TFileName; begin Result := FileName; if Cmp(ExtractFileExt(FileName), '.lnk') then if ResolveLink(Application.Handle, FileName, Result) <> 0 then raise Exception.CreateFmt(SCantGetShortCut, [FileName]); end; function ResolveLink(const hWnd: HWND; const LinkFile: TFileName; var FileName: TFileName): HRESULT; var psl: IShellLink; WLinkFile: array [0..MAX_PATH] of WideChar; wfd: TWIN32FINDDATA; ppf: IPersistFile; begin Pointer(psl) := nil; Pointer(ppf) := nil; Result := CoInitialize(nil); if SUCCEEDED(Result) then begin // Get a Pointer to the IShellLink interface. Result := CoCreateInstance(CLSID_ShellLink, nil, CLSCTX_INPROC_SERVER, IShellLink, psl); if SUCCEEDED(Result) then begin // Get a Pointer to the IPersistFile interface. Result := psl.QueryInterface(IPersistFile, ppf); if SUCCEEDED(Result) then begin StringToWideChar(LinkFile, WLinkFile, SizeOf(WLinkFile) - 1); // Load the shortcut. Result := ppf.Load(WLinkFile, STGM_READ); if SUCCEEDED(Result) then begin // Resolve the link. Result := psl.Resolve(hWnd, SLR_ANY_MATCH); if SUCCEEDED(Result) then begin // Get the path to the link target. SetLength(FileName, MAX_PATH); Result := psl.GetPath(PChar(FileName), MAX_PATH, wfd, SLGP_UNCPRIORITY); if not SUCCEEDED(Result) then Exit; SetLength(FileName, Length(PChar(FileName))); end; end; // Release the Pointer to the IPersistFile interface. ppf._Release; end; // Release the Pointer to the IShellLink interface. psl._Release; end; CoUnInitialize; end; Pointer(psl) := nil; Pointer(ppf) := nil; end; {$ENDIF COMPILER3_UP} { with memEdit do begin Text := ReplaceStrings(Text, SelStart+1, SelLength, memWords.Lines, memFrases.Lines, NewSelStart); SelStart := NewSelStart-1; end; } function ReplaceStrings(S: string; PosBeg, Len: Integer; Words, Frases: TStrings; var NewSelStart: Integer): string; var I, Beg, Ent, LS, F: Integer; Word: string; begin NewSelStart := PosBeg; Result := S; LS := Length(S); if Len = 0 then begin if PosBeg < 1 then Exit; if PosBeg = 1 then PosBeg := 2; for I := PosBeg - 1 downto 1 do if S[I] in Separators then Break; Beg := I + 1; for Ent := PosBeg to LS do if S[Ent] in Separators then Break; if Ent > Beg then Word := Copy(S, Beg, Ent - Beg) else Word := S[PosBeg]; end else begin Word := Copy(S, PosBeg, Len); Beg := PosBeg; Ent := PosBeg + Len; end; if Word = '' then Exit; F := Words.IndexOf(Word); if (F > -1) and (F < Frases.Count) then begin Result := Copy(S, 1, Beg - 1) + Frases[F] + Copy(S, Ent, LS); NewSelStart := Beg + Length(Frases[F]); end; end; { with memEdit do Text := ReplaceAllStrings(Text, memWords.Lines, memFrases.Lines); } function ReplaceAllStrings(S: string; Words, Frases: TStrings): string; var I, LW: Integer; P: PChar; Sm: Integer; begin for I := 0 to Words.Count - 1 do begin LW := Length(Words[I]); P := StrPos(PChar(S), PChar(Words[I])); while P <> nil do begin Sm := P - PChar(S); S := Copy(S, 1, Sm) + Frases[I] + Copy(S, Sm + LW + 1, Length(S)); P := StrPos(PChar(S) + Sm + Length(Frases[I]), PChar(Words[I])); end; end; Result := S; end; function CountOfLines(const S: string): Integer; begin with TStringList.Create do try Text := S; Result := Count; finally Free; end; end; procedure DeleteEmptyLines(Ss: TStrings); var I: Integer; begin I := 0; while I < Ss.Count do if Trim(Ss[I]) = '' then Ss.Delete(I) else Inc(I); end; procedure SQLAddWhere(SQL: TStrings; const Where: string); var I, J: Integer; begin J := SQL.Count - 1; for I := 0 to SQL.Count - 1 do // (rom) does this always work? Think of a fieldname "grouporder" if StrLIComp(PChar(SQL[I]), 'where ', 6) = 0 then begin J := I + 1; while J < SQL.Count do begin if (StrLIComp(PChar(SQL[J]), 'order ', 6) = 0) or (StrLIComp(PChar(SQL[J]), 'group ', 6) = 0) then Break; Inc(J); end; end; SQL.Insert(J, 'and ' + Where); end; var ProcList: TList = nil; type TJvProcItem = class(TObject) private FProcObj: TProcObj; public constructor Create(AProcObj: TProcObj); end; constructor TJvProcItem.Create(AProcObj: TProcObj); begin FProcObj := AProcObj; end; procedure TmrProc(hWnd: HWND; uMsg: Integer; idEvent: Integer; dwTime: Integer); stdcall; var Pr: TProcObj; begin if ProcList[idEvent] <> nil then begin Pr := TJvProcItem(ProcList[idEvent]).FProcObj; TJvProcItem(ProcList[idEvent]).Free; end else Pr := nil; ProcList.Delete(idEvent); KillTimer(hWnd, idEvent); if ProcList.Count <= 0 then begin ProcList.Free; ProcList := nil; end; if Assigned(Pr) then Pr; end; procedure ExecAfterPause(Proc: TProcObj; Pause: Integer); var Num: Integer; I: Integer; begin if ProcList = nil then ProcList := TList.Create; Num := -1; for I := 0 to ProcList.Count - 1 do if @TJvProcItem(ProcList[I]).FProcObj = @Proc then begin Num := I; Break; end; if Num <> -1 then KillTimer(Application.Handle, Num) else Num := ProcList.Add(TJvProcItem.Create(Proc)); SetTimer(Application.Handle, Num, Pause, @TmrProc); end; procedure Roughed(ACanvas: TCanvas; const ARect: TRect; const AVert: Boolean); var I: Integer; J: Integer; R: TRect; V: Boolean; H: Boolean; begin H := True; V := True; for I := 0 to (ARect.Right - ARect.Left) div 4 do begin for J := 0 to (ARect.Bottom - ARect.Top) div 4 do begin if AVert then begin if V then R := Bounds(ARect.Left + I * 4 + 2, ARect.Top + J * 4, 2, 2) else R := Bounds(ARect.Left + I * 4, ARect.Top + J * 4, 2, 2); end else begin if H then R := Bounds(ARect.Left + I * 4, ARect.Top + J * 4 + 2, 2, 2) else R := Bounds(ARect.Left + I * 4, ARect.Top + J * 4, 2, 2); end; Frame3D(ACanvas, R, clBtnHighlight, clBtnShadow, 1); V := not V; end; H := not H; end; end; function BitmapFromBitmap(SrcBitmap: TBitmap; const AWidth, AHeight, Index: Integer): TBitmap; begin Result := TBitmap.Create; Result.Width := AWidth; Result.Height := AHeight; Result.Canvas.CopyRect(Rect(0, 0, AWidth, AHeight), SrcBitmap.Canvas, Bounds(AWidth * Index, 0, AWidth, AHeight)); end; procedure ShowMenu(Form: TForm; MenuAni: TMenuAnimation); var I: Integer; h: Integer; w: Integer; begin case MenuAni of maNone: Form.Show; maRandom: ; maUnfold: begin h := Form.Height; Form.Height := 0; Form.Show; for I := 0 to h div 10 do if Form.Height < h then Form.Height := Form.Height + 10; end; maSlide: begin h := Form.Height; w := Form.Width; Form.Height := 0; Form.Width := 0; Form.Show; for I := 0 to Max(h div 5, w div 5) do begin if Form.Height < h then Form.Height := Form.Height + 5; if Form.Width < w then Form.Width := Form.Width + 5; end; // CS_SAVEBITS end; end; end; function ResSaveToFileEx(Instance: HINST; Typ, Name: PChar; const Compressed: Boolean; const FileName: string): Boolean; var RhRsrc: HRSRC; RhGlobal: HGLOBAL; RAddr: Pointer; RLen: DWORD; Stream: TFileStream; FileDest: string; begin Result := False; RhRsrc := FindResource( Instance, // resource-module handle Name, // address of resource name Typ); // address of resource type if RhRsrc = 0 then Exit; RhGlobal := LoadResource( Instance, // resource-module handle RhRsrc); // resource handle if RhGlobal = 0 then Exit; RAddr := LockResource( RhGlobal); // handle to resource to lock FreeResource(RhGlobal); if RAddr = nil then Exit; RLen := SizeofResource( Instance, // resource-module handle RhRsrc); // resource handle if RLen = 0 then Exit; { And now it is possible to duplicate [translated] } Stream := nil; { for Free [translated] } if Compressed then FileDest := GenTempFileName(FileName) else FileDest := FileName; try try Stream := TFileStream.Create(FileDest, fmCreate or fmOpenWrite or fmShareExclusive); Stream.WriteBuffer(RAddr^, RLen); finally Stream.Free; end; if Compressed then begin Result := LZFileExpand(FileDest, FileName); DeleteFile(FileDest); end else Result := True; except end; end; function ResSaveToFile(const Typ, Name: string; const Compressed: Boolean; const FileName: string): Boolean; begin Result := ResSaveToFileEx(hInstance, PChar(Typ), PChar(Name), Compressed, FileName); end; function ResSaveToString(Instance: HINST; const Typ, Name: string; var S: string): Boolean; var RhRsrc: HRSRC; RhGlobal: HGLOBAL; RAddr: Pointer; RLen: DWORD; begin Result := False; RhRsrc := FindResource( Instance, // resource-module handle PChar(Name), // address of resource name PChar(Typ)); // address of resource type if RhRsrc = 0 then Exit; RhGlobal := LoadResource( Instance, // resource-module handle RhRsrc); // resource handle if RhGlobal = 0 then Exit; RAddr := LockResource( RhGlobal); // handle to resource to lock FreeResource(RhGlobal); if RAddr = nil then Exit; RLen := SizeofResource( Instance, // resource-module handle RhRsrc); // resource handle if RLen = 0 then Exit; { And now it is possible to duplicate [translated] } SetString(S, PChar(RAddr), RLen); end; // (rom) a thread to wait would be more elegant, also JCL function available function Execute(const CommandLine, WorkingDirectory: string): Integer; var R: Boolean; ProcessInformation: TProcessInformation; StartupInfo: TStartupInfo; {$IFDEF COMPILER4_UP} ExCode: Cardinal; {$ELSE} ExCode: Integer; {$ENDIF} begin Result := 0; FillChar(StartupInfo, SizeOf(TStartupInfo), 0); with StartupInfo do begin cb := SizeOf(TStartupInfo); dwFlags := STARTF_USESHOWWINDOW; wShowWindow := SW_SHOW; end; R := CreateProcess( nil, // Pointer to name of executable module PChar(CommandLine), // Pointer to command line string nil, // Pointer to process security attributes nil, // Pointer to thread security attributes False, // handle inheritance flag 0, // creation flags nil, // Pointer to new environment block PChar(WorkingDirectory), // Pointer to current directory name StartupInfo, // Pointer to STARTUPINFO ProcessInformation); // Pointer to PROCESS_INFORMATION if R then while (GetExitCodeProcess(ProcessInformation.hProcess, ExCode) and (ExCode = STILL_ACTIVE)) do Application.ProcessMessages else Result := GetLastError; end; function TextWidth(AStr: string): Integer; var Canvas: TCanvas; DC: HDC; begin DC := GetDC(HWND_DESKTOP); Canvas := TCanvas.Create; // (rom) secured try Canvas.Handle := DC; Result := Canvas.TextWidth(AStr); Canvas.Handle := 0; Canvas.Free; finally ReleaseDC(HWND_DESKTOP, DC); end; end; function AppMinimized: Boolean; begin Result := IsIconic(Application.Handle); end; function MessageBox(const Msg: string; Caption: string; const Flags: Integer): Integer; begin if Caption = '' then Caption := Application.Title; Result := Application.MessageBox(PChar(Msg), PChar(Caption), Flags); end; function MsgDlgDef1(const Msg, ACaption: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; DefButton: TMsgDlgBtn; UseDefButton: Boolean; AHelpContext: Integer; Control: TWinControl): Integer; const {$IFNDEF COMPILER2} ButtonNames: array [TMsgDlgBtn] of PChar = ('Yes', 'No', 'OK', 'Cancel', 'Abort', 'Retry', 'Ignore', 'All', 'NoToAll', 'YesToAll', 'Help'); {$ELSE} ButtonNames: array [TMsgDlgBtn] of string = ('Yes', 'No', 'OK', 'Cancel', 'Abort', 'Retry', 'Ignore', 'All', 'Help'); {$ENDIF COMPILER2} var P: TPoint; I: Integer; Btn: TButton; StayOnTop: Boolean; begin if AHelpContext <> 0 then Buttons := Buttons + [mbHelp]; StayOnTop := False; with CreateMessageDialog(Msg, DlgType, Buttons) do try {$IFDEF COMPILER3_UP} Font.CharSet := MsgDlgCharSet; {$ENDIF COMPILER3_UP} if (Screen.ActiveForm <> nil) and (Screen.ActiveForm.FormStyle = fsStayOnTop) then begin StayOnTop := True; SetWindowTop(Screen.ActiveForm.Handle, False); end; if ACaption <> '' then Caption := ACaption; if Control = nil then begin Left := (Screen.Width - Width) div 2; Top := (Screen.Height - Height) div 2; end else begin P := Point((Control.Width - Width) div 2, (Control.Height - Height) div 2); P := Control.ClientToScreen(P); Left := P.X; Top := P.Y end; if Left < 0 then Left := 0 else if Left > Screen.Width then Left := Screen.Width - Width; if Top < 0 then Top := 0 else if Top > Screen.Height then Top := Screen.Height - Height; HelpContext := AHelpContext; Btn := FindComponent(ButtonNames[DefButton]) as TButton; if UseDefButton and (Btn <> nil) then begin for I := 0 to ComponentCount - 1 do if Components[I] is TButton then (Components[I] as TButton).Default := False; Btn.Default := True; ActiveControl := Btn; end; Btn := FindComponent(ButtonNames[mbIgnore]) as TButton; if Btn <> nil then begin // Btn.Width := Btn.Width * 5 div 4; {To shift the Help button Help [translated] } end; Result := ShowModal; finally Free; if (Screen.ActiveForm <> nil) and StayOnTop then SetWindowTop(Screen.ActiveForm.Handle, True); end; end; function MsgDlgDef(const Msg, ACaption: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; DefButton: TMsgDlgBtn; HelpContext: Integer; Control: TWinControl): Integer; begin Result := MsgDlgDef1(Msg, ACaption, DlgType, Buttons, DefButton, True, HelpContext, Control); end; function MsgDlg2(const Msg, ACaption: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpContext: Integer; Control: TWinControl): Integer; begin Result := MsgDlgDef1(Msg, ACaption, DlgType, Buttons, mbHelp, False, HelpContext, Control); end; procedure CenterHor(Parent: TControl; MinLeft: Integer; Controls: array of TControl); var I: Integer; begin for I := Low(Controls) to High(Controls) do Controls[I].Left := Max(MinLeft, (Parent.Width - Controls[I].Width) div 2) end; procedure EnableControls(Control: TWinControl; const Enable: Boolean); var I: Integer; begin for I := 0 to Control.ControlCount - 1 do Control.Controls[I].Enabled := Enable; end; procedure EnableMenuItems(MenuItem: TMenuItem; const Tag: Integer; const Enable: Boolean); var I: Integer; begin for I := 0 to MenuItem.Count - 1 do if MenuItem[I].Tag <> Tag then MenuItem[I].Enabled := Enable; end; procedure ExpandWidth(Parent: TControl; MinWidth: Integer; Controls: array of TControl); var I: Integer; begin for I := Low(Controls) to High(Controls) do Controls[I].Width := Max(MinWidth, Parent.ClientWidth - 2 * Controls[I].Left); end; function PanelBorder(Panel: TCustomPanel): Integer; begin Result := TPanel(Panel).BorderWidth; if TPanel(Panel).BevelOuter <> bvNone then Inc(Result, TPanel(Panel).BevelWidth); if TPanel(Panel).BevelInner <> bvNone then Inc(Result, TPanel(Panel).BevelWidth); end; {$IFDEF COMPILER2} function CompareMem(P1, P2: Pointer; Length: Integer): Boolean; assembler; asm PUSH ESI PUSH EDI MOV ESI,P1 MOV EDI,P2 MOV EDX,ECX XOR EAX,EAX AND EDX,3 SHR ECX,1 SHR ECX,1 REPE CMPSD JNE @@2 MOV ECX,EDX REPE CMPSB JNE @@2 @@1: Inc EAX @@2: POP EDI POP ESI end; {$ENDIF COMPILER2} { function DefineCursor was typed from book "Secrets of Delphi 2" by Ray Lischner } function DefineCursor(Identifier: PChar): TCursor; var Handle: HCursor; begin Handle := LoadCursor(hInstance, Identifier); if Handle = 0 then raise EOutOfResources.Create('Cannot load cursor resource'); for Result := 1 to High(TCursor) do if Screen.Cursors[Result] = Screen.Cursors[crDefault] then begin Screen.Cursors[Result] := Handle; Exit; end; raise EOutOfResources.Create('Too many user-defined cursors'); end; procedure Delay(MSec: Longword); var T: Longword; begin T := GetTickCount; while GetTickCount - T < MSec do Application.ProcessMessages; end; function Pixels(Control: TControl; APixels: Integer): Integer; var Form: TForm; begin Result := APixels; if Control is TForm then Form := TForm(Control) else Form := TForm(GetParentForm(Control)); if Form.Scaled then Result := Result * Form.PixelsPerInch div 96; end; procedure SetChildPropOrd(Owner: TComponent; PropName: string; Value: Longint); var I: Integer; PropInfo: PPropInfo; begin for I := 0 to Owner.ComponentCount - 1 do begin PropInfo := GetPropInfo(Owner.Components[I].ClassInfo, PropName); if PropInfo <> nil then SetOrdProp(Owner.Components[I], PropInfo, Value); end; end; procedure Error(const Msg: string); begin raise Exception.Create(Msg); end; procedure ItemHtDrawEx(Canvas: TCanvas; Rect: TRect; const State: TOwnerDrawState; const Text: string; const HideSelColor: Boolean; var PlainItem: string; var Width: Integer; CalcWidth: Boolean); var CL: string; I: Integer; M1: string; OriRect: TRect; // it's added oldFontStyles: TFontStyles; oldFontColor: TColor; function Cmp(M1: string): Boolean; begin Result := AnsiStrLIComp(PChar(Text) + I, PChar(M1), Length(M1)) = 0; end; function Cmp1(M1: string): Boolean; begin Result := AnsiStrLIComp(PChar(Text) + I, PChar(M1), Length(M1)) = 0; if Result then Inc(I, Length(M1)); end; function CmpL(M1: string): Boolean; begin Result := Cmp(M1 + '>'); end; function CmpL1(M1: string): Boolean; begin Result := Cmp1(M1 + '>'); end; procedure Draw(const M: string); begin if not Assigned(Canvas) then Exit; if not CalcWidth then Canvas.TextOut(Rect.Left, Rect.Top, M); Rect.Left := Rect.Left + Canvas.TextWidth(M); end; procedure Style(const Style: TFontStyle; const Include: Boolean); begin if not Assigned(Canvas) then Exit; if Include then Canvas.Font.Style := Canvas.Font.Style + [Style] else Canvas.Font.Style := Canvas.Font.Style - [Style]; end; begin PlainItem := ''; oldFontColor := 0; { satisfy compiler } if Canvas <> nil then begin oldFontStyles := Canvas.Font.Style; oldFontColor := Canvas.Font.Color; end; try if HideSelColor and Assigned(Canvas) then begin Canvas.Brush.Color := clWindow; Canvas.Font.Color := clWindowText; end; if Assigned(Canvas) then Canvas.FillRect(Rect); Width := Rect.Left; Rect.Left := Rect.Left + 2; OriRect := Rect; //save origin rectangle M1 := ''; I := 1; while I <= Length(Text) do begin if (Text[I] = '<') and (CmpL('b') or CmpL('/b') or CmpL('i') or CmpL('/i') or CmpL('u') or CmpL('/u') or Cmp('c:')) then begin Draw(M1); PlainItem := PlainItem + M1; if CmpL1('b') then Style(fsBold, True) else if CmpL1('/b') then Style(fsBold, False) else if CmpL1('i') then Style(fsItalic, True) else if CmpL1('/i') then Style(fsItalic, False) else if CmpL1('u') then Style(fsUnderline, True) else if CmpL1('/u') then Style(fsUnderline, False) else if Cmp1('c:') then begin CL := SubStr(PChar(Text) + I, 0, '>'); if (HideSelColor or not (odSelected in State)) and Assigned(Canvas) then try if (Length(CL) > 0) and (CL[1] <> '$') then Canvas.Font.Color := StringToColor('cl' + CL) else Canvas.Font.Color := StringToColor(CL); except end; Inc(I, Length(CL) + 1 {'>'}); end; M1 := ''; end else // next lines were added if (Text[I] = Chr(13)) and Cmp1(string(Chr(10))) then begin // new line Draw(M1); PlainItem := PlainItem + M1; Rect.Left := OriRect.Left; Rect.Top := Rect.Top + Canvas.TextHeight(M1); M1 := ''; end else // add text M1 := M1 + Text[I]; Inc(I); end; { for } Draw(M1); PlainItem := PlainItem + M1; finally if Canvas <> nil then begin Canvas.Font.Style := oldFontStyles; Canvas.Font.Color := oldFontColor; end; end; Width := Rect.Left - Width + 2; end; function ItemHtDraw(Canvas: TCanvas; Rect: TRect; const State: TOwnerDrawState; const Text: string; const HideSelColor: Boolean): string; var S: string; W: Integer; begin ItemHtDrawEx(Canvas, Rect, State, Text, HideSelColor, S, W, False); end; function ItemHtPlain(const Text: string): string; var S: string; W: Integer; begin ItemHtDrawEx(nil, Rect(0, 0, -1, -1), [], Text, False, S, W, False); Result := S; end; function ItemHtWidth(Canvas: TCanvas; Rect: TRect; const State: TOwnerDrawState; const Text: string; const HideSelColor: Boolean): Integer; var S: string; W: Integer; begin ItemHtDrawEx(Canvas, Rect, State, Text, HideSelColor, S, W, True); Result := W; end; procedure ClearList(List: TList); var I: Integer; begin if not Assigned(List) then Exit; for I := 0 to List.Count - 1 do TObject(List[I]).Free; List.Clear; end; procedure MemStreamToClipBoard(MemStream: TMemoryStream; const Format: Word); var Data: THandle; DataPtr: Pointer; begin Clipboard.Open; try Data := GlobalAlloc(GMEM_MOVEABLE, MemStream.Size); try DataPtr := GlobalLock(Data); try Move(MemStream.Memory^, DataPtr^, MemStream.Size); Clipboard.Clear; SetClipboardData(Format, Data); finally GlobalUnlock(Data); end; except GlobalFree(Data); raise; end; finally Clipboard.Close; end; end; procedure ClipBoardToMemStream(MemStream: TMemoryStream; const Format: Word); var Data: THandle; DataPtr: Pointer; begin Clipboard.Open; try Data := GetClipboardData(Format); if Data = 0 then Exit; DataPtr := GlobalLock(Data); if DataPtr = nil then Exit; try MemStream.WriteBuffer(DataPtr^, GlobalSize(Data)); MemStream.Position := 0; finally GlobalUnlock(Data); end; finally Clipboard.Close; end; end; function GetPropType(Obj: TObject; const PropName: string): TTypeKind; var PropInf: PPropInfo; begin PropInf := GetPropInfo(Obj.ClassInfo, PropName); if PropInf = nil then Result := tkUnknown else Result := PropInf^.PropType^.Kind; end; function GetPropStr(Obj: TObject; const PropName: string): string; var PropInf: PPropInfo; begin PropInf := GetPropInfo(Obj.ClassInfo, PropName); if PropInf = nil then raise Exception.CreateFmt(SPropertyNotExists, [PropName]); if not (PropInf^.PropType^.Kind in [tkString, tkLString {$IFDEF COMPILER3_UP}, tkWString {$ENDIF COMPILER3_UP}]) then raise Exception.CreateFmt(SInvalidPropertyType, [PropName]); Result := GetStrProp(Obj, PropInf); end; function GetPropOrd(Obj: TObject; const PropName: string): Integer; var PropInf: PPropInfo; begin PropInf := GetPropInfo(Obj.ClassInfo, PropName); if PropInf = nil then raise Exception.CreateFmt(SPropertyNotExists, [PropName]); if not (PropInf^.PropType^.Kind in [tkInteger, tkChar, tkWChar, tkEnumeration, tkClass]) then raise Exception.CreateFmt(SInvalidPropertyType, [PropName]); Result := GetOrdProp(Obj, PropInf); end; function GetPropMethod(Obj: TObject; const PropName: string): TMethod; var PropInf: PPropInfo; begin PropInf := GetPropInfo(Obj.ClassInfo, PropName); if PropInf = nil then raise Exception.CreateFmt(SPropertyNotExists, [PropName]); if not (PropInf^.PropType^.Kind = tkMethod) then raise Exception.CreateFmt(SInvalidPropertyType, [PropName]); Result := GetMethodProp(Obj, PropInf); end; procedure PrepareIniSection(SS: TStrings); var I: Integer; S: string; begin I := 0; while I < Ss.Count do begin S := Trim(Ss[I]); if (Length(S) = 0) or (S[1] in [';', '#']) then Ss.Delete(I) else Inc(I); end; end; {:Creates a TPointL structure from a pair of coordinates. Call PointL to create a TPointL structure that represents the specified coordinates. Use PointL to construct parameters for functions that require a TPointL, rather than setting up local variables for each parameter. @param X The X coordinate. @param Y The Y coordinate. @return A TPointL structure for coordinates X and Y. @example var p: TPointL; begin p := PointL(100, 100); end; } function PointL(const X, Y: Longint): TPointL; begin Result.X := X; Result.Y := Y; end; {:Conditional assignment. Returns the value in True or False depending on the condition Test. @param Test The test condition. @param True Returns this value if Test is True. @param False Returns this value if Test is False. @return Value in True or False depending on Test. @example bar := iif(foo, 1, 0);
has the same effects as:
if foo then bar := 1 else bar := 0; } function iif(const Test: Boolean; const ATrue, AFalse: Variant): Variant; begin if Test then Result := ATrue else Result := AFalse; end; end.