- Mustangpeak Common Library - 1.7.0 - EasyListview - 1.7.0 git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.Mustangpeak@2 60b41242-d4b9-2247-b156-4ccd40706241
5066 lines
172 KiB
ObjectPascal
5066 lines
172 KiB
ObjectPascal
unit MPCommonUtilities;
|
||
|
||
// Version 1.7.0
|
||
//
|
||
// The contents of this file are subject to the Mozilla Public License
|
||
// Version 1.1 (the "License"); you may not use this file except in compliance
|
||
// with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
|
||
//
|
||
// Alternatively, you may redistribute this library, use and/or modify it under the terms of the
|
||
// GNU Lesser General Public License as published by the Free Software Foundation;
|
||
// either version 2.1 of the License, or (at your option) any later version.
|
||
// You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/.
|
||
//
|
||
// Software distributed under the License is distributed on an "AS IS" basis,
|
||
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
|
||
// specific language governing rights and limitations under the License.
|
||
//
|
||
// The initial developer of this code is Jim Kueneman <jimdk@mindspring.com>
|
||
// Special thanks to the following in no particular order for their help/support/code
|
||
// Danijel Malik, Robert Lee, Werner Lehmann, Alexey Torgashin, Milan Vandrovec
|
||
//
|
||
//----------------------------------------------------------------------------
|
||
|
||
// The following are implemented in Win 95:
|
||
// EnumResourceLanguagesW
|
||
// EnumResourceNamesW
|
||
// EnumResourceTypesW
|
||
// ExtTextOutW
|
||
// FindResourceW
|
||
// FindResourceExW
|
||
// GetCharWidthW
|
||
// GetCommandLineW
|
||
// GetTextExtentPoint32W
|
||
// GetTextExtentPointW
|
||
// lstrlenW
|
||
// MessageBoxExW
|
||
// MessageBoxW
|
||
// MultiByteToWideChar
|
||
// TextOutW
|
||
// WideCharToMultiByte
|
||
|
||
{$IFDEF TNTSUPPORT}
|
||
// IMPORTANT - PLEASE READ then comment this line out.
|
||
// If using TNT you MUST include the TNT package for your specific compiler in the
|
||
// Requires section of this package. It may be possible to compile without doing
|
||
// this but you WILL eventually have strange crashes in your application that will
|
||
// be difficult to understand. The best way to do this in my opinion is to create
|
||
// a new folder in the package install directory called "Delphi_TNT" (or CBuilder_TNT)
|
||
// and copy all the files from the Delphi (or CBuilder) folder into it. Now open the
|
||
// MPCommonLibDx.dpk (or bpk) file in the "Delphi_TNT" (or CBuilder_TNT) based on your compiler
|
||
// version in a text editor. In the "Requires" section add "TNTUnicodeVcl_Rx0", where
|
||
// the "x" is the version of Delphi you are using. Open the dpk (bpk) file in your
|
||
// IDE. Select the menu option Projects>Options>Directories/Conditionals>Conditional
|
||
// and enter TNTSUPPORT. Compile the package, then open the MPCommonLibDxD.dpk (or bpk)
|
||
// and compile and press the Install button.
|
||
// Now when you update the packages you won't have to redo all this. Just install
|
||
// the update then compile the packages in the "Delphi_TNT" (or CBuilder_TNT) folders
|
||
// an you are done.
|
||
{$ENDIF}
|
||
|
||
{$B-}
|
||
|
||
{$I Compilers.inc}
|
||
{$I Options.inc}
|
||
{$I ..\Include\Debug.inc}
|
||
{$I ..\Include\Addins.inc}
|
||
|
||
interface
|
||
|
||
uses
|
||
Windows,
|
||
Messages,
|
||
SysUtils,
|
||
Classes,
|
||
Graphics,
|
||
Controls,
|
||
Forms,
|
||
Math,
|
||
ActiveX,
|
||
ShlObj,
|
||
{$IFDEF COMPILER_6_UP}
|
||
Variants,
|
||
RTLConsts,
|
||
{$ELSE}
|
||
Consts,
|
||
{$ENDIF COMPILER_6_UP}
|
||
{$IFNDEF COMPILER_6_UP}
|
||
Menus,
|
||
{$ENDIF}
|
||
{$IFDEF TNTSUPPORT}
|
||
TntSysUtils,
|
||
TntClasses,
|
||
{$ENDIF}
|
||
ShellAPI,
|
||
ComCtrls,
|
||
ComObj,
|
||
CommCtrl,
|
||
MPShellTypes,
|
||
MPResources;
|
||
|
||
const
|
||
WideNull = WideChar(#0);
|
||
WideCR = WideChar(#13);
|
||
WideLF = WideChar(#10);
|
||
WideLineSeparator = WideChar(#2028);
|
||
WideSpace = WideChar(#32);
|
||
WidePeriod = WideChar('.');
|
||
|
||
{$IFNDEF COMPILER_6_UP}
|
||
NullAsStringValue: string = '';
|
||
{$ENDIF}
|
||
|
||
Shlwapi = 'shlwapi.dll';
|
||
|
||
var
|
||
SEasyNSEMsg_Caption: WideString = 'Shell extension registration';
|
||
SEasyNSEMsg_CannotRegister: WideString = 'Cannot register shell extension.';
|
||
SEasyNSEMsg_CannotUnRegister: WideString = 'Cannot unregister shell extension.';
|
||
SEasyNSEMsg_CannotFindRegSvr: WideString = 'Unable to find RegSvr32.exe executable.';
|
||
SEasyNSEMsg_CannotFindDLL: WideString = 'Unable to find extension DLL.';
|
||
|
||
type
|
||
TCommonWideCharArray = array of WideChar;
|
||
TCommonPWideCharArray = array of PWideChar;
|
||
TCommonWideStringDynArray = array of WideString;
|
||
TCommonIntegerDynArray = array of Integer;
|
||
|
||
{$IFNDEF COMPILER_6_UP}
|
||
TValueRelationship = -1..1;
|
||
TSeekOrigin = (soBeginning, soCurrent, soEnd);
|
||
{$ENDIF}
|
||
|
||
TCommonDropEffect = (
|
||
cdeNone, // No drop effect (the circle with the slash through it
|
||
cdeCopy, // Copy the dropped object
|
||
cdeMove, // Move the dropped object
|
||
cdeLink, // Make a shortcut to the dropped object
|
||
cdeScroll // The dragging is in the middle of a scroll
|
||
);
|
||
TCommonDropEffects = set of TCommonDropEffect;
|
||
|
||
TCommonOLEDragResult = (
|
||
cdrDrop, // The drag resulted in a drop
|
||
cdrCancel, // The drag resulted in being canceled
|
||
cdrError // The drag resulted in an unknown error
|
||
);
|
||
|
||
TCommonKeyState = (
|
||
cksControl, // Control Key is down
|
||
cksLButton, // Left Mouse is down
|
||
cksMButton, // Middle Mouse is down
|
||
cksRButton, // Right Mouse is down
|
||
cksShift, // Shift Key is down
|
||
cksAlt, // Alt Key is down
|
||
cksButton // One of the mouse buttons are down
|
||
);
|
||
TCommonKeyStates = set of TCommonKeyState;
|
||
|
||
TCommonMouseButton = (
|
||
cmbNone, // No Button
|
||
cmbLeft, // Left Button
|
||
cmbRight, // Right Button
|
||
cmbMiddle // Middle Button
|
||
);
|
||
|
||
TCommonVAlignment = (
|
||
cvaTop, // The vertical alignment of the text is at the top of the object
|
||
cvaBottom, // The vertical alignment of the text is at the bottom of the object
|
||
cvaCenter // The vertical alignment of the text is at the center of the object
|
||
);
|
||
|
||
// Flags for the DrawTextWEx function
|
||
TCommonDrawTextWFlag = (
|
||
dtSingleLine, // Put Caption on one line
|
||
dtLeft, // Aligns Text Left
|
||
dtRight, // Aligns Text Right
|
||
dtCenter, // Aligns Text Center
|
||
dtTop, // Vertical Align Text to Bottom of Rect
|
||
dtBottom, // Vertical Align Text to Bottom of Rect
|
||
// Only valid with: dtSingleLine
|
||
dtVCenter, // Vertical Align Text to Center of Rect
|
||
// Only valid with: dtSingleLine
|
||
dtCalcRect, // Modifies the Rectangle to the size required for the Text does
|
||
// not draw the text. By default it does not modify the right
|
||
// edge of the rectangle, it only changes the height to fit
|
||
// the text, see dtCalcRectAdjR
|
||
dtCalcRectAdjR, // Modifies the Rectangles right edge for a best fit of the text
|
||
// Does not increase the width only shortens it,
|
||
// Only valid with: dtCalcRect
|
||
dtCalcRectAlign, // Modifies the rectangle by aligning it with the original
|
||
// rectangle based on the dtLeft, dtRight, dtCenter flag.
|
||
// In other words it ensures that if the text won't fit that
|
||
// only the end of the text is clipped. For instance if
|
||
// the text is horz centered the calculation could clip
|
||
// both ends of the text. Just using the dtCalcRectAdjR
|
||
// flag will only stretch the Right edge and the left will
|
||
// still be clipped. Using this flag will shift the rect
|
||
// to the edge of the passed rect so that the beginning
|
||
// of the text is always shown.
|
||
// Only valid with: dtCalcRect and dtCalcRectAdjR
|
||
dtEndEllipsis, // Adds a "..." to the end of the string if it will not fit in
|
||
// the passed rectangle
|
||
dtWordBreak, // Breaks the passed string to best fit in the rectangle
|
||
// The default Characters to break the line are:
|
||
// WideSpace ( WideChar(#32) )
|
||
// WideCR/WideLF sequence or individually ( WideChar(#13 or #10) )
|
||
// WideLineSeparator ( WideChar(#2028) )
|
||
dtUserBreakChars, // The UserBreakChars parameters should be used for defining
|
||
// what to use to break the passed string into lines
|
||
// Only valid with: dtWordBreak
|
||
dtRTLReading, // Right to Left reading
|
||
dtNoClip // Do not clip the text in the rectangle
|
||
);
|
||
TCommonDrawTextWFlags = set of TCommonDrawTextWFlag;
|
||
|
||
// Describes the mode how to blend pixels.
|
||
TCommonBlendMode = (
|
||
cbmConstantAlpha, // apply given constant alpha
|
||
cbmPerPixelAlpha, // use alpha value of the source pixel
|
||
cbmMasterAlpha, // use alpha value of source pixel and multiply it with the constant alpha value
|
||
cbmConstantAlphaAndColor // blend the destination color with the given constant color und the constant alpha value
|
||
);
|
||
|
||
TShortenStringEllipsis = (
|
||
sseEnd, // Ellipsis on end of string
|
||
sseFront, // Ellipsis on begining of string
|
||
sseMiddle, // Ellipsis in middle of string
|
||
sseFilePathMiddle // Ellipsis is in middle of string but tries to show the entire filename
|
||
);
|
||
|
||
// RGB (red, green, blue) color given in the range [0..1] per component.
|
||
TCommonRGB = record
|
||
R, G, B: Double;
|
||
end;
|
||
|
||
// Hue, luminance, saturation color with all three components in the range [0..1]
|
||
// (so hue's 0..360<EFBFBD> is normalized to 0..1).
|
||
TCommonHLS = record
|
||
H, L, S: Double;
|
||
end;
|
||
|
||
// Enhanced library loading functions that reference counts the loading to make
|
||
// sure that libraries are freed when using cool controls in COM applications
|
||
function CommonLoadLibrary(LibraryName: string): THandle;
|
||
function CommonUnloadLibrary(LibraryName: string): Boolean;
|
||
procedure CommonUnloadAllLibraries;
|
||
|
||
function FlipReverseCopyRect(const Flip, Reverse: Boolean; const Bitmap: TBitmap): TBitmap; overload;
|
||
procedure FlipReverseCopyRect(const Flip, Reverse: Boolean; R: TRect; const Canvas: TCanvas); overload;
|
||
|
||
procedure DrawRadioButton(Canvas: TCanvas; Pos: TPoint; Size: Integer; clBackground, clHotBkGnd,
|
||
clLeftOuter, clRightOuter, clLeftInner, clRightInner: TColor; Checked, Enabled, Hot: Boolean);
|
||
procedure DrawCheckBox(Canvas: TCanvas; Pos: TPoint; Size: Integer; clBackground, clHotBkGnd,
|
||
clLeftOuter, clRightOuter, clLeftInner, clRightInner: TColor; Checked, Enabled, Hot: Boolean);
|
||
function CheckBounds(Size: Integer): TRect;
|
||
|
||
|
||
|
||
{$IFNDEF COMPILER_6_UP}
|
||
function VarToWideStrDef(const V: Variant; const ADefault: WideString): WideString;
|
||
function VarToWideStr(const V: Variant): WideString;
|
||
function BoolToStr(B: Boolean; UseBoolStrs: Boolean = False): string;
|
||
function CompareTime(const A, B: TDateTime): TValueRelationship;
|
||
function WideCompareText(S1, S2: WideString): Integer;
|
||
function ExcludeTrailingBackslash(Path: WideString): WideString;
|
||
function IncludeTrailingBackslash(Path: WideString): WideString;
|
||
function GUIDToString(const GUID: TGUID): string;
|
||
{$ENDIF}
|
||
|
||
function AbsRect(ARect: TRect): TRect;
|
||
function AddContextMenuItem(Menu: HMenu; ACaption: WideString; Index: Integer;
|
||
MenuID: UINT = $FFFF; hSubMenu: UINT = 0; Enabled: Boolean = True;
|
||
Checked: Boolean = False; Default: Boolean = False): Integer;
|
||
function AddCommas(NumberString: WideString): WideString;
|
||
function CalcuateFolderSize(FolderPath: WideString; Recurse: Boolean): Int64;
|
||
function CenterRectHorz(OuterRect, InnerRect: TRect): TRect;
|
||
function CenterRectInRect(OuterRect, InnerRect: TRect): TRect;
|
||
function CenterRectVert(OuterRect, InnerRect: TRect): TRect;
|
||
function CommonSupports(const Instance: IUnknown; const IID: TGUID): Boolean; overload;
|
||
function CommonSupports(const Instance: IUnknown; const IID: TGUID; out Intf): Boolean; overload;
|
||
function CommonSupports(const Instance: TObject; const IID: TGUID): Boolean; overload;
|
||
function CommonSupports(const Instance: TObject; const IID: TGUID; out Intf): Boolean; overload;
|
||
procedure CopyToNullBufferA(S: WideString; Buffer: PChar; CharCount: Cardinal);
|
||
procedure CopyToNullBufferW(S: WideString; Buffer: PWideChar; CharCount: Cardinal);
|
||
procedure CreateProcessMP(ExeFile, Parameters, InitalDir: WideString);
|
||
function DiffRectHorz(Rect1, Rect2: TRect): TRect;
|
||
function DiffRectVert(Rect1, Rect2: TRect): TRect;
|
||
{$IFNDEF COMPILER_6_UP}
|
||
function DirectoryExists(const Directory: string): Boolean;
|
||
{$ENDIF}
|
||
function DiskInDrive(C: Char): Boolean;
|
||
function DragDetectPlus(Handle: HWND; Pt: TPoint): Boolean;
|
||
function DrawTextWEx(DC: HDC; Text: WideString; var lpRect: TRect; Flags: TCommonDrawTextWFlags; MaxLineCount: Integer): Integer;
|
||
function DropEffectToStr(DropEffect: DWORD): WideString;
|
||
function EqualWndMethod(A, B: TWndMethod): Boolean;
|
||
function FileExistsW(const FileName: WideString): Boolean;
|
||
function FileIconInit(FullInit: BOOL): BOOL; stdcall;
|
||
function FindUniqueMenuID(AMenu: HMenu): Cardinal;
|
||
function GetMyDocumentsVirtualFolder: PItemIDList;
|
||
function HasMMX: Boolean;
|
||
function IncludeTrailingBackslashW(const S: WideString): WideString;
|
||
function IsAnyMouseButtonDown: Boolean;
|
||
function IsFTPPath(Path: WideString): Boolean;
|
||
function IsMappedDrivePath(const Path: WideString): Boolean;
|
||
function IsRectNull(ARect: TRect): Boolean;
|
||
function IsTextTrueType(Canvas: TCanvas): Boolean; overload;
|
||
function IsTextTrueType(DC: HDC): Boolean; overload;
|
||
function IsUNCPath(const Path: WideString): Boolean;
|
||
function IsUnicode: Boolean; // OS supports Unicode functions (basiclly means IsWinNT or XP)
|
||
function IsWin2000: Boolean;
|
||
function IsWin95_SR1: Boolean;
|
||
function IsWinME: Boolean;
|
||
function IsWinNT: Boolean;
|
||
function IsWinNT4: Boolean;
|
||
function IsWinXP: Boolean;
|
||
function IsWinXPOrUp: Boolean;
|
||
function IsWinVista: Boolean;
|
||
function IsWinVistaOrUp: Boolean;
|
||
procedure MakeFindDataW(const FindFileDataA: TWIN32FindDataA; var FindFileDataW: TWIN32FindDataW);
|
||
function ModuleFileName(PathOnly: Boolean = True): WideString;
|
||
function PIDLToPath(PIDL: PItemIDList): WideString;
|
||
function SHGetImageList(iImageList: Integer; const RefID: TGUID; out ppvOut): HRESULT; stdcall;
|
||
function ShiftStateToKeys(Keys: TShiftState): LongWord;
|
||
function ShiftStateToStr(Keys: TShiftState): WideString;
|
||
function ShortenStringEx(DC: HDC; const S: WideString; Width: Integer; RTL: Boolean; EllipsisPlacement: TShortenStringEllipsis): WideString;
|
||
function ShortenTextW(DC: hDC; TextToShorten: WideString; MaxSize: Integer): WideString;
|
||
function ShortFileName(const FileName: WideString): WideString;
|
||
function ShortPath(const Path: WideString): WideString;
|
||
function Size(cx, cy: Integer): TSize;
|
||
function SplitTextW(DC: hDC; TextToSplit: WideString; MaxWidth: Integer; var Buffer: TCommonWideCharArray; MaxSplits: Integer): Integer;
|
||
function StrRetToStr(StrRet: TStrRet; APIDL: PItemIDList): WideString;
|
||
function SystemDirectory: WideString;
|
||
function SysMenuFont: HFONT;
|
||
function SysMenuHeight: Integer;
|
||
function TextExtentW(Text: PWideChar; Canvas: TCanvas): TSize; overload;
|
||
function TextExtentW(Text: PWideChar; DC: hDC): TSize; overload;
|
||
function TextExtentW(Text: WideString; Canvas: TCanvas): TSize; overload;
|
||
function TextExtentW(Text: WideString; Font: TFont): TSize; overload;
|
||
function TextTrueExtentsW(Text: WideString; DC: HDC): TSize;
|
||
function TNTConditionallyDefined: Boolean;
|
||
function UnicodeStringLists: Boolean;
|
||
function UniqueDirName(const ADirPath: WideString): WideString;
|
||
function UniqueFileName(const AFilePath: WideString): WideString;
|
||
function VariantToCaption(const V: Variant): WideString;
|
||
function WideCreateDir(Path: WideString): Boolean;
|
||
function WideDirectoryExists(const Name: WideString): Boolean;
|
||
function WideExcludeTrailingBackslash(Path: WideString): WideString;
|
||
function WideExpandEnviromentString(EnviromentString: WideString): WideString;
|
||
function WideExtractFileDir(Path: WideString): WideString;
|
||
function WideExtractFileDrive(Path: WideString): WideString;
|
||
function WideExtractFileExt(Path: WideString): WideString;
|
||
function WideExtractFileName(Path: WideString): WideString;
|
||
function WideExtractFilePath(Path: WideString): WideString;
|
||
function WideFileExists(Path: WideString): Boolean;
|
||
function WideFindFirstFileEx(FileName: WideString; var lpFindFileData: TWIN32FindDataW; Mask: WideString; CaseSensitive: Boolean): THandle;
|
||
function WideFindFirstFileExExists: Boolean;
|
||
function WideGetCurrentDir: WideString;
|
||
function WideGetTempDir: WideString;
|
||
function WideIncludeTrailingBackslash(Path: WideString): WideString;
|
||
function WideIncrementalSearch(CompareStr, Mask: WideString): Integer;
|
||
function WideIntToStr(Value: integer): WideString;
|
||
function WideIsDrive(Drive: WideString): Boolean;
|
||
function WideIsFloppy(FileFolder: WideString): boolean;
|
||
function WideIsPathDelimiter(const S: WideString; Index: Integer): Boolean;
|
||
function WideLowerCase(const Str: WideString): WideString;
|
||
function WideMessageBox(Window: HWND; const ACaption, AMessage: WideString; uType: integer): integer;
|
||
function WideNewFolderName(ParentFolder: WideString; SuggestedFolderName: WideString = ''): WideString;
|
||
function WidePathMatchSpec(Path, Mask: WideString): Boolean;
|
||
function WidePathMatchSpecExists: Boolean;
|
||
function WideShellExecute(hWnd: HWND; Operation, FileName, Parameters, Directory: WideString; ShowCmd: Integer = SW_NORMAL): HINST;
|
||
function WideStrComp(Str1, Str2: PWideChar): Integer;
|
||
function WideStrLower(Str: PWideChar): PWideChar;
|
||
function WideStrIComp(Str1, Str2: PWideChar): Integer;
|
||
function WideStringReplace(const S, OldPattern, NewPattern: WideString; Flags: TReplaceFlags; WholeWord: Boolean = False): WideString;
|
||
function WideStripExt(AFile: WideString): WideString;
|
||
function WideStripLeadingBackslash(const S: WideString): WideString;
|
||
function WideStripRemoteComputer(const UNCPath: WideString): WideString;
|
||
function WideStripTrailingBackslash(const S: WideString; Force: Boolean = False): WideString;
|
||
function WideStrMove(Dest, Source: PWideChar; Count: Cardinal): PWideChar;
|
||
function WideStrPos(Str, SubStr: PWideChar): PWideChar;
|
||
function WideStrRScan(Str: PWideChar; Chr: WideChar): PWideChar;
|
||
function WideStrScan(Str: PWideChar; Chr: WideChar): PWideChar;
|
||
function WideUpperCase(const S: WideString): WideString;
|
||
function WindowsDirectory: WideString;
|
||
procedure AlphaBlend(Source, Destination: HDC; R: TRect; Target: TPoint; Mode: TCommonBlendMode; ConstantAlpha, Bias: Integer);
|
||
procedure ConvertBitmapEx(Image32: TBitmap; var OutImage: TBitmap; const BackGndColor: TColor);
|
||
procedure ShadowBlendBits(Bits: TBitmap; BackGndColor: TColor);
|
||
procedure FillWideChar(var Dest; count: Integer; Value: WideChar);
|
||
procedure FreeMemAndNil(var P: Pointer);
|
||
procedure LoadWideString(S: TStream; var Str: WideString);
|
||
procedure MinMax(var A, B: Integer);
|
||
procedure SaveWideString(S: TStream; Str: WideString);
|
||
procedure WideInsert(Source: WideString; var S: WideString; Index: Integer);
|
||
procedure WideShowMessage(Window: HWND; ACaption, AMessage: WideString);
|
||
procedure WideStrLCopy(Str1, Str2: PWideChar; Count: Integer);
|
||
|
||
// Rectangle functions
|
||
function ProperRect(Rect: TRect): TRect;
|
||
function RectHeight(R: TRect): Integer;
|
||
function RectToStr(R: TRect): string;
|
||
function RectToSquare(R: TRect): TRect;
|
||
function RectWidth(R: TRect): Integer;
|
||
function ContainsRect(OuterRect, InnerRect: TRect): Boolean;
|
||
function IsRectProper(Rect: TRect): Boolean;
|
||
|
||
// WideString routines (many borrowed from Mike Liscke)
|
||
function StrCopyW(Dest, Source: PWideChar): PWideChar;
|
||
|
||
function KeyDataToShiftState(KeyData: Longint): TShiftState;
|
||
function KeyToKeyStates(Keys: Word): TCommonKeyStates;
|
||
function KeyStatesToMouseButton(Keys: Word): TCommonMouseButton;
|
||
function KeyStatesToKey(Keys: TCommonKeyStates): Longword;
|
||
function DropEffectToDropEffectStates(Effect: Integer): TCommonDropEffects;
|
||
function DropEffectStatesToDropEffect(Effect: TCommonDropEffects): Integer;
|
||
function DropEffectToDropEffectState(Effect: Integer): TCommonDropEffect;
|
||
function DropEffectStateToDropEffect(Effect: TCommonDropEffect): Integer;
|
||
function KeyStateToDropEffect(Keys: TCommonKeyStates): TCommonDropEffect;
|
||
function KeyStateToMouseButton(KeyState: TCommonKeyStates): TCommonMouseButton;
|
||
|
||
// Color Functions
|
||
function RGBToHLS(const RGB: TCommonRGB): TCommonHLS;
|
||
function HLSToRGB(const HLS: TCommonHLS): TCommonRGB;
|
||
function BrightenColor(const RGB: TCommonRGB; Amount: Double): TCommonRGB;
|
||
function DarkenColor(const RGB: TCommonRGB; Amount: Double): TCommonRGB;
|
||
function MakeTRBG(Color: TColor): TCommonRGB;
|
||
function MakeTColor(RGB: TCommonRGB): TColor;
|
||
function MakeColorRef(RGB: TCommonRGB; Gamma: Double = 1): COLORREF;
|
||
procedure GammaCorrection(var RGB: TCommonRGB; Gamma: Double);
|
||
function MakeSafeColor(var RGB: TCommonRGB): Boolean;
|
||
function UpsideDownDIB(Bits: TBitmap): Boolean;
|
||
procedure FixFormFont(AFont: TFont);
|
||
|
||
// Window Manipulation
|
||
procedure ActivateTopLevelWindow(Child: HWND);
|
||
|
||
// Graphics
|
||
procedure FillGradient(X1, Y1, X2, Y2: integer; fStartColor, fStopColor: TColor;
|
||
StartPoint, EndPoint: integer; fDrawCanvas: TCanvas);
|
||
|
||
// Helpers to create a callback function out of a object method
|
||
function CreateStub(ObjectPtr: Pointer; MethodPtr: Pointer): Pointer;
|
||
procedure DisposeStub(Stub: Pointer);
|
||
|
||
{$IFNDEF COMPILER_6_UP}
|
||
function Supports(const Instance: IUnknown; const IID: TGUID): Boolean; overload;
|
||
procedure ClearMenuItems(Menu: TMenu);
|
||
{$ENDIF}
|
||
|
||
{$IFNDEF COMPILER_5_UP}
|
||
function Supports(const Instance: IUnknown; const IID: TGUID; out Intf): Boolean; overload;
|
||
function Supports(const Instance: TObject; const IID: TGUID; out Intf): Boolean; overload;
|
||
procedure FreeAndNil(var Obj);
|
||
|
||
type
|
||
TWMContextMenu = packed record
|
||
Msg: Cardinal;
|
||
hWnd: HWND;
|
||
case Integer of
|
||
0: (
|
||
XPos: Smallint;
|
||
YPos: Smallint);
|
||
1: (
|
||
Pos: TSmallPoint;
|
||
Result: Longint);
|
||
end;
|
||
{$ENDIF}
|
||
|
||
// ****************************************************************************
|
||
// Registration function for Shell and Namespace Extensions
|
||
// Donated by by Alexey Torgashin
|
||
// Note: we assume that paths to both RegSvr32.exe and extension DLL are ANSI (not Unicode).
|
||
// ****************************************************************************
|
||
type
|
||
TEasyNSERegMessages = set of (enseMsgShowErrors, enseMsgRegSvr);
|
||
|
||
//True to register or False to unregister
|
||
function RegUnregNSE(const AFileName: WideString; DoRegister: boolean; AMessages: TEasyNSERegMessages = [enseMsgShowErrors]): boolean;
|
||
function RegisterNSE(const AFileName: WideString; AMessages: TEasyNSERegMessages = [enseMsgShowErrors]): boolean;
|
||
function UnregisterNSE(const AFileName: WideString; AMessages: TEasyNSERegMessages = [enseMsgShowErrors]): boolean;
|
||
function ExecShellEx(const Cmd, Params, Dir: WideString; ShowCmd: integer;
|
||
DoWait: boolean): boolean;
|
||
//
|
||
// Dynamically linked Unicode functions that do not have stubs on Win9x
|
||
//
|
||
var
|
||
GetDriveTypeW_MP: function(lpRootPathName: PWideChar): UINT; stdcall;
|
||
DrawTextW_MP: function(hDC: HDC; lpString: PWideChar; nCount: Integer;
|
||
var lpRect: TRect; uFormat: UINT): Integer; stdcall;
|
||
SHGetFileInfoW_MP: function(pszPath: PWideChar; dwFileAttributes: DWORD;
|
||
var psfi: TSHFileInfoW; cbFileInfo, uFlags: UINT): DWORD; stdcall;
|
||
CreateFileW_MP: function(lpFileName: PWideChar; dwDesiredAccess, dwShareMode: DWORD;
|
||
lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: DWORD;
|
||
hTemplateFile: THandle): THandle; stdcall;
|
||
SHGetDataFromIDListW_MP: function(psf: IShellFolder; pidl: PItemIDList;
|
||
nFormat: Integer; ptr: Pointer; cb: Integer): HResult; stdcall;
|
||
FindFirstFileW_MP: function(lpFileName: PWideChar; var lpFindFileData: TWIN32FindDataW): THandle; stdcall;
|
||
FindNextFileW_MP: function(hFindFile: THandle; var lpFindFileData: TWIN32FindDataW): BOOL; stdcall;
|
||
GetDiskFreeSpaceW_MP: function(lpRootPathName: PWideChar; var lpSectorsPerCluster,
|
||
lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters: DWORD): BOOL; stdcall;
|
||
GetCurrentDirectoryW_MP: function(nBufferLength: DWORD; lpBuffer: PWideChar): DWORD; stdcall;
|
||
GetTempPathW_MP: function(nBufferLength: DWORD; lpBuffer: PWideChar): DWORD; stdcall;
|
||
lstrcmpiW_MP: function(lpString1, lpString2: PWideChar): Integer; stdcall;
|
||
lstrcmpW_MP: function(lpString1, lpString2: PWideChar): Integer; stdcall;
|
||
lstrcpynW_MP: function(lpString1, lpString2: PWideChar; iMaxLength: Integer): PWideChar; stdcall;
|
||
lstrcpyW_MP: function(lpString1, lpString2: PWideChar): PWideChar; stdcall;
|
||
CharLowerBuffW_MP: function(lpsz: PWideChar; cchLength: DWORD): DWORD; stdcall;
|
||
CharUpperBuffW_MP: function(lpsz: PWideChar; cchLength: DWORD): DWORD; stdcall;
|
||
CreateDirectoryW_MP: function(lpPathName: PWideChar; lpSecurityAttributes: PSecurityAttributes): BOOL; stdcall;
|
||
GetFullPathNameW_MP: function(lpFileName: PWideChar; nBufferLength: DWORD; lpBuffer: PWideChar; var lpFilePart: PWideChar): DWORD; stdcall;
|
||
ShellExecuteExW_MP: function(lpExecInfo: PShellExecuteInfoW):BOOL; stdcall;
|
||
ShellExecuteW_MP: function(hWnd: HWND; Operation, FileName, Parameters, Directory: PWideChar; ShowCmd: Integer): HINST; stdcall;
|
||
FindFirstChangeNotificationW_MP: function(lpPathName: PWideChar; bWatchSubtree: BOOL; dwNotifyFilter: DWORD): THandle; stdcall;
|
||
GetCharABCWidthsW_MP: function(DC: HDC; FirstChar, LastChar: UINT; const ABCStructs): BOOL; stdcall;
|
||
GetFileAttributesW_MP: function(lpFileName: PWideChar): DWORD; stdcall;
|
||
GetSystemDirectoryW_MP: function(lpBuffer: PWideChar; uSize: UINT): UINT; stdcall;
|
||
GetWindowsDirectoryW_MP: function(lpBuffer: PWideChar; uSize: UINT): UINT; stdcall;
|
||
SetWindowTextW_MP: function(hWnd: HWND; lpString: PWideChar): BOOL; stdcall;
|
||
// Robert
|
||
SHMultiFileProperties_MP: function(pdtobj: IDataObject; dwFlags: DWORD): HResult; stdcall;
|
||
SHDoDragDrop_MP: function(wnd : HWND; dtObj : IDataObject; dsrc : IDropSource; OKEffect : DWORD; var Effect : Integer) : HResult; stdcall;
|
||
GetDiskFreeSpaceExA_MP: function(lpDirectoryName: PAnsiChar;
|
||
var lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes; lpTotalNumberOfFreeBytes: PLargeInteger): BOOL; stdcall;
|
||
GetDiskFreeSpaceExW_MP: function(lpDirectoryName: PWideChar; var lpFreeBytesAvailableToCaller,
|
||
lpTotalNumberOfBytes; lpTotalNumberOfFreeBytes: PLargeInteger): BOOL; stdcall;
|
||
GetNumberFormatW_MP: function(Locale: LCID; dwFlags: DWORD; lpValue: PWideChar;
|
||
lpFormat: PNumberFmtW; lpNumberStr: PWideChar; cchNumber: Integer): Integer; stdcall;
|
||
CDefFolderMenu_Create2_MP: function(pidlFolder: PItemIdList; wnd: HWnd; cidl: uint; var apidl: PItemIdList; psf: IShellFolder; lpfn: TFNDFMCallback; nKeys: UINT; ahkeyClsKeys: PHKEY; var ppcm: IContextMenu): HRESULT; stdcall;
|
||
CDefFolderMenu_Create_MP: function(pidlFolder: PItemIdList): HRESULT; stdcall; // THIS IS NOT THE RIGHT PROTOTYPE DO NOT USE FOR TEST ONLY
|
||
RegOpenKeyW_MP: function(hKey: HKEY; lpSubKey: PWideChar; var phkResult: HKEY): Longint; stdcall;
|
||
RegOpenKeyExW_MP: function(hKey: HKEY; lpSubKey: PWideChar; ulOptions: DWORD; samDesired: REGSAM; var phkResult: HKEY): Longint; stdcall;
|
||
RegQueryValueW_MP: function(hKey: HKEY; lpSubKey: PWideChar; lpValue: PWideChar; var lpcbValue: Longint): Longint; stdcall;
|
||
WritePrivateProfileStringW_MP: function(lpAppName, lpKeyName, lpString, lpFileName: PWideChar): BOOL; stdcall;
|
||
GetPrivateProfileStringW_MP: function(lpAppName, lpKeyName, lpDefault: PWideChar; lpReturnedString: PWideChar; nSize: DWORD; lpFileName: PWideChar): DWORD; stdcall;
|
||
TryEnterCriticalSection_MP: function(var lpCriticalSection: TRTLCriticalSection): BOOL; stdcall;
|
||
CreateFontIndirectW_MP: function(const p1: TLogFontW): HFONT; stdcall;
|
||
SendMessageW_MP: function(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
|
||
InsertMenuItemW_MP: function(p1: HMENU; p2: UINT; p3: BOOL; const p4: TMenuItemInfoW): BOOL; stdcall;
|
||
SetFileAttributesW_MP: function(lpFileName: PWideChar; dwFileAttributes: DWORD): BOOL; stdcall;
|
||
SystemParametersInfoW_MP: function(uiAction, uiParam: UINT; pvParam: Pointer; fWinIni: UINT): BOOL; stdcall;
|
||
SHBrowseForFolderW_MP: function(var lpbi: TBrowseInfoW): PItemIDList; stdcall;
|
||
SHGetPathFromIDListW_MP: function(pidl: PItemIDList; pszPath: PWideChar): BOOL; stdcall;
|
||
SHFileOperationW_MP: function(const lpFileOp: TSHFileOpStructW): Integer; stdcall;
|
||
PathMatchSpecA_MP: function(const pszFileParam, pszSpec: PAnsiChar): Bool; stdcall;
|
||
PathMatchSpecW_MP: function(const pszFileParam, pszSpec: PWideChar): Bool; stdcall;
|
||
CreateProcessW_MP: function(lpApplicationName: PWideChar; lpCommandLine: PWideChar;
|
||
lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
|
||
bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer;
|
||
lpCurrentDirectory: PWideChar; const lpStartupInfo: TStartupInfoW;
|
||
var lpProcessInformation: TProcessInformation): BOOL; stdcall;
|
||
DeleteVolumeMountPoint_MP: function(lpszVolumeMountPoint: LPCSTR): BOOL; stdcall;
|
||
GetVolumeNameForVolumeMountPoint_MP: function(lpszVolumeMountPoint: LPCSTR; lpszVolumeName: LPSTR; cchBufferLength: DWORD): BOOL; stdcall;
|
||
GetVolumePathName_MP: function(lpszFileName: LPCSTR; lpszVolumePathName: LPTSTR; cchBufferLength: DWORD): BOOL; stdcall;
|
||
SetVolumeMountPoint_MP: function(lpszVolumeMountPoint: LPCSTR; lpszVolumeName: LPCSTR): BOOL;
|
||
FindFirstVolume_MP: function(lpszVolumeName: LPTSTR; cchBufferLength: DWORD): THandle; stdcall;
|
||
FindNextVolume_MP: function(hFindVolume: THandle; lpszVolumeName: LPTSTR; cchBufferLength: DWORD): BOOL; stdcall;
|
||
FindVolumeClose_MP: function(hFindVolume: THandle): BOOL; stdcall;
|
||
FindFirstVolumeMountPoint_MP: function(lpszRootPathName: LPTSTR; lpszVolumeMountPoint: LPTSTR; cchBufferLength: DWORD): THandle stdcall;
|
||
FindNextVolumeMountPoint_MP: function(hFindVolumeMountPoint: THandle; lpszVolumeMountPoint: LPTSTR; cchBufferLength: DWORD): BOOL; stdcall;
|
||
FindVolumeMountPointClose_MP: function(hFindVolumeMountPoint: THandle): BOOL; stdcall;
|
||
SHGetKnownFolderPath_MP: function(const rfid: TGUID; dwFlags: DWord; hToken: THandle; out ppszPath: PWideChar): HRESULT; stdcall;
|
||
FindFirstFileExW_MP: function(lpFileName: PWideChar; fInfoLevelId: DWORD; var lpFindFileData: TWIN32FindDataW; fSearchOp: DWORD; lpSearchFilter: Pointer; dwAdditionalFlags: DWORD): THandle; stdcall;
|
||
FindFirstFileExA_MP: function(lpFileName: PChar; fInfoLevelId: DWORD; var lpFindFileData: TWIN32FindDataA; fSearchOp: DWORD; lpSearchFilter: Pointer; dwAdditionalFlags: DWORD): THandle; stdcall;
|
||
ExpandEnvironmentStringsW_MP: function(lpSrc: PWideChar; lpDst: PWideChar; nSize: DWORD): DWORD; stdcall;
|
||
TrackMouseEvent_MP: function(var EventTrack: TTrackMouseEvent): BOOL; stdcall;
|
||
|
||
// Usage of this flag makes the SumFolder Function not thread safe
|
||
SumFolderAbort: Boolean = False;
|
||
|
||
implementation
|
||
|
||
uses
|
||
MPCommonObjects;
|
||
|
||
type
|
||
PLibRec = ^TLibRec;
|
||
TLibRec = packed record
|
||
LibraryName: string;
|
||
ReferenceCount: Integer;
|
||
Handle: THandle;
|
||
end;
|
||
|
||
var
|
||
FLibList: TList;
|
||
PIDLMgr: TCommonPIDLManager;
|
||
Shell32Handle,
|
||
Kernel32Handle,
|
||
User32Handle,
|
||
GDI32Handle,
|
||
AdvAPI32Handle,
|
||
ShlwapiHandle: THandle;
|
||
|
||
|
||
function ShiftStateToKeys(Keys: TShiftState): LongWord;
|
||
begin
|
||
Result := 0;
|
||
if ssShift in Keys then
|
||
Result := Result or MK_SHIFT;
|
||
if ssCtrl in Keys then
|
||
Result := Result or MK_CONTROL;
|
||
if ssLeft in Keys then
|
||
Result := Result or MK_LBUTTON;
|
||
if ssRight in Keys then
|
||
Result := Result or MK_RBUTTON;
|
||
if ssMiddle in Keys then
|
||
Result := Result or MK_MBUTTON;
|
||
if ssAlt in Keys then
|
||
Result := Result or MK_ALT;
|
||
end;
|
||
|
||
function ShiftStateToStr(Keys: TShiftState): WideString;
|
||
begin
|
||
Result := '[';
|
||
if ssShift in Keys then
|
||
Result := Result + 'ssShift, ';
|
||
if ssCtrl in Keys then
|
||
Result := Result + 'ssCtrl, ';
|
||
if ssLeft in Keys then
|
||
Result := Result + 'ssLeft, ';
|
||
if ssRight in Keys then
|
||
Result := Result + 'ssRight, ';
|
||
if ssMiddle in Keys then
|
||
Result := Result + 'ssMiddle, ';
|
||
if ssAlt in Keys then
|
||
Result := Result + 'ssAlt, ';
|
||
if ssDouble in Keys then
|
||
Result := Result + 'ssDouble, ';
|
||
if Length(Result) > 1 then
|
||
SetLength(Result, Length(Result) - 2);
|
||
Result := Result + ']';
|
||
end;
|
||
|
||
function RegSvrPath: WideString;
|
||
const
|
||
ExeName: WideString = 'RegSvr32.exe';
|
||
var
|
||
Path: WideString;
|
||
begin
|
||
Result:= '';
|
||
//Look in System dir
|
||
Path := SystemDirectory + '\' + ExeName;
|
||
if FileExistsW(Path) then
|
||
Result := Path
|
||
else begin
|
||
//Look in Windows dir
|
||
Path:= WindowsDirectory + '\' + ExeName;
|
||
if FileExistsW(Path) then
|
||
Result:= Path;
|
||
end
|
||
end;
|
||
|
||
function ExecShellEx(const Cmd, Params, Dir: WideString; ShowCmd: integer; DoWait: boolean): boolean;
|
||
var
|
||
InfoA: TShellExecuteInfoA;
|
||
InfoW: TShellExecuteInfoW;
|
||
CmdA, ParamsA, DirA: string;
|
||
begin
|
||
if Assigned(ShellExecuteExW_MP) then
|
||
begin
|
||
FillChar(InfoW, SizeOf(InfoW), 0);
|
||
InfoW.cbSize := SizeOf(InfoW);
|
||
InfoW.fMask := SEE_MASK_FLAG_NO_UI or SEE_MASK_NOCLOSEPROCESS;
|
||
InfoW.lpFile := PWideChar(Cmd);
|
||
InfoW.lpParameters := PWideChar(Params);
|
||
InfoW.lpDirectory := PWideChar(Dir);
|
||
InfoW.nShow := ShowCmd;
|
||
Result := ShellExecuteExW_MP(@InfoW);
|
||
if Result and DoWait then
|
||
begin
|
||
WaitForSingleObject(InfoW.hProcess, INFINITE);
|
||
CloseHandle(InfoW.hProcess)
|
||
end;
|
||
end else
|
||
begin
|
||
CmdA := Cmd;
|
||
ParamsA := Params;
|
||
DirA := Dir;
|
||
FillChar(InfoA, SizeOf(InfoA), 0);
|
||
InfoA.cbSize := SizeOf(InfoA);
|
||
InfoA.fMask := SEE_MASK_FLAG_NO_UI or SEE_MASK_NOCLOSEPROCESS;
|
||
InfoA.lpFile := PChar(CmdA);
|
||
InfoA.lpParameters := PChar(ParamsA);
|
||
InfoA.lpDirectory := PChar(DirA);
|
||
InfoA.nShow := ShowCmd;
|
||
Result := ShellExecuteEx(@InfoA);
|
||
if Result and DoWait then
|
||
begin
|
||
WaitForSingleObject(InfoA.hProcess, INFINITE);
|
||
CloseHandle(InfoA.hProcess)
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
function RegUnregNSE(const AFileName: WideString; DoRegister: boolean; AMessages: TEasyNSERegMessages = [enseMsgShowErrors]): boolean;
|
||
var
|
||
Fn, Exe, Msg: WideString;
|
||
begin
|
||
Result:= false;
|
||
|
||
if not FileExistsW(AFileName) then
|
||
begin
|
||
if enseMsgShowErrors in AMessages then
|
||
begin
|
||
if DoRegister then
|
||
Msg := SEasyNSEMsg_CannotRegister
|
||
else
|
||
Msg := SEasyNSEMsg_CannotUnRegister;
|
||
|
||
|
||
WideMessageBox(Application.Handle,
|
||
PWideChar( Msg + #13 + SEasyNSEMsg_CannotFindDLL),
|
||
PWideChar( SEasyNSEMsg_Caption),
|
||
MB_OK or MB_ICONERROR);
|
||
end;
|
||
Exit
|
||
end;
|
||
|
||
Fn := AFileName;
|
||
// If includes spaces then " " it
|
||
if Pos(' ', Fn) > 0 then
|
||
Fn := '"' + Fn + '"';
|
||
|
||
Exe := RegSvrPath;
|
||
|
||
if not FileExistsW(Exe) then
|
||
begin
|
||
if enseMsgShowErrors in AMessages then
|
||
begin
|
||
if DoRegister then
|
||
Msg := SEasyNSEMsg_CannotRegister
|
||
else
|
||
Msg := SEasyNSEMsg_CannotUnRegister;
|
||
|
||
MessageBoxW(Application.Handle,
|
||
PWideChar( Msg + #13 + SEasyNSEMsg_CannotFindRegSvr),
|
||
PWideChar( SEasyNSEMsg_Caption),
|
||
MB_OK or MB_ICONERROR);
|
||
end;
|
||
Exit
|
||
end;
|
||
|
||
if DoRegister then
|
||
Msg := '' else
|
||
Msg := '/U ';
|
||
if not (enseMsgRegSvr in AMessages) then
|
||
Msg := Msg + '/S ';
|
||
|
||
Result:= ExecShellEx(exe, Msg + Fn, '', SW_SHOW, True);
|
||
end;
|
||
|
||
function RegisterNSE(const AFileName: WideString; AMessages: TEasyNSERegMessages = [enseMsgShowErrors]): boolean;
|
||
begin
|
||
Result:= RegUnregNSE(AFileName, True, AMessages);
|
||
end;
|
||
|
||
function UnregisterNSE(const AFileName: WideString; AMessages: TEasyNSERegMessages = [enseMsgShowErrors]): boolean;
|
||
begin
|
||
Result:= RegUnregNSE(AFileName, False, AMessages);
|
||
end;
|
||
|
||
{$IFNDEF COMPILER_6_UP}
|
||
function DirectoryExists(const Directory: string): Boolean;
|
||
var
|
||
Code: Integer;
|
||
begin
|
||
Code := GetFileAttributes(PChar(Directory));
|
||
Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
|
||
end;
|
||
{$ENDIF}
|
||
|
||
{$IFNDEF COMPILER_6_UP}
|
||
function GUIDToString(const GUID: TGUID): string;
|
||
var
|
||
P: PWideChar;
|
||
begin
|
||
Result := '';
|
||
if Succeeded(StringFromCLSID(GUID, P)) then
|
||
begin
|
||
Result := P;
|
||
CoTaskMemFree(P);
|
||
end
|
||
end;
|
||
{$ENDIF}
|
||
|
||
procedure MakeFindDataW(const FindFileDataA: TWIN32FindDataA; var FindFileDataW: TWIN32FindDataW);
|
||
//
|
||
// Makes TWIN32FindDataW from a TWIN32FindDataA structure
|
||
//
|
||
var
|
||
i: Integer;
|
||
WS: WideString;
|
||
begin
|
||
FindFileDataW.dwFileAttributes := FindFileDataA.dwFileAttributes;
|
||
FindFileDataW.ftCreationTime := FindFileDataA.ftCreationTime;
|
||
FindFileDataW.ftLastAccessTime := FindFileDataA.ftLastAccessTime;
|
||
FindFileDataW.ftLastWriteTime := FindFileDataA.ftLastWriteTime;
|
||
FindFileDataW.nFileSizeHigh := FindFileDataA.nFileSizeHigh;
|
||
FindFileDataW.nFileSizeLow := FindFileDataA.nFileSizeLow;
|
||
FindFileDataW.dwReserved0 := FindFileDataA.dwReserved0;
|
||
FindFileDataW.dwReserved1 := FindFileDataA.dwReserved1;
|
||
FillChar(FindFileDataW.cAlternateFileName, SizeOf(FindFileDataW.cAlternateFileName), #0);
|
||
FillChar(FindFileDataW.cFileName, SizeOf(FindFileDataW.cFileName), #0);
|
||
i := 0;
|
||
while FindFileDataA.cAlternateFileName[i] <> #0 do
|
||
begin
|
||
WS := FindFileDataA.cAlternateFileName[i];
|
||
FindFileDataW.cAlternateFileName[i] := WS[1];
|
||
Inc(i)
|
||
end;
|
||
i := 0;
|
||
while FindFileDataA.cFileName[i] <> #0 do
|
||
begin
|
||
WS := FindFileDataA.cFileName[i];
|
||
FindFileDataW.cFileName[i] := WS[1];
|
||
Inc(i)
|
||
end
|
||
end;
|
||
|
||
function WideDirectoryExists(const Name: WideString): Boolean;
|
||
begin
|
||
{$IFDEF TNTSUPPORT}
|
||
Result := TntSysUtils.WideDirectoryExists(Name);
|
||
{$ELSE}
|
||
Result := DirectoryExists(Name)
|
||
{$ENDIF}
|
||
end;
|
||
|
||
function WideCreateDir(Path: WideString): Boolean;
|
||
begin
|
||
{$IFDEF TNTSUPPORT}
|
||
Result := TntSysUtils.WideCreateDir(Path);
|
||
{$ELSE}
|
||
Result := CreateDir(Path)
|
||
{$ENDIF}
|
||
end;
|
||
|
||
function WideExcludeTrailingBackslash(Path: WideString): WideString;
|
||
begin
|
||
{$IFDEF TNTSUPPORT}
|
||
Result := TntSysUtils.WideExcludeTrailingBackslash(Path);
|
||
{$ELSE}
|
||
{$IFDEF COMPILER_6_UP}
|
||
{$WARN SYMBOL_PLATFORM OFF}
|
||
{$ENDIF}
|
||
Result := ExcludeTrailingBackslash(Path)
|
||
{$IFDEF COMPILER_6_UP}
|
||
{$WARN SYMBOL_PLATFORM ON}
|
||
{$ENDIF}
|
||
{$ENDIF}
|
||
end;
|
||
|
||
function WideExpandEnviromentString(EnviromentString: WideString): WideString;
|
||
var
|
||
Length: Integer;
|
||
EnviromentStringA, ResultA: string;
|
||
begin
|
||
Result := EnviromentString;
|
||
if Assigned(ExpandEnvironmentStringsW_MP) then
|
||
begin
|
||
Length := ExpandEnvironmentStringsW_MP(PWideChar( EnviromentString), nil, 0);
|
||
if Length > 0 then
|
||
begin
|
||
SetLength(Result, Length - 1); // Includes the null
|
||
ExpandEnvironmentStringsW_MP( PWideChar( EnviromentString), PWideChar( @Result[1]), Length);
|
||
end
|
||
end else
|
||
begin
|
||
EnviromentStringA := EnviromentString;
|
||
Length := ExpandEnvironmentStringsA(PChar( EnviromentStringA), nil, 0);
|
||
if Length > 0 then
|
||
begin
|
||
SetLength(ResultA, Length - 2); // There is a magic 1 per the MSDN docs for the ANSI version
|
||
ExpandEnvironmentStringsA( PChar( EnviromentStringA), PChar( @ResultA[1]), Length);
|
||
Result := ResultA
|
||
end
|
||
end
|
||
end;
|
||
|
||
function WideExtractFilePath(Path: WideString): WideString;
|
||
begin
|
||
{$IFDEF TNTSUPPORT}
|
||
Result := TntSysUtils.WideExtractFilePath(Path);
|
||
{$ELSE}
|
||
Result := ExtractFilePath(Path);
|
||
{$ENDIF}
|
||
end;
|
||
|
||
function WideExtractFileName(Path: WideString): WideString;
|
||
begin
|
||
{$IFDEF TNTSUPPORT}
|
||
Result := TntSysUtils.WideExtractFileName(Path);
|
||
{$ELSE}
|
||
Result := ExtractFileName(Path);
|
||
{$ENDIF}
|
||
end;
|
||
|
||
function WideFileExists(Path: WideString): Boolean;
|
||
begin
|
||
{$IFDEF TNTSUPPORT}
|
||
Result := TntSysUtils.WideFileExists(Path);
|
||
{$ELSE}
|
||
Result := FileExists(Path);
|
||
{$ENDIF}
|
||
end;
|
||
|
||
function WideExtractFileDir(Path: WideString): WideString;
|
||
begin
|
||
{$IFDEF TNTSUPPORT}
|
||
Result := TntSysUtils.WideExtractFileDir(Path);
|
||
{$ELSE}
|
||
Result := ExtractFileDir(Path);
|
||
{$ENDIF}
|
||
end;
|
||
|
||
function WideExtractFileDrive(Path: WideString): WideString;
|
||
begin
|
||
{$IFDEF TNTSUPPORT}
|
||
Result := TntSysUtils.WideExtractFileDrive(Path);
|
||
{$ELSE}
|
||
Result := ExtractFileDrive(Path);
|
||
{$ENDIF}
|
||
end;
|
||
|
||
function WideExtractFileExt(Path: WideString): WideString;
|
||
begin
|
||
{$IFDEF TNTSUPPORT}
|
||
Result := TntSysUtils.WideExtractFileExt(Path);
|
||
{$ELSE}
|
||
Result := ExtractFileExt(Path);
|
||
{$ENDIF}
|
||
end;
|
||
|
||
function WideFindFirstFileEx(FileName: WideString;
|
||
var lpFindFileData: TWIN32FindDataW; Mask: WideString; CaseSensitive: Boolean): THandle;
|
||
var
|
||
CaseFlag: DWORD;
|
||
FindFileDataA: TWIN32FindDataA;
|
||
begin
|
||
Result := 0;
|
||
|
||
if CaseSensitive then
|
||
CaseFlag := FIND_FIRST_EX_CASE_SENSITIVE
|
||
else
|
||
CaseFlag := 0;
|
||
|
||
if Assigned(FindFirstFileExW_MP) then
|
||
Result := FindFirstFileExW_MP(PWideChar(WideString( FileName + '\' + Mask)), FINDEX_INFO_STANDARD, lpFindFileData, FINDEX_SEARCH_NAMEMATCH, nil, CaseFlag)
|
||
else
|
||
if Assigned(FindFirstFileExA_MP) then
|
||
begin
|
||
Result := FindFirstFileExA_MP(PChar( String( FileName + '\' + Mask)), FINDEX_INFO_STANDARD, FindFileDataA, FINDEX_SEARCH_NAMEMATCH, nil, CaseFlag);
|
||
MakeFindDataW(FindFileDataA, lpFindFileData)
|
||
end
|
||
end;
|
||
|
||
function WideFindFirstFileExExists: Boolean;
|
||
begin
|
||
Result := Assigned(FindFirstFileExA_MP) or Assigned(FindFirstFileExW_MP)
|
||
end;
|
||
|
||
procedure FixFormFont(AFont: TFont);
|
||
var
|
||
LogFont: TLogFont;
|
||
begin
|
||
if SystemParametersInfo(SPI_GETICONTITLELOGFONT, SizeOf(LogFont), @LogFont, 0) then
|
||
AFont.Handle := CreateFontIndirect(LogFont)
|
||
else
|
||
AFont.Handle := GetStockObject(DEFAULT_GUI_FONT);
|
||
end;
|
||
|
||
procedure FillGradient(X1, Y1, X2, Y2: integer; fStartColor, fStopColor: TColor;
|
||
StartPoint, EndPoint: integer; fDrawCanvas: TCanvas);
|
||
// X1, Y1, X2, Y2: TopLeft and BottomRight coordinates of fill area...
|
||
//fStartColor: color to begin the gradient fill with
|
||
//FStopColor: color to end the gradient fill with
|
||
//StartPoint: the first point between X1 and X2 to draw (useful for faster updating of
|
||
// specific areas instead of redrawing the entire gradient fill area such as progress bars)
|
||
//EndPoint: the last point between X1 and X2 to draw
|
||
//fDrawCanvas: the canvas to draw the gradient on
|
||
var
|
||
y: integer;
|
||
tmpColor: TColor;
|
||
|
||
begin
|
||
fStartColor := ColorToRGB(fStartColor);
|
||
fStopColor := ColorToRGB(fStopColor);
|
||
tmpColor := fDrawCanvas.Pen.Color;
|
||
for y := Y1 to Y2 do begin
|
||
fDrawCanvas.MoveTo(X1, y);
|
||
if (EndPoint > 0) and (y <= EndPoint) and (y >= StartPoint) then begin
|
||
fDrawCanvas.Pen.Color := RGB(Round(GetRValue(fStartColor) + (((GetRValue(fStopColor) - GetRValue(fStartColor)) / (Y2 - Y1)) *Abs(y - Y1))),
|
||
Round(GetGValue(fStartColor) + (((GetGValue(fStopColor) - GetGValue(fStartColor)) / (Y2 - Y1)) * Abs(y - Y1))),
|
||
Round(GetBValue(fStartColor) + (((GetBValue(fStopColor) - GetBValue(fStartColor)) / (y2 - Y1)) * Abs(y - Y1))));
|
||
fDrawCanvas.LineTo(X2, y);
|
||
end;
|
||
end;
|
||
fDrawCanvas.Brush.Color := tmpColor;
|
||
end;
|
||
|
||
function DropEffectToStr(DropEffect: DWORD): WideString;
|
||
begin
|
||
Result := '';
|
||
if DropEffect and DROPEFFECT_COPY <> 0 then
|
||
Result := Result + 'DROPEFFECT_COPY|';
|
||
if DropEffect and DROPEFFECT_MOVE <> 0 then
|
||
Result := Result + 'DROPEFFECT_MOVE|';
|
||
if DropEffect and DROPEFFECT_LINK <> 0 then
|
||
Result := Result + 'DROPEFFECT_LINK|';
|
||
if DropEffect and DROPEFFECT_SCROLL <> 0 then
|
||
Result := Result + 'DROPEFFECT_SCROLL|';
|
||
if Length(Result) > 0 then
|
||
SetLength(Result, Length(Result) - 1)
|
||
else
|
||
Result := '(none)';
|
||
end;
|
||
|
||
function EqualWndMethod(A, B: TWndMethod): Boolean;
|
||
begin
|
||
Result := (TMethod(A).Code = TMethod(B).Code) and
|
||
(TMethod(A).Data = TMethod(B).Data)
|
||
end;
|
||
|
||
function FindRootToken(const Path: WideString): PWideChar;
|
||
const
|
||
RootToken = WideString(':\');
|
||
begin
|
||
Result := WideStrPos(PWideChar(Path), RootToken);
|
||
end;
|
||
|
||
function ExtractFileDirW(const FileName: WideString): WideString;
|
||
var
|
||
WP: PWideChar;
|
||
begin
|
||
Result := '';
|
||
if (Length(FileName) < 3) and (Length(FileName) > 0) then
|
||
begin
|
||
if (((FileName[1] >= 'A') and (FileName[1] >= 'Z')) or
|
||
((FileName[1] >= 'a') and (FileName[1] >= 'z'))) then
|
||
begin
|
||
Result := WideString(FileName[1]) + ':\';
|
||
end
|
||
end else
|
||
begin
|
||
WP := FindRootToken(FileName);
|
||
if Assigned(WP) then
|
||
begin
|
||
{ Find the last '\' }
|
||
WP := WideStrRScan(PWideChar( FileName), WideChar( '\'));
|
||
if Assigned(WP) then
|
||
begin
|
||
{ The stripped file name leaves just the root directory }
|
||
if (Length(FileName) > 1) and ( (WP - 1)^ = ':') then
|
||
WP := WP + 1; // Tack on the '\'
|
||
SetLength(Result, WP - @FileName[1]);
|
||
WideStrMove(PWideChar(Result), PWideChar(FileName), WP - @FileName[1]);
|
||
end
|
||
end
|
||
end
|
||
end;
|
||
|
||
function DirExistsW(const FileName: PWideChar): Boolean;
|
||
var
|
||
ErrorCode: LongWord;
|
||
S: string;
|
||
begin
|
||
if FileName <> '' then
|
||
begin
|
||
if (Win32Platform = VER_PLATFORM_WIN32_NT) then
|
||
ErrorCode := GetFileAttributesW_MP(FileName)
|
||
else begin
|
||
S := FileName;
|
||
ErrorCode := GetFileAttributesA(PChar(S))
|
||
end;
|
||
Result := (Integer(ErrorCode) <> -1) and (FILE_ATTRIBUTE_DIRECTORY and ErrorCode <> 0);
|
||
end else
|
||
Result := False
|
||
end;
|
||
|
||
function FlipReverseCopyRect(const Flip, Reverse: Boolean; const Bitmap: TBitmap): TBitmap;
|
||
var
|
||
Bottom, Left, Right, Top: integer;
|
||
begin
|
||
Result := TBitmap.Create;
|
||
Result.Width := Bitmap.Width;
|
||
Result.Height := Bitmap.Height;
|
||
Result.PixelFormat := Bitmap.PixelFormat;
|
||
|
||
// Flip Top to Bottom
|
||
if Flip then
|
||
begin
|
||
// Unclear why extra "-1" is needed here.
|
||
Top := Bitmap.Height-1;
|
||
Bottom := -1
|
||
end
|
||
else begin
|
||
Top := 0;
|
||
Bottom := Bitmap.Height
|
||
end;
|
||
|
||
// Reverse Left to Right
|
||
if Reverse then
|
||
begin
|
||
// Unclear why extra "-1" is needed here.
|
||
Left := Bitmap.Width-1;
|
||
Right := -1;
|
||
end
|
||
else begin
|
||
Left := 0;
|
||
Right := Bitmap.Width;
|
||
end;
|
||
|
||
Result.Canvas.CopyRect(Rect(Left,Top, Right,Bottom),
|
||
Bitmap.Canvas,
|
||
Rect(0,0, Bitmap.Width,Bitmap.Height));
|
||
end;
|
||
|
||
procedure FlipReverseCopyRect(const Flip, Reverse: Boolean; R: TRect; const Canvas: TCanvas); overload;
|
||
var
|
||
Bottom, Left, Right, Top: integer;
|
||
begin
|
||
// Flip Top to Bottom
|
||
if Flip then
|
||
begin
|
||
// Unclear why extra "-1" is needed here.
|
||
Top := RectHeight(R)-1;
|
||
Bottom := -1
|
||
end
|
||
else begin
|
||
Top := 0;
|
||
Bottom := RectHeight(R)
|
||
end;
|
||
|
||
// Reverse Left to Right
|
||
if Reverse then
|
||
begin
|
||
// Unclear why extra "-1" is needed here.
|
||
Left := RectWidth(R)-1;
|
||
Right := -1;
|
||
end
|
||
else begin
|
||
Left := 0;
|
||
Right := RectWidth(R);
|
||
end;
|
||
|
||
Canvas.CopyRect(Rect(Left, Top, Right, Bottom),
|
||
Canvas,
|
||
Rect(0,0, RectWidth(R), RectHeight(R)));
|
||
end;
|
||
|
||
function FileExistsW(const FileName: WideString): Boolean;
|
||
var
|
||
Handle: THandle;
|
||
FindData: TWin32FindData;
|
||
FindDataW: TWin32FindDataW;
|
||
FileNameA: string;
|
||
begin
|
||
Result := True;
|
||
if Win32Platform = VER_PLATFORM_WIN32_NT then
|
||
Handle := FindFirstFileW_MP(PWideChar(FileName), FindDataW)
|
||
else begin
|
||
FileNameA := FileName;
|
||
Handle := FindFirstFileA(PChar(FileNameA), FindData)
|
||
end;
|
||
if Handle <> INVALID_HANDLE_VALUE then
|
||
Windows.FindClose(Handle)
|
||
else
|
||
Result := False;
|
||
end;
|
||
|
||
function IsMappedDrivePath(const Path: WideString): Boolean;
|
||
var
|
||
WS: WideString;
|
||
begin
|
||
WS := Path;
|
||
SetLength(WS, 3);
|
||
if IsWinNT then
|
||
Result := GetDriveTypeW_MP(PWideChar(WS)) = DRIVE_REMOTE
|
||
else
|
||
Result := GetDriveType(PChar(string(WS))) = DRIVE_REMOTE;
|
||
end;
|
||
|
||
{ Searchs through the passed menu looking for an item identifer that is not }
|
||
{ currently being used. }
|
||
|
||
function FindUniqueMenuID(AMenu: HMenu): Cardinal;
|
||
|
||
|
||
function RunMenu(AMenu: HMenu; var ID: Cardinal): Boolean;
|
||
var
|
||
MenuInfoW: TMenuItemInfoW;
|
||
MenuInfoA: TMenuItemInfoA;
|
||
i, ItemCount: Integer;
|
||
Reset, IsDuplicate: Boolean;
|
||
begin
|
||
Reset := False;
|
||
IsDuplicate := False;
|
||
ItemCount := GetMenuItemCount(AMenu);
|
||
i := 0;
|
||
while (i < ItemCount) and not IsDuplicate do
|
||
begin
|
||
if IsUnicode then
|
||
begin
|
||
FillChar(MenuInfoW, SizeOf(MenuInfoW), #0);
|
||
MenuInfoW.cbSize := SizeOf(MenuInfoW);
|
||
MenuInfoW.fMask := MIIM_SUBMENU or MIIM_ID;
|
||
GetMenuItemInfoW(AMenu, i, True, MenuInfoW);
|
||
if MenuInfoW.hSubMenu <> 0 then
|
||
Reset := RunMenu(MenuInfoW.hSubMenu, ID);
|
||
IsDuplicate := MenuInfoW.wID = ID
|
||
end else
|
||
begin
|
||
FillChar(MenuInfoA, SizeOf(MenuInfoA), #0);
|
||
MenuInfoA.cbSize := SizeOf(MenuInfoA);
|
||
MenuInfoA.fMask := MIIM_SUBMENU or MIIM_ID;
|
||
GetMenuItemInfoA(AMenu, i, True, MenuInfoA);
|
||
if MenuInfoA.hSubMenu <> 0 then
|
||
Reset := RunMenu(MenuInfoA.hSubMenu, ID);
|
||
IsDuplicate := MenuInfoA.wID = ID
|
||
end;
|
||
Inc(i);
|
||
end;
|
||
Result := IsDuplicate and not Reset
|
||
end;
|
||
|
||
begin
|
||
Result := 1000;
|
||
while RunMenu(AMenu, Result) do
|
||
Inc(Result)
|
||
end;
|
||
|
||
function AddContextMenuItem(Menu: HMenu; ACaption: WideString; Index: Integer;
|
||
MenuID: UINT = $FFFF; hSubMenu: UINT = 0; Enabled: Boolean = True;
|
||
Checked: Boolean = False; Default: Boolean = False): Integer;
|
||
//
|
||
// Pass '-' for a separator
|
||
// -1 to add to the end
|
||
// if MenuID = -1 then the function will create a unique ID
|
||
// if hSubMenu > 0 then the item contain sub-items
|
||
// Returns ID of new Item
|
||
//
|
||
var
|
||
InfoA: TMenuItemInfoA;
|
||
InfoW: TMenuItemInfoW;
|
||
begin
|
||
if IsUnicode and Assigned(InsertMenuItemW_MP) then
|
||
begin
|
||
FillChar(InfoW, SizeOf(InfoW), #0);
|
||
InfoW.cbSize := SizeOf(InfoW);
|
||
InfoW.fMask := MIIM_TYPE or MIIM_ID or MIIM_STATE;
|
||
|
||
if Enabled or (ACaption = '-') then
|
||
InfoW.fState := InfoW.fState or MFS_ENABLED
|
||
else
|
||
InfoW.fState := InfoW.fState or MFS_DISABLED;
|
||
|
||
if Checked and (ACaption <> '-') then
|
||
InfoW.fState := InfoW.fState or MFS_CHECKED;
|
||
if Default and (ACaption <> '-') then
|
||
InfoW.fState := InfoW.fState or MFS_DEFAULT;
|
||
|
||
if ACaption = '-' then
|
||
InfoW.fType := MFT_SEPARATOR
|
||
else begin
|
||
InfoW.fType := MFT_STRING;
|
||
if hSubMenu > 0 then
|
||
begin
|
||
InfoW.fMask := InfoW.fMask or MIIM_SUBMENU;
|
||
InfoW.hSubMenu := hSubMenu
|
||
end
|
||
end;
|
||
InfoW.dwTypeData := PWideChar(ACaption);
|
||
InfoW.cch := Length(ACaption);
|
||
|
||
if InfoW.fType = MFT_STRING then
|
||
begin
|
||
if MenuID = $FFFF then
|
||
InfoW.wID := FindUniqueMenuID(Menu)
|
||
else
|
||
if InfoW.fMask and MIIM_SUBMENU <> 0 then
|
||
InfoW.wID := $FFFF // Sub-Item Parents don't get an unique ID
|
||
else
|
||
InfoW.wID := MenuID;
|
||
end else
|
||
InfoW.wID := $FFFF; // Separators don't get an unique ID
|
||
|
||
Result := InfoW.wID;
|
||
if Index < 0 then
|
||
InsertMenuItemW_MP(Menu, GetMenuItemCount(Menu), True, InfoW)
|
||
else
|
||
InsertMenuItemW_MP(Menu, Index, True, InfoW); // Inserts by Position
|
||
end else
|
||
begin
|
||
FillChar(InfoA, SizeOf(InfoA), #0);
|
||
InfoA.cbSize := SizeOf(InfoA);
|
||
|
||
InfoA.fMask := MIIM_TYPE or MIIM_ID or MIIM_STATE;
|
||
if Enabled or (ACaption = '-') then
|
||
InfoA.fState := InfoA.fState or MFS_ENABLED
|
||
else
|
||
InfoA.fState := InfoA.fState or MFS_DISABLED;
|
||
|
||
if Checked and (ACaption <> '-') then
|
||
InfoA.fState := InfoA.fState or MFS_CHECKED;
|
||
if Default and (ACaption <> '-') then
|
||
InfoA.fState := InfoA.fState or MFS_DEFAULT;
|
||
|
||
if ACaption = '-' then
|
||
InfoA.fType := MFT_SEPARATOR
|
||
else begin
|
||
InfoA.fType := MFT_STRING;
|
||
if hSubMenu > 0 then
|
||
begin
|
||
InfoA.fMask := InfoA.fMask or MIIM_SUBMENU;
|
||
InfoA.hSubMenu := hSubMenu
|
||
end
|
||
end;
|
||
|
||
InfoA.dwTypeData := PChar( string(ACaption));
|
||
InfoA.cch := Length(ACaption);
|
||
|
||
if InfoA.fType = MFT_STRING then
|
||
begin
|
||
if MenuID = $FFFF then
|
||
InfoA.wID := FindUniqueMenuID(Menu)
|
||
else
|
||
if InfoA.fMask and MIIM_SUBMENU <> 0 then
|
||
InfoA.wID := $FFFF // Sub-Item Parents don't get an unique ID
|
||
else
|
||
InfoA.wID := MenuID;
|
||
end else
|
||
InfoA.wID := $FFFF; // Separators don't get an unique ID
|
||
|
||
Result := InfoA.wID;
|
||
if Index < 0 then
|
||
InsertMenuItemA(Menu, GetMenuItemCount(Menu), True, InfoA)
|
||
else
|
||
InsertMenuItemA(Menu, Index, True, InfoA);
|
||
end
|
||
end;
|
||
|
||
procedure ShadowBlendBits(Bits: TBitmap; BackGndColor: TColor);
|
||
begin
|
||
if Assigned(Bits) and (Bits.PixelFormat = pf32Bit) then
|
||
begin
|
||
AlphaBlend(Bits.Canvas.Handle, Bits.Canvas.Handle,
|
||
Rect(0, 0, Bits.Width,Bits.Height), Point(0, 0),
|
||
cbmConstantAlphaAndColor, 0, ColorToRGB(BackGndColor));
|
||
ConvertBitmapEx(Bits, Bits, BackGndColor)
|
||
end
|
||
end;
|
||
|
||
|
||
procedure SumFolder(FolderPath: WideString; Recurse: Boolean; var Size: Int64);
|
||
{ Returns the size of all files within the passed folder, including all }
|
||
{ sub-folders. This is recurcive don't initialize Size to 0 in the function! }
|
||
var
|
||
Info: TWin32FindData;
|
||
InfoW: TWin32FindDataW;
|
||
FHandle: THandle;
|
||
FolderPathA: string;
|
||
begin
|
||
if IsUnicode then
|
||
begin
|
||
FHandle := FindFirstFileW_MP(PWideChar( FolderPath + '\*.*'), InfoW);
|
||
if FHandle <> INVALID_HANDLE_VALUE then
|
||
try
|
||
if Recurse and (InfoW.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0) then
|
||
begin
|
||
if (lstrcmpiW_MP(InfoW.cFileName, '.') <> 0) and (lstrcmpiW_MP(InfoW.cFileName, '..') <> 0) and
|
||
(InfoW.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT = 0) then
|
||
SumFolder(FolderPath + '\' + InfoW.cFileName, Recurse, Size)
|
||
end else
|
||
Size := Size + InfoW.nFileSizeHigh * MAXDWORD + InfoW.nFileSizeLow;
|
||
while FindNextFileW_MP(FHandle, InfoW) and not SumFolderAbort do
|
||
begin
|
||
if Recurse and (InfoW.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0) then
|
||
begin
|
||
if (lstrcmpiW_MP(InfoW.cFileName, '.') <> 0) and (lstrcmpiW_MP(InfoW.cFileName, '..') <> 0) and
|
||
(InfoW.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT = 0) then
|
||
SumFolder(FolderPath + '\' + InfoW.cFileName, Recurse, Size)
|
||
end else
|
||
Size := Size + InfoW.nFileSizeHigh * MAXDWORD + InfoW.nFileSizeLow;
|
||
end;
|
||
finally
|
||
Windows.FindClose(FHandle)
|
||
end
|
||
end else
|
||
begin
|
||
FolderPathA := FolderPath;
|
||
FHandle := FindFirstFile(PChar( FolderPathA + '\*.*'), Info);
|
||
if FHandle <> INVALID_HANDLE_VALUE then
|
||
try
|
||
if Recurse and (Info.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0) then
|
||
begin
|
||
if (lstrcmpi(Info.cFileName, '.') <> 0) and (lstrcmpi(Info.cFileName, '..') <> 0) and
|
||
(InfoW.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT = 0) then
|
||
SumFolder(FolderPathA + '\' + Info.cFileName, Recurse, Size)
|
||
end else
|
||
Size := Size + Info.nFileSizeHigh * MAXDWORD + Info.nFileSizeLow;
|
||
while FindNextFile(FHandle, Info) and not SumFolderAbort do
|
||
begin
|
||
if Recurse and (Info.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> 0) then
|
||
begin
|
||
if (lstrcmpi(Info.cFileName, '.') <> 0) and (lstrcmpi(Info.cFileName, '..') <> 0) and
|
||
(InfoW.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT = 0) then
|
||
SumFolder(FolderPathA + '\' + Info.cFileName, Recurse, Size)
|
||
end else
|
||
Size := Size + Info.nFileSizeHigh * MAXDWORD + Info.nFileSizeLow;
|
||
end;
|
||
finally
|
||
Windows.FindClose(FHandle)
|
||
end
|
||
end
|
||
end;
|
||
|
||
function InternalTextExtentW(Text: PWideChar; DC: HDC): TSize;
|
||
var
|
||
S: string;
|
||
begin
|
||
if IsUnicode then
|
||
GetTextExtentPoint32W(DC, PWideChar(Text), Length(Text), Result)
|
||
else begin
|
||
S := WideString( Text);
|
||
GetTextExtentPoint32(DC, PChar(S), Length(S), Result)
|
||
end;
|
||
end;
|
||
|
||
function WideStrMove(Dest, Source: PWideChar; Count: Cardinal): PWideChar;
|
||
// Copies the specified number of characters to the destination string and returns Dest
|
||
// also as result. Dest must have enough room to store at least Count characters.
|
||
asm
|
||
PUSH ESI
|
||
PUSH EDI
|
||
MOV ESI, EDX
|
||
MOV EDI, EAX
|
||
MOV EDX, ECX
|
||
CMP EDI, ESI
|
||
JG @@1
|
||
JE @@2
|
||
SHR ECX, 1
|
||
REP MOVSD
|
||
MOV ECX, EDX
|
||
AND ECX, 1
|
||
REP MOVSW
|
||
JMP @@2
|
||
|
||
@@1:
|
||
LEA ESI, [ESI + 2 * ECX - 2]
|
||
LEA EDI, [EDI + 2 * ECX - 2]
|
||
STD
|
||
AND ECX, 1
|
||
REP MOVSW
|
||
SUB EDI, 2
|
||
SUB ESI, 2
|
||
MOV ECX, EDX
|
||
SHR ECX, 1
|
||
REP MOVSD
|
||
CLD
|
||
@@2:
|
||
POP EDI
|
||
POP ESI
|
||
end;
|
||
|
||
function WideStrRScan(Str: PWideChar; Chr: WideChar): PWideChar;
|
||
// returns a pointer to the last occurance of Chr in Str
|
||
asm
|
||
PUSH EDI
|
||
MOV EDI, Str
|
||
MOV ECX, 0FFFFFFFFH
|
||
XOR AX, AX
|
||
REPNE SCASW
|
||
NOT ECX
|
||
STD
|
||
SUB EDI, 2
|
||
MOV AX, Chr
|
||
REPNE SCASW
|
||
MOV EAX, 0
|
||
JNE @@1
|
||
MOV EAX, EDI
|
||
ADD EAX, 2
|
||
@@1:
|
||
CLD
|
||
POP EDI
|
||
end;
|
||
|
||
function WideStrScan(Str: PWideChar; Chr: WideChar): PWideChar;
|
||
// returns a pointer to first occurrence of a specified character in a string
|
||
asm
|
||
PUSH EDI
|
||
PUSH EAX
|
||
MOV EDI, Str
|
||
MOV ECX, 0FFFFFFFFH
|
||
XOR AX, AX
|
||
REPNE SCASW
|
||
NOT ECX
|
||
POP EDI
|
||
MOV AX, Chr
|
||
REPNE SCASW
|
||
MOV EAX, 0
|
||
JNE @@1
|
||
MOV EAX, EDI
|
||
SUB EAX, 2
|
||
@@1:
|
||
POP EDI
|
||
end;
|
||
|
||
function WideUpperCase(const S: WideString): WideString;
|
||
begin
|
||
Result := S;
|
||
if IsUnicode then
|
||
CharUpperBuffW_MP(PWideChar(Result), Length(Result))
|
||
else
|
||
CharUpperBuffA(PChar(string(Result)), Length(Result))
|
||
end;
|
||
|
||
function LibList: TList;
|
||
begin
|
||
if not Assigned(FLibList) then
|
||
FLibList := TList.Create;
|
||
Result := FLibList
|
||
end;
|
||
|
||
function CommonLoadLibrary(LibraryName: string): THandle;
|
||
var
|
||
i: Integer;
|
||
Found: Boolean;
|
||
LibRec: PLibRec;
|
||
begin
|
||
Result := 0;
|
||
Found := False;
|
||
i := 0;
|
||
while (i < LibList.Count) and not Found do
|
||
begin
|
||
LibRec := PLibRec(LibList[i]);
|
||
if lstrcmpi(PChar(LibRec.LibraryName), PChar(LibraryName)) = 0 then
|
||
begin
|
||
Inc(LibRec.ReferenceCount);
|
||
Result := LibRec.Handle;
|
||
Found := True
|
||
end;
|
||
Inc(i)
|
||
end;
|
||
if not Found then
|
||
begin
|
||
New(LibRec);
|
||
LibRec.Handle := LoadLibrary(PChar(LibraryName));
|
||
if LibRec.Handle <> 0 then
|
||
begin
|
||
LibRec.LibraryName := LibraryName;
|
||
LibRec.ReferenceCount := 1;
|
||
LibList.Add(LibRec);
|
||
Result := LibRec.Handle
|
||
end else
|
||
Dispose(LibRec)
|
||
end
|
||
end;
|
||
|
||
function CommonUnloadLibrary(LibraryName: string): Boolean;
|
||
var
|
||
i: Integer;
|
||
LibRec: PLibRec;
|
||
begin
|
||
Result := False;
|
||
i := 0;
|
||
while (i < LibList.Count) and not Result do
|
||
begin
|
||
LibRec := PLibRec(LibList[i]);
|
||
if lstrcmpi(PChar(LibRec.LibraryName), PChar(LibraryName)) = 0 then
|
||
begin
|
||
Dec(LibRec.ReferenceCount);
|
||
FreeLibrary(LibRec.Handle);
|
||
if LibRec.ReferenceCount = 0 then
|
||
begin
|
||
LibList.Delete(i);
|
||
Dispose(LibRec);
|
||
end;
|
||
Result := True
|
||
end;
|
||
Inc(i)
|
||
end;
|
||
if LibList.Count = 0 then
|
||
FreeAndNil(FLibList)
|
||
end;
|
||
|
||
procedure CommonUnloadAllLibraries;
|
||
var
|
||
i, LibIndex: Integer;
|
||
LibRec: PLibRec;
|
||
begin
|
||
i := 0;
|
||
while i < LibList.Count do
|
||
begin
|
||
LibRec := PLibRec(LibList[i]);
|
||
for LibIndex := 0 to LibRec.ReferenceCount - 1 do
|
||
FreeLibrary(LibRec.Handle);
|
||
LibList.Delete(i);
|
||
Dispose(LibRec);
|
||
Inc(i)
|
||
end;
|
||
FreeAndNil(FLibList);
|
||
end;
|
||
|
||
procedure DrawRadioButton(Canvas: TCanvas; Pos: TPoint; Size: Integer; clBackground, clHotBkGnd,
|
||
clLeftOuter, clRightOuter, clLeftInner, clRightInner: TColor; Checked, Enabled, Hot: Boolean);
|
||
begin
|
||
MarlettFont.Size := Size;
|
||
Canvas.Brush.Style := bsClear;
|
||
Canvas.Font.Assign(MarlettFont);
|
||
|
||
// Draw the background
|
||
if Hot then
|
||
Canvas.Font.Color := clHotBkGnd
|
||
else
|
||
Canvas.Font.Color := clBackground;
|
||
Canvas.TextOut(Pos.X, Pos.Y, 'n');
|
||
|
||
Canvas.Brush.Style := bsClear;
|
||
// Draw the Outer Circle
|
||
Canvas.Font.Color := clLeftOuter;
|
||
Canvas.TextOut(Pos.X, Pos.Y, 'j');
|
||
Canvas.Font.Color := clRightOuter;
|
||
Canvas.TextOut(Pos.X, Pos.Y, 'k');
|
||
// Draw the Inner Circle
|
||
Canvas.Font.Color := clLeftInner;
|
||
Canvas.TextOut(Pos.X, Pos.Y, 'l');
|
||
Canvas.Font.Color := clRightInner;
|
||
Canvas.TextOut(Pos.X, Pos.Y, 'm');
|
||
if Checked then
|
||
begin
|
||
if Enabled then
|
||
Canvas.Font.Color := clBlack
|
||
else
|
||
Canvas.Font.Color := clBtnShadow;
|
||
Canvas.TextOut(Pos.X, Pos.Y, 'i');
|
||
end
|
||
end;
|
||
|
||
procedure DrawCheckBox(Canvas: TCanvas; Pos: TPoint; Size: Integer; clBackground, clHotBkGnd,
|
||
clLeftOuter, clRightOuter, clLeftInner, clRightInner: TColor; Checked, Enabled, Hot: Boolean);
|
||
begin
|
||
MarlettFont.Size := Size;
|
||
Canvas.Brush.Style := bsSolid;
|
||
Canvas.Font.Assign(MarlettFont);
|
||
|
||
// Draw the background
|
||
if Hot then
|
||
Canvas.Font.Color := clHotBkGnd
|
||
else
|
||
Canvas.Font.Color := clBackground;
|
||
Canvas.TextOut(Pos.X, Pos.Y, Char($67));
|
||
|
||
Canvas.Brush.Style := bsClear;
|
||
// Draw the Outer Frame
|
||
Canvas.Font.Color := clLeftOuter;
|
||
Canvas.TextOut(Pos.X, Pos.Y, Char($63));
|
||
Canvas.Font.Color := clRightOuter;
|
||
Canvas.TextOut(Pos.X, Pos.Y, Char($64));
|
||
// Draw the Inner Frame
|
||
Canvas.Font.Color := clLeftInner;
|
||
Canvas.TextOut(Pos.X, Pos.Y, Char($65));
|
||
Canvas.Font.Color := clRightInner;
|
||
Canvas.TextOut(Pos.X, Pos.Y, Char($66));
|
||
if Checked then
|
||
begin
|
||
if Enabled then
|
||
Canvas.Font.Color := clBlack
|
||
else
|
||
Canvas.Font.Color := clBtnShadow;
|
||
Canvas.TextOut(Pos.X, Pos.Y, Char($62));
|
||
end
|
||
end;
|
||
|
||
function CheckBounds(Size: Integer): TRect;
|
||
var
|
||
Canvas: TCanvas;
|
||
begin
|
||
Result := Rect(0, 0, 0, 0);
|
||
Canvas := TCanvas.Create;
|
||
try
|
||
Canvas.Handle := GetDC(0);
|
||
Canvas.Font.Name := 'Marlett';
|
||
Canvas.Font.Size := Size;
|
||
// Use the background for the Checkbox for the size, the Radio will be this
|
||
// size or a bit smaller
|
||
Result.Right := Canvas.TextWidth(Char($67));
|
||
Result.Bottom := Canvas.TextHeight(Char($67));
|
||
finally
|
||
if Assigned(Canvas) then
|
||
begin
|
||
ReleaseDC(0, Canvas.Handle);
|
||
Canvas.Handle := 0
|
||
end;
|
||
Canvas.Free
|
||
end;
|
||
end;
|
||
|
||
|
||
function HasMMX: Boolean;
|
||
|
||
// Helper method to determine whether the current processor supports MMX.
|
||
|
||
asm
|
||
PUSH EBX
|
||
XOR EAX, EAX // Result := False
|
||
PUSHFD // determine if the processor supports the CPUID command
|
||
POP EDX
|
||
MOV ECX, EDX
|
||
XOR EDX, $200000
|
||
PUSH EDX
|
||
POPFD
|
||
PUSHFD
|
||
POP EDX
|
||
XOR ECX, EDX
|
||
JZ @1 // no CPUID support so we can't even get to the feature information
|
||
PUSH EDX
|
||
POPFD
|
||
|
||
MOV EAX, 1
|
||
DW $A20F // CPUID, EAX contains now version info and EDX feature information
|
||
MOV EBX, EAX // free EAX to get the result value
|
||
XOR EAX, EAX // Result := False
|
||
CMP EBX, $50
|
||
JB @1 // if processor family is < 5 then it is not a Pentium class processor
|
||
TEST EDX, $800000
|
||
JZ @1 // if the MMX bit is not set then we don't have MMX
|
||
INC EAX // Result := True
|
||
@1:
|
||
POP EBX
|
||
end;
|
||
|
||
procedure AlphaBlendLineConstant(Source, Destination: Pointer; Count: Integer; ConstantAlpha, Bias: Integer);
|
||
// Blends a line of Count pixels from Source to Destination using a constant alpha value.
|
||
// The layout of a pixel must be BGRA where A is ignored (but is calculated as the other components).
|
||
// ConstantAlpha must be in the range 0..255 where 0 means totally transparent (destination pixel only)
|
||
// and 255 totally opaque (source pixel only).
|
||
// Bias is an additional value which gets added to every component and must be in the range -128..127
|
||
//
|
||
// EAX contains Source
|
||
// EDX contains Destination
|
||
// ECX contains Count
|
||
// ConstantAlpha and Bias are on the stack
|
||
asm
|
||
PUSH ESI // save used registers
|
||
PUSH EDI
|
||
|
||
MOV ESI, EAX // ESI becomes the actual source pointer
|
||
MOV EDI, EDX // EDI becomes the actual target pointer
|
||
|
||
// Load MM6 with the constant alpha value (replicate it for every component).
|
||
// Expand it to word size.
|
||
MOV EAX, [ConstantAlpha]
|
||
DB $0F, $6E, $F0 /// MOVD MM6, EAX
|
||
DB $0F, $61, $F6 /// PUNPCKLWD MM6, MM6
|
||
DB $0F, $62, $F6 /// PUNPCKLDQ MM6, MM6
|
||
|
||
// Load MM5 with the bias value.
|
||
MOV EAX, [Bias]
|
||
DB $0F, $6E, $E8 /// MOVD MM5, EAX
|
||
DB $0F, $61, $ED /// PUNPCKLWD MM5, MM5
|
||
DB $0F, $62, $ED /// PUNPCKLDQ MM5, MM5
|
||
|
||
// Load MM4 with 128 to allow for saturated biasing.
|
||
MOV EAX, 128
|
||
DB $0F, $6E, $E0 /// MOVD MM4, EAX
|
||
DB $0F, $61, $E4 /// PUNPCKLWD MM4, MM4
|
||
DB $0F, $62, $E4 /// PUNPCKLDQ MM4, MM4
|
||
|
||
@1: // The pixel loop calculates an entire pixel in one run.
|
||
// Note: The pixel byte values are expanded into the higher bytes of a word due
|
||
// to the way unpacking works. We compensate for this with an extra shift.
|
||
DB $0F, $EF, $C0 /// PXOR MM0, MM0, clear source pixel register for unpacking
|
||
DB $0F, $60, $06 /// PUNPCKLBW MM0, [ESI], unpack source pixel byte values into words
|
||
DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, move higher bytes to lower bytes
|
||
DB $0F, $EF, $C9 /// PXOR MM1, MM1, clear target pixel register for unpacking
|
||
DB $0F, $60, $0F /// PUNPCKLBW MM1, [EDI], unpack target pixel byte values into words
|
||
DB $0F, $6F, $D1 /// MOVQ MM2, MM1, make a copy of the shifted values, we need them again
|
||
DB $0F, $71, $D1, $08 /// PSRLW MM1, 8, move higher bytes to lower bytes
|
||
|
||
// calculation is: target = (alpha * (source - target) + 256 * target) / 256
|
||
DB $0F, $F9, $C1 /// PSUBW MM0, MM1, source - target
|
||
DB $0F, $D5, $C6 /// PMULLW MM0, MM6, alpha * (source - target)
|
||
DB $0F, $FD, $C2 /// PADDW MM0, MM2, add target (in shifted form)
|
||
DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, divide by 256
|
||
|
||
// Bias is accounted for by conversion of range 0..255 to -128..127,
|
||
// doing a saturated add and convert back to 0..255.
|
||
DB $0F, $F9, $C4 /// PSUBW MM0, MM4
|
||
DB $0F, $ED, $C5 /// PADDSW MM0, MM5
|
||
DB $0F, $FD, $C4 /// PADDW MM0, MM4
|
||
DB $0F, $67, $C0 /// PACKUSWB MM0, MM0, convert words to bytes with saturation
|
||
DB $0F, $7E, $07 /// MOVD [EDI], MM0, store the result
|
||
@3:
|
||
ADD ESI, 4
|
||
ADD EDI, 4
|
||
DEC ECX
|
||
JNZ @1
|
||
POP EDI
|
||
POP ESI
|
||
end;
|
||
|
||
procedure AlphaBlendLinePerPixel(Source, Destination: Pointer; Count, Bias: Integer);
|
||
// Blends a line of Count pixels from Source to Destination using the alpha value of the source pixels.
|
||
// The layout of a pixel must be BGRA.
|
||
// Bias is an additional value which gets added to every component and must be in the range -128..127
|
||
//
|
||
// EAX contains Source
|
||
// EDX contains Destination
|
||
// ECX contains Count
|
||
// Bias is on the stack
|
||
asm
|
||
PUSH ESI // save used registers
|
||
PUSH EDI
|
||
|
||
MOV ESI, EAX // ESI becomes the actual source pointer
|
||
MOV EDI, EDX // EDI becomes the actual target pointer
|
||
|
||
// Load MM5 with the bias value.
|
||
MOV EAX, [Bias]
|
||
DB $0F, $6E, $E8 /// MOVD MM5, EAX
|
||
DB $0F, $61, $ED /// PUNPCKLWD MM5, MM5
|
||
DB $0F, $62, $ED /// PUNPCKLDQ MM5, MM5
|
||
|
||
// Load MM4 with 128 to allow for saturated biasing.
|
||
MOV EAX, 128
|
||
DB $0F, $6E, $E0 /// MOVD MM4, EAX
|
||
DB $0F, $61, $E4 /// PUNPCKLWD MM4, MM4
|
||
DB $0F, $62, $E4 /// PUNPCKLDQ MM4, MM4
|
||
|
||
@1: // The pixel loop calculates an entire pixel in one run.
|
||
// Note: The pixel byte values are expanded into the higher bytes of a word due
|
||
// to the way unpacking works. We compensate for this with an extra shift.
|
||
DB $0F, $EF, $C0 /// PXOR MM0, MM0, clear source pixel register for unpacking
|
||
DB $0F, $60, $06 /// PUNPCKLBW MM0, [ESI], unpack source pixel byte values into words
|
||
DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, move higher bytes to lower bytes
|
||
DB $0F, $EF, $C9 /// PXOR MM1, MM1, clear target pixel register for unpacking
|
||
DB $0F, $60, $0F /// PUNPCKLBW MM1, [EDI], unpack target pixel byte values into words
|
||
DB $0F, $6F, $D1 /// MOVQ MM2, MM1, make a copy of the shifted values, we need them again
|
||
DB $0F, $71, $D1, $08 /// PSRLW MM1, 8, move higher bytes to lower bytes
|
||
|
||
// Load MM6 with the source alpha value (replicate it for every component).
|
||
// Expand it to word size.
|
||
DB $0F, $6F, $F0 /// MOVQ MM6, MM0
|
||
DB $0F, $69, $F6 /// PUNPCKHWD MM6, MM6
|
||
DB $0F, $6A, $F6 /// PUNPCKHDQ MM6, MM6
|
||
|
||
// calculation is: target = (alpha * (source - target) + 256 * target) / 256
|
||
DB $0F, $F9, $C1 /// PSUBW MM0, MM1, source - target
|
||
DB $0F, $D5, $C6 /// PMULLW MM0, MM6, alpha * (source - target)
|
||
DB $0F, $FD, $C2 /// PADDW MM0, MM2, add target (in shifted form)
|
||
DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, divide by 256
|
||
|
||
// Bias is accounted for by conversion of range 0..255 to -128..127,
|
||
// doing a saturated add and convert back to 0..255.
|
||
DB $0F, $F9, $C4 /// PSUBW MM0, MM4
|
||
DB $0F, $ED, $C5 /// PADDSW MM0, MM5
|
||
DB $0F, $FD, $C4 /// PADDW MM0, MM4
|
||
DB $0F, $67, $C0 /// PACKUSWB MM0, MM0, convert words to bytes with saturation
|
||
DB $0F, $7E, $07 /// MOVD [EDI], MM0, store the result
|
||
@3:
|
||
ADD ESI, 4
|
||
ADD EDI, 4
|
||
DEC ECX
|
||
JNZ @1
|
||
POP EDI
|
||
POP ESI
|
||
end;
|
||
|
||
procedure AlphaBlendLineMaster(Source, Destination: Pointer; Count: Integer; ConstantAlpha, Bias: Integer);
|
||
// Blends a line of Count pixels from Source to Destination using the source pixel and a constant alpha value.
|
||
// The layout of a pixel must be BGRA.
|
||
// ConstantAlpha must be in the range 0..255.
|
||
// Bias is an additional value which gets added to every component and must be in the range -128..127
|
||
//
|
||
// EAX contains Source
|
||
// EDX contains Destination
|
||
// ECX contains Count
|
||
// ConstantAlpha and Bias are on the stack
|
||
asm
|
||
PUSH ESI // save used registers
|
||
PUSH EDI
|
||
|
||
MOV ESI, EAX // ESI becomes the actual source pointer
|
||
MOV EDI, EDX // EDI becomes the actual target pointer
|
||
|
||
// Load MM6 with the constant alpha value (replicate it for every component).
|
||
// Expand it to word size.
|
||
MOV EAX, [ConstantAlpha]
|
||
DB $0F, $6E, $F0 /// MOVD MM6, EAX
|
||
DB $0F, $61, $F6 /// PUNPCKLWD MM6, MM6
|
||
DB $0F, $62, $F6 /// PUNPCKLDQ MM6, MM6
|
||
|
||
// Load MM5 with the bias value.
|
||
MOV EAX, [Bias]
|
||
DB $0F, $6E, $E8 /// MOVD MM5, EAX
|
||
DB $0F, $61, $ED /// PUNPCKLWD MM5, MM5
|
||
DB $0F, $62, $ED /// PUNPCKLDQ MM5, MM5
|
||
|
||
// Load MM4 with 128 to allow for saturated biasing.
|
||
MOV EAX, 128
|
||
DB $0F, $6E, $E0 /// MOVD MM4, EAX
|
||
DB $0F, $61, $E4 /// PUNPCKLWD MM4, MM4
|
||
DB $0F, $62, $E4 /// PUNPCKLDQ MM4, MM4
|
||
|
||
@1: // The pixel loop calculates an entire pixel in one run.
|
||
// Note: The pixel byte values are expanded into the higher bytes of a word due
|
||
// to the way unpacking works. We compensate for this with an extra shift.
|
||
DB $0F, $EF, $C0 /// PXOR MM0, MM0, clear source pixel register for unpacking
|
||
DB $0F, $60, $06 /// PUNPCKLBW MM0, [ESI], unpack source pixel byte values into words
|
||
DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, move higher bytes to lower bytes
|
||
DB $0F, $EF, $C9 /// PXOR MM1, MM1, clear target pixel register for unpacking
|
||
DB $0F, $60, $0F /// PUNPCKLBW MM1, [EDI], unpack target pixel byte values into words
|
||
DB $0F, $6F, $D1 /// MOVQ MM2, MM1, make a copy of the shifted values, we need them again
|
||
DB $0F, $71, $D1, $08 /// PSRLW MM1, 8, move higher bytes to lower bytes
|
||
|
||
// Load MM7 with the source alpha value (replicate it for every component).
|
||
// Expand it to word size.
|
||
DB $0F, $6F, $F8 /// MOVQ MM7, MM0
|
||
DB $0F, $69, $FF /// PUNPCKHWD MM7, MM7
|
||
DB $0F, $6A, $FF /// PUNPCKHDQ MM7, MM7
|
||
DB $0F, $D5, $FE /// PMULLW MM7, MM6, source alpha * master alpha
|
||
DB $0F, $71, $D7, $08 /// PSRLW MM7, 8, divide by 256
|
||
|
||
// calculation is: target = (alpha * master alpha * (source - target) + 256 * target) / 256
|
||
DB $0F, $F9, $C1 /// PSUBW MM0, MM1, source - target
|
||
DB $0F, $D5, $C7 /// PMULLW MM0, MM7, alpha * (source - target)
|
||
DB $0F, $FD, $C2 /// PADDW MM0, MM2, add target (in shifted form)
|
||
DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, divide by 256
|
||
|
||
// Bias is accounted for by conversion of range 0..255 to -128..127,
|
||
// doing a saturated add and convert back to 0..255.
|
||
DB $0F, $F9, $C4 /// PSUBW MM0, MM4
|
||
DB $0F, $ED, $C5 /// PADDSW MM0, MM5
|
||
DB $0F, $FD, $C4 /// PADDW MM0, MM4
|
||
DB $0F, $67, $C0 /// PACKUSWB MM0, MM0, convert words to bytes with saturation
|
||
DB $0F, $7E, $07 /// MOVD [EDI], MM0, store the result
|
||
@3:
|
||
ADD ESI, 4
|
||
ADD EDI, 4
|
||
DEC ECX
|
||
JNZ @1
|
||
POP EDI
|
||
POP ESI
|
||
end;
|
||
|
||
procedure AlphaBlendLineMasterAndColor(Destination: Pointer; Count: Integer; ConstantAlpha, Color: Integer);
|
||
// Blends a line of Count pixels in Destination against the given color using a constant alpha value.
|
||
// The layout of a pixel must be BGRA and Color must be rrggbb00 (as stored by a COLORREF).
|
||
// ConstantAlpha must be in the range 0..255.
|
||
//
|
||
// EAX contains Destination
|
||
// EDX contains Count
|
||
// ECX contains ConstantAlpha
|
||
// Color is passed on the stack
|
||
asm
|
||
// The used formula is: target = (alpha * color + (256 - alpha) * target) / 256.
|
||
// alpha * color (factor 1) and 256 - alpha (factor 2) are constant values which can be calculated in advance.
|
||
// The remaining calculation is therefore: target = (F1 + F2 * target) / 256
|
||
|
||
// Load MM3 with the constant alpha value (replicate it for every component).
|
||
// Expand it to word size. (Every calculation here works on word sized operands.)
|
||
DB $0F, $6E, $D9 /// MOVD MM3, ECX
|
||
DB $0F, $61, $DB /// PUNPCKLWD MM3, MM3
|
||
DB $0F, $62, $DB /// PUNPCKLDQ MM3, MM3
|
||
|
||
// Calculate factor 2.
|
||
MOV ECX, $100
|
||
DB $0F, $6E, $D1 /// MOVD MM2, ECX
|
||
DB $0F, $61, $D2 /// PUNPCKLWD MM2, MM2
|
||
DB $0F, $62, $D2 /// PUNPCKLDQ MM2, MM2
|
||
DB $0F, $F9, $D3 /// PSUBW MM2, MM3 // MM2 contains now: 255 - alpha = F2
|
||
|
||
// Now calculate factor 1. Alpha is still in MM3, but the r and b components of Color must be swapped.
|
||
MOV ECX, [Color]
|
||
BSWAP ECX
|
||
ROR ECX, 8
|
||
DB $0F, $6E, $C9 /// MOVD MM1, ECX // Load the color and convert to word sized values.
|
||
DB $0F, $EF, $E4 /// PXOR MM4, MM4
|
||
DB $0F, $60, $CC /// PUNPCKLBW MM1, MM4
|
||
DB $0F, $D5, $CB /// PMULLW MM1, MM3 // MM1 contains now: color * alpha = F1
|
||
|
||
@1: // The pixel loop calculates an entire pixel in one run.
|
||
DB $0F, $6E, $00 /// MOVD MM0, [EAX]
|
||
DB $0F, $60, $C4 /// PUNPCKLBW MM0, MM4
|
||
|
||
DB $0F, $D5, $C2 /// PMULLW MM0, MM2 // calculate F1 + F2 * target
|
||
DB $0F, $FD, $C1 /// PADDW MM0, MM1
|
||
DB $0F, $71, $D0, $08 /// PSRLW MM0, 8 // divide by 256
|
||
|
||
DB $0F, $67, $C0 /// PACKUSWB MM0, MM0 // convert words to bytes with saturation
|
||
DB $0F, $7E, $00 /// MOVD [EAX], MM0 // store the result
|
||
|
||
ADD EAX, 4
|
||
DEC EDX
|
||
JNZ @1
|
||
end;
|
||
|
||
procedure EMMS;
|
||
// Reset MMX state to use the FPU for other tasks again.
|
||
asm
|
||
DB $0F, $77 /// EMMS
|
||
end;
|
||
|
||
function GetBitmapBitsFromDeviceContext(DC: HDC; var Width, Height: Integer): Pointer;
|
||
// Helper function used to retrieve the bitmap selected into the given device context. If there is a bitmap then
|
||
// the function will return a pointer to its bits otherwise nil is returned.
|
||
// Additionally the dimensions of the bitmap are returned.
|
||
var
|
||
Bitmap: HBITMAP;
|
||
DIB: TDIBSection;
|
||
begin
|
||
Result := nil;
|
||
Width := 0;
|
||
Height := 0;
|
||
|
||
Bitmap := GetCurrentObject(DC, OBJ_BITMAP);
|
||
if Bitmap <> 0 then
|
||
begin
|
||
if GetObject(Bitmap, SizeOf(DIB), @DIB) = SizeOf(DIB) then
|
||
begin
|
||
Assert(DIB.dsBm.bmPlanes * DIB.dsBm.bmBitsPixel = 32, 'Alpha blending error: bitmap must use 32 bpp.');
|
||
Result := DIB.dsBm.bmBits;
|
||
Width := DIB.dsBmih.biWidth;
|
||
Height := DIB.dsBmih.biHeight;
|
||
end;
|
||
end;
|
||
Assert(Result <> nil, 'Alpha blending DC error: no bitmap available.');
|
||
end;
|
||
|
||
function CalculateScanline(Bits: Pointer; Width, Height, Row: Integer): Pointer;
|
||
// Helper function to calculate the start address for the given row.
|
||
begin
|
||
if Height > 0 then // bottom-up DIB
|
||
Row := Height - Row - 1;
|
||
// Return DWORD aligned address of the requested scanline.
|
||
Integer(Result) := Integer(Bits) + Row * ((Width * 32 + 31) and not 31) div 8;
|
||
end;
|
||
|
||
procedure ConvertBitmapEx(Image32: TBitmap; var OutImage: TBitmap; const BackGndColor: TColor);
|
||
|
||
var
|
||
I, N: Integer;
|
||
LongColor: DWORD;
|
||
SourceRed, SourceGreen, SourceBlue, BkGndRed, BkGndGreen, BkGndBlue, RedTarget, GreenTarget, BlueTarget, Alpha: Byte;
|
||
Target, Mask: TBitmap;
|
||
LineDeltaImage32, PixelDeltaImage32, LineDeltaTarget, PixelDeltaTarget, LineDeltaMask, PixelDeltaMask: Integer;
|
||
PLineImage32, PLineTarget, PLineMask, PPixelImage32, PPixelTarget, PPixelMask: PByte;
|
||
begin
|
||
// Algorithm only works for bitmaps with a height > 1 pixel, should not be a limitation
|
||
// as it would then be a line!
|
||
if (Image32.PixelFormat = pf32Bit) and (Image32.Height > 1) then
|
||
begin
|
||
Target := TBitmap.Create;
|
||
Mask := TBitmap.Create;
|
||
try
|
||
Target.PixelFormat := pf32Bit;
|
||
Target.Width := Image32.Width;
|
||
Target.Height := Image32.Height;
|
||
Target.Assign(Image32);
|
||
|
||
Mask.PixelFormat := pf32Bit;
|
||
Mask.Width := Image32.Width;
|
||
Mask.Height := Image32.Height;
|
||
Mask.Canvas.Brush.Color := BackGndColor;
|
||
Mask.Canvas.FillRect(Mask.Canvas.ClipRect);
|
||
|
||
LineDeltaImage32 := DWORD( Image32.ScanLine[1]) - DWORD( Image32.ScanLine[0]);
|
||
LineDeltaTarget := DWORD( Target.ScanLine[1]) - DWORD( Target.ScanLine[0]);
|
||
LineDeltaMask := DWORD( Mask.ScanLine[1]) - DWORD( Mask.ScanLine[0]);
|
||
|
||
PixelDeltaImage32 := SizeOf(TRGBQuad);
|
||
PixelDeltaTarget := SizeOf(TRGBQuad);
|
||
PixelDeltaMask := SizeOf(TRGBQuad);
|
||
|
||
PLineImage32 := Image32.ScanLine[0];
|
||
PLineTarget := Target.ScanLine[0];
|
||
PLineMask := Mask.ScanLine[0];
|
||
|
||
for I := 0 to Image32.Height - 1 do
|
||
begin
|
||
PPixelImage32 := PLineImage32;
|
||
PPixelTarget := PLineTarget;
|
||
PPixelMask := PLineMask;
|
||
|
||
for N := 0 to Image32.Width - 1 do
|
||
begin
|
||
// Source GetColorValues ; Profiled = ~24-30% of time
|
||
LongColor := PDWORD( PPixelImage32)^;
|
||
SourceBlue := LongColor and $000000FF;
|
||
SourceGreen := (LongColor and $0000FF00) shr 8;
|
||
SourceRed := (LongColor and $00FF0000) shr 16;
|
||
Alpha := (LongColor and $FF000000) shr 24;
|
||
|
||
// Mask GetColorValues ; Profiled = ~24-30% of time
|
||
LongColor := PDWORD( PPixelMask)^;
|
||
BkGndBlue := LongColor and $000000FF;
|
||
BkGndGreen := (LongColor and $0000FF00) shr 8;
|
||
BkGndRed := (LongColor and $00FF0000) shr 16;
|
||
|
||
if Alpha < High(Byte) then
|
||
begin
|
||
// displayColor = sourceColor<6F>alpha / 255 + backgroundColor<6F>(255 <20> alpha) / 255
|
||
// Profiled = ~15-24% of time
|
||
RedTarget := SourceRed*Alpha shr 8 + BkGndRed*(255-Alpha) shr 8;
|
||
GreenTarget := SourceGreen*Alpha shr 8 + BkGndGreen*(255-Alpha) shr 8;
|
||
BlueTarget := SourceBlue*Alpha shr 8 + BkGndBlue*(255-Alpha) shr 8;
|
||
end else
|
||
begin
|
||
// skip non-blended pixels
|
||
RedTarget := SourceRed;
|
||
GreenTarget := SourceGreen;
|
||
BlueTarget := SourceBlue;
|
||
end;
|
||
|
||
// Create the RGB DWORD color ; Profiled = ~8%-9%% of time
|
||
// Mask out all but the alpha channel then build the backwards stored RGB preserving the alpha channel bits
|
||
PDWORD(PPixelTarget)^ := ((BlueTarget) or (GreenTarget shl 8)or (RedTarget shl 16));
|
||
|
||
Inc(PPixelImage32, PixelDeltaImage32);
|
||
Inc(PPixelTarget, PixelDeltaTarget);
|
||
Inc(PPixelMask, PixelDeltaMask);
|
||
end;
|
||
Inc(PLineImage32, LineDeltaImage32);
|
||
Inc(PLineTarget, LineDeltaTarget);
|
||
Inc(PLineMask, LineDeltaMask);
|
||
end;
|
||
OutImage.Assign(Target);
|
||
finally
|
||
FreeAndNil(Target);
|
||
FreeAndNil(Mask);
|
||
end;
|
||
end else
|
||
OutImage.Assign(Image32)
|
||
end;
|
||
|
||
procedure AlphaBlend(Source, Destination: HDC; R: TRect; Target: TPoint; Mode: TCommonBlendMode; ConstantAlpha, Bias: Integer);
|
||
|
||
// NOTE:::::::::::::
|
||
// AlphaBlend does not respect any clipping in the DC!!!!!!!
|
||
//
|
||
|
||
// Optimized alpha blend procedure using MMX instructions to perform as quick as possible.
|
||
// For this procedure to work properly it is important that both source and target bitmap use the 32 bit color format.
|
||
// R describes the source rectangle to work on.
|
||
// Target is the place (upper left corner) in the target bitmap where to blend to. Note that source width + X offset
|
||
// must be less or equal to the target width. Similar for the height.
|
||
// If Mode is bmConstantAlpha then the blend operation uses the given ConstantAlpha value for all pixels.
|
||
// If Mode is bmPerPixelAlpha then each pixel is blended using its individual alpha value (the alpha value of the source).
|
||
// If Mode is bmMasterAlpha then each pixel is blended using its individual alpha value multiplied by ConstantAlpha.
|
||
// If Mode is bmConstantAlphaAndColor then each destination pixel is blended using ConstantAlpha but also a constant
|
||
// color which will be obtained from Bias. In this case no offset value is added, otherwise Bias is used as offset.
|
||
// Blending of a color into target only (bmConstantAlphaAndColor) ignores Source (the DC) and Target (the position).
|
||
// CAUTION: This procedure does not check whether MMX instructions are actually available! Call it only if MMX is really
|
||
// usable.
|
||
|
||
var
|
||
Y: Integer;
|
||
SourceRun,
|
||
TargetRun: PByte;
|
||
|
||
SourceBits,
|
||
DestBits: Pointer;
|
||
SourceWidth,
|
||
SourceHeight,
|
||
DestWidth,
|
||
DestHeight: Integer;
|
||
|
||
begin
|
||
if not IsRectEmpty(R) then
|
||
begin
|
||
// Note: it is tempting to optimize the special cases for constant alpha 0 and 255 by just ignoring soure
|
||
// (alpha = 0) or simply do a blit (alpha = 255). But this does not take the bias into account.
|
||
case Mode of
|
||
cbmConstantAlpha:
|
||
begin
|
||
// Get a pointer to the bitmap bits for the source and target device contexts.
|
||
// Note: this supposes that both contexts do actually have bitmaps assigned!
|
||
SourceBits := GetBitmapBitsFromDeviceContext(Source, SourceWidth, SourceHeight);
|
||
DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight);
|
||
if Assigned(SourceBits) and Assigned(DestBits) then
|
||
begin
|
||
for Y := 0 to R.Bottom - R.Top - 1 do
|
||
begin
|
||
SourceRun := CalculateScanline(SourceBits, SourceWidth, SourceHeight, Y + R.Top);
|
||
Inc(SourceRun, 4 * R.Left);
|
||
TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + Target.Y);
|
||
Inc(TargetRun, 4 * Target.X);
|
||
AlphaBlendLineConstant(SourceRun, TargetRun, R.Right - R.Left, ConstantAlpha, Bias);
|
||
end;
|
||
end;
|
||
EMMS;
|
||
end;
|
||
cbmPerPixelAlpha:
|
||
begin
|
||
SourceBits := GetBitmapBitsFromDeviceContext(Source, SourceWidth, SourceHeight);
|
||
DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight);
|
||
if Assigned(SourceBits) and Assigned(DestBits) then
|
||
begin
|
||
for Y := 0 to R.Bottom - R.Top - 1 do
|
||
begin
|
||
SourceRun := CalculateScanline(SourceBits, SourceWidth, SourceHeight, Y + R.Top);
|
||
Inc(SourceRun, 4 * R.Left);
|
||
TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + Target.Y);
|
||
Inc(TargetRun, 4 * Target.X);
|
||
AlphaBlendLinePerPixel(SourceRun, TargetRun, R.Right - R.Left, Bias);
|
||
end;
|
||
end;
|
||
EMMS;
|
||
end;
|
||
cbmMasterAlpha:
|
||
begin
|
||
SourceBits := GetBitmapBitsFromDeviceContext(Source, SourceWidth, SourceHeight);
|
||
DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight);
|
||
if Assigned(SourceBits) and Assigned(DestBits) then
|
||
begin
|
||
for Y := 0 to R.Bottom - R.Top - 1 do
|
||
begin
|
||
SourceRun := CalculateScanline(SourceBits, SourceWidth, SourceHeight, Y + R.Top);
|
||
Inc(SourceRun, 4 * Target.X);
|
||
TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + Target.Y);
|
||
AlphaBlendLineMaster(SourceRun, TargetRun, R.Right - R.Left, ConstantAlpha, Bias);
|
||
end;
|
||
end;
|
||
EMMS;
|
||
end;
|
||
cbmConstantAlphaAndColor:
|
||
begin
|
||
// Source is ignore since there is a constant color value.
|
||
DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight);
|
||
if Assigned(DestBits) then
|
||
begin
|
||
for Y := 0 to R.Bottom - R.Top - 1 do
|
||
begin
|
||
TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + R.Top);
|
||
Inc(TargetRun, 4 * R.Left);
|
||
AlphaBlendLineMasterAndColor(TargetRun, R.Right - R.Left, ConstantAlpha, Bias);
|
||
end;
|
||
end;
|
||
EMMS;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
function DrawTextWEx(DC: HDC; Text: WideString; var lpRect: TRect;
|
||
Flags: TCommonDrawTextWFlags; MaxLineCount: Integer): Integer;
|
||
// Creates and extented version of DrawTextW that works in Win9x as well as
|
||
// NT. If MaxLineCount is -1 then the line count will depend on the Text. All
|
||
// lines that are extracted from the text are drawn or calcuated in the rectangle
|
||
//
|
||
// The result is the number of lines actually drawn, note if the CalcRect flags are
|
||
// used the result will be the number of lines that would be drawn
|
||
var
|
||
TextMetrics: TTextMetric;
|
||
Size: TSize;
|
||
TextPosX, TextPosY, i, NewLineTop: Integer;
|
||
TextOutFlags: Longword;
|
||
LineRect, OldlpRect: TRect;
|
||
Buffer: TCommonWideCharArray;
|
||
BufferIndex: PWideChar;
|
||
ShortText: WideString;
|
||
VOffset, SplitCount: Integer;
|
||
begin
|
||
OldlpRect := lpRect;
|
||
GetTextMetrics(DC, TextMetrics);
|
||
|
||
TextOutFlags := 0;
|
||
if dtRTLReading in Flags then
|
||
TextOutFlags := TextOutFlags or ETO_RTLREADING;
|
||
if not (dtNoClip in Flags) then
|
||
TextOutFlags := TextOutFlags or ETO_CLIPPED;
|
||
|
||
if dtSingleLine in Flags then
|
||
begin
|
||
Result := 1; // Easy one!
|
||
|
||
// Set up the LineRect in the Vertical Direction
|
||
// Default to the top
|
||
LineRect := Rect(lpRect.Left, lpRect.Top, lpRect.Right, lpRect.Top + TextMetrics.tmHeight);
|
||
if dtVCenter in Flags then
|
||
OffsetRect(LineRect, 0, (RectHeight(lpRect) - RectHeight(LineRect)) div 2)
|
||
else
|
||
if dtBottom in Flags then
|
||
OffsetRect(LineRect, 0, RectHeight(lpRect) - RectHeight(LineRect));
|
||
TextPosX := LineRect.Left;
|
||
TextPosY := LineRect.Top;
|
||
|
||
if dtEndEllipsis in Flags then
|
||
Text := ShortenTextW(DC, Text, RectWidth(LineRect));
|
||
|
||
GetTextExtentPoint32W(DC, PWideChar(Text), Length(Text), Size);
|
||
if Flags * [dtCenter, dtRight] <> [] then
|
||
begin
|
||
if dtCenter in Flags then
|
||
TextPosX := TextPosX + (RectWidth(LineRect) - Size.cx) div 2
|
||
else
|
||
TextPosX := LineRect.Right - Size.cx
|
||
end;
|
||
|
||
{ if dtCenter in Flags then
|
||
SetTextAlign(DC, TA_CENTER)
|
||
else
|
||
if dtLeft in Flags then
|
||
SetTextAlign(DC, TA_LEFT)
|
||
else
|
||
if dtRight in Flags then
|
||
SetTextAlign(DC, TA_RIGHT); }
|
||
|
||
// See if the caller wants to only calculate the rectangle for the text
|
||
if dtCalcRect in Flags then
|
||
begin
|
||
// Assume that the text will fit in the calulated line/rect
|
||
lpRect.Left := TextPosX;
|
||
lpRect.Top := TextPosY;
|
||
lpRect.Bottom := LineRect.Bottom;
|
||
lpRect.Right := lpRect.Left + Size.cx;
|
||
|
||
// If it does not then we have to do some adjusting
|
||
if Size.cx > RectWidth(OldlpRect) then
|
||
begin
|
||
if dtCalcRectAlign in Flags then
|
||
begin
|
||
lpRect.Left := OldlpRect.Left;
|
||
lpRect.Right := OldlpRect.Right;
|
||
end;
|
||
if dtCalcRectAdjR in Flags then
|
||
lpRect.Right := lpRect.Left + Size.cx;
|
||
end
|
||
end else
|
||
ExtTextOutW(DC, TextPosX, TextPosY, TextOutFlags, @LineRect, PWideChar(Text), Length(Text), nil);
|
||
|
||
end else
|
||
begin
|
||
// It is multi-line
|
||
SplitCount := SplitTextW(DC, Text, lpRect.Right-lpRect.Left, Buffer, MaxLineCount);
|
||
i := 0;
|
||
if Length(Buffer) > 0 then
|
||
begin
|
||
// We call ourselves recursivly one line at a time to draw the multi line text
|
||
Include(Flags, dtSingleLine);
|
||
BufferIndex := @Buffer[0];
|
||
|
||
// Calculate where the center of the text block is with respect to the
|
||
// rectangle
|
||
{ if dtVCenter in Flags then
|
||
begin
|
||
if (SplitCount > MaxLineCount) and (MaxLineCount > -1) then
|
||
VOffset := (RectHeight(OldlpRect) - (TextMetrics.tmHeight * MaxLineCount)) div 2
|
||
else
|
||
VOffset := (RectHeight(OldlpRect) - (TextMetrics.tmHeight * SplitCount)) div 2;
|
||
if VOffset < 0 then
|
||
VOffset := 0;
|
||
end else
|
||
if dtBottom in Flags then
|
||
begin
|
||
VOffset := (RectHeight(OldlpRect) - (TextMetrics.tmHeight * MaxLineCount))
|
||
end else
|
||
VOffset := 0; }
|
||
|
||
// Fix for multitext vertical alignment from Solerman Kaplon 11.9.04
|
||
if (dtVCenter in Flags) or (dtBottom in Flags) then
|
||
begin
|
||
if (SplitCount > MaxLineCount) and (MaxLineCount > -1) then
|
||
VOffset := (RectHeight(OldlpRect) - (TextMetrics.tmHeight * MaxLineCount))
|
||
else
|
||
VOffset := (RectHeight(OldlpRect) - (TextMetrics.tmHeight * SplitCount));
|
||
if VOffset < 0 then
|
||
VOffset := 0
|
||
else
|
||
if dtVCenter in Flags then
|
||
VOffset := VOffset shr 1;
|
||
end else
|
||
VOffset := 0;
|
||
while ((i < MaxLineCount) or (MaxLineCount < 0)) and (BufferIndex^ <> WideNull) do
|
||
begin
|
||
// Calculate where the top of a single line of text starts
|
||
NewLineTop := OldlpRect.Top + (i * TextMetrics.tmHeight) + VOffset;
|
||
LineRect := Rect(OldlpRect.Left, NewLineTop, OldlpRect.Right, NewLineTop + TextMetrics.tmHeight);
|
||
if (dtEndEllipsis in Flags) {and not(dtCalcRect in Flags)} then
|
||
begin
|
||
ShortText := ShortenTextW(DC, WideString(BufferIndex), RectWidth(OldlpRect));
|
||
DrawTextWEx(DC, ShortText, LineRect, Flags, MaxLineCount);
|
||
end else
|
||
DrawTextWEx(DC, WideString(BufferIndex), LineRect, Flags, MaxLineCount);
|
||
|
||
if dtCalcRect in Flags then
|
||
begin
|
||
if i = 0 then
|
||
lpRect := LineRect
|
||
else
|
||
UnionRect(lpRect, lpRect, LineRect);
|
||
end;
|
||
Inc(BufferIndex, lStrLenW(BufferIndex) + 1);
|
||
Inc(i)
|
||
end;
|
||
|
||
if (SplitCount = 0) and (dtCalcRect in Flags) then
|
||
begin
|
||
if dtCalcRectAdjR in Flags then
|
||
begin
|
||
lpRect.Right := lpRect.Left;
|
||
lpRect.Bottom := lpRect.Top + TextMetrics.tmHeight
|
||
end else
|
||
begin
|
||
lpRect.Bottom := lpRect.Top;
|
||
lpREct.Right := lpRect.Left + TextMetrics.tmAveCharWidth
|
||
end
|
||
end;
|
||
|
||
if SplitCount > MaxLineCount then
|
||
Result := MaxLineCount
|
||
else
|
||
Result := SplitCount
|
||
end else
|
||
Result := 0;
|
||
end
|
||
end;
|
||
|
||
// Helpers to create a callback function out of a object method
|
||
{ ----------------------------------------------------------------------------- }
|
||
{ This is a piece of magic by Jeroen Mineur. Allows a class method to be used }
|
||
{ as a callback. Create a stub using CreateStub with the instance of the object }
|
||
{ the callback should call as the first parameter and the method as the second }
|
||
{ parameter, ie @TForm1.MyCallback or declare a type of object for the callback }
|
||
{ method and then use a variable of that type and set the variable to the }
|
||
{ method and pass it: }
|
||
{ }
|
||
{ type }
|
||
{ TEnumWindowsFunc = function (AHandle: hWnd; Param: lParam): BOOL of object; stdcall; }
|
||
{ }
|
||
{ TForm1 = class(TForm) }
|
||
{ private }
|
||
{ function EnumWindowsProc(AHandle: hWnd; Param: lParam): BOOL; stdcall; }
|
||
{ end; }
|
||
{ }
|
||
{ var }
|
||
{ MyFunc: TEnumWindowsFunc; }
|
||
{ Stub: pointer; }
|
||
{ begin }
|
||
{ MyFunct := EnumWindowsProc; }
|
||
{ Stub := CreateStub(Self, MyFunct); }
|
||
{ .... }
|
||
{ or }
|
||
{ }
|
||
{ var }
|
||
{ Stub: pointer; }
|
||
{ begin }
|
||
{ MyFunct := EnumWindowsProc; }
|
||
{ Stub := CreateStub(Self, TForm1.EnumWindowsProc); }
|
||
{ .... }
|
||
{ Now Stub can be passed as the callback pointer to any windows API }
|
||
{ Don't forget to call Dispose Stub when not needed }
|
||
{ ----------------------------------------------------------------------------- }
|
||
const
|
||
AsmPopEDX = $5A;
|
||
AsmMovEAX = $B8;
|
||
AsmPushEAX = $50;
|
||
AsmPushEDX = $52;
|
||
AsmJmpShort = $E9;
|
||
|
||
type
|
||
TStub = packed record
|
||
PopEDX: Byte;
|
||
MovEAX: Byte;
|
||
SelfPointer: Pointer;
|
||
PushEAX: Byte;
|
||
PushEDX: Byte;
|
||
JmpShort: Byte;
|
||
Displacement: Integer;
|
||
end;
|
||
|
||
{ ----------------------------------------------------------------------------- }
|
||
function CreateStub(ObjectPtr: Pointer; MethodPtr: Pointer): Pointer;
|
||
var
|
||
Stub: ^TStub;
|
||
begin
|
||
// Allocate memory for the stub
|
||
// 1/10/04 Support for 64 bit, executable code must be in virtual space
|
||
Stub := VirtualAlloc(nil, SizeOf(TStub), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||
|
||
// Pop the return address off the stack
|
||
Stub^.PopEDX := AsmPopEDX;
|
||
|
||
// Push the object pointer on the stack
|
||
Stub^.MovEAX := AsmMovEAX;
|
||
Stub^.SelfPointer := ObjectPtr;
|
||
Stub^.PushEAX := AsmPushEAX;
|
||
|
||
// Push the return address back on the stack
|
||
Stub^.PushEDX := AsmPushEDX;
|
||
|
||
// Jump to the 'real' procedure, the method.
|
||
Stub^.JmpShort := AsmJmpShort;
|
||
Stub^.Displacement := (Integer(MethodPtr) - Integer(@(Stub^.JmpShort))) -
|
||
(SizeOf(Stub^.JmpShort) + SizeOf(Stub^.Displacement));
|
||
|
||
// Return a pointer to the stub
|
||
Result := Stub;
|
||
end;
|
||
{ ----------------------------------------------------------------------------- }
|
||
|
||
{ ----------------------------------------------------------------------------- }
|
||
procedure DisposeStub(Stub: Pointer);
|
||
begin
|
||
// 1/10/04 Support for 64 bit, executable code must be in virtual space
|
||
VirtualFree(Stub, SizeOf(TStub),MEM_DECOMMIT);
|
||
end;
|
||
{ ----------------------------------------------------------------------------- }
|
||
|
||
{$IFNDEF COMPILER_5_UP}
|
||
function Supports(const Instance: IUnknown; const IID: TGUID; out Intf): Boolean;
|
||
begin
|
||
Result := (Instance <> nil) and (Instance.QueryInterface(IID, Intf) = 0);
|
||
end;
|
||
|
||
function Supports(const Instance: TObject; const IID: TGUID; out Intf): Boolean; overload;
|
||
begin
|
||
Result := False;
|
||
Pointer( Intf) := nil;
|
||
if Assigned(Instance) then
|
||
Result := Instance.GetInterface(IID, Intf)
|
||
end;
|
||
|
||
procedure FreeAndNil(var Obj);
|
||
var
|
||
Temp: TObject;
|
||
begin
|
||
Temp := TObject(Obj);
|
||
Pointer(Obj) := nil;
|
||
Temp.Free;
|
||
end;
|
||
{$ENDIF}
|
||
|
||
{$IFNDEF COMPILER_6_UP}
|
||
function Supports(const Instance: IUnknown; const IID: TGUID): Boolean;
|
||
var
|
||
Temp: IUnknown;
|
||
begin
|
||
{$IFNDEF COMPILER_5_UP}
|
||
Result := Supports(Instance, IID, Temp);
|
||
{$ELSE}
|
||
Result := SysUtils.Supports(Instance, IID, Temp)
|
||
{$ENDIF}
|
||
end;
|
||
|
||
procedure ClearMenuItems(Menu: TMenu);
|
||
var
|
||
I: Integer;
|
||
begin
|
||
for I := Menu.Items.Count - 1 downto 0 do
|
||
Menu.Items[I].Free;
|
||
end;
|
||
{$ENDIF}
|
||
|
||
procedure CreateProcessMP(ExeFile, Parameters, InitalDir: WideString);
|
||
var
|
||
pi: TProcessInformation;
|
||
siW: TStartupInfoW;
|
||
siA: _STARTUPINFOA;
|
||
wA, wB, wC: PWideChar;
|
||
aA, aB, aC: PChar;
|
||
begin
|
||
FillChar(pi, SizeOf(pi), #0);
|
||
if Assigned(CreateProcessW_MP) then
|
||
begin
|
||
FillChar(siW, SizeOf(siW), #0);
|
||
wA := nil;
|
||
wB := nil;
|
||
wC := nil;
|
||
if ExeFile <> '' then
|
||
wA := PWideChar(ExeFile);
|
||
if Parameters <> '' then
|
||
wB := PWideChar(Parameters);
|
||
if InitalDir <> '' then
|
||
wC := PWideChar(InitalDir);
|
||
|
||
CreateProcessW_MP(
|
||
wA, // path to the executable file:
|
||
wB,
|
||
nil,
|
||
nil,
|
||
False,
|
||
NORMAL_PRIORITY_CLASS,
|
||
nil,
|
||
wC,
|
||
siW,
|
||
pi );
|
||
end else
|
||
begin
|
||
FillChar(siA, SizeOf(siA), #0);
|
||
aA := nil;
|
||
aB := nil;
|
||
aC := nil;
|
||
if ExeFile <> '' then
|
||
aA := PChar( string(ExeFile));
|
||
if Parameters <> '' then
|
||
aB := PChar( string(Parameters));
|
||
if InitalDir <> '' then
|
||
aC := PChar( string(InitalDir));
|
||
CreateProcessA(
|
||
aA,
|
||
aB, // path to the executable file:
|
||
nil,
|
||
nil,
|
||
False,
|
||
NORMAL_PRIORITY_CLASS,
|
||
nil,
|
||
aC,
|
||
siA,
|
||
pi );
|
||
end;
|
||
if pi.hProcess <> 0 then
|
||
CloseHandle(pi.hProcess);
|
||
if pi.hThread <> 0 then
|
||
CloseHandle(pi.hThread)
|
||
end;
|
||
|
||
|
||
function DiffRectHorz(Rect1, Rect2: TRect): TRect;
|
||
// Returns the "difference" rectangle of the passed rects in the Horz direction.
|
||
// Assumes that one corner is common between the two rects
|
||
begin
|
||
Rect1 := ProperRect(Rect1);
|
||
Rect2 := ProperRect(Rect2);
|
||
// Make sure we contain every thing horizontally
|
||
Result.Left := Min(Rect1.Left, Rect2.Left);
|
||
Result.Right := Max(Rect1.Right, Rect1.Right);
|
||
// Now find the difference rect height
|
||
if Rect1.Top = Rect2.Top then
|
||
begin
|
||
// The tops are equal so it must be the bottom that contains the difference
|
||
Result.Bottom := Max(Rect1.Bottom, Rect2.Bottom);
|
||
Result.Top := Min(Rect1.Bottom, Rect2.Bottom);
|
||
end else
|
||
begin
|
||
// The bottoms are equal so it must be the tops that contains the difference
|
||
Result.Bottom := Max(Rect1.Top, Rect2.Top);
|
||
Result.Top := Min(Rect1.Top, Rect2.Top);
|
||
end
|
||
end;
|
||
|
||
function DiffRectVert(Rect1, Rect2: TRect): TRect;
|
||
// Returns the "difference" rectangle of the passed rects in the Vert direction.
|
||
// Assumes that one corner is common between the two rects
|
||
begin
|
||
Rect1 := ProperRect(Rect1);
|
||
Rect2 := ProperRect(Rect2);
|
||
// Make sure we contain every thing vertically
|
||
Result.Top := Min(Rect1.Top, Rect2.Bottom);
|
||
Result.Bottom := Max(Rect1.Top, Rect1.Bottom);
|
||
// Now find the difference rect width
|
||
if Rect1.Left = Rect2.Left then
|
||
begin
|
||
// The tops are equal so it must be the bottom that contains the difference
|
||
Result.Right := Max(Rect1.Right, Rect2.Right);
|
||
Result.Left := Min(Rect1.Right, Rect2.Right);
|
||
end else
|
||
begin
|
||
// The bottoms are equal so it must be the tops that contains the difference
|
||
Result.Right := Max(Rect1.Left, Rect2.Left);
|
||
Result.Left := Min(Rect1.Left, Rect2.Left);
|
||
end
|
||
end;
|
||
|
||
function AbsRect(ARect: TRect): TRect;
|
||
// Makes all coodinates positive
|
||
begin
|
||
Result := ARect;
|
||
if Result.Left < 0 then
|
||
Result.Left := 0;
|
||
if Result.Top < 0 then
|
||
Result.Top := 0;
|
||
if Result.Right < 0 then
|
||
Result.Right := 0;
|
||
if Result.Bottom < 0 then
|
||
Result.Bottom := 0;
|
||
end;
|
||
|
||
function CenterRectInRect(OuterRect, InnerRect: TRect): TRect;
|
||
begin
|
||
if RectWidth(InnerRect) > RectWidth(OuterRect) then
|
||
begin
|
||
// If the inner rect is wider than the result is the outer rect x bounds
|
||
Result.Left := OuterRect.Left;
|
||
Result.Right := OuterRect.Right;
|
||
end else
|
||
begin
|
||
// If not then center the inner rectangle in the outer in the x direction
|
||
Result.Left := OuterRect.Left;
|
||
Result.Right := Result.Left + RectWidth(InnerRect);
|
||
OffsetRect(Result, (RectWidth(OuterRect) - RectWidth(InnerRect)) div 2, 0);
|
||
end;
|
||
if RectHeight(InnerRect) > RectHeight(OuterRect) then
|
||
begin
|
||
// If the inner rect is wider than the result is the outer rect y bounds
|
||
Result.Top := OuterRect.Top;
|
||
Result.Bottom := OuterRect.Bottom;
|
||
end else
|
||
begin
|
||
// If not then center the inner rectangle in the outer in the y direction
|
||
Result.Top := OuterRect.Top;
|
||
Result.Bottom := Result.Top + RectHeight(InnerRect);
|
||
OffsetRect(Result, 0, (RectHeight(OuterRect) - RectHeight(InnerRect)) div 2);
|
||
end;
|
||
end;
|
||
|
||
function CenterRectHorz(OuterRect, InnerRect: TRect): TRect;
|
||
begin
|
||
if RectWidth(InnerRect) > RectWidth(OuterRect) then
|
||
begin
|
||
// If the inner rect is wider than the result is the outer rect x bounds
|
||
Result.Left := OuterRect.Left;
|
||
Result.Right := OuterRect.Right;
|
||
end else
|
||
begin
|
||
// If not then center the inner rectangle in the outer in the x direction
|
||
Result.Left := OuterRect.Left;
|
||
Result.Right := Result.Left + RectWidth(InnerRect);
|
||
OffsetRect(Result, (RectWidth(OuterRect) - RectWidth(InnerRect)) div 2, 0);
|
||
end;
|
||
end;
|
||
|
||
function CenterRectVert(OuterRect, InnerRect: TRect): TRect;
|
||
begin
|
||
if RectHeight(InnerRect) > RectHeight(OuterRect) then
|
||
begin
|
||
// If the inner rect is wider than the result is the outer rect y bounds
|
||
Result.Top := OuterRect.Top;
|
||
Result.Bottom := OuterRect.Bottom;
|
||
end else
|
||
begin
|
||
// If not then center the inner rectangle in the outer in the y direction
|
||
Result.Top := OuterRect.Top;
|
||
Result.Bottom := Result.Top + RectHeight(InnerRect);
|
||
OffsetRect(Result, 0, (RectHeight(OuterRect) - RectHeight(InnerRect)) div 2);
|
||
end;
|
||
end;
|
||
|
||
function CommonSupports(const Instance: IUnknown; const IID: TGUID; out Intf): Boolean; overload;
|
||
begin
|
||
Result := (Instance <> nil) and (Instance.QueryInterface(IID, Intf) = S_OK);
|
||
end;
|
||
|
||
function CommonSupports(const Instance: TObject; const IID: TGUID; out Intf): Boolean; overload;
|
||
var
|
||
LUnknown: IUnknown;
|
||
begin
|
||
Result := (Instance <> nil) and
|
||
(Instance.GetInterface(IID, Intf) or
|
||
(Instance.GetInterface(IUnknown, LUnknown) and Supports(LUnknown, IID, Intf)));
|
||
end;
|
||
|
||
function CommonSupports(const Instance: IUnknown; const IID: TGUID): Boolean; overload;
|
||
var
|
||
Temp: IUnknown;
|
||
begin
|
||
Result := Supports(Instance, IID, Temp);
|
||
end;
|
||
|
||
function CommonSupports(const Instance: TObject; const IID: TGUID): Boolean; overload;
|
||
var
|
||
Temp: IUnknown;
|
||
begin
|
||
Result := Supports(Instance, IID, Temp);
|
||
end;
|
||
|
||
procedure CopyToNullBufferA(S: WideString; Buffer: PChar; CharCount: Cardinal);
|
||
var
|
||
ANSI: string;
|
||
begin
|
||
ANSI := S;
|
||
FillChar(Buffer^, CharCount, #0);
|
||
if Length(ANSI) > 0 then
|
||
begin
|
||
if Cardinal(Length(ANSI)) + 1 > CharCount then
|
||
CharCount := CharCount - 1 // Leave room for the null
|
||
else
|
||
CharCount := Length(ANSI);
|
||
MoveMemory(Buffer, PChar(ANSI), CharCount);
|
||
end
|
||
end;
|
||
|
||
procedure CopyToNullBufferW(S: WideString; Buffer: PWideChar; CharCount: Cardinal);
|
||
begin
|
||
FillChar(Buffer^, CharCount * 2, #0);
|
||
if Length(S) > 0 then
|
||
begin
|
||
if Cardinal(Length(S)) + 2 > CharCount then
|
||
CharCount := CharCount - 2 // Leave room for the null
|
||
else
|
||
CharCount := Length(S);
|
||
MoveMemory(Buffer, PWideChar(S), CharCount * 2);
|
||
end
|
||
end;
|
||
|
||
procedure MinMax(var A, B: Integer);
|
||
// Makes sure that A < B
|
||
var
|
||
Temp: Integer;
|
||
begin
|
||
if A > B then
|
||
begin
|
||
Temp := A;
|
||
A := B;
|
||
B := Temp
|
||
end
|
||
end;
|
||
|
||
function IsRectProper(Rect: TRect): Boolean;
|
||
begin
|
||
Result := (Rect.Right >= Rect.Left) and (Rect.Bottom >= Rect.Top)
|
||
end;
|
||
|
||
function AddCommas(NumberString: WideString): WideString;
|
||
var
|
||
// i: integer;
|
||
BufferA: array[0..128] of Char;
|
||
BufferW: array[0..128] of WideChar;
|
||
begin
|
||
// Make the number format based on the local not the US 3 digit comma format
|
||
if Assigned(GetNumberFormatW_MP) then
|
||
begin
|
||
GetNumberFormatW_MP(LOCALE_USER_DEFAULT, 0, PWideChar(NumberString), nil, BufferW, SizeOf(BufferW));
|
||
Result := BufferW;
|
||
end
|
||
else begin
|
||
GetNumberFormatA(LOCALE_USER_DEFAULT, 0, PChar(string(NumberString)), nil, BufferA, SizeOf(BufferA));
|
||
Result := BufferA
|
||
end;
|
||
|
||
{ Trimming white space in Unicode is tough don't pass any }
|
||
{ i := Length(NumberString) mod 3;
|
||
if i = 0 then
|
||
i := 3;
|
||
while i < Length(NumberString) do
|
||
begin
|
||
InsertW(ThousandSeparator, NumberString, i);
|
||
Inc(i, 4);
|
||
end;
|
||
Result := NumberString }
|
||
end;
|
||
|
||
function CalcuateFolderSize(FolderPath: WideString; Recurse: Boolean): Int64;
|
||
|
||
// Recursivly gets the size of the folder and subfolders
|
||
var
|
||
S: string;
|
||
FreeSpaceAvailable, TotalSpace: Int64;
|
||
SectorsPerCluster,
|
||
BytesPerSector,
|
||
FreeClusters,
|
||
TotalClusters: DWORD;
|
||
begin
|
||
Result := 0;
|
||
if Recurse and WideIsDrive(FolderPath) then
|
||
begin
|
||
if IsUnicode and Assigned(GetDiskFreeSpaceExW_MP) then
|
||
begin
|
||
if GetDiskFreeSpaceExW_MP(PWideChar(FolderPath), FreeSpaceAvailable, TotalSpace, nil) then
|
||
Result := TotalSpace - FreeSpaceAvailable
|
||
end else
|
||
if not IsWin95_SR1 and Assigned(GetDiskFreeSpaceExA_MP) then
|
||
begin
|
||
S := FolderPath;
|
||
if GetDiskFreeSpaceExA_MP(PChar(S), FreeSpaceAvailable, TotalSpace, nil) then
|
||
Result := TotalSpace - FreeSpaceAvailable;
|
||
end else
|
||
begin
|
||
GetDiskFreeSpaceA(PChar( S), SectorsPerCluster, BytesPerSector, FreeClusters,
|
||
TotalClusters);
|
||
Result := SectorsPerCluster * BytesPerSector * TotalClusters
|
||
end;
|
||
end else
|
||
begin
|
||
SumFolderAbort := False;
|
||
SumFolder(FolderPath, Recurse, Result);
|
||
end
|
||
end;
|
||
|
||
function GetMyDocumentsVirtualFolder: PItemIDList;
|
||
|
||
const
|
||
MYCOMPUTER_GUID = WideString('::{450d8fba-ad25-11d0-98a8-0800361b1103}');
|
||
|
||
var
|
||
dwAttributes, pchEaten: ULONG;
|
||
Desktop: IShellFolder;
|
||
begin
|
||
Result := nil;
|
||
dwAttributes := 0;
|
||
SHGetDesktopFolder(Desktop);
|
||
pchEaten := Length(MYCOMPUTER_GUID);
|
||
if not Succeeded(Desktop.ParseDisplayName(0, nil,
|
||
PWideChar(MYCOMPUTER_GUID), pchEaten, Result, dwAttributes))
|
||
then
|
||
Result := nil
|
||
end;
|
||
|
||
procedure WideInsert(Source: WideString; var S: WideString; Index: Integer);
|
||
{ It appears there is a WideString Insert in the VCL already but since mine }
|
||
{ looks better and is simpler and I spent my time I will use mine <g> }
|
||
{ _WStrInsert in System through compiler magic. }
|
||
var
|
||
OriginalLen: integer;
|
||
begin
|
||
if (Index < Length(S) + 1) and (Index > - 1) then
|
||
begin
|
||
OriginalLen := Length(S);
|
||
SetLength(S, Length(Source) + Length(S));
|
||
{ We are correct up to Index }
|
||
{ Slide to end of new string leaving space for insert }
|
||
Move(S[Index + 1], S[Index + 1 + Length(Source)], (OriginalLen - Index) * 2);
|
||
Move(Source[1], S[Index + 1], Length(Source) * 2);
|
||
end
|
||
end;
|
||
|
||
function WideGetCurrentDir: WideString;
|
||
var
|
||
BufferW: array[0..MAX_PATH] of Widechar;
|
||
BufferA: array[0..MAX_PATH] of Char;
|
||
begin
|
||
if Assigned(GetCurrentDirectoryW_MP) then
|
||
begin
|
||
if GetCurrentDirectoryW_MP(MAX_PATH, BufferW) > 0 then
|
||
Result := BufferW;
|
||
end else
|
||
begin
|
||
if GetCurrentDirectoryA(MAX_PATH, BufferA) > 0 then
|
||
Result := BufferA;
|
||
end
|
||
end;
|
||
|
||
function WideGetTempDir: WideString;
|
||
var
|
||
BufferW: array[0..MAX_PATH] of Widechar;
|
||
BufferA: array[0..MAX_PATH] of Char;
|
||
begin
|
||
if Assigned(GetTempPathW_MP) then
|
||
begin
|
||
if GetTempPathW_MP(MAX_PATH, BufferW) > 0 then
|
||
Result := BufferW;
|
||
end else
|
||
begin
|
||
if GetTempPathA(MAX_PATH, BufferA) > 0 then
|
||
Result := BufferA;
|
||
end
|
||
end;
|
||
|
||
function WideIncludeTrailingBackslash(Path: WideString): WideString;
|
||
begin
|
||
{$IFDEF TNTSUPPORT}
|
||
Result := TntSysUtils.WideIncludeTrailingBackslash(Path);
|
||
{$ELSE}
|
||
{$IFDEF COMPILER_6_UP}
|
||
{$WARN SYMBOL_PLATFORM OFF}
|
||
{$ENDIF}
|
||
Result := IncludeTrailingBackslash(Path);
|
||
{$IFDEF COMPILER_6_UP}
|
||
{$WARN SYMBOL_PLATFORM ON}
|
||
{$ENDIF}
|
||
{$ENDIF}
|
||
end;
|
||
|
||
function WideIncrementalSearch(CompareStr, Mask: WideString): Integer;
|
||
begin
|
||
SetLength(CompareStr, Length(Mask));
|
||
|
||
if IsUnicode then
|
||
Result := lstrcmpiW(PWideChar(Mask), PWideChar(CompareStr))
|
||
else
|
||
Result := lstrcmpi(PChar(string(Mask)), PChar(string(CompareStr)));
|
||
end;
|
||
|
||
function WideIntToStr(Value: integer): WideString;
|
||
{ Need to find a way to do this in Unicode. }
|
||
begin
|
||
Result := IntToStr(Value);
|
||
end;
|
||
|
||
function WideIsDrive(Drive: WideString): Boolean;
|
||
begin
|
||
if Length(Drive) = 3 then
|
||
Result := (LowerCase(Drive[1]) >= 'a') and (LowerCase(Drive[1]) <= 'z') and (Drive[2] = ':') and (Drive[3] = '\')
|
||
else
|
||
if Length(Drive) = 2 then
|
||
Result := (LowerCase(Drive[1]) >= 'a') and (LowerCase(Drive[1]) <= 'z') and (Drive[2] = ':')
|
||
else
|
||
Result := False
|
||
end;
|
||
|
||
function WideIsFloppy(FileFolder: WideString): boolean;
|
||
begin
|
||
if Length(FileFolder) > 0 then
|
||
Result := WideIsDrive(FileFolder) and (Char(FileFolder[1]) in ['A', 'a', 'B', 'b'])
|
||
else
|
||
Result := False
|
||
end;
|
||
|
||
|
||
function IsAnyMouseButtonDown: Boolean;
|
||
begin
|
||
Result := not(((GetAsyncKeyState(VK_LBUTTON) and $8000) = 0) and
|
||
((GetAsyncKeyState(VK_RBUTTON) and $8000) = 0) and
|
||
((GetAsyncKeyState(VK_MBUTTON) and $8000) = 0))
|
||
end;
|
||
|
||
function IsFTPPath(Path: WideString): Boolean;
|
||
begin
|
||
if Length(Path) > 3 then
|
||
begin
|
||
Path := UpperCase(Path);
|
||
Result := (Path[1] = 'F') and (Path[2] = 'T') and (Path[3] = 'P')
|
||
end else
|
||
Result := False
|
||
end;
|
||
|
||
function WideNewFolderName(ParentFolder: WideString; SuggestedFolderName: WideString = ''): WideString;
|
||
var
|
||
i: integer;
|
||
TempFoldername: String;
|
||
begin
|
||
ParentFolder := WideStripTrailingBackslash(ParentFolder, True); // Strip even if a root folder
|
||
i := 1;
|
||
if SuggestedFolderName = '' then
|
||
Begin
|
||
Result := ParentFolder + '\' + STR_NEWFOLDER;
|
||
TempFoldername := STR_NEWFOLDER;
|
||
end
|
||
else
|
||
Begin
|
||
Result := ParentFolder + '\' + SuggestedFolderName;
|
||
Tempfoldername := SuggestedFolderName;
|
||
End;
|
||
while DirExistsW(PWideChar(Result)) and (i <= High(WORD)) do
|
||
begin
|
||
Result := ParentFolder + '\' + Tempfoldername + ' (' + IntToStr(i) + ')';
|
||
Inc(i);
|
||
end;
|
||
if i > High(WORD) then
|
||
Result := '';
|
||
end;
|
||
|
||
function WidePathMatchSpec(Path, Mask: WideString): Boolean;
|
||
begin
|
||
if Assigned(PathMatchSpecW_MP) then
|
||
Result := PathMatchSpecW_MP(PWideChar(Path), PWideChar( Mask))
|
||
else
|
||
if Assigned(PathMatchSpecA_MP) then
|
||
Result := PathMatchSpecA_MP(PChar( string(Path)), PChar( string(Mask)))
|
||
else
|
||
Result := False
|
||
end;
|
||
|
||
function WidePathMatchSpecExists: Boolean;
|
||
begin
|
||
Result := Assigned(PathMatchSpecW_MP) or Assigned(PathMatchSpecA_MP)
|
||
end;
|
||
|
||
function WideIsPathDelimiter(const S: WideString; Index: Integer): Boolean;
|
||
begin
|
||
Result := (Index > 0) and (Index <= Length(S)) and (S[Index] = '\');
|
||
end;
|
||
|
||
function IsTextTrueType(DC: HDC): Boolean;
|
||
var
|
||
TextMetrics: TTextMetric;
|
||
begin
|
||
GetTextMetrics(DC, TextMetrics);
|
||
Result := TextMetrics.tmPitchAndFamily and TMPF_TRUETYPE <> 0
|
||
end;
|
||
|
||
function IsTextTrueType(Canvas: TCanvas): Boolean;
|
||
begin
|
||
Result := IsTextTrueType(Canvas.Handle);
|
||
end;
|
||
|
||
function IsUNCPath(const Path: WideString): Boolean;
|
||
begin
|
||
Result := ((Path[1] = '\') and (Path[2] = '\')) and (DirExistsW(PWideChar(Path)) or FileExistsW(Path))
|
||
end;
|
||
|
||
function StrRetToStr(StrRet: TStrRet; APIDL: PItemIDList): WideString;
|
||
{ Extracts the string from the StrRet structure. }
|
||
var
|
||
P: PChar;
|
||
// S: string;
|
||
begin
|
||
case StrRet.uType of
|
||
STRRET_CSTR:
|
||
begin
|
||
SetString(Result, StrRet.cStr, lStrLen(StrRet.cStr));
|
||
// Result := S
|
||
end;
|
||
STRRET_OFFSET:
|
||
begin
|
||
if Assigned(APIDL) then
|
||
begin
|
||
{$R-}
|
||
P := PChar(@(APIDL).mkid.abID[StrRet.uOffset - SizeOf(APIDL.mkid.cb)]);
|
||
{$R+}
|
||
SetString(Result, P, StrLen(P));
|
||
// Result := S;
|
||
end else
|
||
Result := '';
|
||
end;
|
||
STRRET_WSTR:
|
||
begin
|
||
Result := StrRet.pOleStr;
|
||
if Assigned(StrRet.pOleStr) then
|
||
PIDLMgr.FreeOLEStr(StrRet.pOLEStr);
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
function SystemDirectory: WideString;
|
||
var
|
||
Len: integer;
|
||
S: string;
|
||
begin
|
||
Result := '';
|
||
if Win32Platform = VER_PLATFORM_WIN32_NT then
|
||
Len := GetSystemDirectoryW_MP(PWideChar(Result), 0)
|
||
else
|
||
Len := GetSystemDirectoryA(PChar(S), 0);
|
||
if Len > 0 then
|
||
begin
|
||
if Win32Platform = VER_PLATFORM_WIN32_NT then
|
||
begin
|
||
SetLength(Result, Len - 1);
|
||
GetSystemDirectoryW_MP(PWideChar(Result), Len);
|
||
end else
|
||
begin
|
||
SetLength(S, Len - 1);
|
||
GetSystemDirectoryA(PChar(S), Len);
|
||
Result := S
|
||
end
|
||
end
|
||
end;
|
||
|
||
function SysMenuFont: HFONT;
|
||
var
|
||
MetricsA: TNonClientMetricsA;
|
||
MetricsW: TNonClientMetricsW;
|
||
begin
|
||
if IsUnicode then
|
||
begin
|
||
FillChar(MetricsW, SizeOf(MetricsW), #0);
|
||
MetricsW.cbSize := SizeOf(MetricsW);
|
||
SystemParametersInfoW_MP(SPI_GETNONCLIENTMETRICS, Sizeof(MetricsW), @MetricsW, 0);
|
||
Result := CreateFontIndirectW_MP(MetricsW.lfMenuFont);
|
||
end else
|
||
begin
|
||
FillChar(MetricsA, SizeOf(MetricsA), #0);
|
||
MetricsA.cbSize := SizeOf(MetricsA);
|
||
SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, Sizeof(MetricsA), @MetricsA, 0);
|
||
Result := CreateFontIndirectA(MetricsA.lfMenuFont);
|
||
end
|
||
end;
|
||
|
||
function SysMenuHeight: Integer;
|
||
var
|
||
MetricsA: TNonClientMetricsA;
|
||
MetricsW: TNonClientMetricsW;
|
||
begin
|
||
if IsUnicode then
|
||
begin
|
||
FillChar(MetricsW, SizeOf(MetricsW), #0);
|
||
MetricsW.cbSize := SizeOf(MetricsW);
|
||
SystemParametersInfoW_MP(SPI_GETNONCLIENTMETRICS, Sizeof(MetricsW), @MetricsW, 0);
|
||
Result := MetricsW.iMenuHeight
|
||
end else
|
||
begin
|
||
FillChar(MetricsA, SizeOf(MetricsA), #0);
|
||
MetricsA.cbSize := SizeOf(MetricsA);
|
||
SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, Sizeof(MetricsA), @MetricsA, 0);
|
||
Result := MetricsA.iMenuHeight
|
||
end
|
||
end;
|
||
|
||
function TextExtentW(Text: WideString; Font: TFont): TSize;
|
||
var
|
||
Canvas: TCanvas;
|
||
begin
|
||
FillChar(Result, SizeOf(Result), #0);
|
||
if Text <> '' then
|
||
begin
|
||
Canvas := TCanvas.Create;
|
||
try
|
||
Canvas.Handle := GetDC(0);
|
||
Canvas.Lock;
|
||
Canvas.Font.Assign(Font);
|
||
Result := InternalTextExtentW(PWideChar(Text), Canvas.Handle);
|
||
finally
|
||
if Assigned(Canvas) and (Canvas.Handle <> 0) then
|
||
ReleaseDC(0, Canvas.Handle);
|
||
Canvas.Unlock;
|
||
Canvas.Free
|
||
end
|
||
end
|
||
end;
|
||
|
||
function TextExtentW(Text: WideString; Canvas: TCanvas): TSize;
|
||
begin
|
||
FillChar(Result, SizeOf(Result), #0);
|
||
if Assigned(Canvas) and (Text <> '') then
|
||
begin
|
||
Canvas.Lock;
|
||
Result := InternalTextExtentW(PWideChar(Text), Canvas.Handle);
|
||
Canvas.Unlock;
|
||
end;
|
||
end;
|
||
|
||
function TextExtentW(Text: PWideChar; Canvas: TCanvas): TSize;
|
||
begin
|
||
FillChar(Result, SizeOf(Result), #0);
|
||
if Assigned(Canvas) and (Assigned(Text)) then
|
||
begin
|
||
Canvas.Lock;
|
||
Result := InternalTextExtentW(Text, Canvas.Handle);
|
||
Canvas.Unlock;
|
||
end;
|
||
end;
|
||
|
||
function TextExtentW(Text: PWideChar; DC: hDC): TSize;
|
||
begin
|
||
FillChar(Result, SizeOf(Result), #0);
|
||
if (DC <> 0) and (Assigned(Text)) then
|
||
Result := InternalTextExtentW(Text, DC);
|
||
end;
|
||
|
||
type
|
||
TABCArray = array of TABC;
|
||
|
||
function TextTrueExtentsW(Text: WideString; DC: HDC): TSize;
|
||
var
|
||
ABC: TABC;
|
||
TextMetrics: TTextMetric;
|
||
S: string;
|
||
i: integer;
|
||
begin
|
||
// Get the Height at least
|
||
GetTextExtentPoint32W(DC, PWideChar(Text), Length(Text), Result);
|
||
|
||
GetTextMetrics(DC, TextMetrics);
|
||
if TextMetrics.tmPitchAndFamily and TMPF_TRUETYPE <> 0 then
|
||
begin
|
||
Result.cx := 0;
|
||
// Is TrueType
|
||
if Win32Platform = VER_PLATFORM_WIN32_NT then
|
||
begin
|
||
for i := 1 to Length(Text) do
|
||
begin
|
||
GetCharABCWidthsW_MP(DC, Ord(Text[i]), Ord(Text[i]), ABC);
|
||
Result.cx := Result.cx + ABC.abcA + integer(ABC.abcB) + ABC.abcC;
|
||
end
|
||
end else
|
||
begin
|
||
S := Text;
|
||
for i := 1 to Length(S) do
|
||
begin
|
||
GetCharABCWidthsA(DC, Ord(S[i]), Ord(S[i]), ABC);
|
||
Result.cx := Result.cx + ABC.abcA + integer(ABC.abcB) + ABC.abcC;
|
||
end
|
||
end;
|
||
end
|
||
end;
|
||
|
||
function UniqueFileName(const AFilePath: WideString): WideString;
|
||
|
||
{ Creates a unique file name in based on other files in the passed path }
|
||
|
||
var
|
||
i: integer;
|
||
WP: PWideChar;
|
||
begin
|
||
Result := AFilePath;
|
||
i := 2;
|
||
while FileExistsW(Result) and (i < 20) do
|
||
begin
|
||
Result := AFilePath;
|
||
WP := WideStrRScan(PWideChar( Result), '.');
|
||
if Assigned(WP) then
|
||
WideInsert( ' (' + WideIntToStr(i) + ')', Result, PWideChar(WP) - PWideChar(Result))
|
||
else begin
|
||
Result := '';
|
||
Break;
|
||
end;
|
||
Inc(i)
|
||
end;
|
||
end;
|
||
|
||
function TNTConditionallyDefined: Boolean;
|
||
begin
|
||
{$IFDEF TNTSUPPORT}
|
||
Result := True;
|
||
{$ELSE}
|
||
Result := False;
|
||
{$ENDIF}
|
||
end;
|
||
|
||
function UnicodeStringLists: Boolean;
|
||
begin
|
||
{$IFDEF TNTSUPPORT}
|
||
Result := True;
|
||
{$ELSE}
|
||
Result := False;
|
||
{$ENDIF}
|
||
end;
|
||
|
||
function UniqueDirName(const ADirPath: WideString): WideString;
|
||
var
|
||
i: integer;
|
||
begin
|
||
Result := ADirPath;
|
||
i := 2;
|
||
while DirExistsW(PWideChar(Result)) and (i < 20) do
|
||
begin
|
||
Result := ADirPath;
|
||
WideInsert( ' (' + WideIntToStr(i) + ')', Result, Length(Result));
|
||
Inc(i)
|
||
end;
|
||
end;
|
||
|
||
function WideStripExt(AFile: WideString): WideString;
|
||
{ Strips the extenstion off a file name }
|
||
var
|
||
i: integer;
|
||
Done: Boolean;
|
||
begin
|
||
i := Length(AFile);
|
||
Done := False;
|
||
Result := AFile;
|
||
while (i > 0) and not Done do
|
||
begin
|
||
if AFile[i] = '.' then
|
||
begin
|
||
Done := True;
|
||
SetLength(Result, i - 1);
|
||
end;
|
||
Dec(i);
|
||
end;
|
||
end;
|
||
|
||
function WideStripRemoteComputer(const UNCPath: WideString): WideString;
|
||
// Strips the \\RemoteComputer\ part of an UNC path
|
||
var
|
||
Head: PWideChar;
|
||
begin
|
||
Result := '';
|
||
if IsUNCPath(UNCPath) then
|
||
begin
|
||
Result := '';
|
||
if IsUNCPath(UNCPath) then
|
||
begin
|
||
Result := UNCPath;
|
||
Head := @Result[1];
|
||
Head := Head + 2; // Skip past the '\\'
|
||
Head := WideStrScan(Head, WideChar('\'));
|
||
if Assigned(Head) then
|
||
begin
|
||
Head := Head + 1;
|
||
Move(Head[0], Result[1], (lstrlenW(Head) + 1) * 2);
|
||
end;
|
||
SetLength(Result, lstrlenW(PWideChar(Result)));
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
function WideStripTrailingBackslash(const S: WideString; Force: Boolean = False): WideString;
|
||
begin
|
||
Result := S;
|
||
if Result <> '' then
|
||
begin
|
||
// Works with FilePaths and FTP Paths
|
||
if Result[ Length(Result)] in [WideChar('/'), WideChar('\')] then
|
||
if not WideIsDrive(Result) or Force then // Don't strip off if is a root drive
|
||
SetLength(Result, Length(Result) - 1);
|
||
end;
|
||
end;
|
||
|
||
function WideStripLeadingBackslash(const S: WideString): WideString;
|
||
begin
|
||
Result := S;
|
||
if Result <> '' then
|
||
begin
|
||
if (S[1] = '\') and (Length(S) > 1) then
|
||
Result := PWideChar( @S[2])
|
||
else
|
||
Result := ''
|
||
end;
|
||
end;
|
||
|
||
function WideStringReplace(const S, OldPattern, NewPattern: WideString; Flags: TReplaceFlags; WholeWord: Boolean = False): WideString;
|
||
begin
|
||
{$IFDEF TNTSUPPORT}
|
||
Result := Tnt_WideStringReplace(S, OldPattern, NewPattern, [rfReplaceAll, rfIgnoreCase], WholeWord);
|
||
{$ELSE}
|
||
StringReplace(S, OldPattern, NewPattern, [rfReplaceAll, rfIgnoreCase])
|
||
{$ENDIF};
|
||
end;
|
||
|
||
function WideShellExecute(hWnd: HWND; Operation, FileName, Parameters, Directory: WideString; ShowCmd: Integer = SW_NORMAL): HINST;
|
||
var
|
||
OperationA, FileNameA, ParametersA, DirectoryA: string;
|
||
PA, DA: PChar;
|
||
PW, DW: PWideChar;
|
||
begin
|
||
if Assigned(ShellExecuteW_MP) then
|
||
begin
|
||
PW := nil;
|
||
DW := nil;
|
||
if Parameters = '' then
|
||
PW := PWideChar(Parameters);
|
||
if Directory = '' then
|
||
DW := PWideChar(Directory);
|
||
Result := ShellExecuteW_MP(hWnd, PWideChar(Operation), PWideChar(FileName), PW, DW, SW_NORMAL)
|
||
end else
|
||
begin
|
||
OperationA := Operation;
|
||
FileNameA := FileName;
|
||
ParametersA := Parameters;
|
||
DirectoryA := Directory;
|
||
PA := nil;
|
||
DA := nil;
|
||
if ParametersA <> '' then
|
||
PA := PChar( ParametersA);
|
||
if DirectoryA <> '' then
|
||
DA := PChar( DirectoryA);
|
||
Result := ShellExecuteA(hWnd, PChar(OperationA), PChar(FileNameA), PA, DA, SW_NORMAL)
|
||
end
|
||
end;
|
||
|
||
procedure WideShowMessage(Window: HWND; ACaption, AMessage: WideString);
|
||
var
|
||
TextA, CaptionA: string;
|
||
begin
|
||
if IsUnicode then
|
||
MessageBoxW(Window, PWideChar( AMessage), PWideChar( ACaption), MB_ICONEXCLAMATION or MB_OK)
|
||
else begin
|
||
TextA := AMessage;
|
||
CaptionA := ACaption;
|
||
MessageBoxA(Window, PChar( TextA), PChar( CaptionA), MB_ICONEXCLAMATION or MB_OK)
|
||
end
|
||
end;
|
||
|
||
function WideLowerCase(const Str: WideString): WideString;
|
||
begin
|
||
Result := Str;
|
||
if IsUnicode then
|
||
CharLowerBuffW_MP(PWideChar(Result), Length(Result))
|
||
else
|
||
CharLowerBuffA(PChar(string(Result)), Length(Result))
|
||
end;
|
||
|
||
function WideMessageBox(Window: HWND; const ACaption, AMessage: WideString; uType: integer): integer;
|
||
var
|
||
TextA, CaptionA: string;
|
||
begin
|
||
if IsUnicode then
|
||
Result := MessageBoxW(Window, PWideChar( AMessage), PWideChar( ACaption), uType)
|
||
else begin
|
||
TextA := AMessage;
|
||
CaptionA := ACaption;
|
||
Result := MessageBoxA(Window, PChar( TextA), PChar( CaptionA), uType)
|
||
end
|
||
end;
|
||
|
||
function IncludeTrailingBackslashW(const S: WideString): WideString;
|
||
begin
|
||
Result := S;
|
||
if not WideIsPathDelimiter(Result, Length(Result)) then Result := Result + '\';
|
||
end;
|
||
|
||
function DiskInDrive(C: Char): Boolean;
|
||
var
|
||
OldErrorMode: Integer;
|
||
begin
|
||
C := UpCase(C);
|
||
if C in ['A'..'Z'] then
|
||
begin
|
||
OldErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
|
||
Result := DiskFree(Ord(C) - Ord('A') + 1) > -1;
|
||
SetErrorMode(OldErrorMode);
|
||
end else
|
||
Result := False
|
||
end;
|
||
|
||
function WideStrIComp(Str1, Str2: PWideChar): Integer;
|
||
// Insensitive case comparison
|
||
var
|
||
S1, S2: string;
|
||
begin
|
||
if Win32Platform = VER_PLATFORM_WIN32_NT then
|
||
Result := lstrcmpiW_MP(Str1, Str2)
|
||
else begin
|
||
S1 := Str1;
|
||
S2 := Str2;
|
||
Result := lstrcmpi(PChar(S1), PChar(S2))
|
||
end
|
||
end;
|
||
|
||
function StrRScanW(Str: PWideChar; Chr: WideChar): PWideChar;
|
||
// returns a pointer to the last occurance of Chr in Str
|
||
asm
|
||
PUSH EDI
|
||
MOV EDI, Str
|
||
MOV ECX, 0FFFFFFFFH
|
||
XOR AX, AX
|
||
REPNE SCASW
|
||
NOT ECX
|
||
STD
|
||
SUB EDI, 2
|
||
MOV AX, Chr
|
||
REPNE SCASW
|
||
MOV EAX, 0
|
||
JNE @@1
|
||
MOV EAX, EDI
|
||
ADD EAX, 2
|
||
@@1:
|
||
CLD
|
||
POP EDI
|
||
end;
|
||
|
||
function WideStrComp(Str1, Str2: PWideChar): Integer;
|
||
// Sensitive case comparison
|
||
var
|
||
S1, S2: string;
|
||
begin
|
||
if Win32Platform = VER_PLATFORM_WIN32_NT then
|
||
Result := lstrcmpW_MP(Str1, Str2)
|
||
else begin
|
||
S1 := Str1;
|
||
S2 := Str2;
|
||
Result := lstrcmp(PChar(S1), PChar(S2))
|
||
end
|
||
end;
|
||
|
||
function WideStrLower(Str: PWideChar): PWideChar;
|
||
// Returns the string in Str converted to lower case
|
||
var
|
||
S: string;
|
||
WS: WideString;
|
||
begin
|
||
Result := Str;
|
||
if IsUnicode then
|
||
CharLowerBuffW_MP(Str, lstrlenW(Str))
|
||
else begin
|
||
S := Str;
|
||
CharLowerBuffA(PChar(S), Length(S));
|
||
WS := S;
|
||
{ WS is a string index from 1, Result is PWideChar index from 0 }
|
||
Move(WS[1], Result[0], Length(WS));
|
||
end;
|
||
end;
|
||
|
||
procedure WideStrLCopy(Str1, Str2: PWideChar; Count: Integer);
|
||
// Count must include the terminating null
|
||
begin
|
||
if Win32Platform = VER_PLATFORM_WIN32_NT then
|
||
lstrcpynW_MP(Str1, Str2, Count)
|
||
else
|
||
Move(Str2, Str1, Count * 2);
|
||
end;
|
||
|
||
function ShortenStringEx(DC: HDC; const S: WideString; Width: Integer; RTL: Boolean;
|
||
EllipsisPlacement: TShortenStringEllipsis): WideString;
|
||
// Shortens the passed string and inserts ellipsis "..." in the requested place.
|
||
// This is not a fast function but it is clear how it works. Also the RTL implmentation
|
||
// is still being understood.
|
||
var
|
||
Len: Integer;
|
||
EllipsisWidth: Integer;
|
||
TargetString: WideString;
|
||
Tail, Head, Middle: PWideChar;
|
||
L, ResultW: integer;
|
||
begin
|
||
Len := Length(S);
|
||
if (Len = 0) or (Width <= 0) then
|
||
Result := ''
|
||
else begin
|
||
// Determine width of triple point using the current DC settings
|
||
TargetString := '...';
|
||
EllipsisWidth := TextExtentW(PWideChar(TargetString), DC).cx;
|
||
|
||
if Width <= EllipsisWidth then
|
||
Result := ''
|
||
else begin
|
||
TargetString := S;
|
||
Head := PWideChar(TargetString);
|
||
Tail := Head;
|
||
Inc(Tail, lstrlenW(PWideChar(TargetString)));
|
||
case EllipsisPlacement of
|
||
sseEnd:
|
||
begin
|
||
L := EllipsisWidth + TextExtentW(PWideChar(TargetString), DC).cx;
|
||
while (L > Width) do
|
||
begin
|
||
Dec(Tail);
|
||
Tail^ := WideNull;
|
||
L := EllipsisWidth + TextExtentW(PWideChar(TargetString), DC).cx;
|
||
end;
|
||
Result := PWideChar(TargetString) + '...';
|
||
end;
|
||
sseFront:
|
||
begin
|
||
L := EllipsisWidth + TextExtentW(PWideChar(TargetString), DC).cx;
|
||
while (L > Width) do
|
||
begin
|
||
Inc(Head);
|
||
L := EllipsisWidth + TextExtentW(PWideChar(Head), DC).cx;
|
||
end;
|
||
Result := '...' + PWideChar(Head);
|
||
end;
|
||
sseMiddle:
|
||
begin
|
||
L := EllipsisWidth + TextExtentW(PWideChar(TargetString), DC).cx;
|
||
while (L > Width div 2 - EllipsisWidth div 2) do
|
||
begin
|
||
Dec(Tail);
|
||
Tail^ := WideNull;
|
||
L := TextExtentW(PWideChar(TargetString), DC).cx;
|
||
end;
|
||
Result := PWideChar(TargetString) + '...';
|
||
ResultW := TextExtentW(PWideChar(Result), DC).cx;
|
||
|
||
TargetString := S;
|
||
Head := PWideChar(TargetString);
|
||
Middle := Head;
|
||
Inc(Middle, lstrlenW(PWideChar(Result)) - 3); // - 3 for ellipsis letters
|
||
Tail := Head;
|
||
Inc(Tail, lstrlenW(PWideChar(TargetString)));
|
||
Head := Tail - 1;
|
||
|
||
L := ResultW + TextExtentW(Head, DC).cx;
|
||
while (L < Width) and (Head >= Middle) do
|
||
begin
|
||
Dec(Head);
|
||
L := ResultW + TextExtentW(PWideChar(Head), DC).cx;
|
||
end;
|
||
Inc(Head);
|
||
|
||
Result := Result + Head;
|
||
end;
|
||
sseFilePathMiddle:
|
||
begin
|
||
Head := Tail - 1;
|
||
L := EllipsisWidth + TextExtentW(Head, DC).cx;
|
||
while (Head^ <> '\') and (Head <> @TargetString[1]) and (L < Width) do
|
||
begin
|
||
Dec(Head);
|
||
L := EllipsisWidth + TextExtentW(Head, DC).cx;
|
||
end;
|
||
if Head^ <> '\' then
|
||
Inc(Head);
|
||
Result := '...' + Head;
|
||
|
||
ResultW := TextExtentW(PWideChar(Result), DC).cx;
|
||
|
||
Head^ := WideNull;
|
||
SetLength(TargetString, lstrlenW(PWideChar(TargetString)));
|
||
|
||
Head := PWideChar(TargetString);
|
||
Tail := Head;
|
||
Inc(Tail, lstrlenW(Head));
|
||
|
||
L := ResultW + TextExtentW(PWideChar(TargetString), DC).cx;
|
||
while (L > Width) and (Tail > @TargetString[1]) do
|
||
begin
|
||
Dec(Tail);
|
||
Tail^ := WideNull;
|
||
L := ResultW + TextExtentW(PWideChar(TargetString), DC).cx;
|
||
end;
|
||
|
||
Result := Head + Result;
|
||
end;
|
||
end;
|
||
|
||
// Windows 2000 automatically switches the order in the string. For every other system we have to take care.
|
||
{ if IsWin2000 or not RTL then
|
||
Result := Copy(S, 1, N - 1) + '...'
|
||
else
|
||
Result := '...' + Copy(S, 1, N - 1); }
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
function WindowsDirectory: WideString;
|
||
var
|
||
Len: integer;
|
||
S: string;
|
||
begin
|
||
Result := '';
|
||
if Win32Platform = VER_PLATFORM_WIN32_NT then
|
||
Len := GetWindowsDirectoryW_MP(PWideChar(Result), 0)
|
||
else
|
||
Len := GetWindowsDirectoryA(PChar(S), 0);
|
||
if Len > 0 then
|
||
begin
|
||
if IsUnicode then
|
||
begin
|
||
SetLength(Result, Len - 1);
|
||
GetWindowsDirectoryW_MP(PWideChar(Result), Len);
|
||
end else
|
||
begin
|
||
SetLength(S, Len - 1);
|
||
GetWindowsDirectoryA(PChar(S), Len);
|
||
Result := S
|
||
end
|
||
end
|
||
end;
|
||
|
||
function ModuleFileName(PathOnly: Boolean = True): Widestring;
|
||
var
|
||
BufferA: array[0..MAX_PATH] of Char;
|
||
BufferW: array[0..MAX_PATH] of WideChar;
|
||
begin
|
||
if IsUnicode then
|
||
begin
|
||
FillChar(BufferW, SizeOf(BufferW), #0);
|
||
if GetModuleFileNameW(0, BufferW, SizeOf(BufferW)) > 0 then
|
||
begin
|
||
if PathOnly then
|
||
Result := ExtractFileDirW(BufferW)
|
||
else
|
||
Result := BufferW;
|
||
end
|
||
end else
|
||
begin
|
||
FillChar(BufferA, SizeOf(BufferA), #0);
|
||
if GetModuleFileNameA(0 , BufferA, SizeOf(BufferA)) > 0 then
|
||
begin
|
||
if PathOnly then
|
||
Result := ExtractFileDirW(BufferA)
|
||
else
|
||
Result := BufferA
|
||
end
|
||
end
|
||
end;
|
||
|
||
function PIDLToPath(PIDL: PItemIDList): WideString;
|
||
var
|
||
PIDLMgr: TCommonPIDLManager;
|
||
LastID: PItemIDList;
|
||
LastCB: Word;
|
||
Desktop, Folder: IShellFolder;
|
||
StrRet: TStrRet;
|
||
begin
|
||
Result := '';
|
||
if Assigned(PIDL) then
|
||
begin
|
||
FillChar(StrRet, SizeOf(StrRet), #0);
|
||
PIDLMgr := TCommonPIDLManager.Create;
|
||
try
|
||
SHGetDesktopFolder(Desktop);
|
||
if PIDLMgr.IsDesktopFolder(PIDL) then
|
||
begin
|
||
end else
|
||
begin
|
||
PIDLMgr.StripLastID(PIDL, LastCB, LastID);
|
||
try
|
||
if Succeeded(Desktop.BindToObject(PIDL, nil, IShellFolder, pointer(Folder))) then
|
||
begin
|
||
LastID.mkid.cb := LastCB;
|
||
if Succeeded(Folder.GetDisplayNameOf(LastID, SHGDN_FORPARSING, StrRet)) then
|
||
Result := StrRetToStr(StrRet, LastID);
|
||
end
|
||
finally
|
||
LastID.mkid.cb := LastCB;
|
||
end
|
||
end
|
||
finally
|
||
PIDLMgr.Free
|
||
end
|
||
end
|
||
end;
|
||
|
||
function ShortFileName(const FileName: WideString): WideString;
|
||
var
|
||
S: string;
|
||
BufferA: array[0..MAX_PATH] of char;
|
||
BufferW: array[0..MAX_PATH] of WideChar;
|
||
begin
|
||
if IsUnicode then
|
||
begin
|
||
if GetShortPathNameW(PWideChar(FileName), BufferW, SizeOf(BufferW)) > 0 then
|
||
Result := BufferW
|
||
end else
|
||
begin
|
||
S := FileName;
|
||
if GetShortPathNameA(PChar(S), BufferA, SizeOf(BufferA)) > 0 then
|
||
Result := BufferA
|
||
end
|
||
end;
|
||
|
||
function ShortPath(const Path: WideString): WideString;
|
||
begin
|
||
Result := ShortFileName(Path)
|
||
end;
|
||
|
||
procedure LoadWideString(S: TStream; var Str: WideString);
|
||
var
|
||
Count: Integer;
|
||
begin
|
||
S.Read(Count, SizeOf(Integer));
|
||
SetLength(Str, Count);
|
||
S.Read(PWideChar(Str)^, Count * 2)
|
||
end;
|
||
|
||
procedure SaveWideString(S: TStream; Str: WideString);
|
||
var
|
||
Count: Integer;
|
||
begin
|
||
Count := Length(Str);
|
||
S.Write(Count, SizeOf(Integer));
|
||
S.Write(PWideChar(Str)^, Count * 2)
|
||
end;
|
||
|
||
|
||
function WideStrPos(Str, SubStr: PWideChar): PWideChar;
|
||
// returns a pointer to the first occurance of SubStr in Str
|
||
asm
|
||
PUSH EDI
|
||
PUSH ESI
|
||
PUSH EBX
|
||
OR EAX, EAX
|
||
JZ @@2
|
||
OR EDX, EDX
|
||
JZ @@2
|
||
MOV EBX, EAX
|
||
MOV EDI, EDX
|
||
XOR AX, AX
|
||
MOV ECX, 0FFFFFFFFH
|
||
REPNE SCASW
|
||
NOT ECX
|
||
DEC ECX
|
||
JZ @@2
|
||
MOV ESI, ECX
|
||
MOV EDI, EBX
|
||
MOV ECX, 0FFFFFFFFH
|
||
REPNE SCASW
|
||
NOT ECX
|
||
SUB ECX, ESI
|
||
JBE @@2
|
||
MOV EDI, EBX
|
||
LEA EBX, [ESI - 1]
|
||
@@1:
|
||
MOV ESI, EDX
|
||
LODSW
|
||
REPNE SCASW
|
||
JNE @@2
|
||
MOV EAX, ECX
|
||
PUSH EDI
|
||
MOV ECX, EBX
|
||
REPE CMPSW
|
||
POP EDI
|
||
MOV ECX, EAX
|
||
JNE @@1
|
||
LEA EAX, [EDI - 2]
|
||
JMP @@3
|
||
|
||
@@2:
|
||
XOR EAX, EAX
|
||
@@3:
|
||
POP EBX
|
||
POP ESI
|
||
POP EDI
|
||
end;
|
||
|
||
function ProperRect(Rect: TRect): TRect;
|
||
// Makes sure a rectangle's left is less than its right and its top is less than its bottom
|
||
var
|
||
Temp: integer;
|
||
begin
|
||
Result := Rect;
|
||
if Result.Right < Result.Left then
|
||
begin
|
||
Temp := Result.Right;
|
||
Result.Right := Rect.Left;
|
||
Result.Left := Temp;
|
||
end;
|
||
if Rect.Bottom < Rect.Top then
|
||
begin
|
||
Temp := Result.Top;
|
||
Result.Top := Rect.Bottom;
|
||
Result.Bottom := Temp;
|
||
end
|
||
end;
|
||
|
||
function DragDetectPlus(Handle: HWND; Pt: TPoint): Boolean;
|
||
// Replacement for DragDetect API which is buggy.
|
||
// Pt is in Client Coords of the Handle window
|
||
var
|
||
DragRect: TRect;
|
||
Msg: TMsg;
|
||
TestPt: TPoint;
|
||
HadCapture, Done: Boolean;
|
||
begin
|
||
Result := False;
|
||
Done := False;
|
||
HadCapture := GetCapture = Handle;
|
||
if (not ClientToScreen(Handle, Pt)) then
|
||
Exit;
|
||
DragRect.TopLeft := Pt;
|
||
DragRect.BottomRight := Pt;
|
||
InflateRect(DragRect, GetSystemMetrics(SM_CXDRAG), GetSystemMetrics(SM_CYDRAG));
|
||
SetCapture(Handle);
|
||
try
|
||
while (not Result) and (not Done) do
|
||
if (PeekMessage(Msg, Handle, 0,0, PM_REMOVE)) then
|
||
begin
|
||
case (Msg.message) of
|
||
WM_MOUSEMOVE:
|
||
begin
|
||
TestPt := Msg.Pt;
|
||
// Not sure why this works. The Message point "should" be in client
|
||
// coordinates but seem to be screen
|
||
// Windows.ClientToScreen(Msg.hWnd, TestPt);
|
||
Result := not(PtInRect(DragRect, TestPt));
|
||
end;
|
||
WM_RBUTTONUP,
|
||
WM_LBUTTONUP,
|
||
WM_CANCELMODE,
|
||
WM_LBUTTONDBLCLK,
|
||
WM_MBUTTONUP:
|
||
begin
|
||
// Let the window get these messages after we have ended our
|
||
// local message loop
|
||
PostMessage(Msg.hWnd, Msg.message, Msg.wParam, Msg.lParam);
|
||
Done := True;
|
||
end;
|
||
WM_QUIT:
|
||
begin
|
||
PostQuitMessage(Msg.wParam);
|
||
Done := True;
|
||
end
|
||
else
|
||
TranslateMessage(Msg);
|
||
DispatchMessage(Msg)
|
||
end
|
||
end else
|
||
Sleep(0);
|
||
finally
|
||
ReleaseCapture;
|
||
if HadCapture then
|
||
Mouse.Capture := Handle;
|
||
end;
|
||
end;
|
||
|
||
procedure FillWideChar(var Dest; count: Integer; Value: WideChar);
|
||
var
|
||
I: Integer;
|
||
P: PWideChar;
|
||
begin
|
||
P := PWideChar(@Dest);
|
||
for I := count-1 downto 0 do
|
||
P[I] := Value;
|
||
end;
|
||
|
||
procedure FreeMemAndNil(var P: Pointer);
|
||
{ Frees the memeory allocated with GetMem and nils the pointer }
|
||
var
|
||
Temp: Pointer;
|
||
begin
|
||
Temp := P;
|
||
P := nil;
|
||
FreeMem(Temp);
|
||
end;
|
||
|
||
function IsRectNull(ARect: TRect): Boolean;
|
||
begin
|
||
Result := EqualRect(ARect, Rect(0, 0, 0, 0))
|
||
end;
|
||
|
||
function IsUnicode: Boolean;
|
||
begin
|
||
Result := Win32Platform = VER_PLATFORM_WIN32_NT
|
||
end;
|
||
|
||
function IsWinNT: Boolean;
|
||
begin
|
||
Result := Win32Platform = VER_PLATFORM_WIN32_NT
|
||
end;
|
||
|
||
function IsWin2000: Boolean;
|
||
begin
|
||
Result := False;
|
||
if Win32Platform = VER_PLATFORM_WIN32_NT then
|
||
Result := LoWord(Win32MajorVersion) >= 5
|
||
end;
|
||
|
||
function IsWin95_SR1: Boolean;
|
||
begin
|
||
Result := False;
|
||
if Win32Platform = VER_PLATFORM_WIN32_WINDOWS then
|
||
Result := ((Win32MajorVersion = 4) and
|
||
(Win32MinorVersion = 0) and
|
||
(LoWord(Win32BuildNumber) <= 1080))
|
||
end;
|
||
|
||
function IsWinME: Boolean;
|
||
begin
|
||
Result := False;
|
||
if Win32Platform = VER_PLATFORM_WIN32_WINDOWS then
|
||
Result := Win32BuildNumber >= $045A0BB8
|
||
end;
|
||
|
||
function IsWinNT4: Boolean;
|
||
begin
|
||
Result := False;
|
||
if Win32Platform = VER_PLATFORM_WIN32_NT then
|
||
Result := Win32MajorVersion < 5
|
||
end;
|
||
|
||
function IsWinXP: Boolean;
|
||
begin
|
||
Result := (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion = 5)
|
||
and (Win32MinorVersion > 0)
|
||
end;
|
||
|
||
function IsWinXPOrUp: Boolean;
|
||
begin
|
||
Result := (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion >= 5)
|
||
and (Win32MinorVersion > 0)
|
||
end;
|
||
|
||
function IsWinVista: Boolean;
|
||
begin
|
||
Result := (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion = 6)
|
||
and (Win32MinorVersion >= 0)
|
||
end;
|
||
|
||
function IsWinVistaOrUp: Boolean;
|
||
begin
|
||
Result := (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion >= 6)
|
||
and (Win32MinorVersion >= 0)
|
||
end;
|
||
|
||
function RectHeight(R: TRect): Integer;
|
||
begin
|
||
Result := R.Bottom - R.Top
|
||
end;
|
||
|
||
function RectToStr(R: TRect): string;
|
||
begin
|
||
Result := 'Left = ' + IntToStr(R.Left) +
|
||
' Top = ' + IntToStr(R.Top) +
|
||
' Right = ' + IntToStr(R.Right) +
|
||
' Bottom = ' + IntToStr(R.Bottom)
|
||
end;
|
||
|
||
function RectToSquare(R: TRect): TRect;
|
||
// Takes the passed rectangle and makes it square based on the longest dimension
|
||
begin
|
||
if RectWidth(R) > RectHeight(R) then
|
||
R.Right := R.Left + RectHeight(R)
|
||
else
|
||
if RectHeight(R) > RectWidth(R) then
|
||
begin
|
||
R.Bottom := R.Top + RectWidth(R);
|
||
end else
|
||
Result := R
|
||
end;
|
||
|
||
function RectWidth(R: TRect): Integer;
|
||
begin
|
||
Result := R.Right - R.Left
|
||
end;
|
||
|
||
function ContainsRect(OuterRect, InnerRect: TRect): Boolean;
|
||
//
|
||
// Returns true if the InnerRect is completely contained within the
|
||
// OuterRect
|
||
//
|
||
begin
|
||
Result := (InnerRect.Left >= OuterRect.Left) and
|
||
(InnerRect.Right <= OuterRect.Right) and
|
||
(InnerRect.Top >= OuterRect.Top) and
|
||
(InnerRect.Bottom <= OuterRect.Bottom)
|
||
end;
|
||
|
||
function KeyDataToShiftState(KeyData: Longint): TShiftState;
|
||
begin
|
||
Result := [];
|
||
if GetKeyState(VK_SHIFT) < 0 then
|
||
Include(Result, ssShift);
|
||
if GetKeyState(VK_CONTROL) < 0 then
|
||
Include(Result, ssCtrl);
|
||
if KeyData and $20000000 <> 0 then
|
||
Include(Result, ssAlt);
|
||
end;
|
||
|
||
function DropEffectToDropEffectState(Effect: Integer): TCommonDropEffect;
|
||
begin
|
||
Result := cdeNone;
|
||
if Effect and DROPEFFECT_COPY <> 0 then
|
||
Result := cdeCopy
|
||
else
|
||
if Effect and DROPEFFECT_MOVE <> 0 then
|
||
Result := cdeMove
|
||
else
|
||
if Effect and DROPEFFECT_LINK <> 0 then
|
||
Result := cdeLink
|
||
end;
|
||
|
||
function DropEffectStateToDropEffect(Effect: TCommonDropEffect): Integer;
|
||
begin
|
||
Result := 0;
|
||
if cdeCopy = Effect then
|
||
Result := Result or DROPEFFECT_COPY
|
||
else
|
||
if cdeMove = Effect then
|
||
Result := Result or DROPEFFECT_MOVE
|
||
else
|
||
if cdeLink = Effect then
|
||
Result := Result or DROPEFFECT_LINK
|
||
end;
|
||
|
||
function DropEffectToDropEffectStates(Effect: Integer): TCommonDropEffects;
|
||
begin
|
||
Result := [];
|
||
if (Effect = 0) or (Longword(Effect) = DROPEFFECT_SCROLL) then
|
||
Include(Result, cdeNone);
|
||
if Effect and DROPEFFECT_COPY <> 0 then
|
||
Include(Result, cdeCopy);
|
||
if Effect and DROPEFFECT_MOVE <> 0 then
|
||
Include(Result, cdeMove);
|
||
if Effect and DROPEFFECT_LINK <> 0 then
|
||
Include(Result, cdeLink);
|
||
if Effect and DROPEFFECT_SCROLL <> 0 then
|
||
Include(Result, cdeScroll)
|
||
end;
|
||
|
||
function DropEffectStatesToDropEffect(Effect: TCommonDropEffects): Integer;
|
||
begin
|
||
Result := 0;
|
||
if cdeCopy in Effect then
|
||
Result := Result or DROPEFFECT_COPY;
|
||
if cdeMove in Effect then
|
||
Result := Result or DROPEFFECT_MOVE;
|
||
if cdeLink in Effect then
|
||
Result := Result or DROPEFFECT_LINK;
|
||
if cdeScroll in Effect then
|
||
Result := Result or Integer(DROPEFFECT_SCROLL);
|
||
end;
|
||
|
||
function KeyToKeyStates(Keys: Word): TCommonKeyStates;
|
||
begin
|
||
Result := [];
|
||
if Keys and MK_CONTROL <> 0 then
|
||
Include(Result, cksControl);
|
||
if Keys and MK_LBUTTON <> 0 then
|
||
Include(Result, cksLButton);
|
||
if Keys and MK_MBUTTON <> 0 then
|
||
Include(Result, cksMButton);
|
||
if Keys and MK_RBUTTON <> 0 then
|
||
Include(Result, cksRButton);
|
||
if Keys and MK_SHIFT <> 0 then
|
||
Include(Result, cksShift);
|
||
if Keys and MK_ALT <> 0 then
|
||
Include(Result, cksAlt);
|
||
if Keys and MK_BUTTON <> 0 then
|
||
Include(Result, cksButton);
|
||
end;
|
||
|
||
function KeyStatesToMouseButton(Keys: Word): TCommonMouseButton;
|
||
begin
|
||
if Keys and MK_LBUTTON <> 0 then
|
||
Result := cmbLeft
|
||
else
|
||
if Keys and MK_MBUTTON <> 0 then
|
||
Result := cmbMiddle
|
||
else
|
||
if Keys and MK_RBUTTON <> 0 then
|
||
Result := cmbRight
|
||
else
|
||
Result := cmbNone
|
||
end;
|
||
|
||
function KeyStatesToKey(Keys: TCommonKeyStates): Longword;
|
||
begin
|
||
Result := 0;
|
||
if cksControl in Keys then
|
||
Result := Result or MK_CONTROL;
|
||
if cksLButton in Keys then
|
||
Result := Result or MK_LBUTTON;
|
||
if cksMButton in Keys then
|
||
Result := Result or MK_MBUTTON;
|
||
if cksRButton in Keys then
|
||
Result := Result or MK_RBUTTON;
|
||
if cksShift in Keys then
|
||
Result := Result or MK_SHIFT;
|
||
if cksAlt in Keys then
|
||
Result := Result or MK_ALT;
|
||
end;
|
||
|
||
function KeyStateToDropEffect(Keys: TCommonKeyStates): TCommonDropEffect;
|
||
begin
|
||
Result := cdeMove; // The default
|
||
if (cksControl in Keys) and not ((cksShift in Keys) or (cksAlt in Keys)) then
|
||
Result := cdeCopy
|
||
else
|
||
if ((cksAlt in Keys) and not ((cksShift in Keys) or (cksControl in Keys))) or
|
||
((cksShift in Keys) and (cksControl in Keys)) then
|
||
Result := cdeLink
|
||
end;
|
||
|
||
function KeyStateToMouseButton(KeyState: TCommonKeyStates): TCommonMouseButton;
|
||
begin
|
||
if KeyState * [cksLButton] <> [] then
|
||
Result := cmbLeft
|
||
else
|
||
if KeyState * [cksRButton] <> [] then
|
||
Result := cmbRight
|
||
else
|
||
if KeyState * [cksMButton] <> [] then
|
||
Result := cmbMiddle
|
||
else
|
||
Result := cmbNone
|
||
end;
|
||
|
||
function FileIconInit(FullInit: BOOL): BOOL; stdcall;
|
||
// Forces the system to load all Images into the ImageList. Normally with NT
|
||
// system icons are only loaded as needed.
|
||
type
|
||
TFileIconInit = function(FullInit: BOOL): BOOL; stdcall;
|
||
var
|
||
ShellDLL: HMODULE;
|
||
PFileIconInit: TFileIconInit;
|
||
begin
|
||
Result := False;
|
||
if (Win32Platform = VER_PLATFORM_WIN32_NT) then
|
||
begin
|
||
ShellDLL := CommonLoadLibrary(Shell32);
|
||
PFileIconInit := GetProcAddress(ShellDLL, PChar(660));
|
||
if (Assigned(PFileIconInit)) then
|
||
Result := PFileIconInit(FullInit);
|
||
end;
|
||
end;
|
||
|
||
function SHGetImageList(iImageList: Integer; const RefID: TGUID; out ppvOut): HRESULT; stdcall;
|
||
// Retrieves the system ImageList interface
|
||
var
|
||
ShellDLL: HMODULE;
|
||
ImageList: TSHGetImageList;
|
||
begin
|
||
Result := E_NOTIMPL;
|
||
if (Win32Platform = VER_PLATFORM_WIN32_NT) then
|
||
begin
|
||
// if GetFileVersion(comctl32) >= $00060000 then
|
||
begin
|
||
ShellDLL := CommonLoadLibrary(Shell32);
|
||
ImageList := GetProcAddress(ShellDLL, PChar(727));
|
||
if (Assigned(ImageList)) then
|
||
Result := ImageList(iImageList, RefID, ppvOut);
|
||
end
|
||
end;
|
||
end;
|
||
|
||
function Size(cx, cy: Integer): TSize;
|
||
begin
|
||
Result.cy := cy;
|
||
Result.cx := cx
|
||
end;
|
||
|
||
function ShortenTextW(DC: hDC; TextToShorten: WideString; MaxSize: Integer): WideString;
|
||
// Shortens the passed string in such a way that if it does not fit in the MaxSize
|
||
// (in Pixels) a "..." is inserted at the correct place where the new string fixs
|
||
// in MaxSize
|
||
var
|
||
Size: TSize;
|
||
EllipsisSize: TSize;
|
||
// TailA: String;
|
||
StrLen, Middle, Low, High{, LastHigh}: Cardinal;
|
||
// WChar: WideChar;
|
||
// Done: Boolean;
|
||
begin
|
||
if TextToShorten <> '' then
|
||
begin
|
||
GetTextExtentPoint32W(DC, PWideChar(TextToShorten), Length(TextToShorten), Size);
|
||
GetTextExtentPoint32W(DC, '...', 3, EllipsisSize);
|
||
StrLen := Length(TextToShorten);
|
||
if Size.cx > MaxSize then
|
||
begin
|
||
(* Middle := StrLen div 2;
|
||
Done := False;
|
||
Low := 0;
|
||
High := StrLen;
|
||
LastHigh := High;
|
||
// Do a psudo binary search
|
||
while not Done do
|
||
begin
|
||
GetTextExtentPoint32W(DC, @TextToShorten[1], Middle, Size);
|
||
Size.cx := Size.cx + EllipsisSize.cx;
|
||
|
||
if Size.cx > MaxSize then
|
||
begin
|
||
// Still to long
|
||
LastHigh := High;
|
||
High := Middle;
|
||
Middle := Low + (High - Low) div 2;
|
||
end else
|
||
begin
|
||
// Too short
|
||
High := LastHigh;
|
||
Low := Middle;
|
||
|
||
Middle := Low + (High - Low) div 2;
|
||
end;
|
||
Done := High - Low <= 2;
|
||
end; *)
|
||
|
||
// Milan's version
|
||
Low:=0;
|
||
High:=StrLen-1;
|
||
while (Low<High) do
|
||
begin
|
||
Middle:=(Low+High+1) shr 1;
|
||
// if IsUnicode then
|
||
GetTextExtentPoint32W(DC, @TextToShorten[1], Middle, Size);
|
||
// else begin
|
||
// TailA := TextToShorten[1];
|
||
// GetTextExtentPoint32(DC, @TailA[1], 1, Size);
|
||
// end;
|
||
Size.cx := Size.cx + EllipsisSize.cx;
|
||
if (Size.cx<=MaxSize) then
|
||
Low:=Middle
|
||
else
|
||
High:=Middle-1;
|
||
end;
|
||
|
||
SetLength(TextToShorten, Low);
|
||
if Low > 0 then
|
||
Result := TextToShorten + '...'
|
||
else
|
||
Result := '...'
|
||
end else
|
||
Result := TextToShorten
|
||
end else
|
||
Result := '';
|
||
end;
|
||
|
||
(*
|
||
function SplitTextW(DC: hDC; TextToSplit: WideString; MaxWidth: Integer;
|
||
var Buffer: TWideCharArray; MaxSplits: Integer): Integer;
|
||
// Takes the passed string and breaks it up so each piece fits within the MaxWidth
|
||
// The function detects any LF/CR pairs and treats them as one break if CR or LF
|
||
// is defined as a break character.
|
||
// The Buffer is a set of NULL terminated strings for each line, with the last
|
||
// one being terminated with a double NULL. Much like the SHFileOperation API
|
||
// This makes it ready to use to pass the strings to ExtTextOutW in a loop
|
||
// If the buffer is too small the Result will be false
|
||
// If MaxSplits = -1 then the function splits as many time as necessary
|
||
// The Return is the total number of lines the passed text was split into
|
||
var
|
||
Head, Tail, LastBreakChar, BufferHead: PWideChar;
|
||
Size: TSize;
|
||
LineWidth, SplitCount, Len: Integer;
|
||
TextMetrics: TTextMetric;
|
||
{ PeriodW1, PeriodW2, PeriodW3: Integer; }
|
||
begin
|
||
Result := 0;
|
||
if MaxWidth = 0 then
|
||
begin
|
||
SetLength(Buffer, 2);
|
||
Buffer[0] := WideNull;
|
||
Buffer[1] := WideNull;
|
||
end else
|
||
begin
|
||
GetTextMetrics(DC, TextMetrics);
|
||
|
||
// Can get into deep trouble if a single letter won't fit in the MaxWidth
|
||
if TextMetrics.tmMaxCharWidth > MaxWidth then
|
||
begin
|
||
Len := Length(TextToSplit);
|
||
SetLength(Buffer, Len + 2);
|
||
if Len > 0 then
|
||
begin
|
||
Head := @TextToSplit[1];
|
||
CopyMemory(Buffer, Head, Len*2);
|
||
Result := 1;
|
||
end;
|
||
Buffer[Len] := #0;
|
||
Buffer[Len + 1] := #0;
|
||
end else
|
||
begin
|
||
FillChar(Size, SizeOf(Size), #0);
|
||
// Arbitrary size that should be ok in most instances. This will be enough space
|
||
// for 127 lines
|
||
SetLength(Buffer, Length(TextToSplit) + 128);
|
||
BufferHead := @Buffer[0];
|
||
Head := PWideChar(TextToSplit);
|
||
Tail := Head;
|
||
SplitCount := 0;
|
||
while (Tail^ <> #0) and ((SplitCount < MaxSplits) or (MaxSplits = -1)) do
|
||
begin
|
||
LineWidth := 0;
|
||
LastBreakChar := nil;
|
||
while (Tail^ <> WideNull) and (LineWidth <= MaxWidth) and (Tail^ <> WideCR) and (Tail^ <> WideLF) do
|
||
begin
|
||
GetTextExtentPoint32W(DC, PWideChar(Tail), 1, Size);
|
||
Inc(LineWidth, Size.cx);
|
||
|
||
Inc(Tail);
|
||
|
||
if (LineWidth <= MaxWidth) and (Tail^ = WideSpace) then
|
||
LastBreakChar := Tail;
|
||
end;
|
||
|
||
if (LineWidth > MaxWidth) {and (Tail^ <> WideSpace)} then
|
||
begin
|
||
// Over ran the line unless it exactly fits
|
||
if Assigned(LastBreakChar) and (LineWidth > MaxWidth) then
|
||
begin
|
||
// We have word break to go back to
|
||
Tail := LastBreakChar;
|
||
Inc(SplitCount);
|
||
if SplitCount = MaxSplits then
|
||
begin
|
||
// If no more splits allows copy the entire rest of the string to the buffer
|
||
Len := lStrLenW(Head);
|
||
CopyMemory(BufferHead, Head, Len*2);
|
||
Inc(BufferHead, Len);
|
||
end else
|
||
begin
|
||
CopyMemory(BufferHead, Head, (Tail-Head)*2);
|
||
Inc(BufferHead, Tail-Head);
|
||
end;
|
||
BufferHead^ := WideNull;
|
||
Inc(BufferHead);
|
||
end else
|
||
begin
|
||
// Special case, the Tail is the end of the Text to split
|
||
if Tail^ <> WideNull then
|
||
Dec(Tail);
|
||
Inc(SplitCount);
|
||
if SplitCount = MaxSplits then
|
||
begin
|
||
// If no more splits allows copy the entire rest of the string to the buffer
|
||
Len := lStrLenW(Head);
|
||
CopyMemory(BufferHead, Head, Len*2);
|
||
Inc(BufferHead, Len);
|
||
end else
|
||
begin
|
||
CopyMemory(BufferHead, Head, (Tail-Head)*2);
|
||
Inc(BufferHead, Tail-Head);
|
||
end;
|
||
BufferHead^ := WideNull;
|
||
Inc(BufferHead);
|
||
end;
|
||
Inc(Result);
|
||
end else
|
||
begin
|
||
Inc(SplitCount);
|
||
if SplitCount = MaxSplits then
|
||
begin
|
||
// If no more splits allows copy the entire rest of the string to the buffer
|
||
Len := lStrLenW(Head);
|
||
CopyMemory(BufferHead, Head, Len*2);
|
||
Inc(BufferHead, Len);
|
||
end else
|
||
begin
|
||
CopyMemory(BufferHead, Head, (Tail-Head)*2);
|
||
Inc(BufferHead, Tail-Head);
|
||
end;
|
||
BufferHead^ := WideNull;
|
||
Inc(BufferHead);
|
||
Inc(Result)
|
||
end;
|
||
|
||
while (Tail^ <> #0) and ((Tail^ = WideCR) or (Tail^ = WideLF) or (Tail^ = WideSpace)) do
|
||
Inc(Tail);
|
||
Head := Tail
|
||
end
|
||
end
|
||
end
|
||
end;
|
||
*)
|
||
|
||
|
||
// Solerman's version
|
||
function SplitTextW(DC: hDC; TextToSplit: WideString; MaxWidth: Integer;
|
||
var Buffer: TCommonWideCharArray; MaxSplits: Integer): Integer;
|
||
// Takes the passed string and breaks it up so each piece fits within the MaxWidth
|
||
// The function detects any LF/CR pairs and treats them as one break if CR or LF
|
||
// is defined as a break character.
|
||
// The Buffer is a set of NULL terminated strings for each line, with the last
|
||
// one being terminated with a double NULL. Much like the SHFileOperation API
|
||
// This makes it ready to use to pass the strings to ExtTextOutW in a loop
|
||
// If the buffer is too small the Result will be false
|
||
// If MaxSplits = -1 then the function splits as many time as necessary
|
||
// The Return is the total number of lines the passed text was split into
|
||
var
|
||
Head, Tail, LastBreakChar, BufferHead: PWideChar;
|
||
// TailA: String;
|
||
Size: TSize;
|
||
LineWidth, SplitCount, Len: Integer;
|
||
TextMetrics: TTextMetric;
|
||
begin
|
||
Result := 0;
|
||
if MaxWidth = 0 then
|
||
begin
|
||
SetLength(Buffer, 2);
|
||
Buffer[0] := WideNull;
|
||
Buffer[1] := WideNull;
|
||
end else
|
||
begin
|
||
GetTextMetrics(DC, TextMetrics);
|
||
|
||
// Can get into deep trouble if a single letter won't fit in the MaxWidth
|
||
if TextMetrics.tmMaxCharWidth > MaxWidth then
|
||
begin
|
||
Len := Length(TextToSplit);
|
||
SetLength(Buffer, Len + 2);
|
||
if Len > 0 then
|
||
begin
|
||
Head := @TextToSplit[1];
|
||
CopyMemory(Buffer, Head, Len*2);
|
||
Result := 1;
|
||
end;
|
||
Buffer[Len] := #0;
|
||
Buffer[Len + 1] := #0;
|
||
end else
|
||
begin
|
||
FillChar(Size, SizeOf(Size), #0);
|
||
// Arbitrary size that should be ok in most instances. This will be enough space
|
||
// for 127 lines
|
||
SetLength(Buffer, Length(TextToSplit) + 128);
|
||
BufferHead := @Buffer[0];
|
||
Head := PWideChar(TextToSplit);
|
||
Tail := Head;
|
||
SplitCount := 0;
|
||
while (Tail^ <> #0) and ((SplitCount < MaxSplits) or (MaxSplits = -1)) do
|
||
begin
|
||
LineWidth := 0;
|
||
LastBreakChar := nil;
|
||
while (Tail^ <> WideNull) and (LineWidth <= MaxWidth) and (Tail^ <> WideCR) and (Tail^ <> WideLF) do
|
||
begin
|
||
// if IsUnicode then
|
||
GetTextExtentPoint32W(DC, PWideChar(Tail), 1, Size);
|
||
// else begin
|
||
// TailA := Tail^;
|
||
// GetTextExtentPoint32(DC, @TailA[1], 1, Size);
|
||
// end;
|
||
Inc(LineWidth, Size.cx);
|
||
|
||
Inc(Tail);
|
||
|
||
if (LineWidth <= MaxWidth) and (Tail^ = WideSpace) then
|
||
LastBreakChar := Tail;
|
||
end;
|
||
|
||
if (LineWidth > MaxWidth) then
|
||
begin
|
||
// We overran the MaxWidth if entering this block
|
||
|
||
// Over ran the line unless it exactly fits
|
||
if Assigned(LastBreakChar) and (LineWidth > MaxWidth) then
|
||
// We have word break to go back to
|
||
Tail := LastBreakChar
|
||
else
|
||
// Special case, the Tail is the end of the Text to split
|
||
if {(Tail^ <> WideNull) and} ((SplitCount + 1 < MaxSplits) or (MaxSplits < 0)) then
|
||
Dec(Tail);
|
||
end;
|
||
Inc(SplitCount);
|
||
// If we reach the MaxSplits make the last line be the rest of the text.
|
||
if (SplitCount > 0) and (SplitCount = MaxSplits) then
|
||
Inc(Tail, lstrlenW(Tail));
|
||
CopyMemory(BufferHead, Head, (Tail-Head)*2);
|
||
Inc(BufferHead, Tail-Head);
|
||
BufferHead^ := WideNull;
|
||
Inc(BufferHead);
|
||
Inc(Result);
|
||
|
||
while (Tail^ <> #0) and ((Tail^ = WideCR) or (Tail^ = WideLF) or (Tail^ = WideSpace)) do
|
||
Inc(Tail);
|
||
Head := Tail
|
||
end
|
||
end
|
||
end
|
||
end;
|
||
|
||
{$IFNDEF COMPILER_6_UP}
|
||
function VarToWideStrDef(const V: Variant; const ADefault: WideString): WideString;
|
||
begin
|
||
if not VarIsNull(V) then
|
||
Result := V
|
||
else
|
||
Result := ADefault;
|
||
end;
|
||
|
||
function VarToWideStr(const V: Variant): WideString;
|
||
begin
|
||
Result := VarToWideStrDef(V, NullAsStringValue);
|
||
end;
|
||
|
||
function BoolToStr(B: Boolean; UseBoolStrs: Boolean = False): string;
|
||
const
|
||
cSimpleBoolStrs: array [boolean] of String = ('0', '-1');
|
||
begin
|
||
if UseBoolStrs then
|
||
begin
|
||
if B then
|
||
Result := 'True'
|
||
else
|
||
Result := 'False'
|
||
end
|
||
else
|
||
Result := cSimpleBoolStrs[B];
|
||
end;
|
||
|
||
function CompareTime(const A, B: TDateTime): TValueRelationship;
|
||
begin
|
||
if Abs(Frac(A) - Frac(B)) < (1 / MSecsPerDay) then
|
||
Result := 0
|
||
else if Frac(A) < Frac(B) then
|
||
Result := Low(TValueRelationship)
|
||
else
|
||
Result := High(TValueRelationship);
|
||
end;
|
||
|
||
function WideCompareText(S1, S2: WideString): Integer;
|
||
begin
|
||
Result := WideStrComp( PWideChar(S1), PWideChar(S2))
|
||
end;
|
||
|
||
function ExcludeTrailingBackslash(Path: WideString): WideString;
|
||
begin
|
||
Result := Path;
|
||
if Result <> '' then
|
||
begin
|
||
Result := Trim(Result);
|
||
if Length(Result) > 0 then
|
||
if Result[Length(Result)] = '\' then
|
||
SetLength(Result, Length(Result) - 1)
|
||
end
|
||
end;
|
||
|
||
function IncludeTrailingBackslash(Path: WideString): WideString;
|
||
begin
|
||
Result := Path;
|
||
if Path <> '' then
|
||
Result := ExcludeTrailingBackslash(Path) + '\'
|
||
end;
|
||
|
||
{$ENDIF}
|
||
|
||
function VariantToCaption(const V: Variant): WideString;
|
||
var
|
||
DateTime: TDateTime;
|
||
begin
|
||
case VarType(V) of
|
||
varString, varOleStr:
|
||
Result := VarToWideStr(V);
|
||
|
||
varInteger,{$IFDEF COMPILER_6_UP}varWord, varShortInt, varLongWord,{$ENDIF} varSmallint, varByte:
|
||
Result := IntToStr(V);
|
||
varDate:
|
||
begin
|
||
DateTime := V;
|
||
if Trunc(DateTime) = DateTime then // no time portion
|
||
Result := DateToStr(DateTime)
|
||
else
|
||
Result := DateTimeToStr(DateTime);
|
||
end;
|
||
varCurrency:
|
||
Result := CurrToStr(V);
|
||
varSingle, varDouble:
|
||
Result := FloatToStrF(V, ffFixed, 15, 2);
|
||
varBoolean:
|
||
Result := BoolToStr(V, True);
|
||
else
|
||
Result := VarToWideStrDef(V, '');
|
||
end;
|
||
end;
|
||
|
||
function StrCopyW(Dest, Source: PWideChar): PWideChar;
|
||
// copies Source to Dest and returns Dest
|
||
asm
|
||
PUSH EDI
|
||
PUSH ESI
|
||
MOV ESI, EAX
|
||
MOV EDI, EDX
|
||
MOV ECX, 0FFFFFFFFH
|
||
XOR AX, AX
|
||
REPNE SCASW
|
||
NOT ECX
|
||
MOV EDI, ESI
|
||
MOV ESI, EDX
|
||
MOV EDX, ECX
|
||
MOV EAX, EDI
|
||
SHR ECX, 1
|
||
REP MOVSD
|
||
MOV ECX, EDX
|
||
AND ECX, 1
|
||
REP MOVSW
|
||
POP ESI
|
||
POP EDI
|
||
end;
|
||
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
|
||
function BrightenColor(const RGB: TCommonRGB; Amount: Double): TCommonRGB;
|
||
var
|
||
HLS: TCommonHLS;
|
||
|
||
begin
|
||
HLS := RGBToHLS(RGB);
|
||
HLS.L := (1 + Amount) * HLS.L;
|
||
Result := HLSToRGB(HLS);
|
||
end;
|
||
|
||
function DarkenColor(const RGB: TCommonRGB; Amount: Double): TCommonRGB;
|
||
var
|
||
HLS: TCommonHLS;
|
||
|
||
begin
|
||
HLS := RGBToHLS(RGB);
|
||
// Darken means to decrease luminance.
|
||
HLS.L := (1 - Amount) * HLS.L;
|
||
Result := HLSToRGB(HLS);
|
||
end;
|
||
|
||
function RGBToHLS(const RGB: TCommonRGB): TCommonHLS;
|
||
|
||
// Converts from RGB to HLS.
|
||
// Input parameters and result values are all in the range 0..1.
|
||
// Note: Hue is normalized so 360<36> corresponds to 1.
|
||
|
||
var
|
||
Delta,
|
||
Max,
|
||
Min: Double;
|
||
|
||
begin
|
||
with RGB, Result do
|
||
begin
|
||
Max := MaxValue([R, G, B]);
|
||
Min := MinValue([R, G, B]);
|
||
|
||
L := (Max + Min) / 2;
|
||
|
||
if Max = Min then
|
||
begin
|
||
// Achromatic case.
|
||
S := 0;
|
||
H := 0; // Undefined
|
||
end
|
||
else
|
||
begin
|
||
Delta := Max - Min;
|
||
|
||
if L < 0.5 then
|
||
S := Delta / (Max + Min)
|
||
else
|
||
S := Delta / (2 - (Max + Min));
|
||
|
||
if R = Max then
|
||
H := (G - B) / Delta
|
||
else
|
||
if G = Max then
|
||
H := 2 + (B - R) / Delta
|
||
else
|
||
if B = Max then
|
||
H := 4 + (R - G) / Delta;
|
||
|
||
H := H / 6;
|
||
if H < 0 then
|
||
H := H + 1;
|
||
end
|
||
end;
|
||
end;
|
||
|
||
function HLSToRGB(const HLS: TCommonHLS): TCommonRGB;
|
||
|
||
// Converts from HLS (hue, luminance, saturation) to RGB.
|
||
// Input parameters and result values are all in the range 0..1.
|
||
// Note: Hue is normalized so 360<36> corresponds to 1.
|
||
|
||
//--------------- local function --------------------------------------------
|
||
|
||
function HueToRGB(m1, m2, Hue: Double): Double;
|
||
|
||
begin
|
||
if Hue > 1 then
|
||
Hue := Hue - 1
|
||
else
|
||
if Hue < 0 then
|
||
Hue := Hue + 1;
|
||
|
||
if 6 * Hue < 1 then
|
||
Result := m1 + (m2 - m1) * Hue * 6
|
||
else
|
||
if 2 * Hue < 1 then
|
||
Result := m2
|
||
else
|
||
if 3 * Hue < 2 then
|
||
Result := m1 + (m2 - m1) * (2 / 3 - Hue) * 6
|
||
else
|
||
Result := m1;
|
||
end;
|
||
|
||
//--------------- end local function ----------------------------------------
|
||
|
||
var
|
||
m1, m2: Double;
|
||
|
||
begin
|
||
with HLS, Result do
|
||
begin
|
||
if S = 0 then
|
||
begin
|
||
// Achromatic case (no hue).
|
||
R := L;
|
||
G := L;
|
||
B := L;
|
||
end
|
||
else
|
||
begin
|
||
if L <= 0.5 then
|
||
m2 := L * (S + 1)
|
||
else
|
||
m2 := L + S - L * S;
|
||
m1 := 2 * L - m2;
|
||
|
||
R := HueToRGB(m1, m2, H + 1 / 3);
|
||
G := HueToRGB(m1, m2, H);
|
||
B := HueToRGB(m1, m2, H - 1 / 3)
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
function MakeTRBG(Color: TColor): TCommonRGB;
|
||
var
|
||
RGB: Longint;
|
||
begin
|
||
RGB := ColorToRGB(Color);
|
||
Result.B := GetBValue(RGB) / 255;
|
||
Result.G := GetGValue(RGB) / 255;
|
||
Result.R := GetRValue(RGB) / 255;
|
||
end;
|
||
|
||
function MakeTColor(RGB: TCommonRGB): TColor;
|
||
begin
|
||
Result := TColor(MakeColorRef(RGB));
|
||
end;
|
||
|
||
function MakeColorRef(RGB: TCommonRGB; Gamma: Double = 1): COLORREF;
|
||
// Converts a floating point RGB color to an 8 bit color reference as used by Windows.
|
||
// The function takes care not to produce out-of-gamut colors and allows to apply an optional gamma correction
|
||
// (inverse gamma).
|
||
begin
|
||
GammaCorrection(RGB, Gamma);
|
||
with RGB do
|
||
Result := Windows.RGB(Round(R * 255), Round(G * 255), Round(B * 255));
|
||
end;
|
||
|
||
procedure GammaCorrection(var RGB: TCommonRGB; Gamma: Double);
|
||
|
||
// Computes the gamma corrected RGB color and ensures the result is in-gamut.
|
||
|
||
begin
|
||
if Gamma <> 1 then
|
||
begin
|
||
Gamma := 1 / Gamma;
|
||
with RGB do
|
||
begin
|
||
if R > 0 then
|
||
R := Power(R, Gamma)
|
||
else
|
||
R := 0;
|
||
if G > 0 then
|
||
G := Power(G, Gamma)
|
||
else
|
||
G := 0;
|
||
if B > 0 then
|
||
B := Power(B, Gamma)
|
||
else
|
||
B := 0;
|
||
end;
|
||
end;
|
||
|
||
MakeSafeColor(RGB);
|
||
end;
|
||
|
||
function MakeSafeColor(var RGB: TCommonRGB): Boolean;
|
||
// Ensures the given RGB color is in-gamut, that is, no component is < 0 or > 1.
|
||
// Returns True if the color had to be adjusted to be in-gamut, otherwise False.
|
||
begin
|
||
Result := False;
|
||
|
||
if RGB.R < 0 then
|
||
begin
|
||
Result := True;
|
||
RGB.R := 0;
|
||
end;
|
||
if RGB.R > 1 then
|
||
begin
|
||
Result := True;
|
||
RGB.R := 1;
|
||
end;
|
||
|
||
if RGB.G < 0 then
|
||
begin
|
||
Result := True;
|
||
RGB.G := 0;
|
||
end;
|
||
if RGB.G > 1 then
|
||
begin
|
||
Result := True;
|
||
RGB.G := 1;
|
||
end;
|
||
|
||
if RGB.B < 0 then
|
||
begin
|
||
Result := True;
|
||
RGB.B := 0;
|
||
end;
|
||
if RGB.B > 1 then
|
||
begin
|
||
Result := True;
|
||
RGB.B := 1;
|
||
end;
|
||
end;
|
||
|
||
function UpsideDownDIB(Bits: TBitmap): Boolean;
|
||
var
|
||
OldRGB, TempRGB: LongInt;
|
||
P: PLongInt;
|
||
begin
|
||
Result := False;
|
||
Assert(Bits.PixelFormat = pf32Bit, 'UpsideDownDIB only works with 32 bit bitmaps');
|
||
if Bits.PixelFormat = pf32Bit then
|
||
begin
|
||
P := Bits.ScanLine[0];
|
||
OldRGB := P^;
|
||
Result := True;
|
||
// if Equal then we can can't be sure if upsidedown
|
||
if (P^ and $00FFFFFF) = (ColorToRGB(Bits.Canvas.Pixels[0, 0]) and $00FFFFFF) then
|
||
begin
|
||
// Flip the pixel bits
|
||
TempRGB := not OldRGB and $00FFFFFF;
|
||
Bits.Canvas.Pixels[0, 0] := TempRGB;
|
||
|
||
Result := (P^ and $00FFFFFF) <> (ColorToRGB(Bits.Canvas.Pixels[0, 0]) and $00FFFFFF);
|
||
P^ := OldRGB
|
||
end
|
||
end
|
||
end;
|
||
|
||
procedure ActivateTopLevelWindow(Child: HWND);
|
||
var
|
||
Parent: HWND;
|
||
Style: LongWord;
|
||
begin
|
||
Parent := GetParent(Child);
|
||
while Parent <> 0 do
|
||
begin
|
||
Style := GetWindowLong(Parent, GWL_STYLE);
|
||
if ((Style and WS_POPUP <> 0)) or (Style and WS_CHILD = 0) then
|
||
begin
|
||
BringWindowToTop(Parent);
|
||
Exit
|
||
end;
|
||
Parent := GetParent(Parent);
|
||
end
|
||
end;
|
||
|
||
initialization
|
||
PIDLMgr := TCommonPIDLManager.Create;
|
||
|
||
// We can be sure these are already loaded. This keeps us from having to
|
||
// reference count when VSTools is being used in an OCX
|
||
Shell32Handle := GetModuleHandle(Shell32);
|
||
Kernel32Handle := GetModuleHandle(Kernel32);
|
||
User32Handle := GetModuleHandle(User32);
|
||
GDI32Handle := GetModuleHandle(GDI32);
|
||
AdvAPI32Handle := GetModuleHandle(AdvAPI32);
|
||
ShlwapiHandle := CommonLoadLibrary(Shlwapi);
|
||
|
||
GetDiskFreeSpaceExA_MP := GetProcAddress(Kernel32Handle, 'GetDiskFreeSpaceA');
|
||
TrackMouseEvent_MP := GetProcAddress(User32Handle, 'TrackMouseEvent');
|
||
|
||
if Win32Platform = VER_PLATFORM_WIN32_NT then
|
||
begin
|
||
GetDriveTypeW_MP := GetProcAddress(Kernel32Handle, 'GetDriveTypeW');
|
||
DrawTextW_MP := GetProcAddress(User32Handle, 'DrawTextW');
|
||
SHGetFileInfoW_MP := GetProcAddress(Shell32Handle, 'SHGetFileInfoW');
|
||
CreateFileW_MP := GetProcAddress(Kernel32Handle, 'CreateFileW');
|
||
SHGetDataFromIDListW_MP := GetProcAddress(Shell32Handle, 'SHGetDataFromIDListW');
|
||
FindFirstFileW_MP := GetProcAddress(Kernel32Handle, 'FindFirstFileW');
|
||
FindNextFileW_MP := GetProcAddress(Kernel32Handle, 'FindNextFileW');
|
||
lstrcmpiW_MP := GetProcAddress(Kernel32Handle, 'lstrcmpiW');
|
||
lstrcmpW_MP := GetProcAddress(Kernel32Handle, 'lstrcmpW');
|
||
lstrcpynW_MP := GetProcAddress(Kernel32Handle, 'lstrcpynW');
|
||
lstrcpyW_MP := GetProcAddress(Kernel32Handle, 'lstrcpyW');
|
||
CharLowerBuffW_MP := GetProcAddress(User32Handle, 'CharLowerBuffW');
|
||
CharUpperBuffW_MP := GetProcAddress(User32Handle, 'CharUpperBuffW');
|
||
CreateDirectoryW_MP := GetProcAddress(Kernel32Handle, 'CreateDirectoryW');
|
||
GetFullPathNameW_MP := GetProcAddress(Kernel32Handle, 'GetFullPathNameW');
|
||
ShellExecuteExW_MP := GetProcAddress(Shell32Handle, 'ShellExecuteExW');
|
||
ShellExecuteW_MP := GetProcAddress(Shell32Handle, 'ShellExecuteW');
|
||
FindFirstChangeNotificationW_MP := GetProcAddress(Kernel32Handle, 'FindFirstChangeNotificationW');
|
||
GetCharABCWidthsW_MP := GetProcAddress(GDI32Handle, 'GetCharABCWidthsW');
|
||
GetFileAttributesW_MP := GetProcAddress(Kernel32Handle, 'GetFileAttributesW');
|
||
GetSystemDirectoryW_MP := GetProcAddress(Kernel32Handle, 'GetSystemDirectoryW');
|
||
GetWindowsDirectoryW_MP := GetProcAddress(Kernel32Handle, 'GetWindowsDirectoryW');
|
||
GetDiskFreeSpaceExW_MP := GetProcAddress(Kernel32Handle, 'GetDiskFreeSpaceExW');
|
||
SetWindowTextW_MP := GetProcAddress(User32Handle, 'SetWindowTextW');
|
||
GetNumberFormatW_MP := GetProcAddress(Kernel32Handle, 'GetNumberFormatW');
|
||
RegOpenKeyW_MP := GetProcAddress(AdvAPI32Handle, 'RegOpenKeyW');
|
||
RegOpenKeyExW_MP := GetProcAddress(AdvAPI32Handle, 'RegOpenKeyExW');
|
||
RegQueryValueW_MP := GetProcAddress(AdvAPI32Handle, 'RegQueryValueW');
|
||
WritePrivateProfileStringW_MP := GetProcAddress(Kernel32Handle, 'WritePrivateProfileStringW');
|
||
GetPrivateProfileStringW_MP := GetProcAddress(Kernel32Handle, 'GetPrivateProfileStringW');
|
||
TryEnterCriticalSection_MP := GetProcAddress(Kernel32Handle, 'TryEnterCriticalSection');
|
||
InsertMenuItemW_MP := GetProcAddress(User32Handle, 'InsertMenuItemW');
|
||
SendMessageW_MP := GetProcAddress(User32Handle, 'SendMessageW');
|
||
SetFileAttributesW_MP := GetProcAddress(Kernel32Handle, 'SetFileAttributesW');
|
||
CreateFontIndirectW_MP := GetProcAddress(GDI32Handle, 'CreateFontIndirectW');
|
||
SystemParametersInfoW_MP := GetProcAddress(User32Handle, 'SystemParametersInfoW');
|
||
SHGetPathFromIDListW_MP := GetProcAddress(Shell32Handle, 'SHGetPathFromIDListW');
|
||
SHFileOperationW_MP := GetProcAddress(Shell32Handle, 'SHFileOperationW');
|
||
SHBrowseForFolderW_MP := GetProcAddress(Shell32Handle, 'SHBrowseForFolderW');
|
||
GetDiskFreeSpaceW_MP := GetProcAddress(Kernel32Handle, 'GetDiskFreeSpaceW');
|
||
GetCurrentDirectoryW_MP := GetProcAddress(Kernel32Handle, 'GetCurrentDirW');
|
||
GetTempPathW_MP := GetProcAddress(Kernel32Handle, 'GetTempPathW');
|
||
if ShlwapiHandle <> 0 then
|
||
begin
|
||
PathMatchSpecA_MP := GetProcAddress(ShlwapiHandle, 'PathMatchSpecA');
|
||
PathMatchSpecW_MP := GetProcAddress(ShlwapiHandle, 'PathMatchSpecW');
|
||
end;
|
||
CreateProcessW_MP := GetProcAddress(Kernel32Handle, 'CreateProcessW');
|
||
SHDoDragDrop_MP := GetProcAddress(Shell32Handle, 'SHDoDragDrop');
|
||
SHGetKnownFolderPath_MP := GetProcAddress(Shell32Handle, 'SHGetKnownFolderPath');
|
||
ExpandEnvironmentStringsW_MP := GetProcAddress(Kernel32Handle, 'ExpandEnvironmentStringsW');
|
||
|
||
// NTFS Volume (Junction) only functions
|
||
DeleteVolumeMountPoint_MP := GetProcAddress(Kernel32Handle, 'DeleteVolumeMountPointA');
|
||
GetVolumeNameForVolumeMountPoint_MP := GetProcAddress(Kernel32Handle, 'GetVolumeNameForVolumeMountPointA');
|
||
GetVolumePathName_MP := GetProcAddress(Kernel32Handle, 'GetVolumePathNameA');
|
||
SetVolumeMountPoint_MP := GetProcAddress(Kernel32Handle, 'SetVolumeMountPointA');
|
||
FindFirstVolume_MP := GetProcAddress(Kernel32Handle, 'FindFirstVolumeA');
|
||
FindNextVolume_MP := GetProcAddress(Kernel32Handle, 'FindNextVolumeA');
|
||
FindVolumeClose_MP := GetProcAddress(Kernel32Handle, 'FindVolumeClose');
|
||
FindFirstVolumeMountPoint_MP := GetProcAddress(Kernel32Handle, 'FindFirstVolumeMountPointA');
|
||
FindNextVolumeMountPoint_MP := GetProcAddress(Kernel32Handle, 'FindNextVolumeMountPointA');
|
||
FindVolumeMountPointClose_MP := GetProcAddress(Kernel32Handle, 'FindVolumeMountPointClose');
|
||
FindFirstFileExW_MP := GetProcAddress(Kernel32Handle, 'FindFirstFileExW');
|
||
end;
|
||
FindFirstFileExA_MP := GetProcAddress(Kernel32Handle, 'FindFirstFileExA');
|
||
|
||
// SHMultiFileProperties only supported on Win2k and WinXP
|
||
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/shmultifileproperties.asp
|
||
SHMultiFileProperties_MP := GetProcAddress(Shell32Handle, PChar(716));
|
||
CDefFolderMenu_Create2_MP := GetProcAddress(Shell32Handle, PChar(701));
|
||
CDefFolderMenu_Create_MP := GetProcAddress(Shell32Handle, PChar(700));
|
||
|
||
|
||
|
||
// If this unit is to be weak packages this must be removed
|
||
finalization
|
||
FreeAndNil(PIDLMgr);
|
||
CommonUnloadAllLibraries;
|
||
|
||
end.
|
||
|