打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
ts.Core.Utils
{  Copyright (C) 2013 Tim Sinaeve tim.sinaeve@gmail.com  This library is free software; you can redistribute it and/or modify it  under the terms of the GNU Library General Public License as published by  the Free Software Foundation; either version 2 of the License, or (at your  option) any later version.  This program is distributed in the hope that it will be useful, but WITHOUT  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License  for more details.  You should have received a copy of the GNU Library General Public License  along with this library; if not, write to the Free Software Foundation,  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.}unit ts.Core.Utils;{$MODE Delphi}interfaceuses  Graphics, SysUtils, Classes, Controls, ExtCtrls, Forms, Menus, TypInfo,  StdCtrls, Character,  LCLType,{$IFDEF Windows}  Windows,{$ENDIF}  DB;type  TVarRecArray = array of TVarRec;const  AnsiWhitespace = [' '];type  TShellLink = record    Filename    : string;    Description : string;    ShortcutTo  : string;    Parameters  : string;    WorkingDir  : string;    IconPath    : string;    IconIndex   : Integer;    ShowCommand : TWindowState;    HotKey      : Integer;  end;{ Sets DoubleBuffered property for all TWinControl instances owned by the given  component. }procedure SetDoubleBuffered(AOwner: TComponent; AEnable: Boolean = True);procedure CloneComponent(AFrom: TComponent; ATo: TComponent);{$IFDEF Windows}function VirtualKeyToChar(AKey : Word) : string;{$ENDIF}function GetFullName(AComponent: TComponent) : string;// string manipulation routinesprocedure StrToStrings(const AString    : string;                             AList      : TStrings;                             ASeparator : Char);function Unformat(const ASource,                        APattern : string;                  const AArgs    : array of const): Integer;function Like(const ASource, ATemplate: string): Boolean;{ original author: Vladimir Gaitanoff }{ Returns a number of words delimited with AWordDelims }function WordCount(const AString     : string;                   const AWordDelims : TSysCharSet = AnsiWhiteSpace) : Integer;{ Returns a position of word number AIndex in the string AString }function WordPosition(const AIndex      : Integer;                      const AString     : string;                      const AWordDelims : TSysCharSet = AnsiWhiteSpace) : Integer;{ Returns a word number AIndex in the string AString }function ExtractWord(const AIndex      : Integer;                     const AString     : string;                     const AWordDelims : TSysCharSet = AnsiWhiteSpace): string;function URLEncode(const AString: string): string;function URLDecode(const AString: string): string;// string formatting routinesfunction FormatElapsedTime(ASeconds: Extended): string;function FormatByteText(ABytes: Integer): string;// windows utilities{$IFDEF Windows}function CreateGUIDString: string;function CreateUniqueID: string;function GetLocalUserName: string;function GetLocalComputerName: string;{$ENDIF}function GetParentDir(sPath : string) : string;{$IFDEF Windows}procedure CreateShellLink(ShellLink: TShellLink);function ExploreFile(const AFileName: string): Boolean;{$ENDIF}// FCL utilitiesprocedure ChangeOwner(AComponent, ANewOwner : TComponent);procedure EnableControls(AControlContainer : TWinControl;                         AEnabled          : Boolean = True);procedure DisableControls(AControlContainer : TWinControl);function GetTextWidth(const AText : string;                            AFont : TFont): Integer;function GetTextHeight(const AText : string;                             AFont : TFont): Integer;procedure OptimizeWidth(APanel: TPanel);function CloneMenuItem(SourceItem: TMenuItem): TMenuItem; // Variants and TVarRec conversionsfunction VariantToTypedVarRec(const Item: Variant; VarType: TVarType): TVarRec;procedure VariantToVarRec(    AVariant     : Variant;                          var AVarRecArray : TVarRecArray);function VariantToVarRec(const Item: Variant): TVarRec;procedure ClearVarRec(var AVarRecArray : TVarRecArray);procedure FinalizeVarRec(var Item: TVarRec);function VarRecToVariant(const AVarRec : TVarRec): Variant;function VarRecToString(const AVarRec : TVarRec): string;function VarRecToOleVariant(const AVarRec : TVarRec): OleVariant;function VarArrayElemCount(const AVarArray: Variant): Integer;function VarIsValue(const V: Variant): Boolean;function VarAsTypeDef(const AValue    : Variant;                            AVarType  : TVarType;                      const ADefValue : Variant) : Variant;procedure OleVarFromVariant(var   AOleVariant : OleVariant;                            const AVariant    : Variant);function GetVariantTypeName(const AVariant: Variant): string;function VariantCompare(AVariant1, AVariant2 : Variant) : Boolean;function VariantTypeForFieldType(const AFieldType : TFieldType): Integer;function FieldTypeForVariant(const AVariant : Variant) : TFieldType;function ConvertValueToFieldType(const AVariant : Variant;                                 const AField   : TField): Variant;function ValueNeedsConversion(const AVarType   : Integer;                              const AFieldType : TFieldType): Boolean;function StringToVariant(AString : string): Variant;function MixColors(C1, C2: TColor; W1: Integer): TColor;function StringReplaceMultiple(const Source: AnsiString;  const OldPatterns, NewPatterns: array of AnsiString;  CaseSensitive: Boolean = True): AnsiString;// Interface utility routinesfunction GetPIMTOffset(const I : IInterface): Integer;// UI windows utils{$IFDEF Windows}{ Displays a size grip on a window. This only works for WIN32/WIN64 widget set.}procedure SetWindowSizeGrip(hWnd: HWND; Enable: Boolean);function TaskBarHeight: Integer;function GetCommonPath(ASL: TStrings): string;function IsFormCovered(AForm: TForm): Boolean;function DrawHTML(const ARect: TRect; const ACanvas: TCanvas; const Text: string): Integer;{$ENDIF}procedure SetCheckedState(ACheckBox : TCheckBox; ACheck : Boolean);function SetToString(        ATypeInfo    : PTypeInfo;  const AValue;        AQuoteValues : Boolean = True;        ABrackets    : Boolean = True;        ATrimChars   : Integer = -1): string;//*****************************************************************************implementationuses{$IFDEF Windows}  ActiveX, ShlObj, Registry,{$ENDIF}  Variants, ActnList;//=============================================================================resourcestring  SNoCorrespondingFieldType = 'No corresponding fieldtype found for Variant ' +                              'with value %s';{$IFDEF Windows}// code used by SetWindowSizeGripconst  SizeGripProp = 'SizeGrip';type  TWndProc = function(hWnd: hWnd; Msg: UINT; wParam: wParam; lParam: lParam)    : LRESULT; stdcall;  PGripInfo = ^TGripInfo;  TGripInfo = record    OldWndProc : TWndProc;    Enabled    : Boolean;    GripRect   : TRect;  end;{  Code taken from SizeGripHWND.pas:  Copyright (C) 2005, 2006 Volker Siebert <flocke@vssd.de>  Alle Rechte vorbehalten.  Permission is hereby granted, free of charge, to any person obtaining a  copy of this software and associated documentation files (the "Software"),  to deal in the Software without restriction, including without limitation  the rights to use, copy, modify, merge, publish, distribute, sublicense,  and/or sell copies of the Software, and to permit persons to whom the  Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in  all copies or substantial portions of the Software.}function SizeGripWndProc(hWnd: hWnd; Msg: UINT; wParam: wParam; lParam: lParam)  : LRESULT; stdcall;var  Info : PGripInfo;  dc   : HDC;  pt   : TPoint;  // Invalidate the current grip rectangle  procedure InvalidateGrip;  begin    with Info^ do      if (GripRect.Right > GripRect.Left)        and (GripRect.Bottom > GripRect.Top) then        InvalidateRect(hWnd, @GripRect, true);  end;  // Update (and invalidate) the current grip rectangle  procedure UpdateGrip;  begin    with Info^ do    begin      GetClientRect(hWnd, GripRect);      GripRect.Left := GripRect.Right - GetSystemMetrics(SM_CXHSCROLL);      GripRect.Top := GripRect.Bottom - GetSystemMetrics(SM_CYVSCROLL);    end;    InvalidateGrip;  end;  function CallOld: LRESULT;  begin    Result := CallWindowProc(@Info^.OldWndProc, hWnd, Msg, wParam, lParam);  end;begin  Info := PGripInfo(GetProp(hWnd, SizeGripProp));  if Info = nil then    Result := DefWindowProc(hWnd, Msg, wParam, lParam)  else if not Info^.Enabled then    Result := CallOld  else  begin    case Msg of      WM_NCDESTROY:      begin        Result := CallOld;        SetWindowLong(hWnd, GWL_WNDPROC, LongInt(@Info^.OldWndProc));        RemoveProp(hWnd, SizeGripProp);        Dispose(Info);      end;      WM_PAINT:      begin        Result := CallOld;        if wParam = 0 then        begin          dc := GetDC(hWnd);          DrawFrameControl(dc, Info^.GripRect, DFC_SCROLL,            DFCS_SCROLLSIZEGRIP);          ReleaseDC(hWnd, dc);        end;      end;      WM_NCHITTEST:      begin        pt.x := TSmallPoint(Integer(lParam)).x;        pt.y := TSmallPoint(Integer(lParam)).y;        ScreenToClient(hWnd, pt);        if PtInRect(Info^.GripRect, pt) then          Result := HTBOTTOMRIGHT        else          Result := CallOld;      end;      WM_SIZE:      begin        InvalidateGrip;        Result := CallOld;        UpdateGrip;      end;    else      Result := CallOld;    end;  end;end;{ Note that SetWindowSizeGrip(..., false) does not really remove the hook -  it just sets "Enabled" to false. The hook plus all data is removed when  the window is destroyed.}procedure SetWindowSizeGrip(hWnd: hWnd; Enable: boolean);var  Info: PGripInfo;begin  Info := PGripInfo(GetProp(hWnd, SizeGripProp));  if (Info = nil) and Enable then  begin    New(Info);    FillChar(Info^, SizeOf(TGripInfo), 0);    with Info^ do    begin      Info^.OldWndProc := TWndProc(Pointer(GetWindowLong(hWnd, GWL_WNDPROC)));      GetClientRect(hWnd, GripRect);      GripRect.Left := GripRect.Right - GetSystemMetrics(SM_CXHSCROLL);      GripRect.Top := GripRect.Bottom - GetSystemMetrics(SM_CYVSCROLL);    end;    SetProp(hWnd, SizeGripProp, Cardinal(Info));    SetWindowLong(hWnd, GWL_WNDPROC, LongInt(@SizeGripWndProc));  end;  if Info <> nil then    if Enable <> Info^.Enabled then      with Info^ do      begin        Enabled := Enable;        if (GripRect.Right > GripRect.Left) and          (GripRect.Bottom > GripRect.Top) then          InvalidateRect(hWnd, @GripRect, true);      end;end;{$ENDIF}function GetCommonPath(ASL: TStrings): string;var  I        : Integer;  NextPath : string;begin  if not Assigned(ASL) or (ASL.Count = 0) then    Exit;  Result := ExtractFilePath(ASL[0]);  I := 1;  while I < ASL.Count do begin    NextPath :=  ASL[I];    while Copy(NextPath, 1, Length(Result)) <> Result do      Result := ExtractFilePath(ExtractFileDir(Result));    Inc(I);  end;end;procedure SetDoubleBuffered(AOwner: TComponent; AEnable: Boolean);var  I : Integer;begin for I := 0 to AOwner.ComponentCount - 1 do    if AOwner.Components[I] is TWinControl then      TWinControl(AOwner.Components[I]).DoubleBuffered := AEnable;end;{ Based on code of Xavier Pacheco. Fixed name assignment of ATo and removed  assignment of Parent property.   This procedure clones the published properties of AFrom and writes them to   ATo.   AFrom and ATo must be of the same type.  Use it for components that do   not have an Assign method.   AOwner is the owner of the cloned component. If AOwner is nil, the owner of   the source component is used.}procedure CloneComponent(AFrom: TComponent; ATo: TComponent);var  MS : TMemoryStream;  S1 : string;  S2 : string;begin  if AFrom.ClassType <> ATo.ClassType then    raise EComponentError.Create('Object types are incompatible');  MS := TMemoryStream.Create; // Create the memory stream.  with MS do try    S1 := AFrom.Name;    S2 := ATo.Name;    AFrom.Name := '';    WriteComponent(AFrom);        // Write C1 properties to stream    AFrom.Name := S1;    Seek(0, soFromBeginning);  // Position to beginning of stream.    ReadComponent(ATo);         // read properties from stream into C2    ATo.Name := S2;  finally    Free;                      // IAC, free stream.  end;end;{ Returns fully qualified component instance name. The name is preceded by its  owner name(s) (seperated by dots). }function GetFullName(AComponent: TComponent) : string;begin  Result := AComponent.Name;  while Assigned(AComponent.Owner) do  begin    if AComponent.Owner.Name <> '' then      Result := AComponent.Owner.Name + '.' + Result;    AComponent := AComponent.Owner;  end;end;procedure ClearVarRec(var AVarRecArray: TVarRecArray);var  I : Integer;begin  for I := 0 to Length(AVarRecArray) - 1 do    if AVarRecArray[I].VType in [vtExtended, vtString, vtVariant, vtInt64] then      Dispose(AVarRecArray[I].VExtended);  Finalize(AVarRecArray);end;procedure FinalizeVarRec(var Item: TVarRec);begin  case Item.VType of    vtExtended: Dispose(Item.VExtended);    vtString: Dispose(Item.VString);    vtPChar: StrDispose(Item.VPChar);    vtPWideChar: FreeMem(Item.VPWideChar);    vtAnsiString: AnsiString(Item.VAnsiString) := '';    vtCurrency: Dispose(Item.VCurrency);    vtVariant: Dispose(Item.VVariant);    vtInterface: IInterface(Item.VInterface) := nil;    vtWideString: WideString(Item.VWideString) := '';    vtInt64: Dispose(Item.VInt64);    {$IFDEF UNICODE}    vtUnicodeString: UnicodeString(Item.VUnicodeString) := '';    {$ENDIF}  end;  Item.VInteger := 0;end;function ConvertValueToFieldType(const AVariant: Variant;  const AField: TField): Variant;begin  if (AField <> nil) and ValueNeedsConversion(VarType(AVariant), AField.DataType) then    Result := VarAsType(AVariant, VariantTypeForFieldType(AField.DataType))  else   Result := AVariant;end;{  Returns True if the Variant represents a value of a primitive type.  Following variant values will return False:    - Null    - Unassigned    - EmptyParam    - varError    - empty strings (because they are the same as Unassigned)}function VarIsValue(const V: Variant): Boolean;begin  Result := (not VarIsNull(V)) and (not VarIsEmpty(V)) and            (not VarIsEmptyParam(V)) and (not VarIsError(V)) and            not (VarIsStr(V) and (V = ''));end;function FieldTypeForVariant(const AVariant: Variant): TFieldType;begin  case VarType(AVariant) and varTypeMask of   //varEmpty:    Result := ftVariant;   varSmallint: Result := ftSmallint;   varInteger:  Result := ftInteger;   varSingle:   Result := ftFloat;   varDouble:   Result := ftFloat;   varCurrency: Result := ftCurrency;   varDate:     Result := ftDateTime;   varOleStr:   Result := ftString;   varBoolean:  Result := ftBoolean;   varString:   Result := ftString;   else     raise Exception.CreateFmt(SNoCorrespondingFieldType, [AVariant]);  end;end;{$IFDEF Windows}function GetLocalComputerName: string;var  Count : DWORD;  S     : string;begin  Count := MAX_COMPUTERNAME_LENGTH + 1;  SetLength(S, Count);  if GetComputerName(PChar(S), Count) then    SetLength(S, StrLen(PChar(S)))  else    S := '';  Result := S;end;function GetLocalUserName: string;var  Count : DWORD;  S     : string;begin  Count := 256 + 1; // UNLEN + 1  // set buffer size to 256 + 2 characters  SetLength(S, Count);  if GetUserName(PChar(S), Count) then    SetLength(S, StrLen(PChar(S)))  else    S := '';  Result := S;end;{$ENDIF}function GetTextHeight(const AText: string; AFont: TFont): Integer;var  Bitmap: Graphics.TBitmap;begin  Bitmap := Graphics.TBitmap.Create;  try    Bitmap.Canvas.Font.Assign(AFont);    Result := Bitmap.Canvas.TextExtent(AText).cy;  finally    Bitmap.Free;  end;end;procedure OptimizeWidth(APanel: TPanel);var  S: string;begin  S := APanel.Caption;  if Trim(S) <> '' then    APanel.Width := GetTextWidth(APanel.Caption, APanel.Font) + 10  else    APanel.Width := 0;end;function CloneMenuItem(SourceItem: TMenuItem): TMenuItem;var  I: Integer;Begin  with SourceItem do  Begin    Result := NewItem(Caption, Shortcut, Checked, Enabled, OnClick, HelpContext, Name + 'Copy');    for I := 0 To Count - 1 do      Result.Add(CloneMenuItem(Items[I]));  end;end;function GetTextWidth(const AText: string; AFont: TFont): Integer;var  Bitmap : Graphics.TBitmap;begin  Bitmap := Graphics.TBitmap.Create;  try    Bitmap.Canvas.Font.Assign(AFont);    Result := Bitmap.Canvas.TextExtent(AText).cx;  finally    Bitmap.Free;  end;end;function GetVariantTypeName(const AVariant: Variant): string;begin  case VarType(AVariant) and varTypeMask of    varEmpty:    Result := 'varEmpty';    varNull:     Result := 'varNull';    varSmallint: Result := 'varSmallint';    varInteger:  Result := 'varInteger';    varSingle:   Result := 'varSingle';    varDouble:   Result := 'varDouble';    varCurrency: Result := 'varCurrency';    varDate:     Result := 'varDate';    varOleStr:   Result := 'varOleStr';    varDispatch: Result := 'varDispatch';    varError:    Result := 'varError';    varBoolean:  Result := 'varBoolean';    varVariant:  Result := 'varVariant';    varUnknown:  Result := 'varUnknown';    varByte:     Result := 'varByte';    varString:   Result := 'varString';    varDecimal:  Result := 'varDecimal';    varShortInt: Result := 'varShortInt';    varWord:     Result := 'varWord';    varLongWord: Result := 'varLongWord';    varInt64:    Result := 'varInt64';    varQWord:    Result := 'varQWord';    varRecord:   Result := 'varRecord';   else     Result := 'Unkown Variant Type';  end;  if VarType(AVariant) and varArray <> 0 then    Result := Result + ' [Array]';  if VarType(AVariant) and varByRef <> 0 then    Result := Result + ' (By Reference)';end;procedure OleVarFromVariant(var AOleVariant: OleVariant; const AVariant: Variant);begin  if VarType(AVariant) = varString then   AOleVariant := WideString(AVariant)  else   AOleVariant := AVariant;end;function StringToVariant(AString : string): Variant;var  I    : Int64;  K    : Integer;  iPos : Integer;begin  Result := Null;  if AString <> '' then    if IsCharAlpha(AString[1]) then      Result := AString    else    begin      Val(AString, I, K);      if K = 0 then        Result := Integer(I)      else      begin        if FormatSettings.DecimalSeparator <> '.' then        begin          iPos := Pos('.', AString);          if iPos > 0 then            AString[iPos] := FormatSettings.DecimalSeparator;        end;        Result := StrToFloat(AString);      end;    end;end;{$IFDEF Windows}function VirtualKeyToChar(AKey : Word) : string;var  KS : TKeyboardState;  AR : Integer;begin  GetKeyboardState(KS);  SetLength(Result, 2);  AR := ToAscii(AKey, MapVirtualKey(AKey, 0), KS, @Result[1], 0);  case AR of    0 : Result := '';    1 : SetLength(Result, 1);    2 : ;    else      Result := '';  end;end;{$ENDIF}procedure StrToStrings(const AString: string; AList: TStrings; ASeparator: Char);var  S : string;  I : Integer;begin  if Assigned(AList) then  try    AList.BeginUpdate;    AList.Clear;    S := '';    for I := 1 to Length(AString) do      if AString[I] = ASeparator then      begin        AList.Add(Trim(S));        S := '';      end      else if AString <> ' ' then        S := S + AString[I];    if S <> '' then      AList.Add(Trim(S));  finally    AList.EndUpdate;  end;end;function ValueNeedsConversion(const AVarType: Integer;  const AFieldType: TFieldType): Boolean;begin   if AVarType and varByRef <> 0 then    Result := (AFieldType <> ftReference) and              ValueNeedsConversion(AVarType and not varByRef, AFieldType)  else  if AVarType and varArray <> 0 then    Result := (AFieldType <> ftArray) and              ValueNeedsConversion(AVarType and not varArray, AFieldType)  else  case AVarType and VarTypeMask of   varSmallint, varInteger:     Result := not (AFieldType in                 [ftSmallint, ftInteger, ftWord, ftAutoInc, ftLargeint]);   varSingle, varDouble:     Result := not (AFieldType in [ftFloat]);   varCurrency:     Result := not (AFieldType in [ftCurrency, ftBCD]);   varDate:     Result := not (AFieldType in [ftDate, ftTime, ftDateTime]);   varOleStr, varString:     Result := not (AFieldType in [ftString, ftFixedChar, ftWideString]);   varBoolean:     Result := not (AFieldType in [ftBoolean]);   varUnknown, varDispatch:     Result := not (AFieldType in [ftDataSet, ftADT]);   varByte:     Result := not (AFieldType in                 [ftBytes, ftVarBytes, ftBlob, ftMemo, ftGraphic, ftFmtMemo,                  ftParadoxOle, ftDBaseOle, ftTypedBinary, ftCursor]);   //varEmpty, varAny, varError varVariant ???   else     Result := False;  end;end;function VarArrayElemCount(const AVarArray: Variant): Integer;begin  if not VarIsArray(AVarArray) then    Result := 1  else  begin    Assert(VarArrayDimCount(AVarArray) = 1, 'VarArrayDimCount(Value) = 1');    Result := VarArrayHighBound(AVarArray, 1) - VarArrayLowBound(AVarArray, 1) + 1;  end;end;function VarAsTypeDef(const AValue: Variant; AVarType: TVarType;  const ADefValue: Variant): Variant;begin  if VarIsType(AValue, AVarType) then    Result := VarAsType(AValue, AVarType)  else    Result := ADefValue;end;function VariantToVarRec(const Item: Variant): TVarRec;begin  Result := VariantToTypedVarRec(Item, TVarData(Item).VType);end;function VariantToTypedVarRec  (const Item: Variant; VarType: TVarType): TVarRec;begin  case VarType of    varInteger, varSmallint, varShortInt, varByte, varWord, varLongWord:    begin      Result.VType    :=vtInteger;      Result.VInteger :=Item;    end;    varNull, varUnknown, varEmpty:    begin      Result.VType    :=vtInteger;      Result.VInteger :=0;    end;    varBoolean:    begin      Result.VType:=vtBoolean;      Result.VBoolean:=Item;    end;    varDouble, varSingle:    begin      Result.VType:=vtExtended;      New(Result.VExtended);      Result.VExtended^ := Item;    end;    varString:    begin      Result.VType:=vtString;      New(Result.VString);      Result.VString^ := ShortString(Item);    end;    varCurrency:    begin      Result.VType:=vtCurrency;      New(Result.VCurrency);      Result.VCurrency^ := Item;    end;    varVariant:      begin        Result.VType:=vtVariant;        New(Result.VVariant);        Result.VVariant^ := Item;      end;    varOleStr:      begin        Result.VType:=vtWideString;        Result.VWideString := nil;        WideString(Result.VWideString) := WideString(Item);      end;    varInt64:      begin        Result.VType:=vtInt64;        New(Result.VInt64);        Result.VInt64^ := Item;      end;    {$IFDEF UNICODE}    varUString:      begin        Result.VType:=vtUnicodeString;        Result.VUnicodeString:=nil;        UnicodeString(Result.VUnicodeString) := UnicodeString(Item);      end;    {$ENDIF}  end;end;procedure VariantToVarRec(AVariant: Variant; var AVarRecArray: TVarRecArray);var  I : Integer;begin  SetLength(AVarRecArray, VarArrayHighBound(AVariant, 1) + 1);  for I := 0 to VarArrayHighBound(AVariant, 1) do    case TVarData(AVariant[I]).VType of      varSmallint, varInteger, varByte:        begin          AVarRecArray[I].VType := vtInteger;          AVarRecArray[I].VInteger := AVariant[I];        end;      varInt64:        begin          AVarRecArray[I].VType := vtInt64;          New(AVarRecArray[I].VInt64);          AVarRecArray[I].VInt64^ := AVariant[I];        end;      varSingle, varDouble, varCurrency, varDate:        begin          AVarRecArray[I].VType := vtExtended;          New(AVarRecArray[I].VExtended);          AVarRecArray[I].VExtended^ := AVariant[I];        end;      varBoolean:        begin          AVarRecArray[I].VType := vtBoolean;          AVarRecArray[I].VBoolean := AVariant[I];        end;      varOleStr, varString:        begin          AVarRecArray[I].VType := vtString;          New(AVarRecArray[I].VString);          AVarRecArray[I].VString^ := AVariant[I];        end;      varVariant:        begin          AVarRecArray[I].VType := vtVariant;          New(AVarRecArray[I].VVariant);          AVarRecArray[I].VVariant^ := AVariant[I];        end;    end;end;function VariantTypeForFieldType(const AFieldType: TFieldType): Integer;begin  case AFieldType of   ftString:     Result := varString;   ftSmallint:     Result := varSmallint;   ftInteger, ftWord, ftAutoInc:     Result := varInteger;   ftBoolean:     Result := varBoolean;   ftFloat:     Result := varDouble;   ftCurrency, ftBCD:     Result := varCurrency;   ftDate, ftTime, ftDateTime:     Result := varDate;   ftBytes, ftVarBytes, ftBlob, ftMemo, ftGraphic, ftFmtMemo, ftParadoxOle,     ftDBaseOle, ftTypedBinary, ftCursor:     Result := varByte or varArray;   ftFixedChar:     Result := varString;   ftLargeint:     Result := varInteger;   ftWideString:     Result := varOleStr;   ftArray:     Result := varVariant or varArray;   ftReference:     Result := varVariant or varByRef;   ftDataSet, ftADT:     Result := varUnknown;   // ftUnknown   else     Result := varNull;  end;end;function VarRecToOleVariant(const AVarRec: TVarRec): OleVariant;begin  case AVarRec.VType of   vtInteger    : Result := AVarRec.VInteger;   vtBoolean    : Result := AVarRec.VBoolean;   vtChar       : Result := AVarRec.VChar;   vtExtended   : Result := AVarRec.VExtended^;   vtString     : Result := AVarRec.VString^;   vtPChar      : Result := string(AVarRec.VPChar);   vtWideChar   : Result := AVarRec.VWideChar;   vtPWideChar  : Result := WideString(AVarRec.VPWideChar);   vtAnsiString : Result := string(AVarRec.VAnsiString);   vtCurrency   : Result := AVarRec.VCurrency^;   vtVariant    : Result := AVarRec.VVariant^;   vtWideString : Result := WideString(AVarRec.VWideString);   vtPointer    : TVarData(Result).VPointer := AVarRec.VPointer;   vtObject     : TVarData(Result).VPointer := AVarRec.VObject;   vtClass      : TVarData(Result).VPointer := AVarRec.VClass;   vtInterface  : TVarData(Result).VDispatch := AVarRec.VInterface;  end;end;function VarRecToString(const AVarRec: TVarRec): string;var  S : string;begin  case AVarRec.VType of    vtInteger    : S := Format('%d', [AVarRec.VInteger]);    vtInt64      : S := Format('%d', [AVarRec.VInt64^]);    vtString     : S := Format('%s', [AVarRec.VString^]);    vtWideString : S := Format('%s', [WideString(AVarRec.VWideString)]);    vtAnsiString : S := Format('%s', [AnsiString(AVarRec.VAnsiString)]);    vtCurrency   : S := Format('%s', [CurrToStr(AVarRec.VCurrency^)]);    vtExtended   : S := Format('%s', [FloatToStr(AVarRec.VExtended^)]);    vtChar       : S := Format('%s', [AVarRec.VChar]);    vtPChar      : S := Format('%s', [AVarRec.VPChar]);    vtWideChar   : S := Format('%s', [AVarRec.VWideChar]);    vtPWideChar  : S := Format('%s', [AVarRec.VPWideChar]);    vtVariant    : S := Format('%s', [VarToStr(AVarRec.VVariant^)]);  else    S := 'Unassigned'    // TODO: better: raise exception  end;  Result := S;end;function VarRecToVariant(const AVarRec: TVarRec): Variant;begin  with AVarRec do    case VType of      vtInteger,      vtObject     : Result := VInteger;      vtInt64      : Result := VInt64^;      vtBoolean    : Result := VBoolean;      vtExtended   : Result := VExtended^;      vtCurrency   : Result := VCurrency^;      vtChar       : Result := VChar;      vtString     : Result := VString^;      vtAnsiString : Result := string(VAnsiString);      vtVariant    : Result := VVariant^;      else        Result := Null;    end;end;procedure ChangeOwner(AComponent, ANewOwner: TComponent);begin  if Assigned(AComponent) and Assigned(ANewOwner) then  begin    AComponent.Owner.RemoveComponent(AComponent);    ANewOwner.InsertComponent(AComponent);  end;end;function Unformat(const ASource, APattern: string; const AArgs: array of const)  : Integer;{ The opposite of Format, Unformat splits up a formatted source string into  substrings and Integers.  It is an alternative to parsing when the format is  known to be fixed. The pattern parameter contains the format string, which is  a combination of plain characters and format specifiers.  Note: only short strings (fixed length strings) can be passed as a parameter        to this function.  The following specifiers are supported:  %s   indicates that a string value is required  %d   indicates that an integer value is required  %S   indicates that a string value should be ignored  %D   indicates that an integer value should be ignored  Unformat compares the source with the pattern, and plain characters  that do not match will raise an EConvertError.  When a format specifier  is encountered in the pattern, an argument is fetched and used to  store the result that is obtained from the source.  Then the comparison  continues.  For each %s, the args list must contain a pointer to a string variable,  followed by an integer specifying the maximum length of the string.  For each %d, the args list must contain a pointer to an integer variable.  When the end of the source string is reached, the function returns  without modifying the remaining arguments, so you might wish to initialize  your variables to "default" values before the function call.  Unformat returns the number of values it has extracted.  Examples:  var    s1, s2: string[31];    i: Integer;  Unformat('[abc]123(def)', '[%s]%d(%s)', [@s1, 31, @i, @s2, 31]);    (* s1 = 'abc', i = 123, s2 = 'def' *)  Unformat('Hello, Universe!!!', '%s, %s%d', [@s1, 31, @s2, 31, @i]);    (* s1 = 'Hello', s2 = 'Universe!!!', i is untouched *)  Unformat('How much wood could a woodchuck chuck...',           '%S %S %s could a %S %s...', [@s1, 31, @s2, 31]);    (* s1 = 'wood', s2 = 'chuck' *) }const  Digits = ['0'..'9'];var  I, J      : Integer;  iArgIndex : Integer;  iStart    : Integer;  iEnd      : Integer;  iMaxLen   : Integer;  C         : Char;begin  Result := 0;  iArgIndex := 0;  I := 1;  J := 1;  while (I < Length(APattern)) and (J <= Length(ASource)) do  begin    if APattern[I] = '%' then      case APattern[I+1] of        'D': begin               Inc(I, 2);               while (J <= Length(ASource)) and                 ((ASource[J] in Digits) or (ASource[J] = '-')) do Inc(J);               Inc(Result);             end;        'S': begin               Inc(I, 2);               if I > Length(APattern) then break               else               begin                 c := APattern[I];                 while (J <= Length(ASource)) and (ASource[J] <> c) do                   Inc(J);               end;               Inc(Result);             end;        'd': begin               if iArgIndex > High(AArgs) then                 raise EConvertError.Create('Not enough arguments');               Inc(I, 2);               iStart := J;               while (J <= Length(ASource)) and                 ((ASource[J] in Digits) or (ASource[J] = '-')) do Inc(J);               iEnd := J;               if iEnd > iStart then                 PInteger(AArgs[iArgIndex].VPointer)^ :=                   StrToInt(Copy(ASource, iStart, iEnd - iStart));               Inc(iArgIndex);               Inc(Result);             end;        's': begin               if iArgIndex > High(AArgs) - 1 then                 raise EConvertError.Create('Not enough arguments');               if AArgs[iArgIndex + 1].VType <> vtInteger then                 raise EConvertError.Create('No string size specified');               iMaxLen := AArgs[iArgIndex+1].VInteger;               Inc(I, 2);               if I > Length(APattern) then               begin                 AArgs[iArgIndex].VString^ :=                   Copy(ASource, J, Min(Length(ASource) + 1 - J, iMaxLen));                 break;               end               else               begin                 c := APattern[I];                 iStart := J;                 while (J <= Length(ASource)) and (ASource[J] <> c) do                   Inc(J);                 iEnd := J;                 AArgs[iArgIndex].VString^ :=                   Copy(ASource, iStart, Min(iEnd - iStart, iMaxLen));                 Inc(iArgIndex, 2);               end;               Inc(Result);             end;      else Inc(I);      end    else      {if APattern[I] <> ASource[J] then        raise EConvertError.Create('Pattern mismatch')      else}      begin        Inc(I);        Inc(J);      end;  end;end;function VariantCompare(AVariant1, AVariant2 : Variant) : Boolean;begin  Result := False;  if (VarType(AVariant1) = VarType(AVariant2)) then     Result := AVariant1 = AVariant2;end;{ 'Like' code is written by Wladimir Perepletchick }function Like(const ASource, ATemplate: string): Boolean;const  SpecialChars: TSysCharSet = ['%', '*', '?', '_'];var I, J, K, LTemplate, LSource: Integer;begin  Result := False;  LTemplate := Length(ATemplate);  LSource := Length(ASource);  I := 1;  J := 1;  while (I <= LTemplate) and (J <= LSource) do  begin    case ATemplate[I] of      '?', '_': ;      '*', '%':      begin        while (ATemplate[I] in SpecialChars) and (I <= LTemplate) do          Inc(I);        if I > LTemplate then          Result := True        else          while J <= LSource do          begin            while (ASource[J] <> ATemplate[I]) and (J <= LSource) do              Inc(J);            if J > LSource then Break;            K := 0;            while (ASource[J + K] = ATemplate[I + K]) and                  (J + K <= LSource) and (I + K <= LTemplate) and                  (not (ATemplate[I + K] in SpecialChars)) do              Inc(K);            if (ATemplate[I + K] in SpecialChars) or (I + K > LTemplate) then            begin              Inc(I, K - 1);              Inc(J, K - 1);              Break;            end;            Inc(J, K);          end;          if J > LSource then            Break;      end;      else        if (ASource[J] <> ATemplate[I]) then          Break;    end;    Inc(I);    Inc(J);    if (J > LSource) then    begin      K := 0;      while (ATemplate[I + K] in ['%', '*']) and (I + K <= LTemplate) do        Inc(K);      if (I + K > LTemplate) then        Result := True;    end;  end;end;{$IFDEF Windows}function CreateGUIDString: string;var  ClassID : TCLSID;  P       : PWideChar;begin  CoCreateGuid(ClassID);  StringFromCLSID(ClassID, P);  Result := P;  CoTaskMemFree(P);end;function CreateUniqueID: String;var  AGUID       : TGUID;  AGUIDString : Widestring;begin  CoCreateGUID(AGUID);  SetLength(AGUIDString, 39);  StringFromGUID2(AGUID, PWideChar(AGUIDString), 39);  Result := string(PWideChar(AGUIDString));  Result := Copy(Result, 2, 36);  Result := StringReplace(Result, '-', '', [rfReplaceAll]);end;{$ENDIF}{ Formats the given time amount (in seconds) to the form:  <Hours>:<Minutes>:<Seconds>.<Hundreds> }function FormatElapsedTime(ASeconds: Extended): string;var  H  : Integer;  M  : Integer;  S  : Integer;  HS : Integer;begin  HS := Round(Int(100 * Frac(ASeconds)));  S  := Round(Int(ASeconds));  H  := S div 3600;  S  := S mod 3600;  M  := S div 60;  S  := S mod 60;  Result := Format('%2.2d:%2.2d:%2.2d.%2.2d', [H, M, S, HS]);end;{ Author: Michael Haller }function FormatByteText(ABytes: Integer): string;var  D : Double;begin  Result := 'n.a.';  try    D := ABytes / 1024;    if ABytes = 0 then      Result := '0 Byte'    else      if ABytes < 1048576 then        Result := FloatToStrF(D, ffNumber, 18, 1)+' KB'      else        if ABytes < 1073741824 then begin          D := D / 1024;          ABytes := Round(D);          if ABytes < 10 then            Result := FloatToStrF(D, ffNumber, 18, 1)+' MB'          else            Result := IntToStr(ABytes)+' MB';        end else begin          ABytes := Round(D / 1024 / 1024);          Result := IntToStr(ABytes)+' GB';        end;    if (Result[Length(Result)-3] = '0') and (Result[Length(Result)-4] = ',') then      Delete(Result, Length(Result)-4, 2);  except    // ignore exceptions  end;end;{ Mixes two colors for a given transparancy level  }function MixColors(C1, C2: TColor; W1: Integer): TColor;var  W2: Cardinal;begin  Assert(W1 in [0..255]);  W2 := W1 xor 255;{$IFDEF Windows}  if Integer(C1) < 0 then C1 := GetSysColor(C1 and $000000FF);  if Integer(C2) < 0 then C2 := GetSysColor(C2 and $000000FF);{$ELSE}  C1 := ColorToRGB(C1);  C2 := ColorToRGB(C2);{$ENDIF}  Result := Integer(    ((Cardinal(C1) and $FF00FF) * Cardinal(W1) +    (Cardinal(C2) and $FF00FF) * W2) and $FF00FF00 +    ((Cardinal(C1) and $00FF00) * Cardinal(W1) +    (Cardinal(C2) and $00FF00) * W2) and $00FF0000) shr 8;end;function StringReplaceMultiple(const Source: AnsiString;  const OldPatterns, NewPatterns: array of AnsiString;  CaseSensitive: Boolean = True): AnsiString;type  TFoundPos = record    Position: Integer;    PatternNum: Integer;  end;  TPattern = record    Old: AnsiString;    New: PAnsiChar;    LengthOld: Integer;    LengthNew: Integer;    Diff: Integer;  end;var  C: Integer;  FoundCount: Integer;  Positions: array of TFoundPos;  PositionLength: Integer;  Patterns: array of TPattern;  PatternCount: Integer;  PNum: Integer;  SourcePosition: Integer;  SourceLength: Integer;  SearchSource: AnsiString;  DeltaOld: Integer;  Delta: Integer;  PSource, PDest, PNew: PAnsiChar;begin  // Is there anything to do at all?  if (Source = '') or (Length(OldPatterns) <> Length(NewPatterns)) then  begin    Result := Source;    Exit;  end;  // Initialize the Pattern records  PatternCount := Length(OldPatterns);  FoundCount := 0;  SetLength(Patterns, PatternCount);  for C := 0 to PatternCount - 1 do    if (OldPatterns[C] <> '') and (OldPatterns[C] <> NewPatterns[C]) then    begin      if CaseSensitive then        Patterns[FoundCount].Old := OldPatterns[C]      else        Patterns[FoundCount].Old := AnsiLowerCase(OldPatterns[C]);      Patterns[FoundCount].LengthOld := Length(OldPatterns[C]);      Patterns[FoundCount].New := PAnsiChar(NewPatterns[C]);      Patterns[FoundCount].LengthNew := Length(NewPatterns[C]);      Patterns[FoundCount].Diff :=        Patterns[FoundCount].LengthNew - Patterns[FoundCount].LengthOld;      Inc(FoundCount);    end;  PatternCount := FoundCount;  SetLength(Patterns, PatternCount);  // Nothing to replace  if PatternCount = 0 then  begin    Result := Source;    Exit;  end;  if CaseSensitive then    SearchSource := Source  else    SearchSource := AnsiLowerCase(Source);  try    // Initialize some variables    SourceLength := Length(SearchSource);    Delta := 0;    DeltaOld := 0;    for C := 0 to PatternCount - 1 do      Inc(DeltaOld, Patterns[C].LengthOld);    DeltaOld := Round(DeltaOld / PatternCount);    FoundCount := 0;    // ----------------------------------    // Check the amount of replaces    // ----------------------------------    // We *should* range check here, but who has strings > 2GB ?    PositionLength := SourceLength div DeltaOld + 1;    SetLength(Positions, PositionLength);    C := 1;    while C <= SourceLength do    begin      for PNum := 0 to PatternCount - 1 do      begin        // Check first char before we waste a jump to CompareMem        if (SearchSource[C]) = (Patterns[PNum].Old[1]) then        begin          if CompareMem(@SearchSource[C], @Patterns[PNum].Old[1], Patterns[PNum].LengthOld) then          begin            if FoundCount >= PositionLength then            begin              // Make room for more Positions              Inc(PositionLength, 4);              SetLength(Positions, PositionLength);            end;            Positions[FoundCount].Position := C; // Store the found position            Positions[FoundCount].PatternNum := PNum;            Inc(FoundCount);            Inc(C, Patterns[PNum].LengthOld - 1); // Jump to after OldPattern            Inc(Delta, Patterns[PNum].Diff);            Break;          end;        end;      end;      Inc(C);    end;    // ----------------------------------    // Actual replace    // ----------------------------------    if FoundCount > 0 then // Have we found anything?    begin      // We know the length of the result      // Again, we *should* range check here...      SetLength(Result, SourceLength + Delta);      // Initialize some variables      SourcePosition := 1;      PSource := PAnsiChar(Source);      PDest := PAnsiChar(Result);      // Replace...      for C := 0 to FoundCount - 1 do      begin        PNum := Positions[C].PatternNum;        // Copy original and advance resultpos        PNew := Patterns[PNum].New;        Delta := Positions[C].Position - SourcePosition;        Move(PSource^, PDest^, Delta);        Inc(PDest, Delta);        // Append NewPattern and advance resultpos        Move(PNew^, PDest^, Patterns[PNum].LengthNew);        Inc(PDest, Patterns[PNum].LengthNew);        // Jump to after OldPattern        Inc(PSource, Delta + Patterns[PNum].LengthOld);        SourcePosition := Positions[C].Position + Patterns[PNum].LengthOld;      end;      // Append characters after last OldPattern      Move(PSource^, PDest^, SourceLength - SourcePosition + 1);    end else      Result := Source; // Nothing to replace  finally    // Clean up    Finalize(Positions);    Finalize(Patterns);  end;end;{ Returns the offset to the Pointer to the Interface Method Table.  Author : Hallvard Vassbotn  PIMT is short for pointer to interface method table. This is a special  compiler generated "field" that is added to an object instance by the compiler  when you declare that the class implements an interface. The "field" is a  pointer to a kind of virtual method table for the methods declared on the  interface. The function returns the offset of this field. Note that the  compiler uses an ADD assembly instruction to adjust the Self parameter -  but the value added is actually negative. That's why we return the negated  value of the adjustment offset. }function GetPIMTOffset(const I: IInterface): Integer;// PIMT = Pointer to Interface Method Tableconst  AddByte = $04244483; // opcode for ADD DWORD PTR [ESP+4], Shortint  AddLong = $04244481; // opcode for ADD DWORD PTR [ESP+4], Longinttype  PAdjustSelfThunk = ^TAdjustSelfThunk;  TAdjustSelfThunk = packed record    case AddInstruction: longint of      AddByte : (AdjustmentByte : ShortInt);      AddLong : (AdjustmentLong : LongInt);  end;  PInterfaceMT = ^TInterfaceMT;  TInterfaceMT = packed record    QueryInterfaceThunk: PAdjustSelfThunk;  end;  TInterfaceRef = ^PInterfaceMT;var  QueryInterfaceThunk: PAdjustSelfThunk;begin  Result := -1;  if Assigned(Pointer(I)) then    try      QueryInterfaceThunk := TInterfaceRef(I)^.QueryInterfaceThunk;      case QueryInterfaceThunk.AddInstruction of        AddByte: Result := -QueryInterfaceThunk.AdjustmentByte;        AddLong: Result := -QueryInterfaceThunk.AdjustmentLong;      end;    except      // Protect against non-Delphi or invalid interface references    end;end;{$IFDEF Windows}function ExploreFile(const AFileName: string): Boolean;const  PARAM = '/e,/select,"%s"';var  S : string;begin  if FileExists(AFileName) then  begin    S := Format(PARAM, [AFileName]);    ShellExecute(      Application.MainForm.Handle,      'open',      PChar('explorer.exe'),      PChar(S),      nil,      SW_SHOWNORMAL    );    Result := True;  end  else    Result := False;end;{$ENDIF}function GetParentDir(sPath : string) : string;var  I : Integer;begin  Result := '';  sPath := ExcludeTrailingPathDelimiter(sPath);  // Start from one character before last.  for I := length(sPath) - 1 downto 1 do    if sPath[I] = DirectorySeparator then    begin      Result := Copy(sPath, 1, I);      Break;    end;end;{$IFDEF Windows}procedure CreateShellLink(ShellLink: TShellLink);const  IID_IPersistFile: TGUID = (D1:$0000010B;D2:$0000;D3:$0000;D4:($C0,$00,$00,$00,$00,$00,$00,$46));var  SL: IShellLink;  PF: IPersistFile;  WideFilename: array[0..MAX_PATH-1] of WideChar;begin  try    if CoCreateInstance(CLSID_ShellLink, nil, CLSCTX_INPROC_SERVER, IID_IShellLinkA, SL) <> S_OK then      raise Exception.Create('CoCreateInstance failed');    SL.SetPath(PChar(ShellLink.ShortcutTo));    SL.SetArguments(PChar(ShellLink.Parameters));    case ShellLink.ShowCommand of      wsNormal: SL.SetShowCmd(SW_SHOW);      wsMaximized: SL.SetShowCmd(SW_SHOWMAXIMIZED);      wsMinimized: SL.SetShowCmd(SW_SHOWMINNOACTIVE);    end;    SL.SetIconLocation(PChar(ShellLink.IconPath), ShellLink.IconIndex);    //SL.SetHotkey(ShellLink.HotKey);    SL.SetWorkingDirectory(PChar(ShellLink.WorkingDir));    SL.SetDescription(PChar(ShellLink.Description));    if SL.QueryInterface(IID_IPersistFile, PF) <> S_OK then      raise Exception.Create('IShellLink::QueryInterface failed');    MultiByteToWideChar(CP_ACP, 0, PChar(ShellLink.Filename), -1, WideFilename, MAX_PATH);    PF.Save(WideFilename, True);  except    // just ignore the creation  end;end;{$ENDIF}function WordCount(const AString: string; const AWordDelims: TSysCharSet)  : Integer;var  SLen, I: Cardinal;begin  Result := 0;  I := 1;  SLen := Length(AString);  while I <= SLen do    begin      while (I <= SLen) and (AString[I] in AWordDelims) do        Inc(I);      if I <= SLen then        Inc(Result);      while (I <= SLen) and not (AString[I] in AWordDelims) do        Inc(I);    end;end;function WordPosition(const AIndex: Integer; const AString: string;  const AWordDelims: TSysCharSet): Integer;var  Count, I: Integer;begin  Count := 0;  I := 1;  Result := 0;  while (I <= Length(AString)) and (Count <> AIndex) do    begin    { skip over delimiters }      while (I <= Length(AString)) and (AString[I] in AWordDelims) do        Inc(I);    { if we're not beyond end of S, we're at the start of a word }      if I <= Length(AString) then        Inc(Count);    { if not finished, find the end of the current word }      if Count <> AIndex then        while (I <= Length(AString)) and not (AString[I] in AWordDelims) do          Inc(I)      else        Result := I;    end;end;function ExtractWord(const AIndex: Integer; const AString: string;  const AWordDelims: TSysCharSet): string;var  I   : Integer;  Len : Integer;begin  Len := 0;  I := WordPosition(AIndex, AString, AWordDelims);  if I <> 0 then    { find the end of the current word }    while (I <= Length(AString)) and not (AString[I] in AWordDelims) do      begin      { add the I'th character to result }        Inc(Len);        SetLength(Result, Len);        Result[Len] := AString[I];        Inc(I);      end;  SetLength(Result, Len);end;procedure DisableControls(AControlContainer : TWinControl);begin  EnableControls(AControlContainer, False)end;{ Enables/disables all child controls of the AControlContainer control (  eg. TPanel, TGroupBox, etc.). }procedure EnableControls(AControlContainer : TWinControl; AEnabled : Boolean);var  I : Integer;  C : TControl;begin  if not (csAcceptsControls in AControlContainer.ControlStyle) then    raise Exception.Create('Invalid control container!');  for I := 0 to AControlContainer.ControlCount - 1 do  begin    C := AControlContainer.Controls[I];    if (csAcceptsControls in C.ControlStyle) then      EnableControls(TWinControl(C), AEnabled);    if C is TWinControl then    begin      C.Enabled := AEnabled;      if not (csParentBackground in C.ControlStyle) and         IsPublishedProp(C, 'Color') then      begin        if AEnabled then          SetOrdProp(C, 'Color', clWhite)        else          SetOrdProp(C, 'Color', clBtnFace);      end;    end    else if IsPublishedProp(C, 'Enabled') then    begin      if AEnabled then        SetEnumProp(C, 'Enabled', 'True')      else        SetEnumProp(C, 'Enabled', 'False');    end;  end;end;function URLEncode(const AString: string): string;var  I: Integer;begin  Result := '';  for I := 1 to Length(AString) do  begin    case AString[I] of      'A'..'Z', 'a'..'z', '0'..'9', '-', '_', '.':        Result := Result + AString[I];      ' ':        Result := Result + '%20';      else        Result := Result + '%' + SysUtils.IntToHex(Ord(AString[I]), 2);    end;  end;end;function URLDecode(const AString: string): string;const  HexChar = '0123456789ABCDEF';var  I, J: integer;begin  SetLength(Result, Length(AString));  I := 1;  J := 1;  while I <= Length(AString) do  begin    if (AString[I] = '%') and (I + 2 < Length(AString)) then    begin      Result[J] := Chr(((pred(Pos(AString[I + 1], HexChar))) shl 4)        or (Pred(Pos(AString[I + 2], HexChar))));      Inc(I, 2);    end    else      Result[J] := AString[I];    Inc(I);    Inc(J);  end;  SetLength(Result, pred(J));end;//  SetBit()      : Sets a single BIT in a string to true or falseprocedure SetBit(var Str: string; BitNr: dword; Value: boolean);var  CharNr        : dword;  CharBit       : byte;  Original, Mask: byte;begin  CharNr := (BitNr DIV 8) + 1;  CharBit := (BitNr MOD 8);  Original := byte(Str[CharNr]);  Mask := 1 shl CharBit;  if Value = true then    Original := (Original or Mask)  else    Original := (Original and not Mask);  Str[CharNr] := char(Original);end;{   GetBit()      : Returns the state of a single bit in a string }function GetBit(Str: string; BitNr: dword): boolean;var  CharNr        : dword;  CharBit       : byte;  Original, Mask: byte;begin  CharNr := (BitNr DIV 8) + 1;  CharBit := (BitNr MOD 8);  Original := byte(Str[CharNr]);  Mask := 1 shl CharBit;  if (Original and Mask) = Mask then    Result := true  else    Result := false;end;{  FindBest()    : Finds a substring in another string and returns position and                  the number of characters upto where they are equal}procedure FindBest(Main, Sub: string; var FoundLen, FoundPos: integer);var  P, T, FL, MaxLen: integer;begin  if Length(Sub) > Length(Main) then    MaxLen := Length(Main)  else    MaxLen := Length(Sub);  FoundLen := 0;  FoundPos := 0;  for P := 1 to Length(Main) - MaxLen do  begin    FL := 0;    for T := 1 to MaxLen do    begin      if Main[P + T - 1] = Sub[T] then        FL := T      else        Break;    end;    if FL > FoundLen then    begin      FoundLen := FL;      FoundPos := P;    end;  end;end;{$IFDEF Windows}function DrawHTML(const ARect: TRect; const ACanvas: TCanvas; const Text: String): Integer;(*DrawHTML - Draws text on a canvas using tags based on a simple subset of HTML/CSS  <B> - Bold e.g. <B>This is bold</B>  <I> - Italic e.g. <I>This is italic</I>  <U> - Underline e.g. <U>This is underlined</U>  <font-color=x> Font colour e.g.                <font-color=clRed>Delphi red</font-color>                <font-color=#FFFFFF>Web white</font-color>                <font-color=$000000>Hex black</font-color>  <font-size=x> Font size e.g. <font-size=30>This is some big text</font-size>  <font-family> Font family e.g. <font-family=Arial>This is arial</font-family>*)  function CloseTag(const ATag: String): String;  begin    Result := concat('/', ATag);  end;  function GetTagValue(const ATag: String): String;  var    p: Integer;  begin    p := pos('=', ATag);    if p = 0 then      Result := ''    else      Result := copy(ATag, p + 1, MaxInt);  end;  function ColorCodeToColor(const Value: String): TColor;  var    HexValue: String;  begin    Result := 0;    if Value <> '' then    begin      if (length(Value) >= 2) and (copy(Uppercase(Value), 1, 2) = 'CL') then      begin        // Delphi colour        Result := StringToColor(Value);      end else      if Value[1] = '#' then      begin        // Web colour        HexValue := copy(Value, 2, 6);        Result := RGB(StrToInt('$'+Copy(HexValue, 1, 2)),                      StrToInt('$'+Copy(HexValue, 3, 2)),                      StrToInt('$'+Copy(HexValue, 5, 2)));      end      else        // Hex or decimal colour        Result := StrToIntDef(Value, 0);    end;  end;const  TagBold = 'B';  TagItalic = 'I';  TagUnderline = 'U';  TagBreak = 'BR';  TagFontSize = 'FONT-SIZE';  TagFontFamily = 'FONT-FAMILY';  TagFontColour = 'FONT-COLOR';  TagColour = 'COLOUR';var  x, y, idx, CharWidth, MaxCharHeight: Integer;  CurrChar: Char;  Tag, TagValue: String;  PreviousFontColour: TColor;  PreviousFontFamily: String;  PreviousFontSize: Integer;  PreviousColour: TColor;begin  PreviousFontColour := ACanvas.Font.Color;  PreviousFontFamily := ACanvas.Font.Name;  PreviousFontSize := ACanvas.Font.Size;  PreviousColour := ACanvas.Brush.Color;  x := ARect.Left;  y := ARect.Top + 1;  idx := 1;  MaxCharHeight := ACanvas.TextHeight('Ag');  While idx <= length(Text) do  begin    CurrChar := Text[idx];    // Is this a tag?    if CurrChar = '<' then    begin      Tag := '';      inc(idx);      // Find the end of then tag      while (Text[idx] <> '>')            //and (idx <= length(Text)) do            and (idx < length(Text)) do      begin        Tag := concat(Tag,  UpperCase(Text[idx]));        inc(idx);      end;      ///////////////////////////////////////////////////      // Simple tags      ///////////////////////////////////////////////////      if Tag = TagBold then        ACanvas.Font.Style := ACanvas.Font.Style + [fsBold] else      if Tag = TagItalic then        ACanvas.Font.Style := ACanvas.Font.Style + [fsItalic] else      if Tag = TagUnderline then        ACanvas.Font.Style := ACanvas.Font.Style + [fsUnderline] else      if Tag = TagBreak then      begin        x := ARect.Left;        inc(y, MaxCharHeight);      end else      ///////////////////////////////////////////////////      // Closing tags      ///////////////////////////////////////////////////      if Tag = CloseTag(TagBold) then        ACanvas.Font.Style := ACanvas.Font.Style - [fsBold] else      if Tag = CloseTag(TagItalic) then        ACanvas.Font.Style := ACanvas.Font.Style - [fsItalic] else      if Tag = CloseTag(TagUnderline) then        ACanvas.Font.Style := ACanvas.Font.Style - [fsUnderline] else      if Tag = CloseTag(TagFontSize) then        ACanvas.Font.Size := PreviousFontSize else      if Tag = CloseTag(TagFontFamily) then        ACanvas.Font.Name := PreviousFontFamily else      if Tag = CloseTag(TagFontColour) then        ACanvas.Font.Color := PreviousFontColour else      if Tag = CloseTag(TagColour) then        ACanvas.Brush.Color := PreviousColour else      ///////////////////////////////////////////////////      // Tags with values      ///////////////////////////////////////////////////      begin        // Get the tag value (everything after '=')        TagValue := GetTagValue(Tag);        if TagValue <> '' then        begin          // Remove the value from the tag          Tag := copy(Tag, 1, pos('=', Tag) - 1);          if Tag = TagFontSize then          begin            PreviousFontSize := ACanvas.Font.Size;            ACanvas.Font.Size := StrToIntDef(TagValue, ACanvas.Font.Size);          end else          if Tag = TagFontFamily then          begin            PreviousFontFamily := ACanvas.Font.Name;            ACanvas.Font.Name := TagValue;          end;          if Tag = TagFontColour then          begin            PreviousFontColour := ACanvas.Font.Color;            try              ACanvas.Font.Color := ColorCodeToColor(TagValue);            except              //Just in case the canvas colour is invalid            end;          end else          if Tag = TagColour then          begin            PreviousColour := ACanvas.Brush.Color;            try              ACanvas.Brush.Color := ColorCodeToColor(TagValue);            except              //Just in case the canvas colour is invalid            end;          end;        end;      end;    end    else    // Draw the character if it's not a ctrl char    //if CurrChar >= #32 then    begin      CharWidth := ACanvas.TextWidth(CurrChar);      if x + CharWidth > ARect.Right then      begin        x := ARect.Left;        inc(y, MaxCharHeight);      end;      if y + MaxCharHeight < ARect.Bottom then      begin        ACanvas.Brush.Style := bsClear;        ACanvas.TextOut(x, y, CurrChar);      end;      x := x + CharWidth;    end;    inc(idx);  end;  Result := x;end;{ From stackoverflow:  I was looking for a way to determine if a Form is actually visible (even only  partially) to the user. In particular when it was supposed to be visible and  Showing was True but the window was actually entirely behind another one.}function IsFormCovered(AForm: TForm): Boolean;var  R      : TRect;  Rgn    : HRGN;  TmpRgn : HRGN;  RType  : Integer;  H      : HWND;begin  R := AForm.BoundsRect;           // screen coordinates  Rgn := CreateRectRgnIndirect(R); // AForm not overlapped region  H := GetTopWindow(0);            // currently examined topwindow  RType := SIMPLEREGION;           // Rgn type// From topmost window downto AForm, build the not overlapped portion of AForm  while (H <> 0) and (H <> AForm.handle) and (RType <> NULLREGION) do  begin    // nothing to do if hidden window    if IsWindowVisible(H) then    begin      GetWindowRect(H, R);      TmpRgn := CreateRectRgnIndirect(R);// currently examined window region      RType := CombineRgn(Rgn, Rgn, TmpRgn, RGN_DIFF); // diff intersect      DeleteObject( TmpRgn );    end;    if RType <> NULLREGION then // there's a remaining portion      H := GetNextWindow(H, GW_HWNDNEXT);  end;  DeleteObject(Rgn);  Result := RType = NULLREGION;end;{  Associates a given file extension with an application in the windows registry.     example:  RegisterFileType('log','c:\MyLogViewer.exe') ;}procedure RegisterFileType(const AExtension: string; const AAppPath: string);var  R: TRegistry;begin  R := TRegistry.Create;  try    R.RootKey:= HKEY_CLASSES_ROOT;    R.OpenKey('.' + AExtension, True);    R.WriteString('', AExtension + 'file');    R.CloseKey;    R.CreateKey(AExtension + 'file') ;    R.OpenKey(AExtension + 'file\DefaultIcon', True);    R.WriteString('', AAppPath + ',0');    R.CloseKey;    R.OpenKey(AExtension + 'file\shell\open\command', True);    R.WriteString('',AAppPath+' "%1"');    R.CloseKey;  finally    R.Free;  end;  SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);end;{$ENDIF}function SetToString(ATypeInfo: PTypeInfo; const AValue;  AQuoteValues: Boolean = True; ABrackets: Boolean = True;  ATrimChars: Integer = -1): string;var  S    : TIntegerSet;  I    : Integer;  N    : Integer;  Name : string;  function GetOrdValue(Info: PTypeInfo; const SetParam): Integer;  begin    Result := 0;    case GetTypeData(Info)^.OrdType of      otSByte, otUByte:        Result := Byte(SetParam);      otSWord, otUWord:        Result := Word(SetParam);      otSLong, otULong:        Result := Integer(SetParam);    end;  end;  function GetPrefixLength(const AString: string): Integer;  var    C: Char;    N: Integer;  begin    N := 0;    if Length(AString) > 0 then    begin      C := AString[1];      while (N < Length(AString)) and TCharacter.IsLower(C) do      begin        Inc(N);        C := AString[N + 1];      end;    end;    Result := N;  end;begin  Result := '';  Integer(S) := GetOrdValue(ATypeInfo, AValue);  ATypeInfo := GetTypeData(ATypeInfo)^.CompType;  for I := 0 to SizeOf(Integer) * 8 - 1 do  begin    if I in S then    begin      if Result <> '' then        Result := Result + ',';      Name := GetEnumName(ATypeInfo, I);      if ATrimChars >= 0 then        N := ATrimChars      else        N := GetPrefixLength(Name);      if N > 0 then        Name := Copy(Name, N + 1, Length(Name) - N + 1);      if AQuoteValues then        Name := QuotedStr(Name);      Result := Result + Name;    end;  end;  if ABrackets and (Result <> '') then    Result := '(' + Result + ')';end;{ Sets the Checked property of a TCheckbox without firing the OnClick event.  If the checkbox is linked to an action, be sure to enable the AutoCheck  property. } procedure SetCheckedState(ACheckBox : TCheckBox; ACheck : Boolean); var   EH : TNotifyEvent;   AH : TNotifyEvent; begin   EH := ACheckBox.OnClick;   if Assigned(ACheckBox.Action) then   begin     AH := ACheckBox.Action.OnExecute;     ACheckBox.Action.OnExecute := nil;   end;   ACheckBox.OnClick := nil;   ACheckBox.Checked := ACheck;   if Assigned(ACheckBox.Action) then   begin     (ACheckBox.Action as TAction).Checked := ACheckBox.Checked;     ACheckBox.Action.OnExecute := AH;   end;   ACheckBox.OnClick := EH; end; {$IFDEF Windows}function TaskBarHeight: Integer;var  hTB    : HWND; // taskbar handle  TBRect : TRect; // taskbar rectanglebegin  hTB:= FindWindow('Shell_TrayWnd', '');  if hTB = 0 then    Result := 0  else  begin    GetWindowRect(hTB, TBRect);    Result := TBRect.Bottom - TBRect.Top;  end;end;{$ENDIF}end.
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
我对DELPHI写的几个基类型
早些时候写的一个Delphi中的串口通读类.
Delphi常用的函数库
Delphi 关键字详解[整理于 "橙子" 的帖子]
Dokan虚拟磁盘开发实战
delphi基础开发技巧
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服