1908 lines
54 KiB
ObjectPascal
1908 lines
54 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
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/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: JvFunctions.PAS, released on 2001-02-28.
|
|
|
|
The Initial Developer of the Original Code is Sébastien Buysse [sbuysse att buypin dott com]
|
|
Portions created by Sébastien Buysse are Copyright (C) 2001 Sébastien Buysse.
|
|
All Rights Reserved.
|
|
|
|
Contributor(s):
|
|
Michael Beck [mbeck att bigfoot dott com].
|
|
Anthony Steele [asteele att iafrica dott com]
|
|
Peter Thörnqvist [peter3 att users dott sourceforge dott net]
|
|
cginzel [cginzel@hotmail.com]
|
|
Remko Bonte
|
|
|
|
Last Modified: 2003-02-19
|
|
|
|
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
|
|
located at http://jvcl.sourceforge.net
|
|
|
|
Known Issues:
|
|
-----------------------------------------------------------------------------}
|
|
|
|
{$I JVCL.INC}
|
|
|
|
unit JvFunctions;
|
|
|
|
interface
|
|
uses
|
|
Windows, Graphics, Classes, Messages, Controls,
|
|
ComCtrls, SysUtils, ShellApi, ImgList,
|
|
JvTypes;
|
|
|
|
{$IFNDEF COMPILER6_UP}
|
|
type
|
|
EOSError = class(EWin32Error);
|
|
{$ENDIF}
|
|
|
|
type
|
|
TWallpaperStyle = (wpTile, wpCenter, wpStretch);
|
|
TJvWallpaperStyle = TWallpaperStyle;
|
|
PRGBArray = ^TRGBArray;
|
|
TRGBArray = array [0..MaxPixelCount - 1] of TRGBTriple;
|
|
|
|
// Transform an icon to a bitmap
|
|
function IconToBitmap(Ico: HICON): TBitmap;
|
|
// Transform an icon to a bitmap using an image list
|
|
function IconToBitmap2(Ico: HICON; Size: Integer = 32; TransparentColor: TColor = clNone): TBitmap;
|
|
function IconToBitmap3(Ico: HICON; Size: Integer = 32; TransparentColor: TColor = clNone): TBitmap;
|
|
|
|
//Open an object with the shell (url or something like that)
|
|
function OpenObject(Value: PChar): Boolean; overload;
|
|
function OpenObject(Value: string): Boolean; overload;
|
|
|
|
//Raise the last Exception
|
|
procedure RaiseLastWin32; overload;
|
|
procedure RaiseLastWin32(Text: string); overload;
|
|
//Raise the last Exception with a small comment from your part
|
|
|
|
//Same as linux function ;)
|
|
procedure PError(Text: string);
|
|
|
|
//Return the maximum of three integers
|
|
function GetMax(I, J, K: Integer): Integer;
|
|
|
|
//Return the minimum of three integers
|
|
function GetMin(I, J, K: Integer): Integer;
|
|
|
|
//Convert RGB Values to HSV
|
|
procedure RGBToHSV(r, g, b: Integer; var h, s, v: Integer);
|
|
|
|
{ GetFileVersion returns the most significant 32 bits of a file's binary
|
|
version number. Typically, this includes the major and minor version placed
|
|
together in one 32-bit Integer. It generally does not include the release
|
|
or build numbers. It returns 0 if it failed. }
|
|
function GetFileVersion(const AFilename: string): Cardinal;
|
|
{$EXTERNALSYM GetFileVersion}
|
|
|
|
//Get version of Shell.dll
|
|
function GetShellVersion: Cardinal;
|
|
{$EXTERNALSYM GetShellVersion}
|
|
|
|
// set the background wallpaper (two versions)
|
|
procedure SetWallpaper(Path: string); overload;
|
|
procedure SetWallpaper(Path: string; Style: TJvWallpaperStyle); overload;
|
|
|
|
// screen capture functions
|
|
function CaptureScreen: TBitmap; overload;
|
|
function CaptureScreen(Rec: TRect): TBitmap; overload;
|
|
|
|
// CD functions
|
|
procedure OpenCdDrive;
|
|
procedure CloseCdDrive;
|
|
|
|
// bitmap manipulation functions
|
|
// NOTE: returned bitmap must be freed by caller!
|
|
// get red channel bitmap
|
|
function GetRBitmap(Value: TBitmap): TBitmap;
|
|
// get green channel bitmap
|
|
function GetGBitmap(Value: TBitmap): TBitmap;
|
|
// get blue channel bitmap
|
|
function GetBBitmap(Value: TBitmap): TBitmap;
|
|
// get monochrome bitmap
|
|
function GetMonochromeBitmap(Value: TBitmap): TBitmap;
|
|
// get hue bitmap (h part of hsv)
|
|
function GetHueBitmap(Value: TBitmap): TBitmap;
|
|
// get saturation bitmap (s part of hsv)
|
|
function GetSaturationBitmap(Value: TBitmap): TBitmap;
|
|
// get value bbitmap (v part of hsv)
|
|
function GetValueBitmap(Value: TBitmap): TBitmap;
|
|
// hides / shows the a forms caption area
|
|
procedure HideFormCaption(FormHandle: THandle; Hide: Boolean);
|
|
// launches the specified CPL file
|
|
// format: <Filename> [,@n] or [,,m] or [,@n,m]
|
|
// where @n = zero-based index of the applet to start (if there is more than one
|
|
// m is the zero-based index of the tab to display
|
|
procedure LaunchCpl(FileName: string);
|
|
|
|
{
|
|
GetControlPanelApplets retrieves information about all control panel applets in a specified folder.
|
|
APath is the Path to the folder to search and AMask is the filename mask (containing wildcards if necessary) to use.
|
|
|
|
The information is returned in the Strings and Images lists according to the following rules:
|
|
The Display Name and Path to the CPL file is returned in Strings with the following format:
|
|
'<displayname>=<Path>'
|
|
You can access the DisplayName by using the Strings.Names array and the Path by accessing the Strings.Values array
|
|
Strings.Objects can contain either of two values depending on if Images is nil or not:
|
|
* If Images is nil then Strings.Objects contains the image for the applet as a TBitmap. Note that the caller (you)
|
|
is responsible for freeing the bitmaps in this case
|
|
* If Images <> nil, then the Strings.Objects array contains the index of the image in the Images array for the selected item.
|
|
To access and use the ImageIndex, typecast Strings.Objects to an int:
|
|
Tmp.Name := Strings.Name[I];
|
|
Tmp.ImageIndex := Integer(Strings.Objects[I]);
|
|
The function returns True if any Control Panel Applets were found (i.e Strings.Count is > 0 when returning)
|
|
}
|
|
|
|
function GetControlPanelApplets(const APath, AMask: string; Strings: TStrings; Images: TImageList = nil): Boolean;
|
|
{ GetControlPanelApplet works like GetControlPanelApplets, with the difference that it only loads and searches one cpl file (according to AFilename).
|
|
Note though, that some CPL's contains multiple applets, so the Strings and Images lists can contain multiple return values.
|
|
The function returns True if any Control Panel Applets were found in AFilename (i.e if items were added to Strings)
|
|
}
|
|
function GetControlPanelApplet(const AFilename: string; Strings: TStrings; Images: TImageList = nil): Boolean;
|
|
|
|
// execute a program without waiting
|
|
procedure Exec(FileName, Parameters, Directory: string);
|
|
// execute a program and wait for it to finish
|
|
procedure ExecuteAndWait(FileName: string; Visibility: Integer);
|
|
// returns True if Drive is accessible
|
|
function DiskInDrive(Drive: Char): Boolean;
|
|
// returns True if this is the first instance of the program that is running
|
|
function FirstInstance(const ATitle: string): Boolean;
|
|
// restores a window based on it's classname and Caption. Either can be left empty
|
|
// to widen the search
|
|
procedure RestoreOtherInstance(MainFormClassName, MainFormCaption: string);
|
|
|
|
// manipulate the traybar and start button
|
|
procedure HideTraybar;
|
|
procedure ShowTraybar;
|
|
procedure ShowStartButton;
|
|
procedure HideStartButton;
|
|
|
|
// (rom) SC_MONITORPOWER is documented as Windows 95 only
|
|
// (rom) better do some testing
|
|
// set monitor functions
|
|
procedure MonitorOn;
|
|
procedure MonitorOff;
|
|
procedure LowPower;
|
|
|
|
// send a key to the window named AppName
|
|
function SendKey(AppName: string; Key: Char): Boolean;
|
|
|
|
// associates an extension to a specific program
|
|
procedure AssociateExtension(IconPath, ProgramName, Path, Extension: string);
|
|
|
|
function GetRecentDocs: TStringList;
|
|
procedure AddToRecentDocs(const Filename: string);
|
|
// create a region from a bitmap
|
|
function RegionFromBitmap(const Image: TBitmap): HRGN;
|
|
|
|
// returns a list of all windows currently visible, the Objects property is filled with their window handle
|
|
procedure GetVisibleWindows(List: Tstrings);
|
|
|
|
// JvComponentFunctions
|
|
{-----------------------------------------------------------------------------
|
|
Comments:
|
|
Functions pulled out of MemoEx, used in MemoEx.pas and TypedEdit.pas
|
|
|
|
This unit has low internal cohesion (ie it contains routines that do all kinds of stuff)
|
|
Some are very good candidates for wider reuse
|
|
some are quite specific to the controls
|
|
and in a larger library this unit would be broken up
|
|
|
|
I have tried to group related functions together
|
|
}
|
|
|
|
function CharIsMoney(const Ch: Char): Boolean;
|
|
|
|
{ there is a STrToIntDef provided by Delphi, but no "safe" versions of
|
|
StrToFloat or StrToCurr }
|
|
function StrToFloatDef(const Str: string; Def: Extended): Extended;
|
|
function StrToCurrDef(const Str: string; Def: Currency): Currency;
|
|
|
|
{ GetChangedText works out the new text given the current cursor pos & the key pressed
|
|
It is not very useful in other contexts,
|
|
but it is in this unit as it is needed in both MemoEx and TypedEdit }
|
|
function GetChangedText(const Text: string; SelStart, SelLength: Integer; Key: Char): string;
|
|
|
|
function MakeYear4Digit(Year, Pivot: Integer): Integer;
|
|
|
|
function StrIsInteger(const S: string): Boolean;
|
|
function StrIsFloatMoney(const Ps: string): Boolean;
|
|
function StrIsDateTime(const Ps: string): Boolean;
|
|
|
|
function PreformatDateString(Ps: string): string;
|
|
|
|
function BooleanToInteger(const Pb: Boolean): Integer;
|
|
function StringToBoolean(const Ps: string): Boolean;
|
|
|
|
function SafeStrToDateTime(const Ps: string): TDateTime;
|
|
function SafeStrToDate(const Ps: string): TDateTime;
|
|
function SafeStrToTime(const Ps: string): TDateTime;
|
|
|
|
function StrDelete(const psSub, psMain: string): string;
|
|
|
|
{ listview functions }
|
|
function ConvertStates(const State: Integer): TItemStates;
|
|
|
|
function ChangeHasDeselect(const peOld, peNew: TItemStates): Boolean;
|
|
function ChangeHasSelect(const peOld, peNew: TItemStates): Boolean;
|
|
|
|
function ChangeHasDefocus(const peOld, peNew: TItemStates): Boolean;
|
|
function ChangeHasFocus(const peOld, peNew: TItemStates): Boolean;
|
|
|
|
function GetListItemColumn(const pcItem: TListItem; piIndex: Integer): string;
|
|
|
|
{ returns the sum of pc.Left, pc.Width and piSpace}
|
|
function ToRightOf(const pc: TControl; piSpace: Integer = 0): Integer;
|
|
{ sets the top of pc to be in the middle of pcParent }
|
|
procedure CenterHeight(const pc, pcParent: TControl);
|
|
{ returns the fractional value of pcValue}
|
|
function TimeOnly(pcValue: TDateTime): TTime;
|
|
{ returns the integral value of pcValue }
|
|
function DateOnly(pcValue: TDateTime): TDate;
|
|
|
|
type
|
|
TdtKind = (dtkDateOnly, dtkTimeOnly, dtkDateTime);
|
|
|
|
const
|
|
{ TDateTime value used to signify Null value}
|
|
NullEquivalentDate: TDateTime = 0.0;
|
|
|
|
function DateIsNull(const pdtValue: TDateTime; const pdtKind: TdtKind): Boolean;
|
|
// Replacement for Win32Check to avoid platform specific warnings in D6
|
|
function OSCheck(RetVal: Boolean): Boolean;
|
|
|
|
{ Shortens a fully qualified Path name so that it can be drawn with a specified length limit.
|
|
Same as FileCtrl.MinimizeName in functionality (but not implementation). Included here to
|
|
not be forced to use FileCtrl unnecessarily }
|
|
function MinimizeName(const Filename: string; Canvas: TCanvas; MaxLen: Integer): string;
|
|
|
|
{ RunDLL32 runs a function in a DLL using the utility rundll32.exe (on NT) or rundll.exe (on Win95/98)
|
|
ModuleName is the name of the DLL to load, FuncName is the function to call and CmdLine is
|
|
the command-line parameters (if any) to send to the function. Set WaitForCompletion to False to
|
|
return immediately after the call.
|
|
CmdShow should be one of the SW_SHOWXXXX constants and defaults SW_SHOWDEFAULT
|
|
Return value:
|
|
if WaitForCompletion is True, returns True if the wait didn't return WAIT_FAILED
|
|
if WaitForCompletion is False, returns True if the process could be created
|
|
To get information on why RunDLL32 might have failed, call GetLastError
|
|
To get more info on what can actually be called using rundll32.exe, take a look at
|
|
http://www.dx21.com/SCRIPTING/RUNDLL32/REFGUIDE.ASP?NTI=4&SI=6
|
|
}
|
|
type
|
|
// the signature of procedures in DLL's that can be called using rundll32.exe
|
|
TRunDLL32Proc = procedure(Handle: HWND; hInstance: HMODULE; CmdLine: PChar; CmdShow: Integer); stdcall;
|
|
|
|
function RunDLL32(const ModuleName, FuncName, CmdLine: string; WaitForCompletion: Boolean; CmdShow: Integer =
|
|
SW_SHOWDEFAULT): Boolean;
|
|
{ RunDll32Internal does the same as RunDLL32 but does not use the RunDLL32.exe application to do it.
|
|
Rather it loads the DLL, gets a pointer to the function in FuncName and calls it with the given parameters.
|
|
Because of this behaviour, RunDll32Internal works slightly different from RunDLL32:
|
|
* It doesn't return any value indicating success/failure
|
|
* There is no WaitForCompletion parameter (but see comment below on how to circumvent this)
|
|
* You must pass in a valid windows handle in Wnd. Note that if you pass 0, the call might fail, with no indication of why.
|
|
* To simulate WaitForCompletion = False, pass the return value of GetDesktopWindow as the Wnd parameter,
|
|
* To simulate WaitForCompletion = True, pass the handle of the calling window (f ex the form you are calling the procedure from)
|
|
* If you try to call a function in a DLL that doesn't use the TRunDLL32Proc signature, your program
|
|
might crash. Using the RunDLL32 function protects you from any problems with calling the wrong functions
|
|
(a dialog is displayed if do something wrong)
|
|
* RunDll32Internal is slightly faster but RunDLL32 is safer
|
|
}
|
|
procedure RunDll32Internal(Wnd: HWnd; const DLLName, FuncName, CmdLine: string; CmdShow: Integer = SW_SHOWDEFAULT);
|
|
{ GetDLLVersion loads DLLName, gets a pointer to the DLLVersion function and calls it, returning the major and minor version values
|
|
from the function. Returns False if the DLL couldn't be loaded or if GetDLLVersion couldn't be found. }
|
|
function GetDLLVersion(const DLLName: string; var pdwMajor, pdwMinor: Integer): Boolean;
|
|
|
|
{$IFNDEF COMPILER6_UP}
|
|
{ D5 compatibility functions }
|
|
procedure RaiseLastOSError;
|
|
function IncludeTrailingPathDelimiter(const APath: string): string;
|
|
function ExcludeTrailingPathDelimiter(const APath: string): string;
|
|
{$ENDIF}
|
|
|
|
implementation
|
|
|
|
uses
|
|
Forms, Registry, ExtCtrls,
|
|
{$IFDEF COMPILER6_UP}
|
|
Types,
|
|
{$ENDIF}
|
|
MMSystem,
|
|
ShlObj, CommCtrl,
|
|
JclSysInfo,
|
|
JclStrings, JclGraphics;
|
|
|
|
resourcestring
|
|
SWin32Error = 'Win32 Error. Code: %d.'#10'%s';
|
|
|
|
const
|
|
RC_ControlRegistry = 'Control Panel\Desktop';
|
|
RC_WallpaperStyle = 'WallpaperStyle';
|
|
RC_WallpaperRegistry = 'Wallpaper';
|
|
RC_TileWallpaper = 'TileWallpaper';
|
|
RC_OpenCDDrive = 'set cdaudio door open wait';
|
|
RC_CloseCDDrive = 'set cdaudio door closed wait';
|
|
RC_RunCpl = 'rundll32.exe shell32,Control_RunDLL ';
|
|
RC_ShellName = 'Shell_TrayWnd';
|
|
RC_DefaultIcon = 'DefaultIcon';
|
|
|
|
var
|
|
ShellVersion: Integer;
|
|
|
|
{$IFNDEF COMPILER6_UP}
|
|
|
|
{ (rb) Duplicate of JclBase.RaiseLastOSError }
|
|
|
|
procedure RaiseLastOSError;
|
|
begin
|
|
RaiseLastWin32Error;
|
|
end;
|
|
|
|
function IncludeTrailingPathDelimiter(const APath: string): string;
|
|
begin
|
|
if (Length(APath) > 0) and (APath[Length(APath)] <> '\') then
|
|
Result := APath + '\'
|
|
else
|
|
Result := APath;
|
|
end;
|
|
|
|
function ExcludeTrailingPathDelimiter(const APath: string): string;
|
|
begin
|
|
Result := APath;
|
|
while (Length(Result) > 0) and (Result[Length(Result)] = '\') do
|
|
SetLength(Result, Length(Result) - 1);
|
|
end;
|
|
|
|
{$ENDIF}
|
|
|
|
function IconToBitmap(Ico: HICON): TBitmap;
|
|
var
|
|
Pic: TPicture;
|
|
begin
|
|
Pic := TPicture.Create;
|
|
Pic.Icon.Handle := Ico;
|
|
Result := TBitmap.Create;
|
|
Result.Height := Pic.Icon.Height;
|
|
Result.Width := Pic.Icon.Width;
|
|
Result.Canvas.Draw(0, 0, Pic.Icon);
|
|
Pic.Free;
|
|
end;
|
|
|
|
function IconToBitmap2(Ico: HICON; Size: Integer = 32; TransparentColor: TColor = clNone): TBitmap;
|
|
begin
|
|
// (p3) this seems to generate "better" bitmaps...
|
|
with TImageList.CreateSize(Size, Size) do
|
|
try
|
|
Masked := True;
|
|
BkColor := TransparentColor;
|
|
ImageList_AddIcon(Handle, Ico);
|
|
Result := TBitmap.Create;
|
|
Result.PixelFormat := pf24bit;
|
|
if TransparentColor <> clNone then
|
|
Result.TransparentColor := TransparentColor;
|
|
Result.Transparent := TransparentColor <> clNone;
|
|
GetBitmap(0, Result);
|
|
finally
|
|
Free;
|
|
end;
|
|
end;
|
|
|
|
function IconToBitmap3(Ico: HICON; Size: Integer = 32; TransparentColor: TColor = clNone): TBitmap;
|
|
var
|
|
Icon: TIcon;
|
|
Tmp: TBitmap;
|
|
begin
|
|
Icon := TIcon.Create;
|
|
Tmp := TBitmap.Create;
|
|
try
|
|
Icon.Handle := CopyIcon(Ico);
|
|
Result := TBitmap.Create;
|
|
Result.Width := Icon.Width;
|
|
Result.Height := Icon.Height;
|
|
Result.PixelFormat := pf24bit;
|
|
// fill the bitmap with the transparant color
|
|
Result.Canvas.Brush.Color := TransparentColor;
|
|
Result.Canvas.FillRect(Rect(0, 0, Result.Width, Result.Height));
|
|
Result.Canvas.Draw(0, 0, Icon);
|
|
Result.TransparentColor := TransparentColor;
|
|
Tmp.Assign(Result);
|
|
// Result.Width := Size;
|
|
// Result.Height := Size;
|
|
Result.Canvas.StretchDraw(Rect(0, 0, Result.Width, Result.Height), Tmp);
|
|
Result.Transparent := True;
|
|
finally
|
|
Icon.Free;
|
|
Tmp.Free;
|
|
end;
|
|
end;
|
|
|
|
function OpenObject(Value: string): Boolean;
|
|
begin
|
|
Result := OpenObject(PChar(Value));
|
|
end;
|
|
|
|
{ (rb) Duplicate of JvFunctions.Exec }
|
|
|
|
function OpenObject(Value: PChar): Boolean;
|
|
begin
|
|
Result := ShellExecute(0, 'open', Value, nil, nil, SW_SHOWNORMAL) > HINSTANCE_ERROR;
|
|
end;
|
|
|
|
procedure RaiseLastWin32;
|
|
begin
|
|
PError('');
|
|
end;
|
|
|
|
procedure RaiseLastWin32(Text: string);
|
|
begin
|
|
PError(Text);
|
|
end;
|
|
|
|
procedure PError(Text: string);
|
|
var
|
|
LastError: Integer;
|
|
St: string;
|
|
begin
|
|
LastError := GetLastError;
|
|
if LastError <> 0 then
|
|
begin
|
|
St := Format(SWin32Error, [LastError, SysErrorMessage(LastError)]);
|
|
if Text <> '' then
|
|
St := Text + ':' + St;
|
|
raise EOSError.Create(St);
|
|
end;
|
|
end;
|
|
|
|
function GetMax(I, J, K: Integer): Integer;
|
|
begin
|
|
if J > I then
|
|
I := J;
|
|
if K > I then
|
|
I := K;
|
|
Result := I;
|
|
end;
|
|
|
|
function GetMin(I, J, K: Integer): Integer;
|
|
begin
|
|
if J < I then
|
|
I := J;
|
|
if K < I then
|
|
I := K;
|
|
Result := I;
|
|
end;
|
|
|
|
procedure RGBToHSV(r, g, b: Integer; var h, s, v: Integer);
|
|
var
|
|
Delta: Integer;
|
|
Min, Max: Integer;
|
|
begin
|
|
Min := GetMin(r, g, b);
|
|
Max := GetMax(r, g, b);
|
|
v := Max;
|
|
Delta := Max - Min;
|
|
if Max = 0 then
|
|
s := 0
|
|
else
|
|
s := (255 * Delta) div Max;
|
|
if s = 0 then
|
|
h := 0
|
|
else
|
|
begin
|
|
if r = Max then
|
|
h := (60 * (g - b)) div Delta
|
|
else
|
|
if g = Max then
|
|
h := 120 + (60 * (b - r)) div Delta
|
|
else
|
|
h := 240 + (60 * (r - g)) div Delta;
|
|
if h < 0 then
|
|
h := h + 360;
|
|
end;
|
|
end;
|
|
|
|
function GetFileVersion(const AFileName: string): Cardinal;
|
|
var
|
|
FileName: string;
|
|
InfoSize, Wnd: DWORD;
|
|
VerBuf: Pointer;
|
|
FI: PVSFixedFileInfo;
|
|
VerSize: DWORD;
|
|
begin
|
|
Result := 0;
|
|
// GetFileVersionInfo modifies the filename parameter data while parsing.
|
|
// Copy the string const into a local variable to create a writeable copy.
|
|
FileName := AFileName;
|
|
UniqueString(FileName);
|
|
InfoSize := GetFileVersionInfoSize(PChar(FileName), Wnd);
|
|
if InfoSize <> 0 then
|
|
begin
|
|
GetMem(VerBuf, InfoSize);
|
|
try
|
|
if GetFileVersionInfo(PChar(FileName), Wnd, InfoSize, VerBuf) then
|
|
if VerQueryValue(VerBuf, '\', Pointer(FI), VerSize) then
|
|
Result := FI.dwFileVersionMS;
|
|
finally
|
|
FreeMem(VerBuf);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetShellVersion: Cardinal;
|
|
begin
|
|
if ShellVersion = 0 then
|
|
ShellVersion := GetFileVersion('shell32.dll');
|
|
Result := ShellVersion;
|
|
end;
|
|
|
|
procedure SetWallpaper(Path: string);
|
|
begin
|
|
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, PChar(Path), SPIF_UPDATEINIFILE);
|
|
end;
|
|
|
|
procedure SetWallpaper(Path: string; Style: TJvWallpaperStyle);
|
|
begin
|
|
with TRegistry.Create do
|
|
begin
|
|
OpenKey(RC_ControlRegistry, False);
|
|
case Style of
|
|
wpTile:
|
|
begin
|
|
WriteString(RC_TileWallpaper, '1');
|
|
WriteString(RC_Wallpaperstyle, '0');
|
|
end;
|
|
wpCenter:
|
|
begin
|
|
WriteString(RC_TileWallpaper, '0');
|
|
WriteString(RC_Wallpaperstyle, '0');
|
|
end;
|
|
wpStretch:
|
|
begin
|
|
WriteString(RC_TileWallpaper, '0');
|
|
WriteString(RC_Wallpaperstyle, '2');
|
|
end;
|
|
end;
|
|
WriteString(RC_WallpaperRegistry, Path);
|
|
Free;
|
|
end;
|
|
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, nil, SPIF_SENDWININICHANGE);
|
|
end;
|
|
|
|
function CaptureScreen(Rec: TRect): TBitmap;
|
|
const
|
|
NumColors = 256;
|
|
var
|
|
R: TRect;
|
|
C: TCanvas;
|
|
LP: PLogPalette;
|
|
TmpPalette: HPalette;
|
|
Size: Integer;
|
|
Img: TImage; // (p3) change to Bmp?
|
|
begin
|
|
Img := TImage.Create(nil);
|
|
try
|
|
Img.Width := Rec.Right - Rec.Left;
|
|
Img.Height := Rec.Bottom - Rec.Top;
|
|
R := Rec;
|
|
C := TCanvas.Create;
|
|
try
|
|
C.Handle := GetDC(HWND_DESKTOP);
|
|
Img.Canvas.CopyRect(Rect(0, 0, Rec.Right - Rec.Left, Rec.Bottom - Rec.Top), C, R);
|
|
Size := SizeOf(TLogPalette) + (Pred(NumColors) * SizeOf(TPaletteEntry));
|
|
LP := AllocMem(Size);
|
|
try
|
|
LP^.palVersion := $300;
|
|
LP^.palNumEntries := NumColors;
|
|
GetSystemPaletteEntries(C.Handle, 0, NumColors, LP^.palPalEntry);
|
|
TmpPalette := CreatePalette(LP^);
|
|
Img.Picture.Bitmap.Palette := TmpPalette;
|
|
DeleteObject(TmpPalette);
|
|
finally
|
|
FreeMem(LP, Size);
|
|
end
|
|
finally
|
|
ReleaseDC(HWND_DESKTOP, C.Handle);
|
|
C.Free;
|
|
end;
|
|
Result := TBitmap.Create;
|
|
Result.Assign(Img.Picture.Bitmap);
|
|
finally
|
|
Img.Free;
|
|
end;
|
|
end;
|
|
|
|
function CaptureScreen: TBitmap;
|
|
begin
|
|
Result := CaptureScreen(Rect(0, 0, Screen.Width, Screen.Height));
|
|
end;
|
|
|
|
{ (rb) Duplicate of JclMultimedia.OpenCloseCdDrive ?? }
|
|
|
|
procedure OpenCdDrive;
|
|
begin
|
|
mciSendString(PChar(RC_OpenCDDrive), nil, 0, GetForegroundWindow);
|
|
end;
|
|
|
|
procedure CloseCdDrive;
|
|
begin
|
|
mciSendString(PChar(RC_CloseCDDrive), nil, 0, GetForegroundWindow);
|
|
end;
|
|
|
|
function GetRBitmap(Value: TBitmap): TBitmap;
|
|
var
|
|
I, J: Integer;
|
|
rowRGB, rowB: PRGBArray;
|
|
begin
|
|
Value.PixelFormat := pf24bit;
|
|
Result := TBitmap.Create;
|
|
Result.PixelFormat := pf24bit;
|
|
Result.Width := Value.Width;
|
|
Result.Height := Value.Height;
|
|
for J := Value.Height - 1 downto 0 do
|
|
begin
|
|
rowRGB := Value.Scanline[J];
|
|
rowB := Result.Scanline[J];
|
|
for I := Value.Width - 1 downto 0 do
|
|
begin
|
|
TRGBArray(rowB^)[I].rgbtRed := rowRGB[I].rgbtRed;
|
|
TRGBArray(rowB^)[I].rgbtGreen := 0;
|
|
TRGBArray(rowB^)[I].rgbtBlue := 0;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetBBitmap(Value: TBitmap): TBitmap;
|
|
var
|
|
I, J: Integer;
|
|
rowRGB, rowB: PRGBArray;
|
|
begin
|
|
Value.PixelFormat := pf24bit;
|
|
Result := TBitmap.Create;
|
|
Result.PixelFormat := pf24bit;
|
|
Result.Width := Value.Width;
|
|
Result.Height := Value.Height;
|
|
for J := Value.Height - 1 downto 0 do
|
|
begin
|
|
rowRGB := Value.Scanline[J];
|
|
rowB := Result.Scanline[J];
|
|
for I := Value.Width - 1 downto 0 do
|
|
begin
|
|
TRGBArray(rowB^)[I].rgbtRed := 0;
|
|
TRGBArray(rowB^)[I].rgbtGreen := 0;
|
|
TRGBArray(rowB^)[I].rgbtBlue := rowRGB[I].rgbtBlue;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetGBitmap(Value: TBitmap): TBitmap;
|
|
var
|
|
I, J: Integer;
|
|
rowRGB, rowB: PRGBArray;
|
|
begin
|
|
Value.PixelFormat := pf24bit;
|
|
Result := TBitmap.Create;
|
|
Result.PixelFormat := pf24bit;
|
|
Result.Width := Value.Width;
|
|
Result.Height := Value.Height;
|
|
for J := Value.Height - 1 downto 0 do
|
|
begin
|
|
rowRGB := Value.Scanline[J];
|
|
rowB := Result.Scanline[J];
|
|
for I := Value.Width - 1 downto 0 do
|
|
begin
|
|
TRGBArray(rowB^)[I].rgbtRed := 0;
|
|
TRGBArray(rowB^)[I].rgbtGreen := rowRGB[I].rgbtGreen;
|
|
TRGBArray(rowB^)[I].rgbtBlue := 0;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetHueBitmap(Value: TBitmap): TBitmap;
|
|
var
|
|
h, s, v, I, J: Integer;
|
|
rowRGB, rowS: PRGBArray;
|
|
begin
|
|
Value.PixelFormat := pf24bit;
|
|
Result := TBitmap.Create;
|
|
Result.PixelFormat := pf24bit;
|
|
Result.Width := Value.Width;
|
|
Result.Height := Value.Height;
|
|
for J := Value.Height - 1 downto 0 do
|
|
begin
|
|
rowRGB := Value.Scanline[J];
|
|
rowS := Result.Scanline[J];
|
|
for I := Value.Width - 1 downto 0 do
|
|
begin
|
|
with rowRGB[I] do
|
|
RGBToHSV(rgbtRed, rgbtGreen, rgbtBlue, h, s, v);
|
|
rowS[I].rgbtBlue := h;
|
|
rowS[I].rgbtGreen := h;
|
|
rowS[I].rgbtRed := h;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetMonochromeBitmap(Value: TBitmap): TBitmap;
|
|
begin
|
|
Result := TBitmap.Create;
|
|
Result.Assign(Value);
|
|
Result.Monochrome := True;
|
|
end;
|
|
|
|
function GetSaturationBitmap(Value: TBitmap): TBitmap;
|
|
var
|
|
h, s, v, I, J: Integer;
|
|
rowRGB, rowS: PRGBArray;
|
|
begin
|
|
Value.PixelFormat := pf24bit;
|
|
Result := TBitmap.Create;
|
|
Result.PixelFormat := pf24bit;
|
|
Result.Width := Value.Width;
|
|
Result.Height := Value.Height;
|
|
for J := Value.Height - 1 downto 0 do
|
|
begin
|
|
rowRGB := Value.Scanline[J];
|
|
rowS := Result.Scanline[J];
|
|
for I := Value.Width - 1 downto 0 do
|
|
begin
|
|
with rowRGB[I] do
|
|
RGBToHSV(rgbtRed, rgbtGreen, rgbtBlue, h, s, v);
|
|
rowS[I].rgbtBlue := s;
|
|
rowS[I].rgbtGreen := s;
|
|
rowS[I].rgbtRed := s;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetValueBitmap(Value: TBitmap): TBitmap;
|
|
var
|
|
h, s, v, I, J: Integer;
|
|
rowRGB, rowS: PRGBArray;
|
|
begin
|
|
Value.PixelFormat := pf24bit;
|
|
Result := TBitmap.Create;
|
|
Result.PixelFormat := pf24bit;
|
|
Result.Width := Value.Width;
|
|
Result.Height := Value.Height;
|
|
for J := Value.Height - 1 downto 0 do
|
|
begin
|
|
rowRGB := Value.Scanline[J];
|
|
rowS := Result.Scanline[J];
|
|
for I := Value.Width - 1 downto 0 do
|
|
begin
|
|
with rowRGB[I] do
|
|
RGBToHSV(rgbtRed, rgbtGreen, rgbtBlue, h, s, v);
|
|
rowS[I].rgbtBlue := v;
|
|
rowS[I].rgbtGreen := v;
|
|
rowS[I].rgbtRed := v;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ (rb) Duplicate of JvAppUtils.AppTaskbarIcons }
|
|
|
|
procedure HideFormCaption(FormHandle: THandle; Hide: Boolean);
|
|
begin
|
|
if Hide then
|
|
SetWindowLong(FormHandle, GWL_STYLE, GetWindowLong(FormHandle, GWL_STYLE) and not WS_CAPTION)
|
|
else
|
|
SetWindowLong(FormHandle, GWL_STYLE, GetWindowLong(FormHandle, GWL_STYLE) or WS_CAPTION);
|
|
end;
|
|
|
|
procedure LaunchCpl(FileName: string);
|
|
begin
|
|
// rundll32.exe shell32,Control_RunDLL ';
|
|
RunDLL32('shell32.dll', 'Control_RunDLL', Filename, True);
|
|
// WinExec(PChar(RC_RunCpl + FileName), SW_SHOWNORMAL);
|
|
end;
|
|
|
|
const
|
|
{$EXTERNALSYM WM_CPL_LAUNCH}
|
|
WM_CPL_LAUNCH = (WM_USER + 1000);
|
|
{$EXTERNALSYM WM_CPL_LAUNCHED}
|
|
WM_CPL_LAUNCHED = (WM_USER + 1001);
|
|
|
|
{ (p3) just define enough to make the Cpl unnecessary for us (for the benefit of PE users) }
|
|
cCplAddress = 'CPlApplet';
|
|
CPL_INIT = 1;
|
|
{$EXTERNALSYM CPL_INIT}
|
|
CPL_GETCOUNT = 2;
|
|
{$EXTERNALSYM CPL_GETCOUNT}
|
|
CPL_INQUIRE = 3;
|
|
{$EXTERNALSYM CPL_INQUIRE}
|
|
CPL_EXIT = 7;
|
|
{$EXTERNALSYM CPL_EXIT}
|
|
CPL_NEWINQUIRE = 8;
|
|
{$EXTERNALSYM CPL_NEWINQUIRE}
|
|
|
|
type
|
|
TCPLApplet = function(hwndCPl: THandle; uMsg: DWORD;
|
|
lParam1, lParam2: Longint): Longint; stdcall;
|
|
|
|
TCPLInfo = packed record
|
|
idIcon: Integer;
|
|
idName: Integer;
|
|
idInfo: Integer;
|
|
lData: Longint;
|
|
end;
|
|
|
|
TNewCPLInfoA = packed record
|
|
dwSize: DWORD;
|
|
dwFlags: DWORD;
|
|
dwHelpContext: DWORD;
|
|
lData: Longint;
|
|
hIcon: HICON;
|
|
szName: array [0..31] of AnsiChar;
|
|
szInfo: array [0..63] of AnsiChar;
|
|
szHelpFile: array [0..127] of AnsiChar;
|
|
end;
|
|
TNewCPLInfoW = packed record
|
|
dwSize: DWORD;
|
|
dwFlags: DWORD;
|
|
dwHelpContext: DWORD;
|
|
lData: Longint;
|
|
hIcon: HICON;
|
|
szName: array [0..31] of WideChar;
|
|
szInfo: array [0..63] of WideChar;
|
|
szHelpFile: array [0..127] of WideChar;
|
|
end;
|
|
|
|
function GetControlPanelApplet(const AFilename: string; Strings: TStrings; Images: TImageList = nil): Boolean;
|
|
var
|
|
hLib: HMODULE; // Library Handle to *.cpl file
|
|
hIco: HICON;
|
|
CplCall: TCPLApplet; // Pointer to CPlApplet() function
|
|
I: Longint;
|
|
TmpCount, Count: Longint;
|
|
S: WideString;
|
|
// the three types of information that can be returned
|
|
CPLInfo: TCPLInfo;
|
|
InfoW: TNewCPLInfoW;
|
|
InfoA: TNewCPLInfoA;
|
|
hWnd:THandle;
|
|
begin
|
|
Result := False;
|
|
hLib := SafeLoadLibrary(AFilename);
|
|
if hLib = 0 then
|
|
Exit;
|
|
hWnd := GetForegroundWindow;
|
|
TmpCount := Strings.Count;
|
|
try
|
|
@CplCall := GetProcAddress(hLib, PChar(cCplAddress));
|
|
if @CplCall = nil then
|
|
Exit;
|
|
CplCall(hWnd, CPL_INIT, 0, 0); // Init the *.cpl file
|
|
try
|
|
Count := CplCall(hWnd, CPL_GETCOUNT, 0, 0);
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
FillChar(InfoW, SizeOf(InfoW), 0);
|
|
FillChar(InfoA, SizeOf(InfoA), 0);
|
|
FillChar(CPLInfo, SizeOf(CPLInfo), 0);
|
|
S := '';
|
|
CplCall(hWnd, CPL_NEWINQUIRE, I, Longint(@InfoW));
|
|
if InfoW.dwSize = SizeOf(InfoW) then
|
|
begin
|
|
hIco := InfoW.HICON;
|
|
S := WideString(InfoW.szName);
|
|
end
|
|
else
|
|
begin
|
|
if InfoW.dwSize = SizeOf(InfoA) then
|
|
begin
|
|
Move(InfoW, InfoA, SizeOf(InfoA));
|
|
hIco := CopyIcon(InfoA.HICON);
|
|
S := string(InfoA.szName);
|
|
end
|
|
else
|
|
begin
|
|
CplCall(hWnd, CPL_INQUIRE, I, Longint(@CPLInfo));
|
|
LoadStringA(hLib, CPLInfo.idName, InfoA.szName, SizeOf(InfoA.szName));
|
|
hIco := LoadImage(hLib, PChar(CPLInfo.idIcon), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
|
|
S := string(InfoA.szName);
|
|
end;
|
|
end;
|
|
if S <> '' then
|
|
begin
|
|
S := Format('%s=%s,@%d', [S, AFilename, I]);
|
|
if Images <> nil then
|
|
begin
|
|
hIco := CopyIcon(hIco);
|
|
ImageList_AddIcon(Images.Handle, hIco);
|
|
Strings.AddObject(S, TObject(Images.Count - 1));
|
|
end
|
|
else
|
|
Strings.AddObject(S, IconToBitmap2(hIco, 16, clMenu));
|
|
// (p3) not sure this is really needed...
|
|
// DestroyIcon(hIco);
|
|
end;
|
|
end;
|
|
Result := TmpCount < Strings.Count;
|
|
finally
|
|
CplCall(hWnd, CPL_EXIT, 0, 0);
|
|
end;
|
|
finally
|
|
FreeLibrary(hLib);
|
|
end;
|
|
end;
|
|
|
|
function GetControlPanelApplets(const APath, AMask: string; Strings: TStrings; Images: TImageList = nil): Boolean;
|
|
var
|
|
H: THandle;
|
|
F: TSearchRec;
|
|
begin
|
|
H := FindFirst(IncludeTrailingPathDelimiter(APath) + AMask, faAnyFile, F);
|
|
if Images <> nil then
|
|
begin
|
|
Images.Clear;
|
|
Images.BkColor := clMenu;
|
|
end;
|
|
if Strings <> nil then
|
|
Strings.Clear;
|
|
while H = 0 do
|
|
begin
|
|
if F.Attr and faDirectory = 0 then
|
|
// if (F.Name <> '.') and (F.Name <> '..') then
|
|
GetControlPanelApplet(APath + F.Name, Strings, Images);
|
|
H := FindNext(F);
|
|
end;
|
|
SysUtils.FindClose(F);
|
|
Result := Strings.Count > 0;
|
|
end;
|
|
|
|
procedure Exec(FileName, Parameters, Directory: string);
|
|
var
|
|
Operation: string;
|
|
begin
|
|
Operation := 'open';
|
|
ShellExecute(GetForegroundWindow, PChar(Operation), PChar(FileName), PChar(Parameters), PChar(Directory),
|
|
SW_SHOWNORMAL);
|
|
end;
|
|
|
|
{ (rb) Duplicate of JclMiscel.WinExec32AndWait }
|
|
|
|
procedure ExecuteAndWait(FileName: string; Visibility: Integer);
|
|
var
|
|
zAppName: array [0..512] of Char;
|
|
zCurDir: array [0..255] of Char;
|
|
WorkDir: string;
|
|
StartupInfo: TStartupInfo;
|
|
ProcessInfo: TProcessInformation;
|
|
begin
|
|
StrPCopy(zAppName, FileName);
|
|
GetDir(0, WorkDir);
|
|
StrPCopy(zCurDir, WorkDir);
|
|
FillChar(StartupInfo, SizeOf(StartupInfo), #0);
|
|
StartupInfo.cb := SizeOf(StartupInfo);
|
|
StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
|
|
StartupInfo.wShowWindow := Visibility;
|
|
if not CreateProcess(nil, zAppName, nil, nil, False, Create_NEW_CONSOLE or NORMAL_PRIORITY_CLASS,
|
|
nil, nil, StartupInfo, ProcessInfo) then
|
|
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
|
|
end;
|
|
|
|
{ (rb) Duplicate of JclFileUtils.DiskInDrive }
|
|
|
|
function DiskInDrive(Drive: Char): Boolean;
|
|
var
|
|
DrvNum: Byte;
|
|
EMode: Word;
|
|
begin
|
|
DrvNum := Ord(Drive);
|
|
if DrvNum >= Ord('a') then
|
|
Dec(DrvNum, $20);
|
|
EMode := SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
try
|
|
Result := DiskSize(DrvNum - $40) <> -1;
|
|
finally
|
|
SetErrorMode(EMode);
|
|
end;
|
|
end;
|
|
|
|
function FirstInstance(const ATitle: string): Boolean;
|
|
var
|
|
Mutex: THandle;
|
|
begin
|
|
Mutex := CreateMutex(nil, False, PChar(ATitle));
|
|
try
|
|
Result := (Mutex <> 0) and (GetLastError <> ERROR_ALREADY_EXISTS);
|
|
finally
|
|
ReleaseMutex(Mutex);
|
|
end;
|
|
end;
|
|
|
|
procedure RestoreOtherInstance(MainFormClassName, MainFormCaption: string);
|
|
var
|
|
OtherWnd, OwnerWnd: HWND;
|
|
begin
|
|
OtherWnd := FindWindow(PChar(MainFormClassName), PChar(MainFormCaption));
|
|
ShowWindow(OtherWnd, SW_SHOW); //in case the window was not visible before
|
|
|
|
OwnerWnd := 0;
|
|
if OtherWnd <> 0 then
|
|
OwnerWnd := GetWindow(OtherWnd, GW_OWNER);
|
|
|
|
if OwnerWnd <> 0 then
|
|
OtherWnd := OwnerWnd;
|
|
|
|
if OtherWnd <> 0 then
|
|
begin
|
|
{ (rb) Use JvVCLUtils.SwitchToWindow }
|
|
if IsIconic(OtherWnd) then
|
|
ShowWindow(OtherWnd, SW_RESTORE);
|
|
|
|
SetForegroundWindow(OtherWnd);
|
|
end;
|
|
end;
|
|
|
|
procedure HideTraybar;
|
|
var
|
|
Wnd: HWND;
|
|
begin
|
|
Wnd := FindWindow(PChar(RC_ShellName), nil);
|
|
ShowWindow(Wnd, SW_HIDE);
|
|
end;
|
|
|
|
procedure ShowTraybar;
|
|
var
|
|
Wnd: HWND;
|
|
begin
|
|
Wnd := FindWindow(PChar(RC_ShellName), nil);
|
|
ShowWindow(Wnd, SW_SHOW);
|
|
end;
|
|
|
|
procedure HideStartBtn(Visible: Boolean);
|
|
var
|
|
Tray, Child: HWND;
|
|
C: array [0..127] of Char;
|
|
S: string;
|
|
begin
|
|
Tray := FindWindow(PChar(RC_ShellName), nil);
|
|
Child := GetWindow(Tray, GW_CHILD);
|
|
while Child <> 0 do
|
|
begin
|
|
if GetClassName(Child, C, SizeOf(C)) > 0 then
|
|
begin
|
|
S := StrPas(C);
|
|
if UpperCase(S) = 'BUTTON' then
|
|
if Visible then
|
|
ShowWindow(Child, SW_SHOWNORMAL)
|
|
else
|
|
ShowWindow(Child, SW_HIDE);
|
|
end;
|
|
Child := GetWindow(Child, GW_HWNDNEXT);
|
|
end;
|
|
end;
|
|
|
|
procedure ShowStartButton;
|
|
begin
|
|
HideStartBtn(True);
|
|
end;
|
|
|
|
procedure HideStartButton;
|
|
begin
|
|
HideStartBtn(False);
|
|
end;
|
|
|
|
procedure MonitorOn;
|
|
begin
|
|
SendMessage(GetForegroundWindow, WM_SYSCOMMAND, SC_MONITORPOWER, -1);
|
|
end;
|
|
|
|
procedure MonitorOff;
|
|
begin
|
|
SendMessage(GetForegroundWindow, WM_SYSCOMMAND, SC_MONITORPOWER, 2);
|
|
end;
|
|
|
|
procedure LowPower;
|
|
begin
|
|
SendMessage(GetForegroundWindow, WM_SYSCOMMAND, SC_MONITORPOWER, 1);
|
|
end;
|
|
|
|
{$WARNINGS OFF}
|
|
|
|
procedure SendShift(H: HWND; Down: Boolean);
|
|
var
|
|
vKey, ScanCode: Word;
|
|
lParam: Longint;
|
|
begin
|
|
vKey := VK_SHIFT;
|
|
ScanCode := MapVirtualKey(vKey, 0);
|
|
lParam := Longint(ScanCode) shl 16 or 1;
|
|
if not Down then
|
|
lParam := lParam or $C0000000;
|
|
SendMessage(H, WM_KEYDOWN, vKey, lParam);
|
|
end;
|
|
|
|
procedure SendCtrl(H: HWND; Down: Boolean);
|
|
var
|
|
vKey, ScanCode: Word;
|
|
lParam: Longint;
|
|
begin
|
|
vKey := VK_CONTROL;
|
|
ScanCode := MapVirtualKey(vKey, 0);
|
|
lParam := Longint(ScanCode) shl 16 or 1;
|
|
if not Down then
|
|
lParam := lParam or $C0000000;
|
|
SendMessage(H, WM_KEYDOWN, vKey, lParam);
|
|
end;
|
|
|
|
function SendKey(AppName: string; Key: Char): Boolean;
|
|
var
|
|
vKey, ScanCode: Word;
|
|
lParam, ConvKey: Longint;
|
|
Shift, Ctrl: Boolean;
|
|
H: HWND;
|
|
begin
|
|
H := FindWindow(PChar(AppName), nil);
|
|
if H <> 0 then
|
|
begin
|
|
ConvKey := OemKeyScan(Ord(Key));
|
|
Shift := (ConvKey and $00020000) <> 0;
|
|
Ctrl := (ConvKey and $00040000) <> 0;
|
|
ScanCode := ConvKey and $000000FF or $FF00;
|
|
vKey := Ord(Key);
|
|
lParam := Longint(ScanCode) shl 16 or 1;
|
|
if Shift then
|
|
SendShift(H, True);
|
|
if Ctrl then
|
|
SendCtrl(H, True);
|
|
SendMessage(H, WM_KEYDOWN, vKey, lParam);
|
|
SendMessage(H, WM_CHAR, vKey, lParam);
|
|
lParam := lParam or $C0000000;
|
|
SendMessage(H, WM_KEYUP, vKey, lParam);
|
|
if Shift then
|
|
SendShift(H, False);
|
|
if Ctrl then
|
|
SendCtrl(H, False);
|
|
Result := True;
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
{$WARNINGS ON}
|
|
|
|
procedure RebuildIconCache;
|
|
var
|
|
Dummy: DWORD;
|
|
begin
|
|
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS,
|
|
Longint(PChar('WindowMetrics')), SMTO_NORMAL or SMTO_ABORTIFHUNG, 10000, Dummy);
|
|
end;
|
|
|
|
procedure AssociateFileExtension(IconPath, ProgramName, Path, Extension: string);
|
|
begin
|
|
with TRegistry.Create do
|
|
begin
|
|
RootKey := HKEY_CLASSES_ROOT;
|
|
OpenKey(ProgramName, True);
|
|
WriteString('', ProgramName);
|
|
if IconPath <> '' then
|
|
begin
|
|
OpenKey(RC_DefaultIcon, True);
|
|
WriteString('', IconPath);
|
|
end;
|
|
CloseKey;
|
|
OpenKey(ProgramName, True);
|
|
OpenKey('shell', True);
|
|
OpenKey('open', True);
|
|
OpenKey('command', True);
|
|
WriteString('', '"' + Path + '" "%1"');
|
|
Free;
|
|
end;
|
|
with TRegistry.Create do
|
|
begin
|
|
RootKey := HKEY_CLASSES_ROOT;
|
|
OpenKey('.' + extension, True);
|
|
WriteString('', ProgramName);
|
|
Free;
|
|
end;
|
|
RebuildIconCache;
|
|
end;
|
|
|
|
procedure AssociateExtension(IconPath, ProgramName, Path, Extension: string);
|
|
begin
|
|
AssociateFileExtension(IconPath, ProgramName, Path, Extension);
|
|
end;
|
|
|
|
function GetRecentDocs: TStringList;
|
|
var
|
|
Path: string;
|
|
t: TSearchRec;
|
|
Res: Integer;
|
|
begin
|
|
Result := TStringList.Create;
|
|
Result.Clear;
|
|
Path := INcludeTrailingPathDelimiter(GetRecentFolder);
|
|
//search for all files
|
|
Res := FindFirst(Path + '*.*', faAnyFile, t);
|
|
try
|
|
while Res = 0 do
|
|
begin
|
|
if (t.Name <> '.') and (t.Name <> '..') then
|
|
Result.Add(Path + T.Name);
|
|
Res := FindNext(t);
|
|
end;
|
|
finally
|
|
FindClose(t);
|
|
end;
|
|
end;
|
|
|
|
{ (rb) Duplicate of JvWinDialogs.AddToRecentDocs }
|
|
|
|
procedure AddToRecentDocs(const Filename: string);
|
|
begin
|
|
SHAddToRecentDocs(SHARD_PATH, PChar(Filename));
|
|
end;
|
|
|
|
function RegionFromBitmap(const Image: TBitmap): HRGN;
|
|
begin
|
|
Result := 0;
|
|
if Assigned(Image) and not Image.Empty then
|
|
Result := CreateRegionFromBitmap(Image, Image.Canvas.Pixels[0, 0], rmExclude);
|
|
end;
|
|
|
|
function EnumWindowsProc(Handle: THandle; lParam: TStrings): Boolean; stdcall;
|
|
var
|
|
St: array [0..256] of Char;
|
|
St2: string;
|
|
begin
|
|
if IsWindowVisible(Handle) then
|
|
begin
|
|
GetWindowText(Handle, St, SizeOf(St));
|
|
St2 := St;
|
|
if St2 <> '' then
|
|
with TStrings(lParam) do
|
|
AddObject(St2, TObject(Handle));
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
procedure GetVisibleWindows(List: Tstrings);
|
|
begin
|
|
List.BeginUpdate;
|
|
try
|
|
List.Clear;
|
|
EnumWindows(@EnumWindowsProc, Integer(List));
|
|
finally
|
|
List.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
// from JvComponentFunctions
|
|
|
|
function StrPosNoCase(const psSub, psMain: string): Integer;
|
|
begin
|
|
Result := Pos(AnsiUpperCase(psSub), AnsiUpperCase(psMain));
|
|
end;
|
|
|
|
function StrRestOf(const Ps: string; const n: Integer): string;
|
|
begin
|
|
Result := Copy(Ps, n, (Length(Ps) - n + 1));
|
|
end;
|
|
|
|
{!!!!!!!! use these cos the JCL one is badly broken }
|
|
|
|
{ Am using this one purely as an itnernal for StrReplace
|
|
|
|
Replace part of a string with new text. iUpdatePos is the last update position
|
|
i.e. the position the substr was found + the length of the replacement string + 1.
|
|
Use 0 first time in }
|
|
|
|
function StrReplaceInstance(const psSource, psSearch, psReplace: string;
|
|
var piUpdatePos: Integer; const pbCaseSens: Boolean): string;
|
|
var
|
|
liIndex: Integer;
|
|
lsCopy: string;
|
|
begin
|
|
Result := psSource;
|
|
if piUpdatePos >= Length(psSource) then
|
|
Exit;
|
|
if psSearch = '' then
|
|
Exit;
|
|
|
|
Result := StrLeft(psSource, piUpdatePos - 1);
|
|
lsCopy := StrRestOf(psSource, piUpdatePos);
|
|
|
|
if pbCaseSens then
|
|
liIndex := Pos(psSearch, lsCopy)
|
|
else
|
|
liIndex := StrPosNoCase(psSearch, lsCopy);
|
|
if liIndex = 0 then
|
|
begin
|
|
Result := psSource;
|
|
piUpdatePos := Length(psSource) + 1;
|
|
Exit;
|
|
end;
|
|
|
|
Result := Result + StrLeft(lsCopy, liIndex - 1);
|
|
Result := Result + psReplace;
|
|
piUpdatePos := Length(Result) + 1;
|
|
Result := Result + StrRestOf(lsCopy, liIndex + Length(psSearch));
|
|
end;
|
|
|
|
function LStrReplace(const psSource, psSearch, psReplace: string;
|
|
const pbCaseSens: Boolean): string;
|
|
var
|
|
liUpdatePos: Integer;
|
|
begin
|
|
liUpdatePos := 0;
|
|
Result := psSource;
|
|
while liUpdatePos < Length(Result) do
|
|
Result := StrReplaceInstance(Result, psSearch, psReplace, liUpdatePos, pbCaseSens);
|
|
end;
|
|
|
|
{ if it's not a decimal point then it must be a digit, space or Currency symbol
|
|
also always use $ for money }
|
|
|
|
function CharIsMoney(const Ch: Char): Boolean;
|
|
begin
|
|
Result := CharIsDigit(Ch) or (Ch = AnsiSpace) or (Ch = '$') or (Ch = '-') or
|
|
(Pos(Ch, CurrencyString) > 0);
|
|
end;
|
|
|
|
function StrToCurrDef(const Str: string; Def: Currency): Currency;
|
|
var
|
|
lStr: string;
|
|
begin
|
|
try
|
|
lStr := StrStripNonNumberChars(Str);
|
|
|
|
if lStr = '' then
|
|
Result := Def
|
|
else
|
|
Result := StrToCurr(lstr);
|
|
except
|
|
Result := Def;
|
|
end;
|
|
end;
|
|
|
|
function StrToFloatDef(const Str: string; Def: Extended): Extended;
|
|
var
|
|
lStr: string;
|
|
begin
|
|
lStr := StrStripNonNumberChars(Str);
|
|
|
|
if lStr = '' then
|
|
Result := Def
|
|
else
|
|
try
|
|
{ the string '-' fails StrToFloat, but it can be interpreted as 0 }
|
|
if StrRight(lStr, 1) = '-' then
|
|
lStr := lStr + '0';
|
|
|
|
{ a string that ends in a '.' such as '12.' fails StrToFloat,
|
|
but as far as I am concerned, it may as well be interpreted as 12.0 }
|
|
if StrRight(lStr, 1) = '.' then
|
|
lStr := lStr + '0';
|
|
|
|
Result := StrToFloat(lStr);
|
|
except
|
|
Result := Def;
|
|
end;
|
|
end;
|
|
|
|
function GetChangedText(const Text: string; SelStart, SelLength: Integer; Key: Char): string;
|
|
begin
|
|
{ take the original text, replace what will be overwritten with new value }
|
|
Result := Text;
|
|
|
|
if SelLength > 0 then
|
|
Delete(Result, SelStart + 1, SelLength);
|
|
if Key <> #0 then
|
|
Insert(Key, Result, SelStart + 1);
|
|
end;
|
|
|
|
{ "window" technique for years to translate 2 digits to 4 digits.
|
|
The window is 100 years wide
|
|
The windowsill year is the lower edge of the window
|
|
A windowsill year of 1900 is equivalent to putting 1900 before every 2-digit year
|
|
if piWindowsillYear is 1940, then 40 is interpreted as 1940, 00 as 2000 and 39 as 2039
|
|
The system default is 1950
|
|
}
|
|
{ "window" technique for years to translate 2 digits to 4 digits.
|
|
The window is 100 years wide
|
|
The pivot year is the lower edge of the window
|
|
A pivot year of 1900 is equivalent to putting 1900 before every 2-digit year
|
|
if pivot is 1940, then 40 is interpreted as 1940, 00 as 2000 and 39 as 2039
|
|
The system default is 1950
|
|
|
|
Why the reimplementation?
|
|
JclDatetime.Make4DigitYear will fail after 2100, this won't
|
|
note that in this implementation pivot is a 4-digit year
|
|
I have made it accept JclDatetime.Make4DigitYear's 2 digit pivot years.
|
|
They are expanded by adding 1900.
|
|
|
|
It is also better in that a valid 4-digit year will pass through unchanged,
|
|
not fail an assertion.
|
|
}
|
|
|
|
function MakeYear4Digit(Year, Pivot: Integer): Integer;
|
|
var
|
|
Century: Integer;
|
|
begin
|
|
if Pivot < 0 then
|
|
raise EJVCLException.Create('JvFunctions.MakeYear4Digit: Pivot < 0');
|
|
|
|
{ map 100 to zero }
|
|
if Year = 100 then
|
|
Year := 0;
|
|
if Pivot = 100 then
|
|
Pivot := 0;
|
|
|
|
// turn 2 digit pivot to 4 digit
|
|
if Pivot < 100 then
|
|
Pivot := Pivot + 1900;
|
|
|
|
{ turn 2 digit years to 4 digits }
|
|
if (Year >= 0) and (Year < 100) then
|
|
begin
|
|
Century := (Pivot div 100) * 100;
|
|
|
|
Result := Year + Century; // give the result the same century as the pivot
|
|
if Result < Pivot then
|
|
// cannot be lower than the Pivot
|
|
Result := Result + 100;
|
|
end
|
|
else
|
|
Result := Year;
|
|
end;
|
|
|
|
function StrIsInteger(const S: string): Boolean;
|
|
var
|
|
I: Integer;
|
|
Ch: Char;
|
|
begin
|
|
Result := S <> '';
|
|
for I := 1 to Length(S) do
|
|
begin
|
|
Ch := S[I];
|
|
if (not CharIsNumber(Ch)) or (Ch = DecimalSeparator) then //Az
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function StrIsFloatMoney(const Ps: string): Boolean;
|
|
var
|
|
liLoop, liDots: Integer;
|
|
Ch: Char;
|
|
begin
|
|
Result := True;
|
|
liDots := 0;
|
|
|
|
for liLoop := 1 to Length(Ps) do
|
|
begin
|
|
{ allow digits, space, Currency symbol and one decimal dot }
|
|
Ch := Ps[liLoop];
|
|
|
|
if Ch = DecimalSeparator then
|
|
begin
|
|
Inc(liDots);
|
|
if liDots > 1 then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
end
|
|
else
|
|
if not CharIsMoney(Ch) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function StrIsDateTime(const Ps: string): Boolean;
|
|
const
|
|
MIN_DATE_TIME_LEN = 6; {2Jan02 }
|
|
MAX_DATE_TIME_LEN = 30; { 30 chars or so in '12 December 1999 12:23:23:00' }
|
|
var
|
|
liLoop: Integer;
|
|
Ch: Char;
|
|
liColons, liSlashes, liSpaces, liDigits, liAlpha: Integer;
|
|
lbDisqualify: Boolean;
|
|
begin
|
|
if Length(Ps) < MIN_DATE_TIME_LEN then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
|
|
if Length(Ps) > MAX_DATE_TIME_LEN then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
|
|
lbDisqualify := False;
|
|
liColons := 0;
|
|
liSlashes := 0;
|
|
liSpaces := 0;
|
|
liDigits := 0;
|
|
liAlpha := 0;
|
|
|
|
for liLoop := 1 to Length(Ps) do
|
|
begin
|
|
Ch := Ps[liLoop];
|
|
|
|
if Ch = ':' then
|
|
Inc(liColons)
|
|
else
|
|
if Ch = AnsiForwardSlash then
|
|
Inc(liSlashes)
|
|
else
|
|
if Ch = AnsiSpace then
|
|
Inc(liSpaces)
|
|
else
|
|
if CharIsDigit(Ch) then
|
|
Inc(liDigits)
|
|
else
|
|
if CharIsAlpha(Ch) then
|
|
Inc(liAlpha)
|
|
else
|
|
begin
|
|
// no wierd punctuation in dates!
|
|
lbDisqualify := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
Result := False;
|
|
if not lbDisqualify then
|
|
{ a date must have colons and slashes and spaces, but not to many of each }
|
|
if (liColons > 0) or (liSlashes > 0) or (liSpaces > 0) then
|
|
{ only 2 slashes in "dd/mm/yy" or 3 colons in "hh:mm:ss:ms" or 6 spaces "yy mm dd hh mm ss ms" }
|
|
if (liSlashes <= 2) and (liColons <= 3) and (liSpaces <= 6) then
|
|
{ must have some digits (min 3 digits, eg in "2 jan 02", max 16 dgits in "01/10/2000 10:10:10:10"
|
|
longest month name is 8 chars }
|
|
if (liDigits >= 3) and (liDigits <= 16) and (liAlpha <= 10) then
|
|
Result := True;
|
|
|
|
{ define in terms of results - if I can interpret it as a date, then I can }
|
|
if Result then
|
|
Result := (SafeStrToDateTime(PreformatDateString(Ps)) <> 0);
|
|
end;
|
|
|
|
function PreformatDateString(Ps: string): string;
|
|
var
|
|
liLoop: Integer;
|
|
begin
|
|
{ turn any month names to numbers }
|
|
|
|
{ use the StrReplace in stringfunctions -
|
|
the one in JclStrings is badly broken and brings down the app }
|
|
|
|
for liLoop := Low(LongMonthNames) to High(LongMonthNames) do
|
|
Ps := LStrReplace(Ps, LongMonthNames[liLoop], IntToStr(liLoop), False);
|
|
|
|
{ now that 'January' is gone, catch 'Jan' }
|
|
for liLoop := Low(ShortMonthNames) to High(ShortMonthNames) do
|
|
Ps := LStrReplace(Ps, ShortMonthNames[liLoop], IntToStr(liLoop), False);
|
|
|
|
{ remove redundant spaces }
|
|
Ps := LStrReplace(Ps, AnsiSpace + AnsiSpace, AnsiSpace, False);
|
|
|
|
Result := Ps;
|
|
end;
|
|
|
|
function BooleanToInteger(const Pb: Boolean): Integer;
|
|
begin
|
|
// (p3) this works as well:
|
|
// Result := Ord(Pb);
|
|
if Pb then
|
|
Result := 1
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
{ from my ConvertFunctions unit }
|
|
|
|
function StringToBoolean(const Ps: string): Boolean;
|
|
const
|
|
TRUE_STRINGS: array [1..5] of string = ('True', 't', 'y', 'yes', '1');
|
|
var
|
|
liLoop: Integer;
|
|
begin
|
|
Result := False;
|
|
|
|
for liLoop := Low(TRUE_STRINGS) to High(TRUE_STRINGS) do
|
|
if AnsiSameText(Ps, TRUE_STRINGS[liLoop]) then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
function SafeStrToDateTime(const Ps: string): TDateTime;
|
|
begin
|
|
try
|
|
Result := StrToDateTime(PreformatDateString(Ps));
|
|
except
|
|
on E: EConvertError do
|
|
Result := 0.0
|
|
else
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
function SafeStrToDate(const Ps: string): TDateTime;
|
|
begin
|
|
try
|
|
Result := StrToDate(PreformatDateString(Ps));
|
|
except
|
|
on E: EConvertError do
|
|
Result := 0.0
|
|
else
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
function SafeStrToTime(const Ps: string): TDateTime;
|
|
begin
|
|
try
|
|
Result := StrToTime(Ps)
|
|
except
|
|
on E: EConvertError do
|
|
Result := 0.0
|
|
else
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
{ imported from VCLFunctions }
|
|
|
|
procedure CenterHeight(const pc, pcParent: TControl);
|
|
begin
|
|
pc.Top := //pcParent.Top +
|
|
((pcParent.Height - pc.Height) div 2);
|
|
end;
|
|
|
|
function ToRightOf(const pc: TControl; piSpace: Integer): Integer;
|
|
begin
|
|
if pc <> nil then
|
|
Result := pc.Left + pc.Width + piSpace
|
|
else
|
|
Result := piSpace;
|
|
end;
|
|
|
|
{ have to do this as it depends what the datekind of the control is}
|
|
|
|
function DateIsNull(const pdtValue: TDateTime; const pdtKind: TdtKind): Boolean;
|
|
begin
|
|
Result := False;
|
|
case pdtKind of
|
|
dtkDateOnly:
|
|
Result := pdtValue < 1; //if date only then anything less than 1 is considered null
|
|
dtkTimeOnly:
|
|
Result := Frac(pdtValue) = NullEquivalentDate; //if time only then anything without a remainder is null
|
|
dtkDateTime:
|
|
Result := pdtValue = NullEquivalentDate;
|
|
end;
|
|
end;
|
|
|
|
function OSCheck(RetVal: Boolean): Boolean;
|
|
begin
|
|
if not RetVal then
|
|
RaiseLastOSError;
|
|
Result := RetVal;
|
|
end;
|
|
|
|
function MinimizeName(const Filename: string; Canvas: TCanvas; MaxLen: Integer): string;
|
|
var
|
|
b: array [0..MAX_PATH] of Char;
|
|
R: TRect;
|
|
begin
|
|
StrCopy(b, PChar(Filename));
|
|
R := Rect(0, 0, MaxLen, Canvas.TextHeight('Wq'));
|
|
if DrawText(Canvas.Handle, b, Length(Filename), R,
|
|
DT_SINGLELINE or DT_MODIFYSTRING or DT_PATH_ELLIPSIS or DT_CALCRECT or DT_NOPREFIX) > 0 then
|
|
Result := b
|
|
else
|
|
Result := Filename;
|
|
end;
|
|
|
|
function RunDLL32(const ModuleName, FuncName, CmdLine: string; WaitForCompletion: Boolean; CmdShow: Integer =
|
|
SW_SHOWDEFAULT): Boolean;
|
|
var
|
|
SI: TStartUpInfo;
|
|
PI: TProcessInformation;
|
|
S: string;
|
|
begin
|
|
SI.cb := SizeOf(SI);
|
|
GetStartupInfo(SI);
|
|
SI.wShowWindow := CmdShow;
|
|
S := Format('rundll32.exe %s,%s %s', [ModuleName, FuncName, CmdLine]);
|
|
Result := CreateProcess(nil, PChar(S), nil, nil, False, 0, nil, nil, SI, PI);
|
|
try
|
|
if WaitForCompletion then
|
|
Result := WaitForSingleObject(PI.hProcess, INFINITE) <> WAIT_FAILED;
|
|
finally
|
|
CloseHandle(PI.hThread);
|
|
CloseHandle(PI.hProcess);
|
|
end;
|
|
end;
|
|
|
|
procedure RunDll32Internal(Wnd: HWnd; const DLLName, FuncName, CmdLine: string; CmdShow: Integer = SW_SHOWDEFAULT);
|
|
var
|
|
H: THandle;
|
|
ErrMode: Cardinal;
|
|
P: TRunDLL32Proc;
|
|
begin
|
|
ErrMode := SetErrorMode(SEM_FAILCRITICALERRORS or SEM_NOOPENFILEERRORBOX);
|
|
H := LoadLibrary(PChar(DLLName));
|
|
try
|
|
if H <> INVALID_HANDLE_VALUE then
|
|
begin
|
|
P := GetProcAddress(H, PChar(FuncName));
|
|
if Assigned(P) then
|
|
P(Wnd, H, PChar(CmdLine), CmdShow);
|
|
end;
|
|
finally
|
|
SetErrorMode(ErrMode);
|
|
if H <> INVALID_HANDLE_VALUE then
|
|
FreeLibrary(H);
|
|
end;
|
|
end;
|
|
|
|
function TimeOnly(pcValue: TDateTime): TTime;
|
|
begin
|
|
Result := Frac(pcValue);
|
|
end;
|
|
|
|
function DateOnly(pcValue: TDateTime): TDate;
|
|
begin
|
|
Result := Trunc(pcValue);
|
|
end;
|
|
|
|
function HasFlag(a, b: Integer): Boolean;
|
|
begin
|
|
Result := (a and b) <> 0;
|
|
end;
|
|
|
|
{ compiled from ComCtrls.pas's implmentation section }
|
|
|
|
function ConvertStates(const State: Integer): TItemStates;
|
|
begin
|
|
Result := [];
|
|
if HasFlag(State, LVIS_ACTIVATING) then
|
|
Include(Result, isActivating);
|
|
if HasFlag(State, LVIS_CUT) then
|
|
Include(Result, isCut);
|
|
if HasFlag(State, LVIS_DROPHILITED) then
|
|
Include(Result, isDropHilited);
|
|
if HasFlag(State, LVIS_FOCUSED) then
|
|
Include(Result, isFocused);
|
|
if HasFlag(State, LVIS_SELECTED) then
|
|
Include(Result, isSelected);
|
|
end;
|
|
|
|
function ChangeHasSelect(const peOld, peNew: TItemStates): Boolean;
|
|
begin
|
|
Result := (not (isSelected in peOld)) and (isSelected in peNew);
|
|
end;
|
|
|
|
function ChangeHasDeselect(const peOld, peNew: TItemStates): Boolean;
|
|
begin
|
|
Result := (isSelected in peOld) and (not (isSelected in peNew));
|
|
end;
|
|
|
|
function ChangeHasFocus(const peOld, peNew: TItemStates): Boolean;
|
|
begin
|
|
Result := (not (isFocused in peOld)) and (isFocused in peNew);
|
|
end;
|
|
|
|
function ChangeHasDefocus(const peOld, peNew: TItemStates): Boolean;
|
|
begin
|
|
Result := (isFocused in peOld) and (not (isFocused in peNew));
|
|
end;
|
|
|
|
function GetListItemColumn(const pcItem: TListItem; piIndex: Integer): string;
|
|
begin
|
|
if pcItem = nil then
|
|
begin
|
|
Result := '';
|
|
Exit;
|
|
end;
|
|
|
|
if (piIndex < 0) or (piIndex > pcItem.SubItems.Count) then
|
|
begin
|
|
Result := '';
|
|
Exit;
|
|
end;
|
|
|
|
if piIndex = 0 then
|
|
Result := pcItem.Caption
|
|
else
|
|
Result := pcItem.SubItems[piIndex - 1];
|
|
end;
|
|
|
|
{!! from strFunctions }
|
|
|
|
function StrDeleteChars(const Ps: string; const piPos: Integer; const piCount: Integer): string;
|
|
begin
|
|
Result := StrLeft(Ps, piPos - 1) + StrRestOf(Ps, piPos + piCount);
|
|
end;
|
|
|
|
function StrDelete(const psSub, psMain: string): string;
|
|
var
|
|
liPos: Integer;
|
|
begin
|
|
Result := psMain;
|
|
if psSub = '' then
|
|
Exit;
|
|
|
|
liPos := StrIPos(psSub, psMain);
|
|
|
|
while liPos > 0 do
|
|
begin
|
|
Result := StrDeleteChars(Result, liPos, Length(psSub));
|
|
liPos := StrIPos(psSub, Result);
|
|
end;
|
|
end;
|
|
|
|
type
|
|
// (p3) from ShLwAPI
|
|
TDLLVersionInfo = packed record
|
|
cbSize: DWORD;
|
|
dwMajorVersion: DWORD;
|
|
dwMinorVersion: DWORD;
|
|
dwBuildNumber: DWORD;
|
|
dwPlatformID: DWORD;
|
|
end;
|
|
|
|
function GetDLLVersion(const DLLName: string; var pdwMajor, pdwMinor: Integer): Boolean;
|
|
var
|
|
hDLL, hr: THandle;
|
|
pDllGetVersion: function(var Dvi: TDLLVersionInfo): Integer; stdcall;
|
|
Dvi: TDLLVersionInfo;
|
|
begin
|
|
hDLL := LoadLibrary(PChar(DLLName));
|
|
if hDLL < 32 then
|
|
hDLL := 0;
|
|
if hDLL <> 0 then
|
|
begin
|
|
Result := True;
|
|
(* You must get this function explicitly
|
|
because earlier versions of the DLL's
|
|
don't implement this function.
|
|
That makes the lack of implementation
|
|
of the function a version marker in itself. *)
|
|
@pDllGetVersion := GetProcAddress(hDLL, PChar('DllGetVersion'));
|
|
if Assigned(pDllGetVersion) then
|
|
begin
|
|
FillChar(Dvi, SizeOf(Dvi), #0);
|
|
Dvi.cbSize := SizeOf(Dvi);
|
|
hr := pDllGetVersion(Dvi);
|
|
if hr = 0 then
|
|
begin
|
|
pdwMajor := Dvi.dwMajorVersion;
|
|
pdwMinor := Dvi.dwMinorVersion;
|
|
end;
|
|
end
|
|
else (* If GetProcAddress failed, the DLL is a version previous to the one shipped with IE 3.x. *)
|
|
begin
|
|
pdwMajor := 4;
|
|
pdwMinor := 0;
|
|
end;
|
|
FreeLibrary(hDLL);
|
|
Exit;
|
|
end;
|
|
Result := False;
|
|
end;
|
|
|
|
end.
|
|
|