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

本文档提供了一系列Delphi代码片段,包括日期时间转换、文件操作及图形处理等功能的实现方法。介绍了如何将Delphi TDateTime类型转换为Windows FILETIME类型、如何创建URL快捷方式文件等实用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

{
  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. 
 
//▎============================================================▎// //▎================① 扩展的字符串操作函数 ===================▎// //▎============================================================▎// //从文件中返回Ado连接字串。 function GetConnectionString(DataBaseName:string):string; //返回服务器的机器名称. function GetRemoteServerName:string; function InStr(const sShort: string; const sLong: string): Boolean; {测试通过} {* 判断s1是否包含在s2中} function IntToStrEx(Value: Integer; Len: Integer; FillChar: Char = '0'): string; {测试通过} {* 扩展整数转字符串函数 Example: IntToStrEx(1,5,'0'); 返回:"00001"} function IntToStrSp(Value: Integer; SpLen: Integer = 3; Sp: Char = ','): string; {测试通过} {* 带分隔符的整数-字符转换} function ByteToBin(Value: Byte): string; {测试通过} {* 字节转进制串} function StrRight(Str: string; Len: Integer): string; {测试通过} {* 返回字符串右边的字符 Examples: StrRight('ABCEDFG',3); 返回:'DFG' } function StrLeft(Str: string; Len: Integer): string; {测试通过} {* 返回字符串左边的字符} function Spc(Len: Integer): string; {测试通过} {* 返回空格串} function Replace(Str,s1,s2:string;CaseSensitive:Boolean):string; {测试通过} {* 返回将指定字符s1用字符串s2替换后的字符串,可支持大小写敏感由CaseSensitive操作} {example: replace('We know what we want','we','I',false) = 'I Know what I want'} function Replicate(pcChar:Char; piCount:integer):string; {在一个字符串中查找某个字符串的位置} function StrNum(ShortStr:string;LongString:string):Integer; {测试通过} {* 返回某个字符串中某个字符串中出现的次数} function FindStr(ShortStr:String;LongStrIng:String):Integer; {测试通过} {* 返回某个字符串中查找某个字符串的位置} function SubStr(psInput:String; BeginPlace,CutLeng:Integer):String; {测试通过} {* 返回从位置BeginPlace开始切取长度为CatLeng字符串} function LeftStr(psInput:String; CutLeng:Integer):String; {测试通过} {* 返回从左边第一为开始切取 CutLeng长度的字符串} function RightStr(psInput:String; CutLeng:Integer):String; {测试通过} {* 返回从右边第一为开始切取 CutLeng长度的字符串} function PadLStr(psInput:String; piWidth:Integer; pcPadWith:Char):String; {测试通过} {* 返回从psInput字符串左边开始用pcPadWith填充后总长度为PiWidth的字符串} function PadRStr(psInput:String; piWidth:Integer; pcPadWith:Char):String; {测试通过} {* 返回从psInput字符串右边开始用pcPadWith填充后总长度为PiWidth的字符串} function PadCStr(psInput:String; piWidth:Integer; pcPadWith:Char):String; {测试通过} {* 返回从psInput字符串两边开始用pcPadWith填充后总长度为PiWidth的字符串} function ChrTran(psInput:String; pcSearch:Char; pcTranWith:Char):String; {测试通过} {* 返回替换后字符串[替换单个字符] Examples: ChrTran('abCdEgdlkh','d','#'); 返回'abC#Eg#lkh'} function StrTran(psInput:String; psSearch:String; psTranWith:String):String; {测试通过} {* 返回替换后字符串[替换字符串] Examples: StrTran('aruyfbn','ruy','=====');; 返回'a=====fbn'} function Stuff(psInput:String; piBeginPlace,piCount:Integer; psStuffWith:String):String; { *返回替换后字符串[替换字符串] Examples: Stuff('ABCDEFGHI',3,4,'12345');返回'AB12345GHI'} procedure SwapStr(var s1, s2: string); {测试通过} {* 交换字串} function LinesToStr(const Lines: string): string; {测试通过} {* 多行文本转单行(换行符转'\n')} function StrToLines(const Str: string): string; {测试通过} {* 单行文本转多行('\n'转换行符)} function Encrypt(const S: String; Key: Word): String; {* 字符串加密函数} function Decrypt(const S: String; Key: Word): String; {* 字符串解密函数} function varIIF(aTest: Boolean; TrueValue, FalseValue: Variant): Variant; function varToStr(const V: Variant): string; {* VarIIF及VartoStr为变体函数} function IsDigital(Value: string): boolean; {功能说明:判断string是否全是数字} function RandomStr(aLength : Longint) : String; {随机字符串函数} //▎============================================================▎// //▎================② 扩展的日期时间操作函数 =================▎// //▎============================================================▎// function GetYear(Date: TDate): Integer; {测试通过} {* 取日期年份分量} function GetMonth(Date: TDate): Integer; {测试通过} {* 取日期月份分量} function GetDay(Date: TDate): Integer; {测试通过} {* 取日期天数分量} function GetHour(Time: TTime): Integer; {测试通过} {* 取时间小时分量} function GetMinute(Time: TTime): Integer; {测试通过} {* 取时间分钟分量} function GetSecond(Time: TTime): Integer; {测试通过} {* 取时间秒分量} function GetMSecond(Time: TTime): Integer; {测试通过} {* 取时间毫秒分量} function GetMonthLastDay(Cs_Year,Cs_Month:string):string; { *传入年、月,得到该月份最后一天} function IsLeapYear( nYear: Integer ): Boolean; {*/判断某年是否为闰年} function MaxDateTime(const Values: array of TDateTime): TDateTime; {//两个日期取较大的日期} function MinDateTime(const Values: array of TDateTime): TDateTime; {//两个日期取较小的日期} function dateBeginOfMonth(D: TDateTime): TDateTime; {//得到本月的第一天} function DateEndOfMonth(D: TDateTime): TDateTime; {//得到本月的最后一天} function DateEndOfYear(D: TDateTime): TDateTime; {//得到本年的最后一天} function DaysBetween(Date1, Date2: TDateTime): integer; {//得到两个日期相隔的天数} //▎============================================================▎// //▎===================③ 扩展的位操作函数 ====================▎// //▎============================================================▎// type TByteBit = 0..7; {* Byte类型位数范围} TWordBit = 0..15; {* Word类型位数范围} TDWordBit = 0..31; {* DWord类型位数范围} procedure SetBit(var Value: Byte; Bit: TByteBit; IsSet: Boolean); overload; {* 设置进制位} procedure SetBit(var Value: WORD; Bit: TWordBit; IsSet: Boolean); overload; {* 设置进制位} procedure SetBit(var Value: DWORD; Bit: TDWordBit; IsSet: Boolean); overload; {* 设置进制位} function GetBit(Value: Byte; Bit: TByteBit): Boolean; overload; {* 取进制位} function GetBit(Value: WORD; Bit: TWordBit): Boolean; overload; {* 取进制位} function GetBit(Value: DWORD; Bit: TDWordBit): Boolean; overload; {* 取进制位} //▎============================================================▎// //▎=================④扩展的文件及目录操作函数=================▎// //▎============================================================▎// function MoveFile(const sName, dName: string): Boolean; {测试通过} {* 移动文件、目录,参数为源、目标名} procedure FileProperties(const FName: string); {测试通过} {* 打开文件属性窗口} function CreatePath(path : string) : Boolean; function OpenDialog(var FileName: string; Title: string; Filter: string; Ext: string): Boolean; {* 打开文件框} function FormatPath(APath: string; Width: Integer): string; {测试通过} {* 缩短显示不下的长路径名} function GetRelativePath(Source, Dest: string): string; {测试通过} {* 取两个目录的相对路径,注意串尾不能是'\'字符!} procedure RunFile(const FName: string; Handle: THandle = 0; const Param: string = ''); {测试通过} {* 运行一个文件} function WinExecAndWait32(FileName: string; Visibility: Integer = SW_NORMAL): Integer; {测试通过} {* 运行一个文件并等待其结束} function AppPath: string; {测试通过} {* 应用程序路径} function GetDiskInfo(sFile : string; var nDiskFree,nDiskSize : Int64): boolean; {测试通过} {* 取sFile 所在磁盘空间状态 } function GetWindowsDir: string; {测试通过} {* 取Windows系统目录} function GetWinTempDir: string; {测试通过} {* 取临时文件目录} function AddDirSuffix(Dir: string): string; {测试通过} {* 目录尾加'\'修正} function MakePath(Dir: string): string; {测试通过} {* 目录尾加'\'修正} function IsFileInUse(FName: string): Boolean; {测试通过} {* 判断文件是否正在使用} function GetFileSize(FileName: string): Integer; {测试通过} {* 取文件长度} function SetFileDate(FileName: string; CreationTime, LastWriteTime, LastAccessTime: TFileTime): Boolean; {测试通过} {* 设置文件时间 Example: FileSetDate('c:\Test\Test1.exe',753160662); } function GetFileDate(FileName: string; var CreationTime, LastWriteTime, LastAccessTime: TFileTime): Boolean; {测试通过} {* 取文件时间} function FileTimeToLocalSystemTime(FTime: TFileTime): TSystemTime; {测试通过} {* 文件时间转本地时间} function LocalSystemTimeToFileTime(STime: TSystemTime): TFileTime; {测试通过} {* 本地时间转文件时间} function GetFileIcon(FileName: string; var Icon: TIcon): Boolean; {测试通过} {* 取得与文件相关的图标,成功则返回True} function CreateBakFile(FileName, Ext: string): Boolean; {测试通过} {* 创建备份文件} function Deltree(Dir: string): Boolean; {测试通过} {* 删除整个目录} function GetDirFiles(Dir: string): Integer; {测试通过} {* 取文件夹文件数} type TFindCallBack = procedure(const FileName: string; const Info: TSearchRec; var Abort: Boolean); {* 查找指定目录下文件的回调函数} procedure FindFile(const Path: string; const FileName: string = '*.*'; Proc: TFindCallBack = nil; bSub: Boolean = True; const bMsg: Boolean = True); {* 查找指定目录下文件} procedure FindFileList(Path:string;Filter,FileList:TStrings;ContainSubDir:Boolean; lb: TLabel=nil); { 功能说明:查找一个路径下的所有文件。 参数: path:路径,filter:文件扩展名过滤,FileList:文件列表, ContainSubDir:是否包含子目录} function Txtline(const txt: string): integer; {* 返回一文本文件的行数} function Html2Txt(htmlfilename: string): string; {* Html文件转化成文本文件} function OpenWith(const FileName: string): Integer; {测试通过} {* 文件打开方式} //▎============================================================▎// //▎====================⑤扩展的对话框函数======================▎// //▎============================================================▎// procedure InfoDlg(Mess: string; Caption: string = SCnInformation; Flags: Integer = MB_OK + MB_ICONINFORMATION); {测试通过} {* 显示提示窗口} function InfoOk(Mess: string; Caption: string = SCnInformation): Boolean; {测试通过} {* 显示提示确认窗口} procedure ErrorDlg(Mess: string; Caption: string = SCnError); {测试通过} {* 显示错误窗口} procedure WarningDlg(Mess: string; Caption: string = SCnWarning); {测试通过} {* 显示警告窗口} function QueryDlg(Mess: string; Caption: string = SCnInformation): Boolean; {测试通过} {* 显示查询是否窗口} procedure SetWindowAnimate(Sender : TForm; IsSetAni : bool); //▎============================================================▎// //▎=====================⑥系统功能函数=========================▎// //▎============================================================▎// procedure MoveMouseIntoControl(AWinControl: TControl); {测试通过} {* 移动鼠标到控件} function DynamicResolution(x, y: WORD): Boolean; {测试通过} {* 动态设置分辨率} procedure StayOnTop(Handle: HWND; OnTop: Boolean); {测试通过} {* 窗口最上方显示} procedure SetHidden(Hide: Boolean); {测试通过} {* 设置程序是否出现在任务栏} procedure SetTaskBarVisible(Visible: Boolean); {测试通过} {* 设置任务栏是否可见} procedure SetDesktopVisible(Visible: Boolean); {测试通过} {* 设置桌面是否可见} procedure BeginWait; {测试通过} {* 显示等待光标} procedure EndWait; {测试通过} {* 结束等待光标} function CheckWindows9598NT: string; {测试通过} {* 检测是否Win95/98/NT平台} function GetOSInfo : String; {测试通过} {* 取得当前操作平台是 Windows 95/98 还是NT} function GetCurrentUserName : string; {*获取当前Windows登录名的用户} function GetRegistryOrg_User(UserKeyType:string):string; {*获取当前注册的单位及用户名称} function GetSysVersion:string; {*//获取操作系统版本号} function WinBootMode:string; {//Windows启动模式} type PShutType = (UPowerOff, UShutdown, UReboot, ULogOff, USuspend, UHibernate); procedure WinShutDown(ShutWinType:PShutType; PForce:Boolean); {//Windows ShutDown等} //▎============================================================▎// //▎=====================⑦硬件功能函数=========================▎// //▎============================================================▎// function GetClientGUID:string; { 功能描述:在本机上得到一个GUID.去掉两端的大括号和中间的横线 返回值:去掉两端的大括号和中间的横线的一个GUID 适用范围:windows } function SoundCardExist: Boolean; {测试通过} {* 声卡是否存在} function GetDiskSerial(DiskChar: Char): string; {* 获取磁盘序列号} function DiskReady(Root: string) : Boolean; {*检查磁盘准备是否就绪} procedure WritePortB( wPort : Word; bValue : Byte ); {* 写串口} function ReadPortB( wPort : Word ) : Byte; {*读串口} function CPUSpeed: Double; {* 获知当前机器CPU的速率(MHz)} type TCPUID = array[1..4] of Longint; function GetCPUID : TCPUID; assembler; register; {*获取CPU的标识ID号*} function GetMemoryTotalPhys : Dword; {*获取计算机的物理内存} type TDriveState = (DSNODISK, DSUNFORMATTEDDISK, DSEMPTYDISK, DSDISK_WITHFILES); function DriveState (driveletter: Char) : TDriveState; {* 检查驱动器A中磁盘是否有效} //▎============================================================▎// //▎=====================⑧网络功能函数=========================▎// //▎============================================================▎// function GetComputerName:string; {* 获取网络计算机名称} function GetHostIP:string; {* 获取计算机的IP地址} function NetUserChangePassword(Domain:PWideChar; UserName:PWideChar; OldPassword:PWideChar; NewPassword:PWideChar): LongInt; stdcall; external 'netapi32.dll' name 'NetUserChangePassword'; {* // 运行平台:Windows NT/2000/XP {* // Windows 95/98/Me平台:可以用该函数修改用户的Windows登录密码} //▎============================================================▎// //▎=====================⑨汉字拼音功能函数=====================▎// //▎============================================================▎// function GetHzPy(const AHzStr: string): string; {测试通过} {* 取汉字的拼音} function HowManyChineseChar(Const s:String):Integer; {* 判断一个字符串中有多少各汉字} //▎============================================================▎// //▎===================⑩数据库功能函数及过程===================▎// //▎============================================================▎// {function PackDbDbf(Var StatusMsg: String): Boolean;} {* 物理删除数据库(Db,Dbf)中的数据[着了删除标记的记录]} procedure RepairDb(DbName: string); {* 修复Access表} function CreateODBCCfgInRegistry(ODBCSourceName:WideString;ServerName, DataBaseDescription:String):boolean; {* 通过注册表创建ODBC配置[创建在系统DSN页下]} function ADOConnectSysBase(Const Adocon:TadoConnection):boolean; {* 用Ado连接SysBase数据库函数} function ADOConnectLocalDB(Const Adocon:TadoConnection;Const Dbname,DbServerName:string;ValidateMode:Integer):boolean; {* 用Ado连接数据库函数} function ADOODBCConnectLocalDB(Const Adocon:TadoConnection;Const Dbname:string;ValidateMode:Integer):boolean; {* 用Ado与ODBC共同连接数据库函数} function CreatTable(LpDataBaseName,LpTableName,LpSentence:string):Boolean; {* //建立新表} function AddField(LpFieldName:string; LpDataType: TFieldType; LpSize: Word):string; {*//在表中添加字段} function KillField(LpFieldName:string):String; {* //在表中删除字段} function AlterTableExec(LpDataBaseName,LpSentence:string):Boolean; {* //修改表结构} function GetSQLSentence(LpTableName,LpSQLsentence:string): string; {* /修改、添加、删除表结构时的SQL句体} //▎============================================================▎// //▎======================⑾进制函数及过程======================▎// //▎============================================================▎// function StrToHex(AStr: string): string; {* 字符转化成十六进制} function HexToStr(AStr: string): string; {* 十六进制转化成字符} function TransChar(AChar: Char): Integer; //▎============================================================▎// //▎=====================⑿其它函数及过程=======================▎// //▎============================================================▎// function TrimInt(Value, Min, Max: Integer): Integer; overload; {测试通过} {* 输出限制在Min..Max之间} function IntToByte(Value: Integer): Byte; overload; {测试通过} {* 输出限制在0..255之间} function InBound(Value: Integer; Min, Max: Integer): Boolean; {测试通过} {* 判断整数Value是否在Min和Max之间} procedure CnSwap(var A, B: Byte); overload; {* 交换两个数} procedure CnSwap(var A, B: Integer); overload; {* 交换两个数} procedure CnSwap(var A, B: Single); overload; {* 交换两个数} procedure CnSwap(var A, B: Double); overload; {* 交换两个数} function RectEqu(Rect1, Rect2: TRect): Boolean; {* 比较两个Rect是否相等} procedure DeRect(Rect: TRect; var x, y, Width, Height: Integer); {* 分解一个TRect为左上角坐标x, y和宽度Width、高度Height} function EnSize(cx, cy: Integer): TSize; {* 返回一个TSize类型} function RectWidth(Rect: TRect): Integer; {* 计算TRect的宽度} function RectHeight(Rect: TRect): Integer; {* 计算TRect的高度} procedure Delay(const uDelay: DWORD); {测试通过} {* 延时} procedure BeepEx(const Freq: WORD = 1200; const Delay: WORD = 1); {Win9X下测试通过} {* 只能在Win9X下让喇叭发声} procedure ShowLastError; {测试通过} {* 显示Win32 Api运行结果信息} function writeFontStyle(FS: TFontStyles; inifile: string; write: boolean):string; {* 将字体Font.Style写入INI文件} function readFontStyle(inifile: string): TFontStyles; {* 从INI文件中读取字体Font.Style文件} //function ReadCursorPos(SourceMemo: TMemo): TPoint; function ReadCursorPos(SourceMemo: TMemo): string; {* 取得TMemo 控件当前光标的行和列信息到Tpoint中} function CanUndo(AMemo: TMemo): Boolean; {* 检查Tmemo控件能否Undo} procedure Undo(Amemo: Tmemo); {*实现Undo功能} procedure AutoListDisplay(ACombox:TComboBox); {* 实现ComBoBox自动下拉} function UpperMoney(small:real):string; {* 小写金额转换为大写 } function Myrandom(Num: Integer): integer; {*利用系统时间产生随机数)} procedure OpenIME(ImeName: string); {*打开输入法} procedure CloseIME; {*关闭输入法} procedure ToChinese(hWindows: THandle; bChinese: boolean); {*打开中文输入法} //数据备份 procedure BackUpData(LpBackDispMessTitle:String); procedure ImageLoadGif(Picture: TPicture; filename: string); procedure ImageLoadJpg(Picture: TPicture; filename: string);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值