我的公共函数单元(二)(Delphi)

{
  This unit was generated on Sun, 10 Dec 2006 09:45:52 +0000
  by the code snippets database at www.delphidabbler.com.
  Check the site for updates.

  The unit is freeware and may be freely distributed providing
  only that this comment is left in the code.
}

unit  DDSnippets ;

interface

uses
   Windows ,  SysUtils ,  ShellAPI ,  Classes ,  IniFiles ,  Graphics ,  UrlMon ,  Nb30 ,
   ShlObj ,  ActiveX ,  Registry ;

function  DateTimeToWinFileTime ( DT :  TDateTime ):  Windows . TFileTime ;
{Converts Delphi TDateTime to Windows FILETIME. Raises exception if date time
is not valid or can't be converted.}

function  GMTToLocalTime ( GMTTime :  TDateTime ):  TDateTime ;
{Converts Delphi TDateTime in GMT local time. Raises exception if date time is
not valid or can't be converted.}

function  WinFileTimeToDateTime ( FT :  Windows . TFileTime ):  TDateTime ;
{Converts Windows FILETIME to Delphi TDateTime. Raises exception if file time
is valid or can't be converted.}

function  WinFileTimeToDOSFileTime ( FT :  Windows . TFileTime ):  Integer ;
{Converts a Windows FILETIME to a DOS file time. Raises exception if file time
is not a valid value.}

function  WinFileTimeToStr ( FT :  Windows . TFileTime ):  string ;
{Converts a Windows FILETIME structure to a string. Raises exception if file
time is not a valid value.}

function  DriveDisplayName ( const  Drive :  string ):  string ;
{Returns the display name for the drive with the given root path.}

procedure  DriveDisplayNames ( const  List :  Classes . TStrings );
{Gets list of display names for all the system's drives and stores in a given
string list.}

function  DriveRootPath ( const  DriveNum :  Byte ):  string ;
{Returns root drive path for drive with given number.}

function  DriveTypeFromPath ( const  Path :  string ):  Integer ;
{Returns type of drive that contains the given (full) path.}

function  HardDiskSerial ( const  Drive :  string ):  Windows . DWORD ;
{Returns the serial number of the hard disk with the given root path or 0 if
the disk is not a hard drive or has no serial number.}

function  IsValidDrive ( const  Drive :  string ):  Boolean ;
{Returns true if the given drive path represents a valid drive and false
otherwise.}

function  IsValidDriveNum ( const  DriveNum :  Byte ):  Boolean ;
{Returns true if the drive specified by the given number is valid and false
otherwise.}

procedure  ListDrives ( const  List :  Classes . TStrings );
{Gets list of the system's drive root paths and stores in a given string list}

function  FileToString ( const  FileName :  string ):  string ;
{Stores content of a file in an ANSI string.}

function  IsUnicodeFile ( const  FileName :  string ):  Boolean ;
{Checks if a file contains unicode text and returns true if so and false if
not.}

function  IsUnicodeStream ( const  Stm :  Classes . TStream ):  Boolean ;
{Checks if a stream contains unicode text at the current position. Returns
true if stream contains unicode and false otherwise.}

function  StreamToString ( const  Stm :  Classes . TStream ):  string ;
{Reads content of a stream into an ansi string. Stream is read from current
positions.}

procedure  StringToFile ( const  Str ,  FileName :  string );
{Writes an ansi string to a text file.}

procedure  StringToStream ( const  Str :  string ;  const  Stm :  Classes . TStream );
{Writes an ansi string into a stream. The string is written at the current
stream position.}

function  UnicodeFileToWideString ( const  FileName :  string ):  WideString ;
{Reads a file into a wide string an returns it. The routine can handle unicode
files or ansi text files. Ansi files are converted to wide strings.}

function  UnicodeStreamToWideString ( const  Stm :  Classes . TStream ):  WideString ;
{Reads from a stream into a wide string an returns the string. The routine can
handle unicode or ansi content on the stream. If the text is unicode the word
at the current stream position must be a unicode marker word. Ansi files are
converted to wide strings.}

procedure  WideStringToUnicodeFile ( const  Str :  WideString ;
   const  FileName :  string );
{Writes a wide string to a unicode text file. The text file begins with a
marker to indicate it is unicode.}

procedure  WideStringToUnicodeStream ( const  Str :  WideString ;
   const  Stm :  Classes . TStream );
{Writes a wide string to a stream in unicode format. The output begins with a
marker to indicate it is unicode.}

procedure  CopyFile ( const  Source ,  Dest :  string );
{Copies Source file to Dest, preserving modification date.}

procedure  CreateURLShortcut ( const  ShortcutFile ,  URL :  string );
{Creates a URL shortcut file with the given name for the given URL,
overwriting any existing file. An exception is raised if file can't be
created.}

function  DeleteFiles ( const  Dir ,  Wildcard :  string ):  Integer ;
{Deletes all files in the directory Dir that match the given wildcard and
returns the number of files deleted. If Wildcard is '' then all files are
deleted. Sub-directories of Dir are not deleted.}

function  DeleteFileWithUndo ( const  FileName :  string ):  Boolean ;
{Deletes given file and sends it to recycle bin. Returns true if file deleted
successfully.}

function  DirToPath ( const  Dir :  string ):  string ;
{Returns the given directory with a trailing backslash. If the directory
already ends in backslash it is returned unchanged.}

function  DOSToUnixPath ( const  PathName :  string ):  string ;
{Converts a DOS path to a Unix path and returns it.}

procedure  EnsureFolders ( Path :  string );
{Ensures that the given folder and all folders on its path exist, and creates
them if they do not. Uses recursion.}

function  GetFileDate ( const  FName :  string ):  Integer ;
{Returns modification date of given file encoded as integer.}

function  GetFixedFileVerInfo ( const  FileName :  string ;
   var  FFI :  Windows . TVSFixedFileInfo ):  Boolean ;
{Extracts fixed version information from a file. If file contains version
information it is returned via FFI parameter and function returns true,
otherwise false is returned and FFI is undefined.}

function  HasVerInfo ( const  FileName :  string ):  Boolean ;
{Returns true if the given file contains version information and false if
not.}

function  IsDirectory ( const  DirName :  string ):  Boolean ;
{Returns true if given name is a valid directory and false otherwise. DirName
can be any file system name (with or without trailing path delimiter).}

function  IsURLShortcut ( const  ShortcutFile :  string ):  Boolean ;
{Returns true if the given file is a URL shortcut file and false if not.}

function  ListFiles ( const  Dir ,  Wildcard :  string ;
   const  List :  Classes . TStrings ):  Boolean ;
{Gets a list of the files and sub-directories of the given directory that
match the given wild card. The files are appended to the given string list.
Returns true if Dir is a valid directory and False if not. If Wildcard is not
specified, *.* is assumed.}

function  LongToShortFilePath ( const  LongName :  string ):  string ;
{Converts the given long file name to the equivalent shortened DOS style 8.3
path.}

function  PathToDir ( const  Path :  string ):  string ;
{Returns the given directory with any single trailing backslash removed. If
the directory does not end in a backslash it is returned unchanged.}

procedure  SetFileDate ( const  FName :  string ;  const  ADate :  Integer );
{Sets modification date of given file to given integer coded value.}

function  ShortToLongFilePath ( const  FilePath :  string ):  string ;
{Converts whole of given DOS style 8.3 path to long file path and returns it.
If path can't be converted then '' is returned.}

function  TempFileName ( const  Stub :  string ;  const  Create :  Boolean ):  string ;
{Returns a unique temporary file name in temporary folder. File name includes
first three characters of Stub followed by hexadecimal characters. If Create
is true file is created. Returns empty string on failure.}

function  Touch ( const  FileName :  string ):  Boolean ;
{Sets modification date of given file to current date and time. Returns true
if date set successfully or false on error.}

function  URLFromShortcut ( const  Shortcut :  string ):  string ;
{Returns the URL referenced by the given URL shortcut file, or the empty
string if the given file is not a shortcut file.}

function  ColorToRGBTriple ( const  C :  Graphics . TColor ):  Windows . TRGBTriple ;
{Converts a Delphi TColor value into an RGB triple value.}

procedure  DrawTextOutline ( const  Canvas :  Graphics . TCanvas ;  const  X ,  Y :  Integer ;
   const  Text :  string );
{Draws specified text in outline on a canvas. The top left corner of the text
is specified by X and Y parameters. Canvas' current brush and pen colours are
used to fill and outline the text respectively. If the canvas' current font is
not a vector font nothing is displayed.}

procedure  MakeGreyScale ( const  SrcBmp :  Graphics . TBitmap ;
   const  Advanced :  Boolean );
{Converts a colour bitmap into a 24bit greyscale bitmap. Setting the Advanced
flag to true uses a more advanced algorithm for the conversion. When the flag
is false red, blue and green values are simply averaged. The provided colour
bitmap is overwritten by the greyscale bitmap.}

function  RGBTripleToColor ( const  C :  Windows . TRGBTriple ):  Graphics . TColor ;
{Converts an RGB triple value into a Delphi TColor value.}

function  BrowseURL ( const  URL :  string ):  Boolean ;
{Activates default browser or email client for given URL. Returns true if
browser/email client is uccessfully launched and false if not. Raises
exception if URL doesn't conform to a known valid protocol.}

function  ColorToHTML ( const  Color :  Graphics . TColor ):  string ;
{Converts a Delphi TColor value into a string suitable for use in HTML or CSS
code. Any system colors (like clBtnFace) are mapped to the actual colour
according to the current Windows settings.}

function  DownloadURLToFile ( const  URL ,  FileName :  string ):  Boolean ;
{Downloads file at URL and stores in given file. Returns true if download
succeeds and false on failure. A connection to the internet must be open for
download to succeed.}

function  IsValidURLProtocol ( const  URL :  string ):  Boolean ;
{Checks if the given URL is valid per RFC1738. Returns true is valid and false
if not.}

function  MakeSafeHTMLText ( TheText :  string ):  string ;
{Replaces any characters in the given text that are HTML-compatible with
suitable escaped versions and returns modified string.}

function  URLDecode ( const  S :  string ):  string ;
{Decodes the given encoded URL or URL query string. Raises exception if the
encoded URL is badly formed.}

function  URLEncode ( const  S :  string ;  const  InQueryString :  Boolean ):  string ;
{Encodes the given string, making it suitable for use in a URL. The function
can encode strings for use in the main part of a URL (where spaces are
encoded as '%20') or in URL query strings (where spaces are encoded as '+'
characters). Set InQueryString to true to encode for a query string.}

function  CompressWhiteSpace ( const  S :  string ):  string ;
{Returns a copy of given string with all white space characters replaced by
space characters and all sequences of white space replaced by a single space
character.}

function  CountDelims ( const  S ,  Delims :  string ):  Integer ;
{Returns count of all occurences of any of the given delimiter characters in
the string S.}

function  ExplodeStr ( S :  string ;  const  Delim :  Char ;  const  List :  Classes . TStrings ;
   const  AllowEmpty :  Boolean  =  True ):  Integer ;
{Splits the string S into a list of strings, separated by Delim, and returns
the number of strings in the list. If AllowEmpty is true then any empty
strings are added to the list, while they are ignored if AllowEmpty is
false.}

function  IsHexStr ( const  S :  string ):  Boolean ;
{Returns true if string S contains only valid hex digits, false otherwise.}

function  JoinStr ( const  SL :  Classes . TStrings ;  const  Delim :  string ;
   const  AllowEmpty :  Boolean  =  True ):  string ;
{Joins all strings in given string list together into single string separated
by given delimiter. If AllowEmpty is true then any empty strings are included
in output string, but are ignored if false.}

procedure  MultiSzToStrings ( const  MultiSz :  PChar ;
   const  Strings :  Classes . TStrings );
{Splits out individual strings from given 'MultiSz' strings buffer and adds
each string to the given string list. A MultiSz string is a sequence of #0
delimited strings terminated by an extra #0 character. Does nothing if string
list or MultiSz buffer are nil.}

function  ParseDelims ( const  TextLine :  string ;  var  StartPos :  Integer ;
   const  Delims :  string ):  string ;
{Returns the sub-string of TextLine that begins at StartPos and is terminated
by one of the delimiting characters Delims or the end of the string. StartPos
is updated to index of character after delimiter. Returns '' if there is no
sub-string after StartPos.}

function  SplitStr ( const  S :  string ;  Delim :  Char ;  out  S1 ,  S2 :  string ):  Boolean ;
{Splits the string S at the first occurence of delimiter character Delim and
sets S1 to the sub-string before Delim and S2 to substring following Delim.
If Delim is found in string True is returned, while if Delim is not in string
False is returned, S1 is set to S and S2 is set to ''.}

function  StringsToMutliSz ( const  Strings :  Classes . TStrings ;
   const  MultiSz :  PChar ;  const  BufSize :  Integer ):  Integer ;
{Copies the strings from a given string list and stores in a provided MulitiSz
buffer of a given size. The strings in the buffer are separated by #0 and the
buffer is terminated by an additional #0. Returns 0 on success or required
buffer size if MultiSz is nil or buffer size is too small. To get required
buffer size call function with MultiSz=nil and BufSize=0.}

function  GetMacAddress :  string ;
{Returns MAC address of first ethernet adapter on computer.}

function  IsLockKeyOn ( const  KeyCode :  Integer ):  Boolean ;
{Detects if a given lock key is on and returns true if so. An exception is
raised if KeyCode is not a valid lock key code. Valid lock key codes are
VK_CAPITAL, VK_NUMLOCK and VK_SCROLL.}

procedure  SetLockKeyState ( KeyCode :  Integer ;  IsOn :  Boolean );
{Sets the given lock key state to given value. Passing True switches lock key
on and passing False switches it off. An exception is raised if KeyCode is
not a valid lock key code. Valid lock key codes are VK_CAPITAL, VK_NUMLOCK
and VK_SCROLL.}

procedure  AddToRecentDocs ( const  FileName :  string );
{Adds given file to Recent Documents folder that appears on the Start menu.}

procedure  ClearRecentDocs ;
{Clears the Recent Documents folder so that no recent documents appear on
Start menu.}

function  CreateShellLink ( const  LinkFileName ,  AssocFileName ,  Desc ,  WorkDir ,
   Args ,  IconFileName :  string ;  const  IconIdx :  Integer ):  Boolean ;
{Creates a shell link named LinkFileName that is a shortcut to file
AssocFileName with descriprion Desc. The shortcut activates its file in the
given working directory and passes the given command line Args to
AssocFileName. If an icon file and index offset are provided the specified
icon is used for the shortcut. True is returned on success and false on
error.}

function  EmptyRecycleBin :  Boolean ;
{Empties the recycle bin. Returns returns true if bin is emptied and false if
the function fails.}

function  ExecAndWait ( const  CommandLine :  string ):  Boolean ;
{Executes the given command line and waits for the program started by the
command line to exit. Returns true if the program returns a zero exit code
and false if the program doesn't start or returns a non-zero error code.}

function  ExecAssociatedApp ( const  FileName :  string ):  Boolean ;
{Executes the application associated with the given file name. Returns true if
application is started successfully and false if not.}

function  ExploreFile ( const  Filename :  string ):  Boolean ;
{Starts Windows Explorer to explore given file. Returns true if file is valid
and can be explored, or false otherwise.}

function  ExploreFolder ( const  Folder :  string ):  Boolean ;
{Starts Windows Explorer to explore given folder. Returns true if folder is
valid and can be explored, or false otherwise.}

function  FileFromShellLink ( const  LinkFileName :  string ):  string ;
{Returns the fully specified name of the file associated with the given shell
link (shortcut) file. Returns '' if the file is not a shell link or if it is
a shortcut to a non-file shell object.}

function  FindAssociatedApp ( const  Doc :  string ):  string ;
{Returns the fully specified path of the program associated with the given
document file name. Requires ShellAPI. Returns empty string if no such
associated application.}

procedure  FreePIDL ( PIDL :  ShlObj . PItemIDList );
{Uses to shell allocator to free the memory used by a given PIDL.}

function  IsShellLink ( const  LinkFileName :  string ):  Boolean ;
{Checks if the given file is a shell link.}

function  IsSpecialFolderSupported ( CSIDL :  Integer ):  Boolean ;
{Returns true if the given special folder specified by a CSIDL is supported on
the system and false if not.}

function  LoadShellLink ( const  LinkFileName :  string ):  ShlObj . IShellLink ;
{Loads a shell link file into a shell link object and returns the IShellLink
interface of the object. If the given file is not a shell link nil is
returned. The returned object can be used to access information about the
shell link.}

function  OpenFolder ( const  Folder :  string ):  Boolean ;
{Opens given folder in Windows Explorer. Returns true if folder is valid and
can be opened, or false otherwise.}

function  PIDLToFolderPath ( PIDL :  ShlObj . PItemIDList ):  string ;
{Returns the full path to a file system folder from a PIDL or '' if the PIDL
refers to a virtual folder.}

function  ShowFindFilesDlg ( const  Folder :  string ):  Boolean ;
{Displays the Windows find files dialog box ready for searching the given
folder. Returns true if dialog is shown and false if can't be shown (e.g. if
given folder is not valid).}

function  SpecialFolderPath ( CSIDL :  Integer ):  string ;
{Returns the full path to a special file system folder specified by a CSIDL
constant FolderID or '' if the special folder is virtual or CSIDL is not
supported.}

function  TaskAllocWideString ( const  S :  string ):  Windows . PWChar ;
{Converts a given ANSI string to a wide string and stores in a buffer
allocated by the Shell's task allocator. If the buffer needs to be freed
IMalloc.Free should be used to do this.}

function  TaskbarHandle :  Windows . THandle ;
{Returns the window handle of the Windows task bar.}

function  CommonFilesFolder :  string ;
{Returns directory used for common files.}

function  GetCurrentVersionRegStr ( const  ValName :  string ):  string ;
{Gets given string value from given subkey of Windows current version registry
key.}

function  GetRegistryString ( const  RootKey :  Windows . HKEY ;
   const  SubKey ,  Name :  string ):  string ;
{Gets a string value from the registry from the given root and sub key.
Converts integers to strings and raises exception for binary and unknown
value types. Returns '' if the sub key or value name are not known.}

function  IsIntResource ( const  ResID :  PChar ):  Boolean ;
{Returns true if the given resource ID is integer value or false if the ID is
a pointer to a zero terminated string.}

function  IsMediaCenterOS :  Boolean ;
{Returns true if the operating system is a Windows Media Center edition or
false if not.}

function  IsTabletOS :  Boolean ;
{Returns true if the operating system is a Windows Tablet edition or false if
not.}

function  IsWin9x :  Boolean ;
{Returns true if the operating system is on the Windows 9x platform (including
Windows 95, 98 and Me) and false if not.}

function  IsWinNT :  Boolean ;
{Returns true if the operating system is Windows NT (including 2000 and XP)
and false if not.}

function  IsWow64 :  Boolean ;
{Returns true if the current process is executing as a 32 bit process under
WOW64 on 64 bit Windows.}

function  ProgramFilesFolder :  string ;
{Returns directory used for program files.}

function  SystemFolder :  string ;
{Returns path to Windows system folder.}

function  TempFolder :  string ;
{Returns path to Windows temporary folder.}

function  WindowsFolder :  string ;
{Returns path to Windows folder.}

function  WindowsProductID :  string ;
{Returns the Windows product ID.}

implementation

{ Implementation of public and private routines }

function  DateTimeToWinFileTime ( DT :  TDateTime ):  Windows . TFileTime ;
{Converts Delphi TDateTime to Windows FILETIME. Raises exception if date time
is not valid or can't be converted.}
var
   ST :  Windows . TSystemTime ;
begin
   SysUtils . DateTimeToSystemTime ( DT ,  ST );
   SysUtils . Win32Check ( Windows . SystemTimeToFileTime ( ST ,  Result ));
end ;

function  GMTToLocalTime ( GMTTime :  TDateTime ):  TDateTime ;
{Converts Delphi TDateTime in GMT local time. Raises exception if date time is
not valid or can't be converted.}
var
   GMTST :  Windows . TSystemTime ;
   LocalST :  Windows . TSystemTime ;
begin
   SysUtils . DateTimeToSystemTime ( GMTTime ,  GMTST );
   SysUtils . Win32Check (
     Windows . SystemTimeToTzSpecificLocalTime (
     nil ,  GMTST ,  LocalST
     )
     );
   Result  :=  SysUtils . SystemTimeToDateTime ( LocalST );
end ;

function  WinFileTimeToDateTime ( FT :  Windows . TFileTime ):  TDateTime ;
{Converts Windows FILETIME to Delphi TDateTime. Raises exception if file time
is valid or can't be converted.}
var
   SysTime :  Windows . TSystemTime ;          // stores date/time in system time format
begin
   // Convert file time to system time, raising exception on error
   SysUtils . Win32Check ( Windows . FileTimeToSystemTime ( FT ,  SysTime ));
   // Convert system time to Delphi date time, raising excpetion on error
   Result  :=  SysUtils . SystemTimeToDateTime ( SysTime );
end ;

function  WinFileTimeToDOSFileTime ( FT :  Windows . TFileTime ):  Integer ;
{Converts a Windows FILETIME to a DOS file time. Raises exception if file time
is not a valid value.}
begin
   SysUtils . Win32Check (
     Windows . FileTimeToDosDateTime (
     FT ,  SysUtils . LongRec ( Result ). Hi ,  SysUtils . LongRec ( Result ). Lo
     )
     );
end ;

function  WinFileTimeToStr ( FT :  Windows . TFileTime ):  string ;
{Converts a Windows FILETIME structure to a string. Raises exception if file
time is not a valid value.}
begin
   Result  :=  SysUtils . DateTimeToStr ( WinFileTimeToDateTime ( FT ));
end ;

function  DriveDisplayName ( const  Drive :  string ):  string ;
{Returns the display name for the drive with the given root path.}
var
   FI :  ShellAPI . TSHFileInfo ;              // info about drive
begin
   if  ShellAPI . SHGetFileInfo (
     PChar ( Drive ),
     0 ,
     FI ,
     SizeOf ( FI ),
     ShellAPI . SHGFI_DISPLAYNAME
     )  =  0  then
     SysUtils . RaiseLastWin32Error ;
   Result  :=  FI . szDisplayName ;
end ;

procedure  DriveDisplayNames ( const  List :  Classes . TStrings );
{Gets list of display names for all the system's drives and stores in a given
string list.}
var
   Drives :  Classes . TStringList ;           // list of drives
   Idx :  Integer ;                          // loops thru drives
begin
   // Get list of drives
   Drives  :=  Classes . TStringList . Create ;
   try
     ListDrives ( Drives );
     // Loop thru drive list getting drive info
     for  Idx  :=  0  to  Pred ( Drives . Count )  do
       List . Add ( DriveDisplayName ( Drives [ Idx ]));
   finally
     Drives . Free ;
   end ;
end ;

function  DriveRootPath ( const  DriveNum :  Byte ):  string ;
{Returns root drive path for drive with given number.}
begin
   if  DriveNum  in  [ 0..25 ]  then
     Result  :=  Char ( DriveNum  +  Ord ( 'A' ))  +  ':/'
   else
     Result  :=  '' ;
end ;

function  DriveTypeFromPath ( const  Path :  string ):  Integer ;
{Returns type of drive that contains the given (full) path.}
var
   Drive :  string ;                         // the drive name
begin
   Drive  :=  SysUtils . ExtractFileDrive ( Path )  +  '/' ;
   Result  :=  Integer ( Windows . GetDriveType ( PChar ( Drive )));
end ;

function  HardDiskSerial ( const  Drive :  string ):  Windows . DWORD ;
{Returns the serial number of the hard disk with the given root path or 0 if
the disk is not a hard drive or has no serial number.}
var
   Unused :  Windows . DWORD ;                 // unused parameters
   PrevErrorMode :  Windows . UINT ;           // stores Windows error mode
begin
   // Inhibit system dialog appearing on error
   PrevErrorMode  :=  Windows . SetErrorMode (
     Windows . SEM_FAILCRITICALERRORS
     );
   try
     Result  :=  0 ;
     Windows . GetVolumeInformation (
       PChar ( Drive ),  nil ,  0 ,  @ Result ,  Unused ,  Unused ,  nil ,  0
       );
   finally
     // Restore old error mode
     Windows . SetErrorMode ( PrevErrorMode );
   end ;
end ;

function  IsValidDrive ( const  Drive :  string ):  Boolean ;
{Returns true if the given drive path represents a valid drive and false
otherwise.}
begin
   Result  :=  DriveTypeFromPath ( Drive )  <>  1 ;
end ;

function  IsValidDriveNum ( const  DriveNum :  Byte ):  Boolean ;
{Returns true if the drive specified by the given number is valid and false
otherwise.}
begin
   if  DriveNum  in  [ 0..25 ]  then
     Result  :=  Windows . GetLogicalDrives  and  ( 1  shl  DriveNum )  <>  0
   else
     Result  :=  False ;
end ;

procedure  ListDrives ( const  List :  Classes . TStrings );
{Gets list of the system's drive root paths and stores in a given string list}
var
   Drives :  PChar ;                         // buffer for list of drives
   BufSize :  Integer ;                      // size of drive buffer
begin
   // Get buffer size and allocate it
   BufSize  :=  Windows . GetLogicalDriveStrings ( 0 ,  nil );
   GetMem ( Drives ,  BufSize );
   try
     // Get #0 delimited drives list and convert to string list
     if  Windows . GetLogicalDriveStrings ( BufSize ,  Drives )  =  0  then
       SysUtils . RaiseLastWin32Error ;
     MultiSzToStrings ( Drives ,  List );
   finally
     FreeMem ( Drives );
   end ;
end ;

function  FileToString ( const  FileName :  string ):  string ;
{Stores content of a file in an ANSI string.}
var
   FS :  Classes . TFileStream ;               // stream used to read file
begin
   // Open stream to file and copy stream to string
   FS  :=  Classes . TFileStream . Create (
     FileName ,  SysUtils . fmOpenRead  or  SysUtils . fmShareDenyNone
     );
   try
     Result  :=  StreamToString ( FS );
   finally
     FS . Free ;
   end ;
end ;

function  IsUnicodeFile ( const  FileName :  string ):  Boolean ;
{Checks if a file contains unicode text and returns true if so and false if
not.}
var
   FS :  Classes . TFileStream ;               // stream onto file being tested
begin
   // Open stream to file and examine stream for unicode marker
   FS  :=  Classes . TFileStream . Create (
     FileName ,  SysUtils . fmOpenRead  or  SysUtils . fmShareDenyNone
     );
   try
     Result  :=  IsUnicodeStream ( FS );
   finally
     FS . Free ;
   end ;
end ;

function  IsUnicodeStream ( const  Stm :  Classes . TStream ):  Boolean ;
{Checks if a stream contains unicode text at the current position. Returns
true if stream contains unicode and false otherwise.}
var
   StmPos :  LongInt ;                       // current position in stream
   UnicodeMarker :  Word ;                   // marker that indicates a unicode stream
begin
   // Record current location in stream
   StmPos  :=  Stm . Position ;
   // Check if stream large enough to contain unicode marker
   if  StmPos  <=  Stm . Size  -  SizeOf ( Word )  then
   begin
     // Read first word and check if it is the unicode marker
     Stm . ReadBuffer ( UnicodeMarker ,  SizeOf ( UnicodeMarker ));
     Result  :=  ( UnicodeMarker  =  $FEFF );
     // Restore stream positions
     Stm . Position  :=  StmPos ;
   end
   else
     // Stream too small: can't be unicode
     Result  :=  False ;
end ;

function  StreamToString ( const  Stm :  Classes . TStream ):  string ;
{Reads content of a stream into an ansi string. Stream is read from current
positions.}
var
   SS :  Classes . TStringStream ;             // used to copy stream to string
begin
   SS  :=  Classes . TStringStream . Create ( '' );
   try
     // Copy given stream to string stream and return value
     SS . CopyFrom ( Stm ,  0 );
     Result  :=  SS . DataString ;
   finally
     SS . Free ;
   end ;
end ;

procedure  StringToFile ( const  Str ,  FileName :  string );
{Writes an ansi string to a text file.}
var
   FS :  Classes . TFileStream ;               // stream used to write file
begin
   // Create stream onto file and write to it
   FS  :=  Classes . TFileStream . Create ( FileName ,  Classes . fmCreate );
   try
     StringToStream ( Str ,  FS );
   finally
     FS . Free ;
   end ;
end ;

procedure  StringToStream ( const  Str :  string ;  const  Stm :  Classes . TStream );
{Writes an ansi string into a stream. The string is written at the current
stream position.}
var
   SS :  Classes . TStringStream ;             // used to copy string to stream
begin
   // Create stream onto string and copy it to given stream
   SS  :=  Classes . TStringStream . Create ( Str );
   try
     Stm . CopyFrom ( SS ,  Length ( Str ));
   finally
     SS . Free ;
   end ;
end ;

function  UnicodeFileToWideString ( const  FileName :  string ):  WideString ;
{Reads a file into a wide string an returns it. The routine can handle unicode
files or ansi text files. Ansi files are converted to wide strings.}
var
   FS :  Classes . TFileStream ;               // Stream used to read file
begin
   // Open stream onto file and read unicode from it
   FS  :=  Classes . TFileStream . Create (
     FileName ,  SysUtils . fmOpenRead  or  SysUtils . fmShareDenyNone );
   try
     Result  :=  UnicodeStreamToWideString ( FS );
   finally
     FS . Free ;
   end ;
end ;

function  UnicodeStreamToWideString ( const  Stm :  Classes . TStream ):  WideString ;
{Reads from a stream into a wide string an returns the string. The routine can
handle unicode or ansi content on the stream. If the text is unicode the word
at the current stream position must be a unicode marker word. Ansi files are
converted to wide strings.}
var
   DataSize :  LongInt ;                     // size of the unicode in bytes
begin
   if  IsUnicodeStream ( Stm )  then
   begin
     // Data on stream is unicode
     // set size of unicode (excluding marker word)
     DataSize  :=  Stm . Size  -  Stm . Position  -  SizeOf ( Word );
     // size must be multiple of size of unicode char
     if  DataSize  mod  SizeOf ( WideChar )  <>  0  then
       Classes . EStreamError . CreateFmt (
         'Remaining data in stream must be a mulitple of %d bytes' ,
         [ SizeOf ( WideChar )]
         );
     // Skip over unicode marker
     Stm . Position  :=  Stm . Position  +  SizeOf ( Word );
     // Read stream into result
     SetLength ( Result ,  DataSize  div  SizeOf ( WideChar ));
     Stm . ReadBuffer ( Windows . PByte ( PWideChar ( Result ))^,  DataSize );
   end
   else
     // Data on stream is not unicode: read it with ansi reader
     // result of StreamToString is automatically converted to WideString
     Result  :=  StreamToString ( Stm );
end ;

procedure  WideStringToUnicodeFile ( const  Str :  WideString ;
   const  FileName :  string );
{Writes a wide string to a unicode text file. The text file begins with a
marker to indicate it is unicode.}
var
   FS :  Classes . TFileStream ;               // Stream onto file being created
begin
   // Open stream onto file and write unicode to it
   FS  :=  Classes . TFileStream . Create ( FileName ,  Classes . fmCreate );
   try
     WideStringToUnicodeStream ( Str ,  FS );
   finally
     FS . Free ;
   end ;
end ;

procedure  WideStringToUnicodeStream ( const  Str :  WideString ;
   const  Stm :  Classes . TStream );
{Writes a wide string to a stream in unicode format. The output begins with a
marker to indicate it is unicode.}
var
   UnicodeMarker :  Word ;                   // Marker that begins unicode
begin
   // Write out unicode marker
   UnicodeMarker  :=  $FEFF ;
   Stm . WriteBuffer ( UnicodeMarker ,  SizeOf ( Word ));
   // Write unicode text
   Stm . WriteBuffer (
     Windows . PByte ( PWideChar ( Str ))^,  SizeOf ( WideChar )  *  Length ( Str )
     );
end ;

procedure  CopyFile ( const  Source ,  Dest :  string );
{Copies Source file to Dest, preserving modification date.}
var
   SourceStream ,  DestStream :  Classes . TFileStream ;  // source and dest file streams
begin
   DestStream  :=  nil ;
   // Open source and dest file streams
   SourceStream  :=  Classes . TFileStream . Create (
     Source ,  SysUtils . fmOpenRead  or  SysUtils . fmShareDenyWrite
     );
   try
     DestStream  :=  Classes . TFileStream . Create (
       Dest ,  Classes . fmCreate  or  SysUtils . fmShareExclusive
       );
     // Copy file from source to dest
     DestStream . CopyFrom ( SourceStream ,  SourceStream . Size );
     // Set dest file's modification date to same as source file
     SysUtils . FileSetDate (
       DestStream . Handle ,  SysUtils . FileGetDate ( SourceStream . Handle )
       );
   finally
     // Close files
     DestStream . Free ;
     SourceStream . Free ;
   end ;
end ;

procedure  CreateURLShortcut ( const  ShortcutFile ,  URL :  string );
{Creates a URL shortcut file with the given name for the given URL,
overwriting any existing file. An exception is raised if file can't be
created.}
var
   F :  TextFile ;                           // text file
begin
{$I+}                                    // ensure file i/o raises exception on error
   // Open new file for writing (overwrites any existing file)
   AssignFile ( F ,  ShortcutFile );
   Rewrite ( F );
   try
     // Write file contents: this is simplest basic format of shortcut file
     WriteLn ( F ,  '[InternetShortcut]' );
     WriteLn ( F ,  'URL=' ,  URL );
   finally
     // Close file
     CloseFile ( F );
   end ;
end ;

function  DeleteFiles ( const  Dir ,  Wildcard :  string ):  Integer ;
{Deletes all files in the directory Dir that match the given wildcard and
returns the number of files deleted. If Wildcard is '' then all files are
deleted. Sub-directories of Dir are not deleted.}
var
   Files :  Classes . TStringList ;            // stores files to be deleted
   I :  Integer ;                            // loops thru files in folder
   AFile :  string ;                         // a file to be deleted
   Path :  string ;                          // path to directory
   Attr :  Integer ;                         // attributes of a file
begin
   Result  :=  0 ;
   // Create list to stores files to be deleted
   Files  :=  Classes . TStringList . Create ;
   try
     // List files per file spec into string list
     if  not  ListFiles ( Dir ,  Wildcard ,  Files )  then
       Exit ;
     // Get path of directory containing files
     Path  :=  DirToPath ( Dir );
     // Loop through all files
     for  I  :=  0  to  Pred ( Files . Count )  do
     begin
       // Get name and attributes of file to be deleted
       AFile  :=  Path  +  Files [ I ];
       Attr  :=  SysUtils . FileGetAttr ( AFile );
       // Delete file if it is not a directory
       if  ( Attr  and  SysUtils . faDirectory  =  0 )  then
       begin
         if  SysUtils . DeleteFile ( AFile )  then
           // File deleted: count it
           Inc ( Result );
       end ;
     end ;
   finally
     // Tidy up
     Files . Free ;
   end ;
end ;

function  DeleteFileWithUndo ( const  FileName :  string ):  Boolean ;
{Deletes given file and sends it to recycle bin. Returns true if file deleted
successfully.}
var
   FOS :  ShellAPI . TSHFileOpStruct ;         // contains info about required file operation
begin
   // Set up structure that determines file operation
   FillChar ( FOS ,  SizeOf ( FOS ),  0 );
   with  FOS  do
   begin
     wFunc  :=  ShellAPI . FO_DELETE ;         // we're deleting
     pFrom  :=  PChar ( FileName  +  #0 );       // this file (#0#0 terminated)
     fFlags  :=  ShellAPI . FOF_ALLOWUNDO     // with facility to undo op
     or  ShellAPI . FOF_NOCONFIRMATION       // and we don't want any dialogs
     or  ShellAPI . FOF_SILENT ;
   end ;
   // Perform the operation
   Result  :=  ShellAPI . SHFileOperation ( FOS )  =  0 ;
end ;

function  DirToPath ( const  Dir :  string ):  string ;
{Returns the given directory with a trailing backslash. If the directory
already ends in backslash it is returned unchanged.}
begin
   if  ( Dir  <>  '' )  and  ( Dir [ Length ( Dir )]  <>  '/' )  then
     Result  :=  Dir  +  '/'
   else
     Result  :=  Dir ;
end ;

function  DOSToUnixPath ( const  PathName :  string ):  string ;
{Converts a DOS path to a Unix path and returns it.}
begin
   Result  :=  SysUtils . StringReplace ( PathName ,  '/' ,  '/' ,  [ SysUtils . rfReplaceAll ]);
end ;

procedure  EnsureFolders ( Path :  string );
{Ensures that the given folder and all folders on its path exist, and creates
them if they do not. Uses recursion.}
var
   SlashPos :  Integer ;                     // position of last backslash in path
   SubPath :  string ;                       // immediate parent folder of given path
begin
   // Check there's a path to create
   if  Length ( Path )  =  0  then
     Exit ;
   // Remove any trailing '/'
   Path  :=  PathToDir ( Path );
   // Check if folder exists and quit if it does - we're done
   if  IsDirectory ( Path )  then
     Exit ;
   // Recursively call routine on immediate parent folder
   // remove bottomost folder from path - ie move up to parent folder
   SubPath  :=  Path ;
   SlashPos  :=  Length ( SubPath );
   while  ( SlashPos  >  2 )  and  ( SubPath [ SlashPos ]  <>  '/' )  do
     Dec ( SlashPos );
   Delete ( SubPath ,  SlashPos ,  Length ( Path )  -  SlashPos  +  1 );
   // do recursive call - ensures that parent folder of current path exist
   EnsureFolders ( SubPath );
   // Create this current folder now we know parent folder exists
   SysUtils . CreateDir ( Path );
end ;

function  GetFileDate ( const  FName :  string ):  Integer ;
{Returns modification date of given file encoded as integer.}
var
   FileH :  Integer ;                        // file handle
begin
   // Open file
   FileH  :=  SysUtils . FileOpen ( FName ,  SysUtils . fmOpenRead );
   if  FileH  =  - 1  then
     // Couldn't open file - return -1 to indicate can't get date
     Result  :=  - 1
   else
   begin
     // File opened OK - record date and close file
     Result  :=  SysUtils . FileGetDate ( FileH );
     SysUtils . FileClose ( FileH );
   end ;
end ;

function  GetFixedFileVerInfo ( const  FileName :  string ;
   var  FFI :  Windows . TVSFixedFileInfo ):  Boolean ;
{Extracts fixed version information from a file. If file contains version
information it is returned via FFI parameter and function returns true,
otherwise false is returned and FFI is undefined.}
var
   VerInfoBuf :  Pointer ;                   // points to memory storing version info
   VerInfoSize :  Integer ;                  // size of version info memory
   Dummy :  Windows . THandle ;                // unused parameter required by API function
   PFFI :  Pointer ;                         // points to fixed file info
   FFISize :  Windows . UINT ;                 // size of file file info returned from API (unused)
begin
   // Assume failure: sets zero result
   FillChar ( FFI ,  SizeOf ( FFI ),  0 );
   Result  :=  False ;
   // Get size of version info: there is none if this is zero
   VerInfoSize  :=  Windows . GetFileVersionInfoSize ( PChar ( FileName ),  Dummy );
   if  VerInfoSize  >  0  then
   begin
     // Allocate memory to store ver info
     GetMem ( VerInfoBuf ,  VerInfoSize );
     try
       // Get the version info, filling buffer
       if  Windows . GetFileVersionInfo (
         PChar ( FileName ),  Dummy ,  VerInfoSize ,  VerInfoBuf
         )  then
       begin
         // Get a pointer to fixed file info
         if  Windows . VerQueryValue ( VerInfoBuf ,  '/' ,  PFFI ,  FFISize )  then
         begin
           // Got pointer OK: record file version
           FFI  :=  Windows . PVSFixedFileInfo ( PFFI )^;
           Result  :=  True ;
         end ;
       end ;
     finally
       // Dispose of ver info storage
       FreeMem ( VerInfoBuf ,  VerInfoSize );
     end ;
   end ;
end ;

function  HasVerInfo ( const  FileName :  string ):  Boolean ;
{Returns true if the given file contains version information and false if
not.}
var
   Dummy :  Windows . THandle ;                // dummy variable required by API function
begin
   // API function returns size of ver info: 0 if none
   Result  :=  Windows . GetFileVersionInfoSize ( PChar ( FileName ),  Dummy )  >  0 ;
end ;

function  IsDirectory ( const  DirName :  string ):  Boolean ;
{Returns true if given name is a valid directory and false otherwise. DirName
can be any file system name (with or without trailing path delimiter).}
var
   Attr :  Integer ;                         // directory's file attributes
begin
   Attr  :=  SysUtils . FileGetAttr ( DirName );
   Result  :=  ( Attr  <>  - 1 )
     and  ( Attr  and  SysUtils . faDirectory  =  SysUtils . faDirectory );
end ;

function  IsURLShortcut ( const  ShortcutFile :  string ):  Boolean ;
{Returns true if the given file is a URL shortcut file and false if not.}
var
   Ini :  IniFiles . TIniFile ;                // used to read ini files
begin
   // File must exist
   if  SysUtils . FileExists ( ShortcutFile )  then
   begin
     // Open ini file and check value exists
     Ini  :=  IniFiles . TIniFile . Create ( ShortcutFile );
     try
       Result  :=  Ini . SectionExists ( 'InternetShortcut' )
         and  Ini . ValueExists ( 'InternetShortcut' ,  'URL' )
         and  ( Ini . ReadString ( 'InternetShortcut' ,  'URL' ,  '' )  <>  '' );
     finally
       Ini . Free ;
     end ;
   end
   else
     Result  :=  False ;
end ;

function  ListFiles ( const  Dir ,  Wildcard :  string ;
   const  List :  Classes . TStrings ):  Boolean ;
{Gets a list of the files and sub-directories of the given directory that
match the given wild card. The files are appended to the given string list.
Returns true if Dir is a valid directory and False if not. If Wildcard is not
specified, *.* is assumed.}
var
   FileSpec :  string ;                      // search file specification
   SR :  SysUtils . TSearchRec ;               // file search result
   Success :  Integer ;                      // success code for FindXXX routines
begin
   Assert ( Assigned ( List ));
   // Check if true directory and exit if not
   Result  :=  IsDirectory ( Dir );
   if  not  Result  then
     Exit ;
   // Build file spec from directory and wildcard
   FileSpec  :=  DirToPath ( Dir );
   if  Wildcard  =  ''  then
     FileSpec  :=  FileSpec  +  '*.*'
   else
     FileSpec  :=  FileSpec  +  Wildcard ;
   // Initialise search for matching files
   Success  :=  SysUtils . FindFirst ( FileSpec ,  SysUtils . faAnyFile ,  SR );
   try
     // Loop for all files in directory
     while  Success  =  0  do
     begin
       // only add true files or directories to list
       if  ( SR . Name  <>  '.' )  and  ( SR . Name  <>  '..' )
         and  ( SR . Attr  and  SysUtils . faVolumeId  =  0 )  then
         List . Add ( SR . Name );
       // get next file
       Success  :=  SysUtils . FindNext ( SR );
     end ;
   finally
     // Tidy up
     SysUtils . FindClose ( SR );
   end ;
end ;

function  LongToShortFilePath ( const  LongName :  string ):  string ;
{Converts the given long file name to the equivalent shortened DOS style 8.3
path.}
begin
   SetLength ( Result ,  Windows . MAX_PATH );
   SetLength (
     Result ,
     Windows . GetShortPathName (
     PChar ( LongName ),  PChar ( Result ),  Windows . MAX_PATH
     )
     );
end ;

function  PathToDir ( const  Path :  string ):  string ;
{Returns the given directory with any single trailing backslash removed. If
the directory does not end in a backslash it is returned unchanged.}
begin
   Result  :=  Path ;
   if  ( Path  <>  '' )  and  ( Path [ Length ( Path )]  =  '/' )  then
     Delete ( Result ,  Length ( Result ),  1 );
end ;

procedure  SetFileDate ( const  FName :  string ;  const  ADate :  Integer );
{Sets modification date of given file to given integer coded value.}
var
   FileH :  Integer ;                        // file handle
begin
   // Open file
   FileH  :=  SysUtils . FileOpen ( FName ,  SysUtils . fmOpenWrite );
   if  FileH  <>  - 1  then
   begin
     // File opened OK - set date and close file
     SysUtils . FileSetDate ( FileH ,  ADate );
     SysUtils . FileClose ( FileH );
   end ;
end ;

function  ShortToLongFilePath ( const  FilePath :  string ):  string ;
{Converts whole of given DOS style 8.3 path to long file path and returns it.
If path can't be converted then '' is returned.}
var
   PrevPath :  string ;                      // path before last file/dir in FilePath
   ExpandedName :  string ;                  // long form of file name
   SR :  SysUtils . TSearchRec ;               // record used by file find functions
   Success :  Integer ;                      // indicates success in finding a file
   // ---------------------------------------------------------------------------
   function  CountPathDelims ( const  Name :  string ):  Integer ;
     {Counts path separators in given name}
   var
     Idx :  Integer ;                        // loops thru name string
   begin
     Result  :=  0 ;
     for  Idx  :=  1  to  Length ( Name )  do
       if  SysUtils . IsPathDelimiter ( Name ,  Idx )  then
         Inc ( Result );
   end ;

   function  IsServerName ( const  Name :  string ):  Boolean ;
     {Returns true if Names is in form //Server/Share}
   begin
     Result  :=  ( SysUtils . AnsiPos ( '//' ,  Name )  =  1 )
       and  ( CountPathDelims ( Name )  =  3 );
   end ;
   // ---------------------------------------------------------------------------
begin
   // Check if we have a drive, server/share or root path, and exit if so
   // (we can't apply file search to any of these, so we return them unchanged
   if  ( FilePath  =  '' )
     or  ( FilePath  =  '/' )
     or  (( Length ( FilePath )  =  2 )  and  ( FilePath [ 2 ]  =  ':' ))
     or  (( Length ( FilePath )  =  3 )  and  ( FilePath [ 2 ]  =  ':' )  and  ( FilePath [ 3 ]  =  '/' ))
     or  IsServerName ( FilePath )  then
   begin
     Result  :=  FilePath ;
     Exit ;
   end ;
   // Do a file search on file: this is used to expand name
   Success  :=  SysUtils . FindFirst ( FilePath ,  SysUtils . faAnyFile ,  SR );
   try
     if  Success  =  0  then
       ExpandedName  :=  SR . FindData . cFileName
     else
       ExpandedName  :=  '' ;
   finally
     SysUtils . FindClose ( SR );
   end ;
   // Check if there's any part of path we've not handled, and convert it if so
   PrevPath  :=  SysUtils . ExtractFileDir ( FilePath );
   if  PrevPath  <>  ''  then
   begin
     // We have unprocessed part of path: expand that
     Result  :=  ShortToLongFilePath ( PrevPath );
     // Appended currently expanded name to path
     if  ( Result  <>  '' )  and  ( Result [ Length ( Result )]  <>  '/' )  then
       Result  :=  Result  +  '/' ;
     Result  :=  Result  +  ExpandedName ;
   end
   else
     // No earlier parts of path: just record expanded name
     Result  :=  ExpandedName ;
end ;

function  TempFileName ( const  Stub :  string ;  const  Create :  Boolean ):  string ;
{Returns a unique temporary file name in temporary folder. File name includes
first three characters of Stub followed by hexadecimal characters. If Create
is true file is created. Returns empty string on failure.}
begin
   // Get temporary folder
   SetLength ( Result ,  Windows . MAX_PATH );
   Windows . GetTempPath ( Windows . MAX_PATH ,  PChar ( Result ));
   // Get unique temporary file name (it is created as side effect of this call)
   if  Windows . GetTempFileName (
     PChar ( Result ),  PChar ( Stub ),  0 ,  PChar ( Result )
     )  <>  0  then
   begin
     // Succeeded
     Result  :=  PChar ( Result );
     if  not  Create  then
       // user doesn't want file creating: so we delete the file
       SysUtils . DeleteFile ( Result );
   end
   else
     // Failed
     Result  :=  '' ;
end ;

function  Touch ( const  FileName :  string ):  Boolean ;
{Sets modification date of given file to current date and time. Returns true
if date set successfully or false on error.}
var
   FileH :  Integer ;                        // handle of file
begin
   // Assume failure
   Result  :=  False ;
   // Try to open file: bail out if can't open
   FileH  :=  SysUtils . FileOpen (
     FileName ,  SysUtils . fmOpenWrite  or  SysUtils . fmShareDenyWrite
     );
   if  FileH  =  - 1  then
     Exit ;
   try
     // Set date to current date and time: return true if succeed
     if  SysUtils . FileSetDate (
       FileH ,  SysUtils . DateTimeToFileDate ( SysUtils . Now ())
       )  =  0  then
       Result  :=  True ;
   finally
     // Close the file
     SysUtils . FileClose ( FileH );
   end ;
end ;

function  URLFromShortcut ( const  Shortcut :  string ):  string ;
{Returns the URL referenced by the given URL shortcut file, or the empty
string if the given file is not a shortcut file.}
var
   Ini :  IniFiles . TIniFile ;                // object used to read shortcut file
begin
   // Return URL item from [InternetShortcut] section of shortcut file
   Ini  :=  IniFiles . TIniFile . Create ( Shortcut );
   try
     try
       Result  :=  Ini . ReadString ( 'InternetShortcut' ,  'URL' ,  '' );
     except ;
       // We return '' on error
       Result  :=  '' ;
     end ;
   finally
     Ini . Free ;
   end ;
end ;

function  ColorToRGBTriple ( const  C :  Graphics . TColor ):  Windows . TRGBTriple ;
{Converts a Delphi TColor value into an RGB triple value.}
var
   ColorRGB :  Integer ;                     // RGB value of C
begin
   ColorRGB  :=  Graphics . ColorToRGB ( C );
   Result . rgbtRed  :=  Windows . GetRValue ( ColorRGB );
   Result . rgbtGreen  :=  Windows . GetGValue ( ColorRGB );
   Result . rgbtBlue  :=  Windows . GetBValue ( ColorRGB );
end ;

procedure  DrawTextOutline ( const  Canvas :  Graphics . TCanvas ;  const  X ,  Y :  Integer ;
   const  Text :  string );
{Draws specified text in outline on a canvas. The top left corner of the text
is specified by X and Y parameters. Canvas' current brush and pen colours are
used to fill and outline the text respectively. If the canvas' current font is
not a vector font nothing is displayed.}
var
   OldBkMode :  Integer ;                    // stores previous background mode
begin
   OldBkMode  :=  Windows . SetBkMode ( Canvas . Handle ,  Windows . TRANSPARENT );
   Windows . BeginPath ( Canvas . Handle );
   Canvas . TextOut ( X ,  Y ,  Text );
   Windows . EndPath ( Canvas . Handle );
   Windows . StrokeAndFillPath ( Canvas . Handle );
   Windows . SetBkMode ( Canvas . Handle ,  OldBkMode );
end ;

procedure  MakeGreyScale ( const  SrcBmp :  Graphics . TBitmap ;
   const  Advanced :  Boolean );
{Converts a colour bitmap into a 24bit greyscale bitmap. Setting the Advanced
flag to true uses a more advanced algorithm for the conversion. When the flag
is false red, blue and green values are simply averaged. The provided colour
bitmap is overwritten by the greyscale bitmap.}
type
   // 24 bit bitmap scanline and pointer
   TRGBArray  =  array [ 0.. MaxInt  div  SizeOf ( Windows . TRGBTriple )  -  1 ]
     of  Windows . TRGBTriple ;
   PRGBArray  =  ^ TRGBArray ;
var
   J :  Integer ;                            // loops scanlines of bitmap
   I :  Integer ;                            // loops through pixels in scanline
   GreyColor :  Byte ;                       // grey equivalent of a pixel
   ScanLine :  PRGBArray ;                   // references scanline in a bitmap
   GreyBmp :  Graphics . TBitmap ;             // used to build grey bitmap
begin
   // Draw colour bitmap in 24 bit format onto temp bitmap
   GreyBmp  :=  Graphics . TBitmap . Create ;
   try
     GreyBmp . PixelFormat  :=  Graphics . pf24bit ;
     GreyBmp . Width  :=  SrcBmp . Width ;
     GreyBmp . Height  :=  SrcBmp . Height ;
     GreyBmp . Canvas . Draw ( 0 ,  0 ,  SrcBmp );
     if  GreyBmp . PixelFormat  <>  Graphics . pf24bit  then
       raise  SysUtils . Exception . Create (
         'MakeGrayScale() can''t convert bitmap to 24 bit'
         );
     // Convert bitmap to greyscale by processing scanlines
     for  J  :=  0  to  Pred ( GreyBmp . Height )  do
     begin
       ScanLine  :=  GreyBmp . ScanLine [ j ];
       for  I  :=  0  to  Pred ( GreyBmp . Width )  do
       begin
         if  Advanced  then
           // Advanced greyscale conversion:
           // we use weighting of red, green and blue
           GreyColor  :=  Windows . HiByte (
             ScanLine [ i ]. rgbtRed  *  77
             +  ScanLine [ i ]. rgbtGreen  *  151
             +  ScanLine [ i ]. rgbtBlue  *  28
             )
         else
           // Basic conversion:
           // we use average of colour values
           GreyColor  :=  (
             ScanLine [ i ]. rgbtRed
             +  ScanLine [ i ]. rgbtGreen
             +  ScanLine [ i ]. rgbtBlue
             )  div  3 ;
         ScanLine [ i ]. rgbtRed  :=  GreyColor ;
         ScanLine [ i ]. rgbtGreen  :=  GreyColor ;
         ScanLine [ i ]. rgbtBlue  :=  GreyColor ;
       end ;
     end ;
     // Copy greyscale bitmap to source
     SrcBmp . Assign ( GreyBmp );
   finally
     GreyBmp . Free ;
   end ;
end ;

function  RGBTripleToColor ( const  C :  Windows . TRGBTriple ):  Graphics . TColor ;
{Converts an RGB triple value into a Delphi TColor value.}
begin
   Result  :=  Windows . RGB ( C . rgbtRed ,  C . rgbtGreen ,  C . rgbtBlue );
end ;

function  BrowseURL ( const  URL :  string ):  Boolean ;
{Activates default browser or email client for given URL. Returns true if
browser/email client is uccessfully launched and false if not. Raises
exception if URL doesn't conform to a known valid protocol.}
begin
   if  not  IsValidURLProtocol ( URL )  then
     raise  SysUtils . Exception . CreateFmt ( '"%s" is not a valid URL' ,  [ URL ]);
   Result  :=  ExecAssociatedApp ( URL );
end ;

function  ColorToHTML ( const  Color :  Graphics . TColor ):  string ;
{Converts a Delphi TColor value into a string suitable for use in HTML or CSS
code. Any system colors (like clBtnFace) are mapped to the actual colour
according to the current Windows settings.}
var
   ColorRGB :  Integer ;
begin
   ColorRGB  :=  Graphics . ColorToRGB ( Color );
   Result  :=  SysUtils . Format (
     '#%0.2X%0.2X%0.2X' ,
     [ Windows . GetRValue ( ColorRGB ),
     Windows . GetGValue ( ColorRGB ),
       Windows . GetBValue ( ColorRGB )]
       );
end ;

function  DownloadURLToFile ( const  URL ,  FileName :  string ):  Boolean ;
{Downloads file at URL and stores in given file. Returns true if download
succeeds and false on failure. A connection to the internet must be open for
download to succeed.}
begin
   // URLDownloadFile returns true if URL exists even if file not created
   // hence we also check file has been created.
   Result  :=  Windows . Succeeded (
     UrlMon . URLDownloadToFile ( nil ,  PChar ( URL ),  PChar ( FileName ),  0 ,  nil )
     )  and  SysUtils . FileExists ( FileName );
end ;

function  IsValidURLProtocol ( const  URL :  string ):  Boolean ;
{Checks if the given URL is valid per RFC1738. Returns true is valid and false
if not.}
const
   CNumProtocols  =  10 ;                    // number of known protocols
   CProtocols :  array [ 1.. CNumProtocols ]  of  string  =  (
     // Array of valid protocols - per RFC 1738
     'ftp://' ,  'http://' ,  'gopher://' ,  'mailto:' ,  'news:' ,  'nntp://' ,
     'telnet://' ,  'wais://' ,  'file://' ,  'prospero://'
     );
var
   I :  Integer ;                            // loops thru known protocols
begin
   // Scan array of protocols checking for a match with start of given URL
   Result  :=  False ;
   for  I  :=  1  to  CNumProtocols  do
     if  Pos ( CProtocols [ I ],  SysUtils . LowerCase ( URL ))  <>  0  then
     begin
       Result  :=  True ;
       Break ;
     end ;
end ;

function  MakeSafeHTMLText ( TheText :  string ):  string ;
{Replaces any characters in the given text that are HTML-compatible with
suitable escaped versions and returns modified string.}
var
   Idx :  Integer ;                          // loops thru the given text
begin
   Result  :=  '' ;
   for  Idx  :=  1  to  Length ( TheText )  do
     case  TheText [ Idx ]  of
       '<' :                               // opens tags: replace with special char reference
         Result  :=  Result  +  '&lt;' ;
       '>' :                               // closes tags: replace with special char reference
         Result  :=  Result  +  '&gt;' ;
       '&' :                               // begins char references: replace with special char reference
         Result  :=  Result  +  '&amp;' ;
       '"' :                               // quotes (can be a problem in quoted attributes)
         Result  :=  Result  +  '&quot;' ;
       #0 .. #31 ,  #127 .. #255 :               // control and special chars: replace with encoding
         Result  :=  Result  +  '&#'  +  SysUtils . IntToStr ( Ord ( TheText [ Idx ]))  +  ';' ;
     else                                 // compatible text: pass thru
       Result  :=  Result  +  TheText [ Idx ];
     end ;
end ;

function  URLDecode ( const  S :  string ):  string ;
{Decodes the given encoded URL or URL query string. Raises exception if the
encoded URL is badly formed.}
var
   Idx :  Integer ;                          // loops thru chars in string
   Hex :  string ;                           // string of hex characters
   Code :  Integer ;                         // hex character code (-1 on error)
begin
   // Intialise result and string index
   Result  :=  '' ;
   Idx  :=  1 ;
   // Loop thru string decoding each character
   while  Idx  <=  Length ( S )  do
   begin
     case  S [ Idx ]  of
       '%' :
         begin
           // % should be followed by two hex digits - exception otherwise
           if  Idx  <=  Length ( S )  -  2  then
           begin
             // there are sufficient digits - try to decode hex digits
             Hex  :=  S [ Idx  +  1 ]  +  S [ Idx  +  2 ];
             Code  :=  SysUtils . StrToIntDef ( '$'  +  Hex ,  - 1 );
             Inc ( Idx ,  2 );
           end
           else
             // insufficient digits - error
             Code  :=  - 1 ;
           // check for error and raise exception if found
           if  Code  =  - 1  then
             raise  SysUtils . EConvertError . Create (
               'Invalid hex digit in URL'
               );
           // decoded OK - add character to result
           Result  :=  Result  +  Chr ( Code );
         end ;
       '+' :
         // + is decoded as a space
         Result  :=  Result  +  ' '
     else
       // All other characters pass thru unchanged
       Result  :=  Result  +  S [ Idx ];
     end ;
     Inc ( Idx );
   end ;
end ;

function  URLEncode ( const  S :  string ;  const  InQueryString :  Boolean ):  string ;
{Encodes the given string, making it suitable for use in a URL. The function
can encode strings for use in the main part of a URL (where spaces are
encoded as '%20') or in URL query strings (where spaces are encoded as '+'
characters). Set InQueryString to true to encode for a query string.}
var
   Idx :  Integer ;                          // loops thru characters in string
begin
   Result  :=  '' ;
   for  Idx  :=  1  to  Length ( S )  do
   begin
     case  S [ Idx ]  of
       'A' .. 'Z' ,  'a' .. 'z' ,  '0' .. '9' ,  '-' ,  '_' ,  '.' :
         Result  :=  Result  +  S [ Idx ];
       ' ' :
         if  InQueryString  then
           Result  :=  Result  +  '+'
         else
           Result  :=  Result  +  '%20' ;
     else
       Result  :=  Result  +  '%'  +  SysUtils . IntToHex ( Ord ( S [ Idx ]),  2 );
     end ;
   end ;
end ;

function  CompressWhiteSpace ( const  S :  string ):  string ;
{Returns a copy of given string with all white space characters replaced by
space characters and all sequences of white space replaced by a single space
character.}
var
   Idx :  Integer ;                          // loops thru all characters in string
   ResCount :  Integer ;                     // counts number of characters in result string
   PRes :  PChar ;                           // pointer to characters in result string
const
   // The white space characters we convert to spaces
   cWhiteSpace  =  [ #9 ,  #10 ,  #11 ,  #12 ,  #13 ,  ' ' ];
begin
   // Set length of result to length of source string and set pointer to it
   SetLength ( Result ,  Length ( S ));
   PRes  :=  PChar ( Result );
   // Reset count of characters in result string
   ResCount  :=  0 ;
   // Loop thru characters of source string
   Idx  :=  1 ;
   while  Idx  <=  Length ( S )  do
   begin
     if  S [ Idx ]  in  cWhiteSpace  then
     begin
       // Current char is white space: replace by space char and count it
       PRes ^  :=  ' ' ;
       Inc ( PRes );
       Inc ( ResCount );
       // Skip past any following white space
       Inc ( Idx );
       while  S [ Idx ]  in  cWhiteSpace  do
         Inc ( Idx );
     end
     else
     begin
       // Current char is not white space: copy it literally and count it
       PRes ^  :=  S [ Idx ];
       Inc ( PRes );
       Inc ( ResCount );
       Inc ( Idx );
     end ;
   end ;
   // Reduce length of result string if it is shorter than source string
   if  ResCount  <  Length ( S )  then
     SetLength ( Result ,  ResCount );
end ;

function  CountDelims ( const  S ,  Delims :  string ):  Integer ;
{Returns count of all occurences of any of the given delimiter characters in
the string S.}
var
   Idx :  Integer ;                          //loops thru all characters in string
begin
   Result  :=  0 ;
   for  Idx  :=  1  to  Length ( S )  do
     if  SysUtils . IsDelimiter ( Delims ,  S ,  Idx )  then
       Inc ( Result );
end ;

function  ExplodeStr ( S :  string ;  const  Delim :  Char ;  const  List :  Classes . TStrings ;
   const  AllowEmpty :  Boolean  =  True ):  Integer ;
{Splits the string S into a list of strings, separated by Delim, and returns
the number of strings in the list. If AllowEmpty is true then any empty
strings are added to the list, while they are ignored if AllowEmpty is
false.}
var
   Item :  string ;                          // current delimted text
   Remainder :  string ;                     // remaining unconsumed part of string
begin
   // Clear the list
   List . Clear ;
   // Check we have some entries in the string
   if  S  <>  ''  then
   begin
     // Repeatedly split string until we have no more entries
     while  SplitStr ( S ,  Delim ,  Item ,  Remainder )  do
     begin
       // Add the current string, is required
       if  ( Item  <>  '' )  or  AllowEmpty  then
         List . Add ( Item );
       // Go round again with remainder of string
       S  :=  Remainder ;
     end ;
     // Add any terminal item
     if  ( Item  <>  '' )  or  AllowEmpty  then
       List . Add ( Item );
   end ;
   // Return number of items read
   Result  :=  List . Count ;
end ;

function  IsHexStr ( const  S :  string ):  Boolean ;
{Returns true if string S contains only valid hex digits, false otherwise.}
{Returns true if string S contains only valid hex digits, false otherwise}
const
   cHexChars  =  [ '0' .. '9' ,  'A' .. 'F' ,  'a' .. 'f' ];  // set of valid hex digits
var
   Idx :  Integer ;                          //loops thru all characters in string
begin
   Result  :=  True ;
   for  Idx  :=  1  to  Length ( S )  do
     if  not  ( S [ Idx ]  in  cHexChars )  then
     begin
       Result  :=  False ;
       Break ;
     end ;
end ;

function  JoinStr ( const  SL :  Classes . TStrings ;  const  Delim :  string ;
   const  AllowEmpty :  Boolean  =  True ):  string ;
{Joins all strings in given string list together into single string separated
by given delimiter. If AllowEmpty is true then any empty strings are included
in output string, but are ignored if false.}
var
   Idx :  Integer ;                          // loops thru all items in string list
begin
   Result  :=  '' ;
   for  Idx  :=  0  to  Pred ( SL . Count )  do
   begin
     if  ( SL [ Idx ]  <>  '' )  or  AllowEmpty  then
       if  Result  =  ''  then
         Result  :=  SL [ Idx ]
       else
         Result  :=  Result  +  Delim  +  SL [ Idx ];
   end ;
end ;

procedure  MultiSzToStrings ( const  MultiSz :  PChar ;
   const  Strings :  Classes . TStrings );
{Splits out individual strings from given 'MultiSz' strings buffer and adds
each string to the given string list. A MultiSz string is a sequence of #0
delimited strings terminated by an extra #0 character. Does nothing if string
list or MultiSz buffer are nil.}
var
   P :  PChar ;                              // pointer to strings in buffer
begin
   // Do nothing in MultiSz is nil
   if  not  Assigned ( MultiSz )  then
     Exit ;
   // Scan thru #0 delimited strings until #0#0 found
   P  :=  MultiSz ;
   while  P ^  <>  #0  do
   begin
     // add string to list
     Strings . Add ( P );
     // move pointer to start of next string if any
     Inc ( P ,  SysUtils . StrLen ( P )  +  1 );
   end ;
end ;

function  ParseDelims ( const  TextLine :  string ;  var  StartPos :  Integer ;
   const  Delims :  string ):  string ;
{Returns the sub-string of TextLine that begins at StartPos and is terminated
by one of the delimiting characters Delims or the end of the string. StartPos
is updated to index of character after delimiter. Returns '' if there is no
sub-string after StartPos.}
var
   StringEnd :  Integer ;                    // tracks end of current string being parsed out
begin
   // Find next non-delimiter char - this is where token starts
   while  ( StartPos  <=  Length ( TextLine ))
     and  SysUtils . IsDelimiter ( Delims ,  TextLine ,  StartPos )  do
     Inc ( StartPos );
   // Now find next delimiter - this is where token ends
   StringEnd  :=  StartPos ;
   while  ( StringEnd  <=  Length ( TextLine ))
     and  not  SysUtils . IsDelimiter ( Delims ,  TextLine ,  StringEnd )  do
     Inc ( StringEnd );
   // Copy result out of string
   Result  :=  Copy ( TextLine ,  StartPos ,  StringEnd  -  StartPos );
   StartPos  :=  StringEnd  +  1 ;
end ;

function  SplitStr ( const  S :  string ;  Delim :  Char ;  out  S1 ,  S2 :  string ):  Boolean ;
{Splits the string S at the first occurence of delimiter character Delim and
sets S1 to the sub-string before Delim and S2 to substring following Delim.
If Delim is found in string True is returned, while if Delim is not in string
False is returned, S1 is set to S and S2 is set to ''.}
var
   DelimPos :  Integer ;                     // position of delimiter in source string
begin
   // Find position of first occurence of delimter in string
   DelimPos  :=  SysUtils . AnsiPos ( Delim ,  S );
   if  DelimPos  >  0  then
   begin
     // Delimiter found: do split and return True
     S1  :=  Copy ( S ,  1 ,  DelimPos  -  1 );
     S2  :=  Copy ( S ,  DelimPos  +  1 ,  MaxInt );
     Result  :=  True ;
   end
   else
   begin
     // Delimeter not found: return false and set S1 to whole string
     S1  :=  S ;
     S2  :=  '' ;
     Result  :=  False ;
   end ;
end ;

function  StringsToMutliSz ( const  Strings :  Classes . TStrings ;
   const  MultiSz :  PChar ;  const  BufSize :  Integer ):  Integer ;
{Copies the strings from a given string list and stores in a provided MulitiSz
buffer of a given size. The strings in the buffer are separated by #0 and the
buffer is terminated by an additional #0. Returns 0 on success or required
buffer size if MultiSz is nil or buffer size is too small. To get required
buffer size call function with MultiSz=nil and BufSize=0.}
var
   ReqSize :  Integer ;                      // required buffer size
   Idx :  Integer ;                          // loops thru Strings
   P :  PChar ;                              // pointer into MultiSz
begin
   Result  :=  0 ;
   if  not  Assigned ( Strings )  then
     Exit ;
   // Get required size of buffer
   ReqSize  :=  1 ;
   for  Idx  :=  0  to  Pred ( Strings . Count )  do
     Inc ( ReqSize ,  Length ( Strings [ Idx ])  +  1 );
   if  ( BufSize  >=  ReqSize )  and  Assigned ( MultiSz )  then
   begin
     // BufSize OK and MultiSz not nil: copy string and return zero
     P  :=  MultiSz ;
     for  Idx  :=  0  to  Pred ( Strings . Count )  do
     begin
       // copy current string, #0 terminated
       SysUtils . StrPCopy ( P ,  Strings [ Idx ]);
       // moves to next pos in buffer
       Inc ( P ,  Length ( Strings [ Idx ])  +  1 );
     end ;
     // add terminating additional #0
     P ^  :=  #0 ;
   end
   else
     // BufSize too small or MultiSz is nil: return required size
     Result  :=  ReqSize ;
end ;

function  GetMacAddress :  string ;
{Returns MAC address of first ethernet adapter on computer.}
type
   // This type is defined in MSDN sample code, but tests have found this is
   // not needed (on XP Pro) and Adapter can be of type TAdapterStatus. This
   // method use the type in case other OSs require it
   TAStat  =  packed  record
     Adapt :  Nb30 . TAdapterStatus ;
     NameBuff :  array [ 0..29 ]  of  Nb30 . TNameBuffer ;
   end ;
var
   Adapter :  TAStat ;                       // info about a network adapter
   AdapterList :  Nb30 . TLanaEnum ;           // numbers for current LAN adapters
   Ncb :  Nb30 . TNCB ;                        // network control block descriptor
   I :  Integer ;                            // loops thru all adapters in list
   // ---------------------------------------------------------------------------
   function  NetBiosSucceeded ( const  RetCode :  AnsiChar ):  Boolean ;
   begin
     // Check RetCode is good NetBios function return value
     Result  :=  Windows . UCHAR ( RetCode )  =  Nb30 . NRC_GOODRET ;
   end ;
   // ---------------------------------------------------------------------------
begin
   // Assume not adapter
   Result  :=  '' ;
   // Get list of adapters
   FillChar ( Ncb ,  SizeOf ( Ncb ),  0 );
   Ncb . ncb_command  :=  AnsiChar ( Nb30 . NCBENUM );
   Ncb . ncb_buffer  :=  PAnsiChar (@ AdapterList );
   Ncb . ncb_length  :=  SizeOf ( AdapterList );
   if  not  NetBiosSucceeded ( Nb30 . Netbios (@ Ncb ))  then
     Exit ;
   // Get status of each adapter, exiting when first valid one reached
   // MSDN cautions us not to assume lana[0] is valid
   for  I  :=  0  to  Pred ( Integer ( AdapterList . length ))  do
   begin
     // reset the adapter
     FillChar ( Ncb ,  SizeOf ( Ncb ),  0 );
     Ncb . ncb_command  :=  AnsiChar ( Nb30 . NCBRESET );
     Ncb . ncb_lana_num  :=  AdapterList . lana [ I ];
     if  not  NetBiosSucceeded ( Nb30 . Netbios (@ Ncb ))  then
       Exit ;
     // get status of adapter
     FillChar ( Ncb ,  SizeOf ( Ncb ),  0 );
     Ncb . ncb_command  :=  AnsiChar ( Nb30 . NCBASTAT );
     Ncb . ncb_lana_num  :=  AdapterList . lana [ I ];
     Ncb . ncb_callname  :=  '*               ' ;
     Ncb . ncb_buffer  :=  PAnsiChar (@ Adapter );
     Ncb . ncb_length  :=  SizeOf ( Adapter );
     if  NetBiosSucceeded ( Nb30 . Netbios (@ Ncb ))  then
     begin
       // we have a MAC address: return it
       with  Adapter . Adapt  do
         Result  :=  SysUtils . Format (
           '%.2x-%.2x-%.2x-%.2x-%.2x-%.2x' ,
           [
           Ord ( adapter_address [ 0 ]),
             Ord ( adapter_address [ 1 ]),
             Ord ( adapter_address [ 2 ]),
             Ord ( adapter_address [ 3 ]),
             Ord ( adapter_address [ 4 ]),
             Ord ( adapter_address [ 5 ])
             ]
             );
       Exit ;
     end ;
   end ;
end ;

function  IsLockKeyOn ( const  KeyCode :  Integer ):  Boolean ;
{Detects if a given lock key is on and returns true if so. An exception is
raised if KeyCode is not a valid lock key code. Valid lock key codes are
VK_CAPITAL, VK_NUMLOCK and VK_SCROLL.}
begin
   if  not  (
     KeyCode  in  [ Windows . VK_CAPITAL ,  Windows . VK_NUMLOCK ,  Windows . VK_SCROLL ]
     )  then
     raise  SysUtils . Exception . Create ( 'Invalid lock key specified.' );
   Result  :=  Odd ( Windows . GetKeyState ( KeyCode ));
end ;

procedure  SetLockKeyState ( KeyCode :  Integer ;  IsOn :  Boolean );
{Sets the given lock key state to given value. Passing True switches lock key
on and passing False switches it off. An exception is raised if KeyCode is
not a valid lock key code. Valid lock key codes are VK_CAPITAL, VK_NUMLOCK
and VK_SCROLL.}
// ---------------------------------------------------------------------------
   procedure  MoveKey ( KeyCode :  Integer ;  Up :  Boolean );
   var
     Flags :  Integer ;                      // flags for MapVirtualKey()
   begin
     // Set up flags
     Flags  :=  Windows . KEYEVENTF_EXTENDEDKEY ;
     if  Up  then
       Flags  :=  Flags  or  Windows . KEYEVENTF_KEYUP ;
     // Simulate key movement
     Windows . keybd_event (
       KeyCode ,
       Windows . MapVirtualkey ( KeyCode ,  0 ),
       Flags ,
       0
       );
   end ;
   // ---------------------------------------------------------------------------
begin
   if  not  (
     KeyCode  in  [ Windows . VK_CAPITAL ,  Windows . VK_NUMLOCK ,  Windows . VK_SCROLL ]
     )  then
     raise  SysUtils . Exception . Create ( 'Invalid lock key specified.' );
   if  IsLockKeyOn ( KeyCode )  <>  IsOn  then
   begin
     // Need to change state: press & release key
     MoveKey ( KeyCode ,  False );
     MoveKey ( KeyCode ,  True );
   end ;
end ;

procedure  AddToRecentDocs ( const  FileName :  string );
{Adds given file to Recent Documents folder that appears on the Start menu.}
begin
   ShlObj . SHAddToRecentDocs ( ShlObj . SHARD_PATH ,  PChar ( FileName ));
end ;

procedure  ClearRecentDocs ;
{Clears the Recent Documents folder so that no recent documents appear on
Start menu.}
begin
   ShlObj . SHAddToRecentDocs ( ShlObj . SHARD_PATH ,  nil );
end ;

function  CreateShellLink ( const  LinkFileName ,  AssocFileName ,  Desc ,  WorkDir ,
   Args ,  IconFileName :  string ;  const  IconIdx :  Integer ):  Boolean ;
{Creates a shell link named LinkFileName that is a shortcut to file
AssocFileName with descriprion Desc. The shortcut activates its file in the
given working directory and passes the given command line Args to
AssocFileName. If an icon file and index offset are provided the specified
icon is used for the shortcut. True is returned on success and false on
error.}
var
   SL :  ShlObj . IShellLink ;                 // shell link object
   PF :  ActiveX . IPersistFile ;              // persistant file interface to shell link object
begin
   // Assume failure
   Result  :=  False ;
   // Ensure COM is initialised
   ActiveX . CoInitialize ( nil );
   try
     // Create shell link object
     if  ActiveX . Succeeded (
       ActiveX . CoCreateInstance (
       ShlObj . CLSID_ShellLink ,
       nil ,
       ActiveX . CLSCTX_INPROC_SERVER ,
       ShlObj . IShellLink ,  SL
       )
       )  then
     begin
       // Store required properties of shell link
       SL . SetPath ( PChar ( AssocFileName ));
       SL . SetDescription ( PChar ( Desc ));
       SL . SetWorkingDirectory ( PChar ( WorkDir ));
       SL . SetArguments ( PChar ( Args ));
       if  ( IconFileName  <>  '' )  and  ( IconIdx  >=  0 )  then
         SL . SetIconLocation ( PChar ( IconFileName ),  IconIdx );
       // Create persistant file interface to shell link to save link file
       PF  :=  SL  as  ActiveX . IPersistFile ;
       Result  :=  ActiveX . Succeeded (
         PF . Save ( PWideChar ( WideString ( LinkFileName )),  True )
         );
     end ;
   finally
     // Finalize COM
     ActiveX . CoUninitialize ;
   end ;
end ;

function  EmptyRecycleBin :  Boolean ;
{Empties the recycle bin. Returns returns true if bin is emptied and false if
the function fails.}
const
   // Flags passed to SHEmptyRecycleBin
   SHERB_NOCONFIRMATION  =  $00000001 ;
   SHERB_NOPROGRESSUI  =  $00000002 ;
   SHERB_NOSOUND  =  $00000004 ;
   // DLL containing function
   cDLLName  =  'Shell32.dll' ;
   // Function name
   cFnName  =  'SHEmptyRecycleBinA' ;
type
   // Prototype of API function
   TSHEmptyRecycleBin  =  function (
     Wnd :  Windows . HWND ;
     pszRootPath :  PChar ;
     dwFlags :  Windows . DWORD
     ):  HRESULT ;  stdcall ;
var
   SHEmptyRecycleBin :  TSHEmptyRecycleBin ;  // API function address
   DLLHandle :  Windows . THandle ;            // Handle of required DLL
begin
   // Assume failure
   Result  :=  False ;
   // Load required DLL
   DLLHandle  :=  Windows . LoadLibrary ( cDLLName );
   if  DLLHandle  <>  0  then
   begin
     try
       // Get reference of API function from DLL
       @ SHEmptyRecycleBin  :=  Windows . GetProcAddress ( DLLHandle ,  cFnName );
       if  Assigned (@ SHEmptyRecycleBin )  then
       begin
         // Try to empty recycle bin
         Result  :=  Windows . Succeeded (
           SHEmptyRecycleBin (
           0 ,
           nil ,
           SHERB_NOCONFIRMATION  or  SHERB_NOSOUND  or  SHERB_NOPROGRESSUI
           )
           );
       end ;
     finally
       Windows . FreeLibrary ( DLLHandle );
     end ;
   end ;
end ;

function  ExecAndWait ( const  CommandLine :  string ):  Boolean ;
{Executes the given command line and waits for the program started by the
command line to exit. Returns true if the program returns a zero exit code
and false if the program doesn't start or returns a non-zero error code.}
var
   StartupInfo :  Windows . TStartupInfo ;     // start-up info passed to process
   ProcessInfo :  Windows . TProcessInformation ;  // info about the process
   ProcessExitCode :  Windows . DWord ;        // process's exit code
begin
   // Set default error result
   Result  :=  False ;
   // Initialise startup info structure to 0, and record length
   FillChar ( StartupInfo ,  SizeOf ( StartupInfo ),  0 );
   StartupInfo . cb  :=  SizeOf ( StartupInfo );
   // Execute application commandline
   if  Windows . CreateProcess ( nil ,  PChar ( CommandLine ),
     nil ,  nil ,  False ,  0 ,  nil ,  nil ,
     StartupInfo ,  ProcessInfo )  then
   begin
     try
       // Now wait for application to complete
       if  Windows . WaitForSingleObject ( ProcessInfo . hProcess ,  INFINITE )
         =  WAIT_OBJECT_0  then
         // It's completed - get its exit code
         if  Windows . GetExitCodeProcess ( ProcessInfo . hProcess ,
           ProcessExitCode )  then
           // Check exit code is zero => successful completion
           if  ProcessExitCode  =  0  then
             Result  :=  True ;
     finally
       // Tidy up
       Windows . CloseHandle ( ProcessInfo . hProcess );
       Windows . CloseHandle ( ProcessInfo . hThread );
     end ;
   end ;
end ;

function  ExecAssociatedApp ( const  FileName :  string ):  Boolean ;
{Executes the application associated with the given file name. Returns true if
application is started successfully and false if not.}
begin
   Result  :=  ShellAPI . ShellExecute (
     0 ,
     nil ,
     PChar ( FileName ),
     nil ,
     nil ,
     Windows . SW_SHOW
     )  >  32 ;
end ;

function  ExploreFile ( const  Filename :  string ):  Boolean ;
{Starts Windows Explorer to explore given file. Returns true if file is valid
and can be explored, or false otherwise.}
var
   Params :  string ;                        // params passed to explorer
begin
   if  SysUtils . FileExists ( Filename )  then
   begin
     Params  :=  '/n, /e, /select, '  +  Filename ;
     Result  :=  ShellAPI . ShellExecute (
       0 ,  'open' ,  'explorer' ,  PChar ( Params ),  '' ,  Windows . SW_SHOWNORMAL
       )  >  32 ;
   end
   else
     // Error: filename does not exist
     Result  :=  False ;
end ;

function  ExploreFolder ( const  Folder :  string ):  Boolean ;
{Starts Windows Explorer to explore given folder. Returns true if folder is
valid and can be explored, or false otherwise.}
begin
   if  SysUtils . FileGetAttr ( Folder )  and  faDirectory  =  faDirectory  then
     // Folder is valid directory: try to explore it
     Result  :=  ShellAPI . ShellExecute (
       0 ,  'explore' ,  PChar ( Folder ),  nil ,  nil ,  Windows . SW_SHOWNORMAL
       )  >  32
   else
     // Folder is not a directory: error
     Result  :=  False ;
end ;

function  FileFromShellLink ( const  LinkFileName :  string ):  string ;
{Returns the fully specified name of the file associated with the given shell
link (shortcut) file. Returns '' if the file is not a shell link or if it is
a shortcut to a non-file shell object.}
var
   SL :  ShlObj . IShellLink ;                 // shell link object
   ResolvedFileBuf :  array [ 0.. Windows . MAX_PATH ]  of  AnsiChar ;
   // buffer to receive linked file name
   FindData :  Windows . TWin32FindData ;      // dummy required for IShellLink.GetPath()
begin
   // Assume can't get name of file
   Result  :=  '' ;
   // Ensure COM is initialized
   ActiveX . CoInitialize ( nil );
   try
     // Try to get interface to shell link: fails if file is not shell link
     SL  :=  LoadShellLink ( LinkFileName );
     if  not  Assigned ( SL )  then
       Exit ;
     // Get file path from link object and exit if this fails
     if  ActiveX . Failed (
       SL . GetPath ( ResolvedFileBuf ,  Windows . MAX_PATH ,  FindData ,  0 )
       )  then
       Exit ;
     // Return file name
     Result  :=  ResolvedFileBuf ;
   finally
     // Finalize COM
     ActiveX . CoUninitialize ;
   end ;
end ;

function  FindAssociatedApp ( const  Doc :  string ):  string ;
{Returns the fully specified path of the program associated with the given
document file name. Requires ShellAPI. Returns empty string if no such
associated application.}
var
   PExecFile :  array [ 0.. Windows . MAX_PATH ]  of  Char ;  // buffer to hold exe name
begin
   // Win API call in ShellAPI
   if  ShellAPI . FindExecutable ( PChar ( Doc ),  nil ,  PExecFile )  <  32  then
     // No associated program found
     Result  :=  ''
   else
     // Return program file name
     Result  :=  PExecFile ;
end ;

procedure  FreePIDL ( PIDL :  ShlObj . PItemIDList );
{Uses to shell allocator to free the memory used by a given PIDL.}
var
   Malloc :  ActiveX . IMalloc ;               // shell's allocator
begin
   // Try to get shell allocator
   if  Windows . Succeeded ( ShlObj . SHGetMalloc ( Malloc ))  then
     // Use allocator to free PIDL: Malloc is freed by Delphi
     Malloc . Free ( PIDL );
end ;

function  IsShellLink ( const  LinkFileName :  string ):  Boolean ;
{Checks if the given file is a shell link.}
begin
   // Ensure COM is initialized
   ActiveX . CoInitialize ( nil );
   try
     // Valid shell link if we can load it
     Result  :=  Assigned ( LoadShellLink ( LinkFileName ));
   finally
     // Finalize COM
     ActiveX . CoUninitialize ;
   end ;
end ;

function  IsSpecialFolderSupported ( CSIDL :  Integer ):  Boolean ;
{Returns true if the given special folder specified by a CSIDL is supported on
the system and false if not.}
var
   PIDL :  ShlObj . PItemIDList ;              // PIDL of the special folder
begin
   // Try to get PIDL for folder: fails if not supported
   Result  :=  Windows . Succeeded (
     ShlObj . SHGetSpecialFolderLocation ( 0 ,  CSIDL ,  PIDL )
     );
   if  Result  then
     // Free the PIDL using shell allocator
     FreePIDL ( PIDL );
end ;

function  LoadShellLink ( const  LinkFileName :  string ):  ShlObj . IShellLink ;
{Loads a shell link file into a shell link object and returns the IShellLink
interface of the object. If the given file is not a shell link nil is
returned. The returned object can be used to access information about the
shell link.}
var
   PF :  ActiveX . IPersistFile ;              // persistent file interface to shell link object
begin
   // Create shell link object
   if  ActiveX . Succeeded (
     ActiveX . CoCreateInstance (
     ShlObj . CLSID_ShellLink ,
     nil ,
     ActiveX . CLSCTX_INPROC_SERVER ,
     ShlObj . IShellLink ,
     Result
     )
     )  then
   begin
     // Try to load the shell link: succeeds only of file is shell link
     PF  :=  Result  as  ActiveX . IPersistFile ;
     if  ActiveX . Failed (
       PF . Load ( PWideChar ( WideString ( LinkFileName )),  ActiveX . STGM_READ )
       )  then
       Result  :=  nil ;                     // this frees the shell link object
   end
   else
     Result  :=  nil ;
end ;

function  OpenFolder ( const  Folder :  string ):  Boolean ;
{Opens given folder in Windows Explorer. Returns true if folder is valid and
can be opened, or false otherwise.}
begin
   if  SysUtils . FileGetAttr ( Folder )  and  faDirectory  =  faDirectory  then
     // Folder is valid directory: try to open it
     Result  :=  ShellAPI . ShellExecute (
       0 ,  'open' ,  PChar ( Folder ),  nil ,  nil ,  Windows . SW_SHOWNORMAL
       )  >  32
   else
     // Folder is not a directory: error
     Result  :=  False ;
end ;

function  PIDLToFolderPath ( PIDL :  ShlObj . PItemIDList ):  string ;
{Returns the full path to a file system folder from a PIDL or '' if the PIDL
refers to a virtual folder.}
begin
   // Set max length of return string
   SetLength ( Result ,  Windows . MAX_PATH );
   // Get the path
   if  ShlObj . SHGetPathFromIDList ( PIDL ,  PChar ( Result ))  then
     Result  :=  PChar ( Result )
   else
     Result  :=  '' ;
end ;

function  ShowFindFilesDlg ( const  Folder :  string ):  Boolean ;
{Displays the Windows find files dialog box ready for searching the given
folder. Returns true if dialog is shown and false if can't be shown (e.g. if
given folder is not valid).}
begin
   Result  :=  ShellAPI . ShellExecute (
     0 ,  'find' ,  PChar ( Folder ),  '' ,  '' ,  Windows . SW_SHOW
     )  >  32 ;
end ;

function  SpecialFolderPath ( CSIDL :  Integer ):  string ;
{Returns the full path to a special file system folder specified by a CSIDL
constant FolderID or '' if the special folder is virtual or CSIDL is not
supported.}
var
   PIDL :  ShlObj . PItemIDList ;              // PIDL of the special folder
begin
   Result  :=  '' ;
   // Get PIDL for required folder
   if  Windows . Succeeded (
     ShlObj . SHGetSpecialFolderLocation ( 0 ,  CSIDL ,  PIDL )
     )  then
   begin
     try
       // Get path from PIDL
       Result  :=  PIDLToFolderPath ( PIDL );
     finally
       // Free the PIDL using shell allocator
       FreePIDL ( PIDL );
     end ;
   end
end ;

function  TaskAllocWideString ( const  S :  string ):  Windows . PWChar ;
{Converts a given ANSI string to a wide string and stores in a buffer
allocated by the Shell's task allocator. If the buffer needs to be freed
IMalloc.Free should be used to do this.}
var
   StrLen :  Integer ;                       // length of string in bytes
begin
   // Store length of string allowing for terminal #0
   StrLen  :=  Length ( S )  +  1 ;
   // Alloc buffer for wide string using task allocator
   Result  :=  ActiveX . CoTaskMemAlloc ( StrLen  *  SizeOf ( WideChar ));
   if  Assigned ( Result )  then
     // Convert string to wide string and store in buffer
     StringToWideChar ( S ,  Result ,  StrLen );
end ;

function  TaskbarHandle :  Windows . THandle ;
{Returns the window handle of the Windows task bar.}
begin
   Result  :=  Windows . FindWindow ( 'Shell_TrayWnd' ,  nil );
end ;

function  CommonFilesFolder :  string ;
{Returns directory used for common files.}
begin
   Result  :=  GetCurrentVersionRegStr ( 'CommonFilesDir' );
end ;

function  GetCurrentVersionRegStr ( const  ValName :  string ):  string ;
{Gets given string value from given subkey of Windows current version registry
key.}
const
   cWdwCurrentVer  =  '/Software/Microsoft/Windows/CurrentVersion' ;
begin
   Result  :=  GetRegistryString (
     Windows . HKEY_LOCAL_MACHINE ,
     cWdwCurrentVer ,
     ValName
     );
end ;

function  GetRegistryString ( const  RootKey :  Windows . HKEY ;
   const  SubKey ,  Name :  string ):  string ;
{Gets a string value from the registry from the given root and sub key.
Converts integers to strings and raises exception for binary and unknown
value types. Returns '' if the sub key or value name are not known.}
var
   Reg :  Registry . TRegistry ;               // registry access object
   ValueInfo :  Registry . TRegDataInfo ;      // info about registry value
begin
   Result  :=  '' ;
   // Open registry at required root key
   Reg  :=  Registry . TRegistry . Create ;
   try
     Reg . RootKey  :=  RootKey ;
     // Open registry key and check value exists
     if  Reg . OpenKeyReadOnly ( SubKey )
       and  Reg . ValueExists ( Name )  then
     begin
       // Check if registry value is string or integer
       Reg . GetDataInfo ( Name ,  ValueInfo );
       case  ValueInfo . RegData  of
         Registry . rdString ,  Registry . rdExpandString :
           // string value: just return it
           Result  :=  Reg . ReadString ( Name );
         Registry . rdInteger :
           // integer value: convert to string
           Result  :=  SysUtils . IntToStr ( Reg . ReadInteger ( Name ));
       else
         // unsupported value: raise exception
         raise  SysUtils . Exception . Create (
           'Unsupported registry type'
           );
       end ;
     end ;
   finally
     // Close registry
     Reg . Free ;
   end ;
end ;

function  IsIntResource ( const  ResID :  PChar ):  Boolean ;
{Returns true if the given resource ID is integer value or false if the ID is
a pointer to a zero terminated string.}
begin
   Result  :=  ( Windows . HiWord ( Windows . DWORD ( ResID ))  =  0 );
end ;

function  IsMediaCenterOS :  Boolean ;
{Returns true if the operating system is a Windows Media Center edition or
false if not.}
const
   SM_MEDIACENTER  =  87 ;                   // metrics flag not defined in Windows unit
begin
   Result  :=  Windows . GetSystemMetrics ( SM_MEDIACENTER )  <>  0 ;
end ;

function  IsTabletOS :  Boolean ;
{Returns true if the operating system is a Windows Tablet edition or false if
not.}
const
   SM_TABLETPC  =  86 ;                      // metrics flag not defined in Windows unit
begin
   Result  :=  Windows . GetSystemMetrics ( SM_TABLETPC )  <>  0 ;
end ;

function  IsWin9x :  Boolean ;
{Returns true if the operating system is on the Windows 9x platform (including
Windows 95, 98 and Me) and false if not.}
begin
   Result  :=  SysUtils . Win32Platform  =  Windows . VER_PLATFORM_WIN32_WINDOWS ;
end ;

function  IsWinNT :  Boolean ;
{Returns true if the operating system is Windows NT (including 2000 and XP)
and false if not.}
begin
   Result  :=  ( SysUtils . Win32Platform  =  Windows . VER_PLATFORM_WIN32_NT );
end ;

function  IsWow64 :  Boolean ;
{Returns true if the current process is executing as a 32 bit process under
WOW64 on 64 bit Windows.}
type
   TIsWow64Process  =  function (            // Type of IsWow64Process API fn
     Handle :  Windows . THandle ;  var  Res :  Windows . BOOL
     ):  Windows . BOOL ;  stdcall ;
var
   IsWow64Result :  Windows . BOOL ;           // Result from IsWow64Process
   IsWow64Process :  TIsWow64Process ;       // IsWow64Process fn reference
begin
   // Try to load required function from kernel32
   IsWow64Process  :=  Windows . GetProcAddress (
     Windows . GetModuleHandle ( 'kernel32' ),  'IsWow64Process'
     );
   if  Assigned ( IsWow64Process )  then
   begin
     // Function is implemented: call it
     if  not  IsWow64Process (
       Windows . GetCurrentProcess ,  IsWow64Result
       )  then
       raise  SysUtils . Exception . Create ( 'IsWow64: bad process handle' );
     // Return result of function
     Result  :=  IsWow64Result ;
   end
   else
     // Function not implemented: can't be running on Wow64
     Result  :=  False ;
end ;

function  ProgramFilesFolder :  string ;
{Returns directory used for program files.}
begin
   Result  :=  GetCurrentVersionRegStr ( 'ProgramFilesDir' );
end ;

function  SystemFolder :  string ;
{Returns path to Windows system folder.}
begin
   SetLength ( Result ,  Windows . MAX_PATH );
   SetLength (
     Result ,  Windows . GetSystemDirectory ( PChar ( Result ),  Windows . MAX_PATH )
     );
end ;

function  TempFolder :  string ;
{Returns path to Windows temporary folder.}
begin
   SetLength ( Result ,  Windows . MAX_PATH );
   SetLength (
     Result ,  Windows . GetTempPath ( Windows . MAX_PATH ,  PChar ( Result ))
     );
end ;

function  WindowsFolder :  string ;
{Returns path to Windows folder.}
begin
   SetLength ( Result ,  Windows . MAX_PATH );
   SetLength (
     Result ,  Windows . GetWindowsDirectory ( PChar ( Result ),  Windows . MAX_PATH )
     );
end ;

function  WindowsProductID :  string ;
{Returns the Windows product ID.}
const
   // Registry keys for Win 9x/NT
   cRegKey :  array [ Boolean ]  of  string  =  (
     'Software/Microsoft/Windows/CurrentVersion' ,
     'Software/Microsoft/Windows NT/CurrentVersion'
     );
   // Registry key name
   cName  =  'ProductID' ;
begin
   Result  :=  GetRegistryString (
     Windows . HKEY_LOCAL_MACHINE ,  cRegKey [ IsWinNT ],  cName
     );
end ;

end . 
 
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值