{----------------------------------------------------------------------------- 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: [,@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: '=' 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.