{ @abstract(This unit contains miscellaneous supporting functions)
@author(Tomas Krysl (tk@tkweb.eu))
@created(20 Oct 2001)
@lastmod(20 Jun 2010)
Copyright © 2001 Tomas Krysl (tk@@tkweb.eu)
License:
This code is distributed as a freeware. You are free to use it as part
of your application for any purpose including freeware, commercial and
shareware applications. The origin of this source code must not be
misrepresented; you must not claim your authorship. You may modify this code
solely for your own purpose. Please feel free to contact the author if you
think your changes might be useful for other users. You may distribute only
the original package. The author accepts no liability for any damage
that may result from using this code. }
unit KFunctions;
{$include kcontrols.inc}
{$WEAKPACKAGEUNIT ON}
interface
uses
{$IFDEF FPC}
// use the LCL interface support whenever possible
{$IFDEF USE_WINAPI}
Windows,
{$ENDIF}
LCLType, LCLIntf, LMessages, LCLProc, LCLVersion,
{$ELSE}
Windows, Messages,
{$ENDIF}
Classes, Controls, ComCtrls, Graphics;
const
{$IFNDEF FPC}
{ @exclude }
KM_MOUSELEAVE = WM_MOUSELEAVE;
{ @exclude }
LM_USER = WM_USER;
{ @exclude }
LM_CANCELMODE = WM_CANCELMODE;
{ @exclude }
LM_CHAR = WM_CHAR;
{ @exclude }
LM_DROPFILES = WM_DROPFILES;
{ @exclude }
LM_ERASEBKGND = WM_ERASEBKGND;
{ @exclude }
LM_GETDLGCODE = WM_GETDLGCODE;
{ @exclude }
LM_HSCROLL = WM_HSCROLL;
{ @exclude }
LM_KEYDOWN = WM_KEYDOWN;
{ @exclude }
LM_KILLFOCUS = WM_KILLFOCUS;
{ @exclude }
LM_LBUTTONDOWN = WM_LBUTTONDOWN;
{ @exclude }
LM_LBUTTONUP = WM_LBUTTONUP;
{ @exclude }
LM_MOUSEMOVE = WM_MOUSEMOVE;
{ @exclude }
LM_SETFOCUS = WM_SETFOCUS;
{ @exclude }
LM_SIZE = WM_SIZE;
{ @exclude }
LM_VSCROLL = WM_VSCROLL;
{ @exclude }
LCL_MAJOR = 0;
{ @exclude }
LCL_MINOR = 0;
{ @exclude }
LCL_RELEASE = 0;
{$ELSE}
// hope this is correct about WM_MOUSELEAVE otherwise adapt it as you wish
{$IFDEF LCLWin32}
{$IF ((LCL_MAJOR=0) AND (LCL_MINOR=9) AND (LCL_RELEASE<27))}
{ @exclude }
KM_MOUSELEAVE = LM_LEAVE; // LCL 0.9.26.2-
{$ELSE}
{ @exclude }
KM_MOUSELEAVE = LM_MOUSELEAVE; // LCL 0.9.27+
{$IFEND}
{$ELSE}
{$IFDEF LCLWinCE}
{ @exclude }
KM_MOUSELEAVE = LM_LEAVE;
{$ELSE}
{ @exclude }
KM_MOUSELEAVE = LM_MOUSELEAVE;
{$ENDIF}
{$ENDIF}
{ @exclude }
//WM_CTLCOLORBTN = Messages.WM_CTLCOLORBTN;
{ @exclude }
//WM_CTLCOLORSTATIC = Messages.WM_CTLCOLORSTATIC;
{$ENDIF}
{$IFDEF USE_WINAPI}
{ @exclude }
SHFolderDll = 'SHFolder.dll';
{$ENDIF}
{ Base for custom messages used by KControls suite. }
KM_BASE = LM_USER + 1024;
{ Custom message. }
KM_LATEUPDATE = KM_BASE + 1;
{ Constant for horizontal resize cursor. }
crHResize = TCursor(101);
{ Constant for vertical resize cursor. }
crVResize = TCursor(102);
{ Constant for uncaptured dragging cursor. }
crDragHandFree = TCursor(103);
{ Constant for captured dragging cursor. }
crDragHandGrip = TCursor(104);
{ Checkbox frame size in logical screen units. }
cCheckBoxFrameSize = 13;
{ Set of word break characters. }
cWordBreaks = [#0, #9, #32];
{ Set of line break characters. }
cLineBreaks = [#10, #13];
{ Carriage return character. }
cCR = #10;
{ Line feed character. }
cLF = #13;
{ Text ellipsis string. }
cEllipsis = '...';
type
{$IFNDEF FPC}
{ @exclude }
TLMessage = TMessage;
{ @exclude }
TLMMouse = TWMMouse;
{ @exclude }
TLMNoParams = TWMNoParams;
{ @exclude }
TLMKey = TWMKey;
{ @exclude }
TLMChar = TWMChar;
{ @exclude }
TLMEraseBkGnd = TWMEraseBkGnd;
{ @exclude }
TLMHScroll = TWMHScroll;
{ @exclude }
TLMKillFocus = TWMKillFocus;
{ @exclude }
TLMSetFocus = TWMSetFocus;
{ @exclude }
TLMSize = TWMSize;
{ @exclude }
TLMVScroll = TWMVScroll;
{$ENDIF}
//PInteger = ^Integer; defined by System.pas
{ Static array for Integer. }
TIntegers = array[0..MaxInt div SizeOf(Integer) - 1] of Integer;
{ Pointer for TIntegers. }
PIntegers = ^TIntegers;
{ Dynamic array for Integer. }
TDynIntegers = array of Integer;
//PCardinal = ^Cardinal; defined by System.pas
{ Static array for Cardinal. }
TCardinals = array[0..MaxInt div SizeOf(Cardinal) - 1] of Cardinal;
{ Pointer for TCardinals. }
PCardinals = ^TCardinals;
{ Dynamic array for Cardinal. }
TDynCardinals = array of Cardinal;
//PShortInt = ^ShortInt; defined by System.pas
{ Static array for ShortInt. }
TShortInts = array[0..MaxInt div SizeOf(ShortInt) - 1] of ShortInt;
{ Pointer for TShortInts. }
PShortInts = ^TShortInts;
{ Dynamic array for ShortInt. }
TDynShortInts = array of ShortInt;
//PSmallInt = ^SmallInt; defined by System.pas
{ Static array for SmallInt. }
TSmallInts = array[0..MaxInt div SizeOf(SmallInt) - 1] of SmallInt;
{ Pointer for TSmallInts. }
PSmallInts = ^TSmallInts;
{ Dynamic array for SmallInt. }
TDynSmallInts = array of SmallInt;
//PLongInt = ^LongInt; defined by System.pas
{ Static array for LongInt. }
TLongInts = array[0..MaxInt div SizeOf(LongInt) - 1] of LongInt;
{ Pointer for TLongInts. }
PLongInts = ^TLongInts;
{ Dynamic array for LongInt. }
TDynLongInts = array of LongInt;
//PInt64 = ^Int64; defined by System.pas
{ Static array for Int64. }
TInt64s = array[0..MaxInt div SizeOf(Int64) - 1] of Int64;
{ Pointer for TInt64s. }
PInt64s = ^TInt64s;
{ Dynamic array for Int64. }
TDynInt64s = array of Int64;
//PByte = ^Byte; defined by System.pas
{ Static array for Byte. }
TBytes = array[0..MaxInt div SizeOf(Byte) - 1] of Byte;
{ Pointer for TBytes. }
PBytes = ^TBytes;
{ Dynamic array for Byte. }
TDynBytes = array of Byte;
//PWord = ^Word; defined by System.pas
{ Static array for Word. }
TWords = array[0..MaxInt div SizeOf(Word) - 1] of Word;
{ Pointer for TWords. }
PWords = ^TWords;
{ Dynamic array for Word. }
TDynWords = array of Word;
//PLongWord = ^LongWord; defined by System.pas
{ Static array for LongWord. }
TLongWords = array[0..MaxInt div SizeOf(LongWord) - 1] of LongWord;
{ Pointer for TLongWords. }
PLongWords = ^TLongWords;
{ Dynamic array for LongWord. }
TDynLongWords = array of LongWord;
{$IFDEF COMPILER10_UP}
{ Static array for UInt64. }
TUInt64s = array[0..MaxInt div SizeOf(UInt64) - 1] of UInt64;
{ Pointer for TUInt64s. }
PUInt64s = ^TUInt64s;
{ Dynamic array for UInt64. }
TDynUInt64s = array of UInt64;
{$ENDIF}
//PSingle = ^Single; defined by System.pas
{ Static array for Single. }
TSingles = array[0..MaxInt div SizeOf(Single) - 1] of Single;
{ Pointer for TSingles. }
PSingles = ^TSingles;
{ Dynamic array for Single. }
TDynSingles = array of Single;
//PDouble = ^Double; defined by System.pas
{ Static array for Double. }
TDoubles = array[0..MaxInt div SizeOf(Double) - 1] of Double;
{ Pointer for TDoubles. }
PDoubles = ^TDoubles;
{ Dynamic array for Double. }
TDynDoubles = array of Double;
{$IFNDEF FPC}
//PExtended = ^Extended; defined by System.pas
{ Static array for Extended. }
TExtendeds = array[0..MaxInt div SizeOf(Extended) - 1] of Extended;
{ Pointer for TExtendeds. }
PExtendeds = ^TExtendeds;
{ Dynamic array for Extended. }
TDynExtendeds = array of Extended;
{$ENDIF}
//PChar is special type
{ Static array for Char. }
TChars = array[0..MaxInt div SizeOf(Char) - 1] of Char;
{ Pointer for TChars. }
PChars = ^TChars;
{ Dynamic array for Char. }
TDynChars = array of Char;
{ Useful structure to handle general data and size as a single item }
TDataSize = record
Data: Pointer;
Size: Integer;
end;
{ Pointer for TDataSize }
PDataSize = ^TDataSize;
{ Set type for @link(CharInSetEx). }
TKSysCharSet = set of AnsiChar;
{ Defines a currency format settings for @link(FormatCurrency). }
TKCurrencyFormat = record
CurrencyFormat,
CurrencyDecimals: Byte;
CurrencyString: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF};
DecimalSep: Char;
ThousandSep: Char;
UseThousandSep: Boolean;
end;
{ Replaces possible decimal separators in S with DecimalSeparator variable.}
function AdjustDecimalSeparator(const S: string): string;
{$IFNDEF FPC}
{ Converts an AnsiString into a PWideChar string. If CodePage is not set
the current system code page for ANSI-UTFx translations will be used. }
function AnsiStringToWideChar(const Text: AnsiString; CodePage: Cardinal = CP_ACP): PWideChar;
{$ENDIF}
{ Under Windows this function calls the WinAPI TrackMouseEvent. Under other OSes
the implementation is still missing. }
procedure CallTrackMouseEvent(Control: TWinControl; var Status: Boolean);
{ Compiler independent Delphi2009-like CharInSet function for ANSI characters. }
function CharInSetEx(AChar: AnsiChar; const ASet: TKSysCharSet): Boolean; overload;
{ Compiler independent Delphi2009-like CharInSet function for Unicode characters. }
function CharInSetEx(AChar: WideChar; const ASet: TKSysCharSet): Boolean; overload;
{ Compares two Integers. Returns 1 if I1 > I2, -1 if I1 < I2 and 0 if I1 = I2. }
function CompareIntegers(I1, I2: Integer): Integer;
{ Compares two PWideChar strings. Returns 1 if W1 > W2, -1 if W1 < W2 and
0 if W1 = W2. The strings will be compared using the default user locale
unless another locale has been specified in Locale. }
function CompareWideChars(W1, W2: PWideChar{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal = LOCALE_USER_DEFAULT{$ENDIF}): Integer;
{$IFDEF STRING_IS_UNICODE}
{ Compares two Unicode strings (Lazarus, Delphi 2009 and better). Returns 1 if S1 > S2,
-1 if S1 < S2 and 0 if S1 = S2. The strings will be compared using the default
user locale unless another locale has been specified in Locale. }
function CompareChars(S1, S2: PChar{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal = LOCALE_USER_DEFAULT{$ENDIF}): Integer;
{$ENDIF}
{ Compares two WideString strings. Returns 1 if W1 > W2, -1 if W1 < W2 and
0 if W1 = W2. The strings will be compared using the default user locale
unless another locale has been specified in Locale. }
function CompareWideStrings(W1, W2: WideString{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal = LOCALE_USER_DEFAULT{$ENDIF}): Integer;
{$IFDEF STRING_IS_UNICODE}
{ Compares two Unicode strings (Lazarus, Delphi 2009 and better). Returns 1 if S1 > S2,
-1 if S1 < S2 and 0 if S1 = S2. The strings will be compared using the default
user locale unless another locale has been specified in Locale. }
function CompareStrings(S1, S2: string{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal = LOCALE_USER_DEFAULT{$ENDIF}): Integer;
{$ENDIF}
{ Performs integer division. If there is a nonzero remainder,
the result will be incremented. }
function DivUp(Dividend, Divisor: Integer): Integer;
{ Performs integer division. If there is a nonzero remainder,
the result will be decremented. }
function DivDown(Dividend, Divisor: Integer): Integer;
{ Raises a general exception with associated message Msg. }
procedure Error(const Msg: string);
{ Swaps values of two SmallInt variables. }
procedure Exchange(var Value1, Value2: SmallInt); overload;
{ Swaps values of two ShortInt variables. }
procedure Exchange(var Value1, Value2: ShortInt); overload;
{ Swaps values of two Integer variables. }
procedure Exchange(var Value1, Value2: Integer); overload;
{ Swaps values of two Int64 variables. }
procedure Exchange(var Value1, Value2: Int64); overload;
{ Swaps values of two Byte variables. }
procedure Exchange(var Value1, Value2: Byte); overload;
{ Swaps values of two Word variables. }
procedure Exchange(var Value1, Value2: Word); overload;
{ Swaps values of two Cardinal variables. }
procedure Exchange(var Value1, Value2: Cardinal); overload;
{$IFDEF COMPILER10_UP }
{ Swaps values of two UInt64 variables. }
procedure Exchange(var Value1, Value2: UInt64); overload;
{$ENDIF}
{ Swaps values of two Single variables. }
procedure Exchange(var Value1, Value2: Single); overload;
{ Swaps values of two Double variables. }
procedure Exchange(var Value1, Value2: Double); overload;
{$IFNDEF FPC}
{ Swaps values of two Extended variables. }
procedure Exchange(var Value1, Value2: Extended); overload;
{$ENDIF}
{ Swaps values of two Char variables. }
procedure Exchange(var Value1, Value2: Char); overload;
{ Fills the message record. }
function FillMessage(Msg: Cardinal; WParam: WPARAM; LParam: LPARAM): TLMessage;
{ Formats the given currency value with to specified parameters. Not thread safe. }
function FormatCurrency(Value: Currency; const AFormat: TKCurrencyFormat): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF};
{ Returns the module version for given module. Works under WinX only. }
function GetAppVersion(const ALibName: string; var MajorVersion, MinorVersion, BuildNumber, RevisionNumber: Word): Boolean;
{ Returns the Text property of any TWinControl instance as WideString (up to Delphi 2007)
or string (Delphi 2009, Lazarus). }
function GetControlText(Value: TWinControl): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF};
{ Returns current status of Shift, Alt and Ctrl keys. }
function GetShiftState: TShiftState;
{ Converts an integer into binary string with custom alignment
(given by Digits). }
function IntToAscii(Value: Int64; Digits: Integer): string;
{ Converts an integer into binary digit string with custom alignment
(given by Digits) and suffix. }
function IntToBinStr(Value: Int64; Digits: Byte; const Suffix: string): string;
{ Converts an integer value into BCD number. }
function IntToBCD(Value: Cardinal): Cardinal;
{ Converts an integer into decimal digit string. Equals to IntToStr. }
function IntToDecStr(Value: Int64): string;
{ Converts an integer into hexadecimal digit string with custom alignment
(given by Digits), prefix and suffix. Digits represented by alphabetical
characters can be either in lower or upper case. }
function IntToHexStr(Value: Int64; Digits: Byte; const Prefix, Suffix: string;
UseLowerCase: Boolean): string;
function IntPowerInt(Value: Int64; Exponent: Integer): Int64;
{ Converts a binary string into integer with custom alignment (given by Digits). }
function AsciiToInt(S: string; Digits: Integer): Int64;
{ Converts a BCD number into integer value. }
function BCDToInt(Value: Cardinal): Cardinal;
{ Converts a binary digit string into integer with custom alignment
(given by Digits) and sign of a value represented by the string (given by Signed).
Code returns either zero for a successful conversion or the position of
first bad character. }
function BinStrToInt(S: string; Digits: Byte; Signed: Boolean;
var Code: Integer): Int64;
{ Converts a decimal digit string into integer. Code returns either zero for
a successful conversion or the position of first bad character. Equals to Val. }
function DecStrToInt(S: string; var Code: Integer): Int64;
{ Converts a hexadecimal digit string into integer with custom alignment
(given by Digits) and sign of a value represented by the string (given by Signed).
Code returns either zero for a successful conversion or the position of
first bad character. }
function HexStrToInt(S: string; Digits: Byte; Signed: Boolean;
var Code: Integer): Int64;
{ Returns a clipped ShortInt value so that it lies between Min and Max }
function MinMax(Value, Min, Max: ShortInt): ShortInt; overload;
{ Returns a clipped SmallInt value so that it lies between Min and Max }
function MinMax(Value, Min, Max: SmallInt): SmallInt; overload;
{ Returns a clipped Integer value so that it lies between Min and Max }
function MinMax(Value, Min, Max: Integer): Integer; overload;
{ Returns a clipped Int64 value so that it lies between Min and Max }
function MinMax(Value, Min, Max: Int64): Int64; overload;
{ Returns a clipped Single value so that it lies between Min and Max }
function MinMax(Value, Min, Max: Single): Single; overload;
{ Returns a clipped Double value so that it lies between Min and Max }
function MinMax(Value, Min, Max: Double): Double; overload;
{$IFNDEF FPC}
{ Returns a clipped Extended value so that it lies between Min and Max }
function MinMax(Value, Min, Max: Extended): Extended; overload;
{$ENDIF}
{ Under Windows this function calls the WinAPI SetWindowRgn. Under other OSes
the implementation is still missing. }
procedure SetControlClipRect(AControl: TWinControl; const ARect: TRect);
{ Modifies the Text property of any TWinControl instance. The value is given as
WideString (up to Delphi 2007) or string (Delphi 2009, Lazarus). }
procedure SetControlText(Value: TWinControl; const Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF});
{ Returns next character index for given null terminated string and character index.
Takes MBCS (UTF8 in Lazarus) into account. }
function StrNextCharIndex(AText: {$IFDEF STRING_IS_UNICODE}PChar{$ELSE}PWideChar{$ENDIF}; Index: Integer): Integer;
{ Returns the index for given string where character at given index begins.
Takes MBCS (UTF8 in Lazarus) into account. }
function StringCharBegin(const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; Index: Integer): Integer;
{ Returns the number of characters in a string. Under Delphi it equals Length,
under Lazarus it equals UTF8Length. }
function StringLength(const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}): Integer;
{ Returns next character index for given string and character index.
Takes MBCS (UTF8 in Lazarus) into account. }
function StringNextCharIndex(const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; Index: Integer): Integer;
{ Trims characters specified by ASet from the beginning and end of AText.
New text length is returned by ALen. }
procedure TrimWhiteSpaces(var AText: {$IFDEF STRING_IS_UNICODE}PChar{$ELSE}PWideChar{$ENDIF}; var ALen: Integer; const ASet: TKSysCharSet); overload;
{ Trims characters specified by ASet from the beginning and end of AText. }
procedure TrimWhiteSpaces(var AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; const ASet: TKSysCharSet); overload;
{$IFNDEF FPC}
{ Converts a PWideChar string into AnsiString. If CodePage is not set
the current system code page for ANSI-UTFx translations will be used. }
function WideCharToAnsiString(Text: PWideChar; CodePage: Cardinal = CP_ACP): AnsiString;
{$ENDIF}
{$IFDEF USE_WINAPI}
function GetWindowsFolder(CSIDL: Cardinal; var APath: string): Boolean;
{$ENDIF}
implementation
uses
Forms, Math, SysUtils, TypInfo
{$IFDEF USE_WINAPI}
, ShlObj
{$ENDIF}
{$IFDEF USE_WIDEWINPROCS}
, KWideWinProcs
{$ENDIF}
;
function AdjustDecimalSeparator(const S: string): string;
var
I: Integer;
begin
Result := S;
for I := 1 to Length(Result) do
if CharInSetEx(Result[I], [',', '.']) then
Result[I] := DecimalSeparator;
end;
{$IFNDEF FPC}
function AnsiStringToWideChar(const Text: AnsiString; CodePage: Cardinal): PWideChar;
var
Len: Integer;
begin
Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(Text), -1, nil, 0);
GetMem(Result, Len shl 1);
MultiByteToWideChar(CodePage, 0, PAnsiChar(Text), -1, Result, Len);
end;
{$ENDIF}
procedure CallTrackMouseEvent(Control: TWinControl; var Status: Boolean);
{$IFDEF USE_WINAPI}
var
TE: TTrackMouseEvent;
begin
if not Status then
begin
TE.cbSize := SizeOf(TE);
TE.dwFlags := TME_LEAVE;
TE.hwndTrack := Control.Handle;
TE.dwHoverTime := HOVER_DEFAULT;
TrackMouseEvent(TE);
Status := True;
end;
end;
{$ELSE}
begin
// This is a TODO for Lazarus team.
end;
{$ENDIF}
function CharInSetEx(AChar: AnsiChar; const ASet: TKSysCharSet): Boolean;
begin
Result := AChar in ASet;
end;
function CharInSetEx(AChar: WideChar; const ASet: TKSysCharSet): Boolean;
begin
Result := (Ord(AChar) < $100) and
{$IFDEF COMPILER12_UP}
CharInSet(AChar, ASet);
{$ELSE}
(AnsiChar(AChar) in ASet);
{$ENDIF}
end;
function CompareIntegers(I1, I2: Integer): Integer;
begin
if I1 > I2 then Result := 1
else if I1 < I2 then Result := -1
else Result := 0;
end;
function CompareWideChars(W1, W2: PWideChar{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal{$ENDIF}): Integer;
begin
if (W1 = nil) or (W2 = nil) then
begin
if W1 <> nil then Result := 1
else if W2 <> nil then Result := -1
else Result := 0;
end else
begin
{$IFDEF USE_WIDEWINPROCS}
Result := WideWinProcs.CompareString(Locale, 0, W1, -1, W2, -1);
Dec(Result, 2);
{$ELSE}
Result := WideCompareStr(WideString(W1), WideString(W2));
{$ENDIF}
end;
end;
{$IFDEF STRING_IS_UNICODE}
function CompareChars(S1, S2: PChar{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal{$ENDIF}): Integer;
begin
if (S1 = nil) or (S2 = nil) then
begin
if S1 <> nil then Result := 1
else if S2 <> nil then Result := -1
else Result := 0;
end else
begin
{$IFDEF USE_WIDEWINPROCS}
Result := WideWinProcs.CompareString(Locale, 0, PWideChar(S1), -1, PWideChar(S2), -1);
Dec(Result, 2);
{$ELSE}
Result := CompareStr(string(S1), string(S2));
{$ENDIF}
end;
end;
{$ENDIF}
function CompareWideStrings(W1, W2: WideString{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal{$ENDIF}): Integer;
begin
{$IFDEF USE_WIDEWINPROCS}
Result := WideWinProcs.CompareString(Locale, 0, PWideChar(W1), -1, PWideChar(W2), -1);
Dec(Result, 2);
{$ELSE}
Result := WideCompareStr(W1, W2);
{$ENDIF}
end;
{$IFDEF STRING_IS_UNICODE}
function CompareStrings(S1, S2: string{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal{$ENDIF}): Integer;
begin
{$IFDEF USE_WIDEWINPROCS}
Result := WideWinProcs.CompareString(Locale, 0, PWideChar(S1), -1, PWideChar(S2), -1);
Dec(Result, 2);
{$ELSE}
Result := CompareStr(S1, S2);
{$ENDIF}
end;
{$ENDIF}
function DivUp(Dividend, Divisor: Integer): Integer;
begin
if Divisor = 0 then
Result := 0
else if Dividend mod Divisor > 0 then
Result := Dividend div Divisor + 1
else
Result := Dividend div Divisor;
end;
function DivDown(Dividend, Divisor: Integer): Integer;
begin
if Divisor = 0 then
Result := 0
else if Dividend mod Divisor < 0 then
Result := Dividend div Divisor - 1
else
Result := Dividend div Divisor;
end;
procedure Exchange(var Value1, Value2: ShortInt);
var
Tmp: ShortInt;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: SmallInt);
var
Tmp: SmallInt;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: Integer);
var
Tmp: Integer;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: Int64);
var
Tmp: Int64;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: Byte);
var
Tmp: Byte;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: Word);
var
Tmp: Word;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: Cardinal);
var
Tmp: Cardinal;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
{$IFDEF COMPILER10_UP }
procedure Exchange(var Value1, Value2: UINT64);
var
Tmp: UINT64;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
{$ENDIF}
procedure Exchange(var Value1, Value2: Single);
var
Tmp: Single;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: Double);
var
Tmp: Double;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
{$IFNDEF FPC}
procedure Exchange(var Value1, Value2: Extended);
var
Tmp: Extended;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
{$ENDIF}
procedure Exchange(var Value1, Value2: Char);
var
Tmp: Char;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Error(const Msg: string);
begin
raise Exception.Create(Msg);
end;
function FillMessage(Msg: Cardinal; WParam: WPARAM; LParam: LPARAM): TLMessage;
begin
Result.Msg := Msg;
Result.LParam := LParam;
Result.WParam := WParam;
Result.Result := 0;
end;
function FormatCurrency(Value: Currency; const AFormat: TKCurrencyFormat): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF};
var
OldDecimalSep, OldThousandSep: Char;
Fmt: string;
begin
OldThousandSep := ThousandSeparator;
if AFormat.UseThousandSep then
begin
ThousandSeparator := AFormat.ThousandSep;
Fmt := '%.*n';
end else
Fmt := '%.*f';
OldDecimalSep := DecimalSeparator;
DecimalSeparator := AFormat.DecimalSep;
try
case AFormat.CurrencyFormat of
0: Result := {$IFDEF STRING_IS_UNICODE}Format{$ELSE}WideFormat{$ENDIF}(
'%s' + Fmt, [AFormat.CurrencyString, AFormat.CurrencyDecimals, Value]);
1: Result := {$IFDEF STRING_IS_UNICODE}Format{$ELSE}WideFormat{$ENDIF}(
Fmt + '%s', [AFormat.CurrencyDecimals, Value, AFormat.CurrencyString]);
2: Result := {$IFDEF STRING_IS_UNICODE}Format{$ELSE}WideFormat{$ENDIF}(
'%s ' + Fmt, [AFormat.CurrencyString, AFormat.CurrencyDecimals, Value]);
else
Result := {$IFDEF STRING_IS_UNICODE}Format{$ELSE}WideFormat{$ENDIF}(
Fmt + ' %s', [AFormat.CurrencyDecimals, Value, AFormat.CurrencyString]);
end;
finally
DecimalSeparator := OldDecimalSep;
if AFormat.UseThousandSep then
ThousandSeparator := OldThousandSep;
end;
end;
function GetAppVersion(const ALibName: string; var MajorVersion, MinorVersion, BuildNumber, RevisionNumber: Word): Boolean;
{$IFDEF USE_WINAPI}
var
dwHandle, dwLen: DWORD;
BufLen: Cardinal;
lpData: LPTSTR;
pFileInfo: ^VS_FIXEDFILEINFO;
{$ENDIF}
begin
Result := False;
{$IFDEF USE_WINAPI}
dwLen := GetFileVersionInfoSize(PChar(ALibName), dwHandle);
if dwLen <> 0 then
begin
GetMem(lpData, dwLen);
try
if GetFileVersionInfo(PChar(ALibName), dwHandle, dwLen, lpData) then
begin
if VerQueryValue(lpData, '\\', Pointer(pFileInfo), BufLen) then
begin
MajorVersion := HIWORD(pFileInfo.dwFileVersionMS);
MinorVersion := LOWORD(pFileInfo.dwFileVersionMS);
BuildNumber := HIWORD(pFileInfo.dwFileVersionLS);
RevisionNumber := LOWORD(pFileInfo.dwFileVersionLS);
Result := True;
end;
end;
finally
FreeMem(lpData);
end;
end;
{$ENDIF}
end;
function GetControlText(Value: TWinControl): {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF};
function GetTextBuffer(Value: TWinControl): string;
begin
SetLength(Result, Value.GetTextLen);
Value.GetTextBuf(PChar(Result), Length(Result) + 1);
end;
begin
{$IFDEF FPC}
Result := GetTextBuffer(Value); // conversion from UTF8 forced anyway
{$ELSE}
{$IFDEF STRING_IS_UNICODE}
Result := GetTextBuffer(Value);
{$ELSE}
if Value.HandleAllocated and (Win32Platform = VER_PLATFORM_WIN32_NT) then // unicode fully supported
begin
SetLength(Result, GetWindowTextLengthW(Value.Handle));
GetWindowTextW(Value.Handle, PWideChar(Result), Length(Result) + 1);
end else
Result := GetTextBuffer(Value);
{$ENDIF}
{$ENDIF}
end;
function GetShiftState: TShiftState;
begin
Result := [];
if GetKeyState(VK_SHIFT) < 0 then Include(Result, ssShift);
if GetKeyState(VK_CONTROL) < 0 then Include(Result, ssCtrl);
if GetKeyState(VK_MENU) < 0 then Include(Result, ssAlt);
end;
function IntToAscii(Value: Int64; Digits: Integer): string;
var
I: Integer;
begin
Result := '';
I := 0;
while I < Digits do
begin
Result := Result + Chr(Value and $FF);
Value := Value shr 8;
Inc(I);
end;
end;
function IntToBCD(Value: Cardinal): Cardinal;
var
Exp: Cardinal;
begin
Result := 0;
Exp := 1;
while (Value > 0) and (Exp > 0) do
begin
Result := Result + Value mod 10 * Exp;
Value := Value div 10;
Exp := Exp * 16;
end;
end;
function IntToBinStr(Value: Int64; Digits: Byte; const Suffix: string): string;
var
B: Byte;
C: Char;
begin
Result := '';
if Digits <> 0 then
Digits := MinMax(Digits, 1, 64);
repeat
B := Byte(Value and $1);
Value := Value shr 1;
C := Chr(Ord('0') + B);
Result := C + Result;
until (Value = 0) or ((Digits <> 0) and (Length(Result) = Digits));
while Length(Result) < Digits do
Result := '0' + Result;
Result := Result + Suffix;
end;
function IntToDecStr(Value: Int64): string;
var
B: Byte;
C: Char;
begin
Result := '';
repeat
B := Byte(Value mod 10);
Value := Value div 10;
C := Chr(Ord('0') + B);
Result := C + Result;
until Value = 0;
end;
function IntToHexStr(Value: Int64; Digits: Byte; const Prefix, Suffix: string; UseLowerCase: Boolean): string;
var
B: Byte;
C: Char;
begin
Result := '';
if Digits <> 0 then
Digits := MinMax(Digits, 1, 16);
repeat
B := Byte(Value and $F);
Value := Value shr 4;
if B < 10 then
C := Chr(Ord('0') + B) else
if UseLowerCase then
C := Chr(Ord('a') + B - 10)
else
C := Chr(Ord('A') + B - 10);
Result := C + Result;
until (Value = 0) or ((Digits <> 0) and (Length(Result) = Digits));
while Length(Result) < Digits do
Result := '0' + Result;
Result := Prefix + Result + Suffix;
end;
function IntPowerInt(Value: Int64; Exponent: Integer): Int64;
begin
Result := Value;
while Exponent > 1 do
begin
Result := Result * Value;
Dec(Exponent);
end;
end;
function AsciiToInt(S: string; Digits: Integer): Int64;
var
I: Integer;
begin
Result := 0;
I := Min(Length(S), Digits);
while I > 0 do
begin
Result := Result shl 8;
Result := Ord(S[I]) + Result;
Dec(I);
end;
end;
function BCDToInt(Value: Cardinal): Cardinal;
var
Exp: Cardinal;
begin
Result := 0;
Exp := 1;
while Value > 0 do
begin
Result := Result + Min(Value and 15, 9) * Exp;
Value := Value shr 4;
Exp := Exp * 10;
end;
end;
function BinStrToInt(S: string; Digits: Byte; Signed: Boolean; var Code: Integer): Int64;
var
I, L, Len: Integer;
N: Byte;
C: Char;
M: Int64;
begin
Result := 0;
Code := 0;
L := 0;
Len := Length(S);
if (Digits = 0) or (Digits > 64) then
Digits := 64;
if (Len >= 1) and CharInSetEx(S[Len], ['b', 'B']) then
begin
Delete(S, Len, 1);
Dec(Len);
end;
I := 1;
while I <= Len do
begin
C := S[I];
N := 255;
if (C >= '0') and (C <= '1') then N := Ord(C) - Ord('0');
if N > 1 then
begin
Code := I;
Break;
end
else if (N > 0) or (Result <> 0) then
begin
if L >= Digits then
begin
Code := I;
Break;
end;
Result := Result shl 1;
Inc(Result, N);
Inc(L);
end;
Inc(I);
end;
if Signed and (Digits < 64) then
begin
M := Int64(1) shl Digits;
if Result >= M shr 1 - 1 then
Dec(Result, M);
end;
end;
function DecStrToInt(S: string; var Code: Integer): Int64;
var
I, Len: Integer;
N: Byte;
C: Char;
Minus: Boolean;
begin
Result := 0;
Code := 0;
Len := Length(S);
Minus := S[1] = '-';
if Minus then I := 2 else I := 1;
while I <= Len do
begin
C := S[I];
N := 255;
if (C >= '0') and (C <= '9') then N := Ord(C) - Ord('0');
if N > 9 then
begin
Code := I;
Break;
end
else if (N > 0) or (Result <> 0) then
begin
Result := Result * 10;
Inc(Result, N);
end;
Inc(I);
end;
if Minus then Result := -Result;
end;
function HexStrToInt(S: string; Digits: Byte; Signed: Boolean; var Code: Integer): Int64;
var
I, L, Len: Integer;
N: Byte;
C: Char;
M: Int64;
begin
Result := 0;
Code := 0;
L := 0;
Len := Length(S);
if (Digits = 0) or (Digits > 16) then
Digits := 16;
if (Len >= 2) and (AnsiChar(S[1]) = '0') and CharInSetEx(S[2], ['x', 'X']) then
I := 3
else if (Len >= 1) and CharInSetEx(S[1], ['x', 'X', '$']) then
I := 2
else
I := 1;
while I <= Len do
begin
C := S[I];
N := 255;
if (C >= '0') and (C <= '9') then N := Ord(C) - Ord('0')
else if (C >= 'a') and (C <= 'f') then N := Ord(C) - Ord('a') + 10
else if (C >= 'A') and (C <= 'F') then N := Ord(C) - Ord('A') + 10;
if N > 15 then
begin
if CharInSetEx(C, ['h', 'H']) then
begin
if Len > I then Code := I + 1;
end else
Code := I;
Break;
end
else if (N > 0) or (Result <> 0) then
begin
if L >= Digits then
begin
Code := I;
Break;
end;
Result := Result shl 4;
Inc(Result, N);
Inc(L);
end;
Inc(I);
end;
if Signed and (Digits < 16) then
begin
M := Int64(1) shl (Digits shl 2);
if Result >= M shr 1 - 1 then
Dec(Result, M);
end;
end;
function MinMax(Value, Min, Max: ShortInt): ShortInt;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
function MinMax(Value, Min, Max: SmallInt): SmallInt;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
function MinMax(Value, Min, Max: Integer): Integer;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
function MinMax(Value, Min, Max: Int64): Int64;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
function MinMax(Value, Min, Max: Single): Single;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
function MinMax(Value, Min, Max: Double): Double;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
{$IFNDEF FPC}
function MinMax(Value, Min, Max: Extended): Extended;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
{$ENDIF}
procedure SetControlClipRect(AControl: TWinControl; const ARect: TRect);
begin
if AControl.HandleAllocated then
begin
{$IFDEF USE_WINAPI}
SetWindowRgn(AControl.Handle, CreateRectRgn(0, 0, ARect.Right - ARect.Left, ARect.Bottom - ARect.Top), True);
{$ELSE}
//how to do that?
{$ENDIF}
end;
end;
procedure SetControlText(Value: TWinControl; const Text: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF});
procedure SetTextBuffer(Value: TWinControl; const Text: string);
begin
Value.SetTextBuf(PChar(Text));
end;
begin
{$IFDEF FPC}
SetTextBuffer(Value, Text); // conversion to UTF8 forced anyway
{$ELSE}
{$IFDEF STRING_IS_UNICODE}
SetTextBuffer(Value, Text);
{$ELSE}
if Value.HandleAllocated and (Win32Platform = VER_PLATFORM_WIN32_NT) then // unicode fully supported
SetWindowTextW(Value.Handle, PWideChar(Text))
else
SetTextBuffer(Value, Text);
{$ENDIF}
{$ENDIF}
end;
function StrNextCharIndex(AText: {$IFDEF STRING_IS_UNICODE}PChar{$ELSE}PWideChar{$ENDIF}; Index: Integer): Integer;
begin
{$IFDEF FPC}
Result := Index + UTF8CharacterLength(@AText[Index]);
{$ELSE}
Result := Index + 1; // neglecting surrogate pairs
{$ENDIF}
end;
function StringCharBegin(const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; Index: Integer): Integer;
begin
{$IFDEF FPC}
Result := UTF8CharToByteIndex(PChar(AText), Length(AText), Index)
{$ELSE}
Result := Index // neglecting surrogate pairs
{$ENDIF}
end;
function StringLength(const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}): Integer;
begin
{$IFDEF FPC}
Result := UTF8Length(AText)
{$ELSE}
Result := Length(AText) // neglecting surrogate pairs
{$ENDIF}
end;
function StringNextCharIndex(const AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; Index: Integer): Integer;
begin
{$IFDEF FPC}
Result := Index + UTF8CharacterLength(@AText[Index]);
{$ELSE}
Result := Index + 1; // neglecting surrogate pairs
{$ENDIF}
end;
procedure TrimWhiteSpaces(var AText: {$IFDEF STRING_IS_UNICODE}PChar{$ELSE}PWideChar{$ENDIF}; var ALen: Integer; const ASet: TKSysCharSet);
begin
while (ALen > 0) and CharInSetEx(AText[0], ASet) do
begin
AText := @AText[1];
Dec(ALen)
end;
while (ALen > 0) and CharInSetEx(AText[ALen - 1], ASet) do
Dec(ALen);
end;
procedure TrimWhiteSpaces(var AText: {$IFDEF STRING_IS_UNICODE}string{$ELSE}WideString{$ENDIF}; const ASet: TKSysCharSet);
begin
while (Length(AText) > 0) and CharInSetEx(AText[1], ASet) do
Delete(AText, 1, 1);
while (Length(AText) > 0) and CharInSetEx(AText[Length(AText)], ASet) do
Delete(AText, Length(AText), 1);
end;
{$IFNDEF FPC}
function WideCharToAnsiString(Text: PWideChar; CodePage: Cardinal): AnsiString;
var
Len: Integer;
begin
Len := WideCharToMultiByte(CodePage, 0, Text, -1, nil, 0, nil, nil);
SetLength(Result, Len);
WideCharToMultiByte(CodePage, 0, Text, -1, PAnsiChar(Result), Len, nil, nil);
end;
{$ENDIF}
{$IFDEF USE_WINAPI}
function GetWindowsFolder(CSIDL: Cardinal; var APath: string): Boolean;
type
TSHGetFolderPathProc = function(hWnd: HWND; CSIDL: Integer; hToken: THandle;
dwFlags: DWORD; pszPath: PAnsiChar): HResult; stdcall;
var
SHFolderHandle: HMODULE;
SHGetFolderPathProc: TSHGetFolderPathProc;
Buffer: PAnsiChar;
begin
Result := False;
APath := '';
SHFolderHandle := GetModuleHandle(SHFolderDll);
if SHFolderHandle <> 0 then
begin
SHGetFolderPathProc := GetProcAddress(SHFolderHandle, 'SHGetFolderPathA');
if Assigned(SHGetFolderPathProc) then
begin
GetMem(Buffer, MAX_PATH);
try
if Succeeded(SHGetFolderPathProc(0, CSIDL, 0, 0, Buffer)) then
begin
APath := string(Buffer);
Result := True;
end
finally
FreeMem(Buffer);
end;
end;
end;
end;
{$ENDIF}
end.