{----------------------------------------------------------------------------- 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: JvVCLUtils.PAS, released on 2002-07-04. The Initial Developers of the Original Code are: Fedor Koshevnikov, Igor Pavluk and Serge Korolev Copyright (c) 1997, 1998 Fedor Koshevnikov, Igor Pavluk and Serge Korolev Copyright (c) 2001,2002 SGB Software All Rights Reserved. Last Modified: 2002-07-04 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} {$I WINDOWSONLY.INC} unit JvVCLUtils; interface uses {$IFDEF COMPILER6_UP} RTLConsts, Variants, {$ENDIF} Windows, Classes, Graphics, Forms, Controls, Dialogs; { Windows resources (bitmaps and icons) VCL-oriented routines } procedure DrawBitmapTransparent(Dest: TCanvas; DstX, DstY: Integer; Bitmap: TBitmap; TransparentColor: TColor); procedure DrawBitmapRectTransparent(Dest: TCanvas; DstX, DstY: Integer; SrcRect: TRect; Bitmap: TBitmap; TransparentColor: TColor); procedure StretchBitmapRectTransparent(Dest: TCanvas; DstX, DstY, DstW, DstH: Integer; SrcRect: TRect; Bitmap: TBitmap; TransparentColor: TColor); function MakeBitmap(ResID: PChar): TBitmap; function MakeBitmapID(ResID: Word): TBitmap; function MakeModuleBitmap(Module: THandle; ResID: PChar): TBitmap; function CreateTwoColorsBrushPattern(Color1, Color2: TColor): TBitmap; function CreateDisabledBitmap_NewStyle(FOriginal: TBitmap; BackColor: TColor): TBitmap; function CreateDisabledBitmapEx(FOriginal: TBitmap; OutlineColor, BackColor, HighlightColor, ShadowColor: TColor; DrawHighlight: Boolean): TBitmap; function CreateDisabledBitmap(FOriginal: TBitmap; OutlineColor: TColor): TBitmap; function ChangeBitmapColor(Bitmap: TBitmap; Color, NewColor: TColor): TBitmap; procedure AssignBitmapCell(Source: TGraphic; Dest: TBitmap; Cols, Rows, Index: Integer); {$IFDEF WIN32} procedure ImageListDrawDisabled(Images: TImageList; Canvas: TCanvas; X, Y, Index: Integer; HighlightColor, GrayColor: TColor; DrawHighlight: Boolean); {$ENDIF} function MakeIcon(ResID: PChar): TIcon; function MakeIconID(ResID: Word): TIcon; function MakeModuleIcon(Module: THandle; ResID: PChar): TIcon; function CreateBitmapFromIcon(Icon: TIcon; BackColor: TColor): TBitmap; {$IFDEF WIN32} function CreateIconFromBitmap(Bitmap: TBitmap; TransparentColor: TColor): TIcon; {$ENDIF} { Service routines } procedure NotImplemented; procedure ResourceNotFound(ResID: PChar); function PointInRect(const P: TPoint; const R: TRect): Boolean; function PointInPolyRgn(const P: TPoint; const Points: array of TPoint): Boolean; function PaletteColor(Color: TColor): Longint; function WidthOf(R: TRect): Integer; function HeightOf(R: TRect): Integer; procedure PaintInverseRect(const RectOrg, RectEnd: TPoint); procedure DrawInvertFrame(ScreenRect: TRect; Width: Integer); procedure CopyParentImage(Control: TControl; Dest: TCanvas); procedure Delay(MSecs: Longint); procedure CenterControl(Control: TControl); {$IFDEF WIN32} procedure ShowMDIClientEdge(ClientHandle: THandle; ShowEdge: Boolean); function MakeVariant(const Values: array of Variant): Variant; {$ENDIF} function CreateRotatedFont(Font: TFont; Angle: Integer): HFONT; function MsgBox(const Caption, Text: string; Flags: Integer): Integer; function MsgDlg(const Msg: string; AType: TMsgDlgType; AButtons: TMsgDlgButtons; HelpCtx: Longint): Word; {$IFDEF BCB} function FindPrevInstance(const MainFormClass: ShortString; const ATitle: string): HWND; function ActivatePrevInstance(const MainFormClass: ShortString; const ATitle: string): Boolean; {$ELSE} function FindPrevInstance(const MainFormClass, ATitle: string): HWND; function ActivatePrevInstance(const MainFormClass, ATitle: string): Boolean; {$ENDIF BCB} function IsForegroundTask: Boolean; procedure MergeForm(AControl: TWinControl; AForm: TForm; Align: TAlign; Show: Boolean); function GetAveCharSize(Canvas: TCanvas): TPoint; function MinimizeText(const Text: string; Canvas: TCanvas; MaxWidth: Integer): string; procedure FreeUnusedOle; procedure Beep; function GetWindowsVersion: string; function LoadDLL(const LibName: string): THandle; function RegisterServer(const ModuleName: string): Boolean; {$IFNDEF WIN32} function IsLibrary: Boolean; {$ENDIF} { Gradient filling routine } type TFillDirection = (fdTopToBottom, fdBottomToTop, fdLeftToRight, fdRightToLeft); procedure GradientFillRect(Canvas: TCanvas; ARect: TRect; StartColor, EndColor: TColor; Direction: TFillDirection; Colors: Byte); { String routines } function GetEnvVar(const VarName: string): string; function AnsiUpperFirstChar(const S: string): string; function StringToPChar(var S: string): PChar; function StrPAlloc(const S: string): PChar; procedure SplitCommandLine(const CmdLine: string; var ExeName, Params: string); function DropT(const S: string): string; { Memory routines } function AllocMemo(Size: Longint): Pointer; function ReallocMemo(fpBlock: Pointer; Size: Longint): Pointer; procedure FreeMemo(var fpBlock: Pointer); function GetMemoSize(fpBlock: Pointer): Longint; function CompareMem(fpBlock1, fpBlock2: Pointer; Size: Cardinal): Boolean; {$IFNDEF COMPILER5_UP} procedure FreeAndNil(var Obj); {$ENDIF} { Manipulate huge pointers routines } procedure HugeInc(var HugePtr: Pointer; Amount: Longint); procedure HugeDec(var HugePtr: Pointer; Amount: Longint); function HugeOffset(HugePtr: Pointer; Amount: Longint): Pointer; procedure HugeMove(Base: Pointer; Dst, Src, Size: Longint); {$IFDEF WIN32} procedure HMemCpy(DstPtr, SrcPtr: Pointer; Amount: Longint); {$ELSE} procedure ZeroMemory(Ptr: Pointer; Length: Longint); procedure FillMemory(Ptr: Pointer; Length: Longint; Fill: Byte); {$ENDIF WIN32} { Standard Windows colors that are not defined by Delphi } const {$IFNDEF WIN32} clInfoBk = TColor($02E1FFFF); clNone = TColor($02FFFFFF); {$ENDIF} clCream = TColor($A6CAF0); clMoneyGreen = TColor($C0DCC0); clSkyBlue = TColor($FFFBF0); { ModalResult constants } {$IFNDEF COMPILER3_UP} const mrNoToAll = mrAll + 1; mrYesToAll = mrNoToAll + 1; {$ENDIF} {$IFNDEF COMPILER4_UP} { Mouse Wheel message } {$IFDEF WIN32} {$IFDEF COMPILER2} const WM_MOUSEWHEEL = $020A; WHEEL_DELTA = 120; WHEEL_PAGESCROLL = MAXDWORD; SM_MOUSEWHEELPRESENT = 75; MOUSEEVENTF_WHEEL = $0800; SPI_GETWHEELSCROLLLINES = 104; SPI_SETWHEELSCROLLLINES = 105; {$ENDIF} type TWMMouseWheel = record Msg: Cardinal; Keys: Word; Delta: Word; case Integer of 0: ( XPos: Smallint; YPos: Smallint); 1: ( Pos: TSmallPoint; Result: Longint); end; {$ENDIF WIN32} {$ENDIF COMPILER4_UP} { Cursor routines } const WaitCursor: TCursor = crHourGlass; procedure StartWait; procedure StopWait; function DefineCursor(Instance: THandle; ResID: PChar): TCursor; {$IFDEF WIN32} function LoadAniCursor(Instance: THandle; ResID: PChar): HCURSOR; {$ENDIF} { Windows API level routines } procedure StretchBltTransparent(DstDC: HDC; DstX, DstY, DstW, DstH: Integer; SrcDC: HDC; SrcX, SrcY, SrcW, SrcH: Integer; Palette: HPALETTE; TransparentColor: TColorRef); procedure DrawTransparentBitmap(DC: HDC; Bitmap: HBITMAP; DstX, DstY: Integer; TransparentColor: TColorRef); function PaletteEntries(Palette: HPALETTE): Integer; function WindowClassName(Wnd: HWND): string; function ScreenWorkArea: TRect; {$IFNDEF WIN32} procedure MoveWindowOrg(DC: HDC; DX, DY: Integer); {$ENDIF} procedure SwitchToWindow(Wnd: HWND; Restore: Boolean); procedure ActivateWindow(Wnd: HWND); procedure ShowWinNoAnimate(Handle: HWND; CmdShow: Integer); procedure CenterWindow(Wnd: HWND); procedure ShadeRect(DC: HDC; const Rect: TRect); procedure KillMessage(Wnd: HWND; Msg: Cardinal); { Convert dialog units to pixels and backwards } function DialogUnitsToPixelsX(DlgUnits: Word): Word; function DialogUnitsToPixelsY(DlgUnits: Word): Word; function PixelsToDialogUnitsX(PixUnits: Word): Word; function PixelsToDialogUnitsY(PixUnits: Word): Word; { Grid drawing } type TVertAlignment = (vaTopJustify, vaCenter, vaBottomJustify); procedure WriteText(ACanvas: TCanvas; ARect: TRect; DX, DY: Integer; const Text: string; Alignment: TAlignment; WordWrap: Boolean {$IFDEF COMPILER4_UP}; ARightToLeft: Boolean = False {$ENDIF}); procedure DrawCellText(Control: TCustomControl; ACol, ARow: Longint; const S: string; const ARect: TRect; Align: TAlignment; VertAlign: TVertAlignment); {$IFDEF COMPILER4_UP} overload; {$ENDIF} procedure DrawCellTextEx(Control: TCustomControl; ACol, ARow: Longint; const S: string; const ARect: TRect; Align: TAlignment; VertAlign: TVertAlignment; WordWrap: Boolean); {$IFDEF COMPILER4_UP} overload; {$ENDIF} {$IFDEF COMPILER4_UP} procedure DrawCellText(Control: TCustomControl; ACol, ARow: Longint; const S: string; const ARect: TRect; Align: TAlignment; VertAlign: TVertAlignment; ARightToLeft: Boolean); overload; procedure DrawCellTextEx(Control: TCustomControl; ACol, ARow: Longint; const S: string; const ARect: TRect; Align: TAlignment; VertAlign: TVertAlignment; WordWrap: Boolean; ARightToLeft: Boolean); overload; {$ENDIF} procedure DrawCellBitmap(Control: TCustomControl; ACol, ARow: Longint; Bmp: TGraphic; Rect: TRect); type TJvScreenCanvas = class(TCanvas) private FDeviceContext: HDC; protected procedure CreateHandle; override; public destructor Destroy; override; procedure SetOrigin(X, Y: Integer); procedure FreeHandle; end; {$IFNDEF WIN32} TBits = class(TObject) private FSize: Integer; FBits: Pointer; procedure SetSize(Value: Integer); procedure SetBit(Index: Integer; Value: Boolean); function GetBit(Index: Integer): Boolean; public destructor Destroy; override; function OpenBit: Integer; property Bits[Index: Integer]: Boolean read GetBit write SetBit; default; property Size: Integer read FSize write SetSize; end; TMetafileCanvas = class(TCanvas) private FMetafile: TMetafile; public constructor Create(AMetafile: TMetafile; ReferenceDevice: HDC); destructor Destroy; override; property Metafile: TMetafile read FMetafile; end; TResourceStream = class(THandleStream) private FStartPos: LongInt; FEndPos: LongInt; protected constructor CreateFromPChar(Instance: THandle; ResName, ResType: PChar); public constructor Create(Instance: THandle; const ResName: string; ResType: PChar); constructor CreateFromID(Instance: THandle; ResID: Integer; ResType: PChar); destructor Destroy; override; function Seek(Offset: Longint; Origin: Word): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; end; function GetCurrentDir: string; function SetCurrentDir(const Dir: string): Boolean; {$ENDIF WIN32} {$IFDEF WIN32} function CheckWin32(OK: Boolean): Boolean; { obsolete, use Win32Check } {$IFNDEF COMPILER3_UP} function Win32Check(RetVal: Bool): Bool; {$ENDIF} procedure RaiseWin32Error(ErrorCode: DWORD); {$ENDIF WIN32} {$IFNDEF COMPILER3_UP} { for Delphi 3.0 and previous versions compatibility } type TCustomForm = TForm; TDate = TDateTime; TTime = TDateTime; function ResStr(Ident: Cardinal): string; {$ELSE} function ResStr(const Ident: string): string; {$ENDIF COMPILER3_UP} {$IFNDEF COMPILER4_UP} type Longword = Longint; {$ENDIF} implementation uses SysUtils, Messages, Consts, Math, {$IFDEF COMPILER35_UP} SysConst, {$ENDIF} {$IFDEF WIN32} CommCtrl, {$ELSE} JvStr16, {$ENDIF} JvConst, JvxRConst, JvFunctions; { Exceptions } procedure ResourceNotFound(ResID: PChar); var S: string; begin if LongRec(ResID).Hi = 0 then S := IntToStr(LongRec(ResID).Lo) else S := StrPas(ResID); raise EResNotFound.CreateFmt(ResStr(SResNotFound), [S]); end; { Bitmaps } function MakeModuleBitmap(Module: THandle; ResID: PChar): TBitmap; {$IFNDEF WIN32} var S: TStream; {$ENDIF} begin Result := TBitmap.Create; try {$IFDEF WIN32} if Module <> 0 then begin if LongRec(ResID).Hi = 0 then Result.LoadFromResourceID(Module, LongRec(ResID).Lo) else Result.LoadFromResourceName(Module, StrPas(ResID)); end else begin Result.Handle := LoadBitmap(Module, ResID); if Result.Handle = 0 then ResourceNotFound(ResID); end; {$ELSE} Result.Handle := LoadBitmap(Module, ResID); if Result.Handle = 0 then ResourceNotFound(ResID); {$ENDIF} except Result.Free; Result := nil; end; end; function MakeBitmap(ResID: PChar): TBitmap; begin Result := MakeModuleBitmap(hInstance, ResID); end; function MakeBitmapID(ResID: Word): TBitmap; begin Result := MakeModuleBitmap(hInstance, MakeIntResource(ResID)); end; procedure AssignBitmapCell(Source: TGraphic; Dest: TBitmap; Cols, Rows, Index: Integer); var CellWidth, CellHeight: Integer; begin if (Source <> nil) and (Dest <> nil) then begin if Cols <= 0 then Cols := 1; if Rows <= 0 then Rows := 1; if Index < 0 then Index := 0; CellWidth := Source.Width div Cols; CellHeight := Source.Height div Rows; with Dest do begin Width := CellWidth; Height := CellHeight; end; if Source is TBitmap then begin Dest.Canvas.CopyRect(Bounds(0, 0, CellWidth, CellHeight), TBitmap(Source).Canvas, Bounds((Index mod Cols) * CellWidth, (Index div Cols) * CellHeight, CellWidth, CellHeight)); {$IFDEF COMPILER3_UP} Dest.TransparentColor := TBitmap(Source).TransparentColor; {$ENDIF COMPILER3_UP} end else begin Dest.Canvas.Brush.Color := clSilver; Dest.Canvas.FillRect(Bounds(0, 0, CellWidth, CellHeight)); Dest.Canvas.Draw(-(Index mod Cols) * CellWidth, -(Index div Cols) * CellHeight, Source); end; {$IFDEF COMPILER3_UP} Dest.Transparent := Source.Transparent; {$ENDIF COMPILER3_UP} end; end; type TJvParentControl = class(TWinControl); procedure CopyParentImage(Control: TControl; Dest: TCanvas); var I, Count, X, Y, SaveIndex: Integer; DC: HDC; R, SelfR, CtlR: TRect; begin if (Control = nil) or (Control.Parent = nil) then Exit; Count := Control.Parent.ControlCount; DC := Dest.Handle; {$IFDEF WIN32} with Control.Parent do ControlState := ControlState + [csPaintCopy]; try {$ENDIF} with Control do begin SelfR := Bounds(Left, Top, Width, Height); X := -Left; Y := -Top; end; { Copy parent control image } SaveIndex := SaveDC(DC); try SetViewportOrgEx(DC, X, Y, nil); IntersectClipRect(DC, 0, 0, Control.Parent.ClientWidth, Control.Parent.ClientHeight); with TJvParentControl(Control.Parent) do begin Perform(WM_ERASEBKGND, DC, 0); PaintWindow(DC); end; finally RestoreDC(DC, SaveIndex); end; { Copy images of graphic controls } for I := 0 to Count - 1 do begin if Control.Parent.Controls[I] = Control then Break else if (Control.Parent.Controls[I] <> nil) and (Control.Parent.Controls[I] is TGraphicControl) then begin with TGraphicControl(Control.Parent.Controls[I]) do begin CtlR := Bounds(Left, Top, Width, Height); if Bool(IntersectRect(R, SelfR, CtlR)) and Visible then begin {$IFDEF WIN32} ControlState := ControlState + [csPaintCopy]; {$ENDIF} SaveIndex := SaveDC(DC); try SaveIndex := SaveDC(DC); SetViewportOrgEx(DC, Left + X, Top + Y, nil); IntersectClipRect(DC, 0, 0, Width, Height); Perform(WM_PAINT, DC, 0); finally RestoreDC(DC, SaveIndex); {$IFDEF WIN32} ControlState := ControlState - [csPaintCopy]; {$ENDIF} end; end; end; end; end; {$IFDEF WIN32} finally with Control.Parent do ControlState := ControlState - [csPaintCopy]; end; {$ENDIF} end; { Transparent bitmap } procedure StretchBltTransparent(DstDC: HDC; DstX, DstY, DstW, DstH: Integer; SrcDC: HDC; SrcX, SrcY, SrcW, SrcH: Integer; Palette: HPALETTE; TransparentColor: TColorRef); var Color: TColorRef; bmAndBack, bmAndObject, bmAndMem, bmSave: HBITMAP; bmBackOld, bmObjectOld, bmMemOld, bmSaveOld: HBITMAP; MemDC, BackDC, ObjectDC, SaveDC: HDC; palDst, palMem, palSave, palObj: HPALETTE; begin { Create some DCs to hold temporary data } BackDC := CreateCompatibleDC(DstDC); ObjectDC := CreateCompatibleDC(DstDC); MemDC := CreateCompatibleDC(DstDC); SaveDC := CreateCompatibleDC(DstDC); { Create a bitmap for each DC } bmAndObject := CreateBitmap(SrcW, SrcH, 1, 1, nil); bmAndBack := CreateBitmap(SrcW, SrcH, 1, 1, nil); bmAndMem := CreateCompatibleBitmap(DstDC, DstW, DstH); bmSave := CreateCompatibleBitmap(DstDC, SrcW, SrcH); { Each DC must select a bitmap object to store pixel data } bmBackOld := SelectObject(BackDC, bmAndBack); bmObjectOld := SelectObject(ObjectDC, bmAndObject); bmMemOld := SelectObject(MemDC, bmAndMem); bmSaveOld := SelectObject(SaveDC, bmSave); { Select palette } palDst := 0; palMem := 0; palSave := 0; palObj := 0; if Palette <> 0 then begin palDst := SelectPalette(DstDC, Palette, True); RealizePalette(DstDC); palSave := SelectPalette(SaveDC, Palette, False); RealizePalette(SaveDC); palObj := SelectPalette(ObjectDC, Palette, False); RealizePalette(ObjectDC); palMem := SelectPalette(MemDC, Palette, True); RealizePalette(MemDC); end; { Set proper mapping mode } SetMapMode(SrcDC, GetMapMode(DstDC)); SetMapMode(SaveDC, GetMapMode(DstDC)); { Save the bitmap sent here } BitBlt(SaveDC, 0, 0, SrcW, SrcH, SrcDC, SrcX, SrcY, SRCCOPY); { Set the background color of the source DC to the color, } { contained in the parts of the bitmap that should be transparent } Color := SetBkColor(SaveDC, PaletteColor(TransparentColor)); { Create the object mask for the bitmap by performing a BitBlt() } { from the source bitmap to a monochrome bitmap } BitBlt(ObjectDC, 0, 0, SrcW, SrcH, SaveDC, 0, 0, SRCCOPY); { Set the background color of the source DC back to the original } SetBkColor(SaveDC, Color); { Create the inverse of the object mask } BitBlt(BackDC, 0, 0, SrcW, SrcH, ObjectDC, 0, 0, NOTSRCCOPY); { Copy the background of the main DC to the destination } BitBlt(MemDC, 0, 0, DstW, DstH, DstDC, DstX, DstY, SRCCOPY); { Mask out the places where the bitmap will be placed } StretchBlt(MemDC, 0, 0, DstW, DstH, ObjectDC, 0, 0, SrcW, SrcH, SRCAND); { Mask out the transparent colored pixels on the bitmap } BitBlt(SaveDC, 0, 0, SrcW, SrcH, BackDC, 0, 0, SRCAND); { XOR the bitmap with the background on the destination DC } StretchBlt(MemDC, 0, 0, DstW, DstH, SaveDC, 0, 0, SrcW, SrcH, SRCPAINT); { Copy the destination to the screen } BitBlt(DstDC, DstX, DstY, DstW, DstH, MemDC, 0, 0, SRCCOPY); { Restore palette } if Palette <> 0 then begin SelectPalette(MemDC, palMem, False); SelectPalette(ObjectDC, palObj, False); SelectPalette(SaveDC, palSave, False); SelectPalette(DstDC, palDst, True); end; { Delete the memory bitmaps } DeleteObject(SelectObject(BackDC, bmBackOld)); DeleteObject(SelectObject(ObjectDC, bmObjectOld)); DeleteObject(SelectObject(MemDC, bmMemOld)); DeleteObject(SelectObject(SaveDC, bmSaveOld)); { Delete the memory DCs } DeleteDC(MemDC); DeleteDC(BackDC); DeleteDC(ObjectDC); DeleteDC(SaveDC); end; procedure DrawTransparentBitmapRect(DC: HDC; Bitmap: HBITMAP; DstX, DstY, DstW, DstH: Integer; SrcRect: TRect; TransparentColor: TColorRef); var hdcTemp: HDC; begin hdcTemp := CreateCompatibleDC(DC); try SelectObject(hdcTemp, Bitmap); with SrcRect do StretchBltTransparent(DC, DstX, DstY, DstW, DstH, hdcTemp, Left, Top, Right - Left, Bottom - Top, 0, TransparentColor); finally DeleteDC(hdcTemp); end; end; procedure DrawTransparentBitmap(DC: HDC; Bitmap: HBITMAP; DstX, DstY: Integer; TransparentColor: TColorRef); var BM: {$IFDEF WIN32} Windows.TBitmap {$ELSE} WinTypes.TBitmap {$ENDIF}; begin GetObject(Bitmap, SizeOf(BM), @BM); DrawTransparentBitmapRect(DC, Bitmap, DstX, DstY, BM.bmWidth, BM.bmHeight, Rect(0, 0, BM.bmWidth, BM.bmHeight), TransparentColor); end; procedure StretchBitmapTransparent(Dest: TCanvas; Bitmap: TBitmap; TransparentColor: TColor; DstX, DstY, DstW, DstH, SrcX, SrcY, SrcW, SrcH: Integer); var CanvasChanging: TNotifyEvent; begin if DstW <= 0 then DstW := Bitmap.Width; if DstH <= 0 then DstH := Bitmap.Height; if (SrcW <= 0) or (SrcH <= 0) then begin SrcX := 0; SrcY := 0; SrcW := Bitmap.Width; SrcH := Bitmap.Height; end; if not Bitmap.Monochrome then SetStretchBltMode(Dest.Handle, STRETCH_DELETESCANS); CanvasChanging := Bitmap.Canvas.OnChanging; {$IFDEF COMPILER3_UP} Bitmap.Canvas.Lock; {$ENDIF} try Bitmap.Canvas.OnChanging := nil; if TransparentColor = clNone then begin StretchBlt(Dest.Handle, DstX, DstY, DstW, DstH, Bitmap.Canvas.Handle, SrcX, SrcY, SrcW, SrcH, Dest.CopyMode); end else begin {$IFDEF COMPILER3_UP} if TransparentColor = clDefault then TransparentColor := Bitmap.Canvas.Pixels[0, Bitmap.Height - 1]; {$ENDIF} if Bitmap.Monochrome then TransparentColor := clWhite else TransparentColor := ColorToRGB(TransparentColor); StretchBltTransparent(Dest.Handle, DstX, DstY, DstW, DstH, Bitmap.Canvas.Handle, SrcX, SrcY, SrcW, SrcH, Bitmap.Palette, TransparentColor); end; finally Bitmap.Canvas.OnChanging := CanvasChanging; {$IFDEF COMPILER3_UP} Bitmap.Canvas.Unlock; {$ENDIF} end; end; procedure StretchBitmapRectTransparent(Dest: TCanvas; DstX, DstY, DstW, DstH: Integer; SrcRect: TRect; Bitmap: TBitmap; TransparentColor: TColor); begin with SrcRect do StretchBitmapTransparent(Dest, Bitmap, TransparentColor, DstX, DstY, DstW, DstH, Left, Top, Right - Left, Bottom - Top); end; procedure DrawBitmapRectTransparent(Dest: TCanvas; DstX, DstY: Integer; SrcRect: TRect; Bitmap: TBitmap; TransparentColor: TColor); begin with SrcRect do StretchBitmapTransparent(Dest, Bitmap, TransparentColor, DstX, DstY, Right - Left, Bottom - Top, Left, Top, Right - Left, Bottom - Top); end; procedure DrawBitmapTransparent(Dest: TCanvas; DstX, DstY: Integer; Bitmap: TBitmap; TransparentColor: TColor); begin StretchBitmapTransparent(Dest, Bitmap, TransparentColor, DstX, DstY, Bitmap.Width, Bitmap.Height, 0, 0, Bitmap.Width, Bitmap.Height); end; { ChangeBitmapColor. This function create new TBitmap object. You must destroy it outside by calling TBitmap.Free method. } function ChangeBitmapColor(Bitmap: TBitmap; Color, NewColor: TColor): TBitmap; var R: TRect; begin Result := TBitmap.Create; try with Result do begin Height := Bitmap.Height; Width := Bitmap.Width; R := Bounds(0, 0, Width, Height); Canvas.Brush.Color := NewColor; Canvas.FillRect(R); Canvas.BrushCopy(R, Bitmap, R, Color); end; except Result.Free; raise; end; end; { CreateDisabledBitmap. Creating TBitmap object with disable button glyph image. You must destroy it outside by calling TBitmap.Free method. } const ROP_DSPDxax = $00E20746; function CreateDisabledBitmap_NewStyle(FOriginal: TBitmap; BackColor: TColor): TBitmap; var MonoBmp: TBitmap; R: TRect; DestDC, SrcDC: HDC; begin R := Rect(0, 0, FOriginal.Width, FOriginal.Height); Result := TBitmap.Create; try Result.Width := FOriginal.Width; Result.Height := FOriginal.Height; Result.Canvas.Brush.Color := BackColor; Result.Canvas.FillRect(R); MonoBmp := TBitmap.Create; try MonoBmp.Width := FOriginal.Width; MonoBmp.Height := FOriginal.Height; MonoBmp.Canvas.Brush.Color := clWhite; MonoBmp.Canvas.FillRect(R); DrawBitmapTransparent(MonoBmp.Canvas, 0, 0, FOriginal, BackColor); MonoBmp.Monochrome := True; SrcDC := MonoBmp.Canvas.Handle; { Convert Black to clBtnHighlight } Result.Canvas.Brush.Color := clBtnHighlight; DestDC := Result.Canvas.Handle; Windows.SetTextColor(DestDC, clWhite); Windows.SetBkColor(DestDC, clBlack); BitBlt(DestDC, 1, 1, FOriginal.Width, FOriginal.Height, SrcDC, 0, 0, ROP_DSPDxax); { Convert Black to clBtnShadow } Result.Canvas.Brush.Color := clBtnShadow; DestDC := Result.Canvas.Handle; Windows.SetTextColor(DestDC, clWhite); Windows.SetBkColor(DestDC, clBlack); BitBlt(DestDC, 0, 0, FOriginal.Width, FOriginal.Height, SrcDC, 0, 0, ROP_DSPDxax); finally MonoBmp.Free; end; except Result.Free; raise; end; end; function CreateDisabledBitmapEx(FOriginal: TBitmap; OutlineColor, BackColor, HighlightColor, ShadowColor: TColor; DrawHighlight: Boolean): TBitmap; var MonoBmp: TBitmap; IRect: TRect; begin IRect := Rect(0, 0, FOriginal.Width, FOriginal.Height); Result := TBitmap.Create; try Result.Width := FOriginal.Width; Result.Height := FOriginal.Height; MonoBmp := TBitmap.Create; try with MonoBmp do begin Width := FOriginal.Width; Height := FOriginal.Height; Canvas.CopyRect(IRect, FOriginal.Canvas, IRect); {$IFDEF COMPILER3_UP} HandleType := bmDDB; {$ENDIF} Canvas.Brush.Color := OutlineColor; if Monochrome then begin Canvas.Font.Color := clWhite; Monochrome := False; Canvas.Brush.Color := clWhite; end; Monochrome := True; end; with Result.Canvas do begin Brush.Color := BackColor; FillRect(IRect); if DrawHighlight then begin Brush.Color := HighlightColor; SetTextColor(Handle, clBlack); SetBkColor(Handle, clWhite); BitBlt(Handle, 1, 1, WidthOf(IRect), HeightOf(IRect), MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax); end; Brush.Color := ShadowColor; SetTextColor(Handle, clBlack); SetBkColor(Handle, clWhite); BitBlt(Handle, 0, 0, WidthOf(IRect), HeightOf(IRect), MonoBmp.Canvas.Handle, 0, 0, ROP_DSPDxax); end; finally MonoBmp.Free; end; except Result.Free; raise; end; end; function CreateDisabledBitmap(FOriginal: TBitmap; OutlineColor: TColor): TBitmap; begin Result := CreateDisabledBitmapEx(FOriginal, OutlineColor, clBtnFace, clBtnHighlight, clBtnShadow, True); end; {$IFDEF WIN32} procedure ImageListDrawDisabled(Images: TImageList; Canvas: TCanvas; X, Y, Index: Integer; HighlightColor, GrayColor: TColor; DrawHighlight: Boolean); var Bmp: TBitmap; SaveColor: TColor; begin SaveColor := Canvas.Brush.Color; Bmp := TBitmap.Create; try Bmp.Width := Images.Width; Bmp.Height := Images.Height; with Bmp.Canvas do begin Brush.Color := clWhite; FillRect(Rect(0, 0, Images.Width, Images.Height)); ImageList_Draw(Images.Handle, Index, Handle, 0, 0, ILD_MASK); end; Bmp.Monochrome := True; if DrawHighlight then begin Canvas.Brush.Color := HighlightColor; SetTextColor(Canvas.Handle, clWhite); SetBkColor(Canvas.Handle, clBlack); BitBlt(Canvas.Handle, X + 1, Y + 1, Images.Width, Images.Height, Bmp.Canvas.Handle, 0, 0, ROP_DSPDxax); end; Canvas.Brush.Color := GrayColor; SetTextColor(Canvas.Handle, clWhite); SetBkColor(Canvas.Handle, clBlack); BitBlt(Canvas.Handle, X, Y, Images.Width, Images.Height, Bmp.Canvas.Handle, 0, 0, ROP_DSPDxax); finally Bmp.Free; Canvas.Brush.Color := SaveColor; end; end; {$ENDIF} { Brush Pattern } function CreateTwoColorsBrushPattern(Color1, Color2: TColor): TBitmap; var X, Y: Integer; begin Result := TBitmap.Create; Result.Width := 8; Result.Height := 8; with Result.Canvas do begin Brush.Style := bsSolid; Brush.Color := Color1; FillRect(Rect(0, 0, Result.Width, Result.Height)); for Y := 0 to 7 do for X := 0 to 7 do if (Y mod 2) = (X mod 2) then { toggles between even/odd pixles } Pixels[X, Y] := Color2; { on even/odd rows } end; end; { Icons } function MakeIcon(ResID: PChar): TIcon; begin Result := MakeModuleIcon(hInstance, ResID); end; function MakeIconID(ResID: Word): TIcon; begin Result := MakeModuleIcon(hInstance, MakeIntResource(ResID)); end; function MakeModuleIcon(Module: THandle; ResID: PChar): TIcon; begin Result := TIcon.Create; Result.Handle := LoadIcon(Module, ResID); if Result.Handle = 0 then begin Result.Free; Result := nil; end; end; { Create TBitmap object from TIcon } function CreateBitmapFromIcon(Icon: TIcon; BackColor: TColor): TBitmap; var IWidth, IHeight: Integer; begin IWidth := Icon.Width; IHeight := Icon.Height; Result := TBitmap.Create; try Result.Width := IWidth; Result.Height := IHeight; with Result.Canvas do begin Brush.Color := BackColor; FillRect(Rect(0, 0, IWidth, IHeight)); Draw(0, 0, Icon); end; {$IFDEF COMPILER3_UP} Result.TransparentColor := BackColor; Result.Transparent := True; {$ENDIF} except Result.Free; raise; end; end; {$IFDEF WIN32} function CreateIconFromBitmap(Bitmap: TBitmap; TransparentColor: TColor): TIcon; begin with TImageList.CreateSize(Bitmap.Width, Bitmap.Height) do try {$IFDEF COMPILER3_UP} if TransparentColor = clDefault then TransparentColor := Bitmap.TransparentColor; {$ENDIF} AllocBy := 1; AddMasked(Bitmap, TransparentColor); Result := TIcon.Create; try GetIcon(0, Result); except Result.Free; raise; end; finally Free; end; end; {$ENDIF WIN32} { Dialog units } function DialogUnitsToPixelsX(DlgUnits: Word): Word; begin Result := (DlgUnits * LoWord(GetDialogBaseUnits)) div 4; end; function DialogUnitsToPixelsY(DlgUnits: Word): Word; begin Result := (DlgUnits * HiWord(GetDialogBaseUnits)) div 8; end; function PixelsToDialogUnitsX(PixUnits: Word): Word; begin Result := PixUnits * 4 div LoWord(GetDialogBaseUnits); end; function PixelsToDialogUnitsY(PixUnits: Word): Word; begin Result := PixUnits * 8 div HiWord(GetDialogBaseUnits); end; { Service routines } type TJvHack = class(TCustomControl); function LoadDLL(const LibName: string): THandle; var ErrMode: Cardinal; {$IFNDEF WIN32} P: array [0..255] of Char; {$ENDIF} begin ErrMode := SetErrorMode(SEM_NOOPENFILEERRORBOX); {$IFDEF WIN32} Result := LoadLibrary(PChar(LibName)); {$ELSE} Result := LoadLibrary(StrPCopy(P, LibName)); {$ENDIF} SetErrorMode(ErrMode); if Result < HINSTANCE_ERROR then {$IFDEF WIN32} OSCheck(False); {$ELSE} raise EOutOfResources.CreateResFmt(SLoadLibError, [LibName]); {$ENDIF} end; function RegisterServer(const ModuleName: string): Boolean; { RegisterServer procedure written by Vladimir Gaitanoff, 2:50/430.2 } type TProc = procedure; var Handle: THandle; DllRegServ: Pointer; begin Result := False; Handle := LoadDLL(ModuleName); try DllRegServ := GetProcAddress(Handle, 'DllRegisterServer'); if Assigned(DllRegServ) then begin TProc(DllRegServ); Result := True; end; finally FreeLibrary(Handle); end; end; procedure Beep; begin MessageBeep(0); end; procedure FreeUnusedOle; begin {$IFDEF WIN32} FreeLibrary(GetModuleHandle('OleAut32')); {$ENDIF} end; procedure NotImplemented; begin Screen.Cursor := crDefault; MessageDlg(SNotImplemented, mtInformation, [mbOk], 0); Abort; end; {$IFNDEF WIN32} procedure MoveWindowOrg(DC: HDC; DX, DY: Integer); var P: TPoint; begin GetWindowOrgEx(DC, @P); SetWindowOrgEx(DC, P.X - DX, P.Y - DY, nil); end; function IsLibrary: Boolean; begin Result := (PrefixSeg = 0); end; {$ENDIF WIN32} procedure PaintInverseRect(const RectOrg, RectEnd: TPoint); var DC: HDC; R: TRect; begin DC := GetDC(0); try R := Rect(RectOrg.X, RectOrg.Y, RectEnd.X, RectEnd.Y); InvertRect(DC, R); finally ReleaseDC(0, DC); end; end; procedure DrawInvertFrame(ScreenRect: TRect; Width: Integer); var DC: HDC; I: Integer; begin DC := GetDC(0); try for I := 1 to Width do begin DrawFocusRect(DC, ScreenRect); InflateRect(ScreenRect, -1, -1); end; finally ReleaseDC(0, DC); end; end; function WidthOf(R: TRect): Integer; begin Result := R.Right - R.Left; end; function HeightOf(R: TRect): Integer; begin Result := R.Bottom - R.Top; end; function PointInRect(const P: TPoint; const R: TRect): Boolean; begin with R do Result := (Left <= P.X) and (Top <= P.Y) and (Right >= P.X) and (Bottom >= P.Y); end; function PointInPolyRgn(const P: TPoint; const Points: array of TPoint): Boolean; type PPoints = ^TPoints; TPoints = array [0..0] of TPoint; var Rgn: HRGN; begin Rgn := CreatePolygonRgn(PPoints(@Points)^, High(Points) + 1, WINDING); try Result := PtInRegion(Rgn, P.X, P.Y); finally DeleteObject(Rgn); end; end; function PaletteColor(Color: TColor): Longint; begin Result := ColorToRGB(Color) or PaletteMask; end; procedure KillMessage(Wnd: HWND; Msg: Cardinal); { Delete the requested message from the queue, but throw back } { any WM_QUIT msgs that PeekMessage may also return. } { Copied from DbGrid.pas } var M: TMsg; begin M.Message := 0; if PeekMessage(M, Wnd, Msg, Msg, PM_REMOVE) and (M.Message = WM_QUIT) then PostQuitMessage(M.WParam); end; function CreateRotatedFont(Font: TFont; Angle: Integer): HFONT; var LogFont: TLogFont; begin FillChar(LogFont, SizeOf(LogFont), 0); with LogFont do begin lfHeight := Font.Height; lfWidth := 0; lfEscapement := Angle * 10; lfOrientation := 0; if fsBold in Font.Style then lfWeight := FW_BOLD else lfWeight := FW_NORMAL; lfItalic := Ord(fsItalic in Font.Style); lfUnderline := Ord(fsUnderline in Font.Style); lfStrikeOut := Byte(fsStrikeOut in Font.Style); {$IFDEF COMPILER3_UP} lfCharSet := Byte(Font.Charset); if AnsiCompareText(Font.Name, 'Default') = 0 then StrPCopy(lfFaceName, DefFontData.Name) else StrPCopy(lfFaceName, Font.Name); {$ELSE} {$IFDEF BCB1} lfCharSet := Byte(Font.Charset); {$ELSE} lfCharSet := DEFAULT_CHARSET; {$ENDIF} StrPCopy(lfFaceName, Font.Name); {$ENDIF} lfQuality := DEFAULT_QUALITY; lfOutPrecision := OUT_TT_PRECIS; lfClipPrecision := CLIP_DEFAULT_PRECIS; case Font.Pitch of fpVariable: lfPitchAndFamily := VARIABLE_PITCH; fpFixed: lfPitchAndFamily := FIXED_PITCH; else lfPitchAndFamily := DEFAULT_PITCH; end; end; Result := CreateFontIndirect(LogFont); end; procedure Delay(MSecs: Longint); var FirstTickCount, Now: Longint; begin FirstTickCount := GetTickCount; repeat Application.ProcessMessages; { allowing access to other controls, etc. } Now := GetTickCount; until (Now - FirstTickCount >= MSecs) or (Now < FirstTickCount); end; function PaletteEntries(Palette: HPALETTE): Integer; begin GetObject(Palette, SizeOf(Integer), @Result); end; procedure CenterControl(Control: TControl); var X, Y: Integer; begin X := Control.Left; Y := Control.Top; if Control is TForm then begin with Control do begin if (TForm(Control).FormStyle = fsMDIChild) and (Application.MainForm <> nil) then begin X := (Application.MainForm.ClientWidth - Width) div 2; Y := (Application.MainForm.ClientHeight - Height) div 2; end else begin X := (Screen.Width - Width) div 2; Y := (Screen.Height - Height) div 2; end; end; end else if Control.Parent <> nil then begin with Control do begin Parent.HandleNeeded; X := (Parent.ClientWidth - Width) div 2; Y := (Parent.ClientHeight - Height) div 2; end; end; if X < 0 then X := 0; if Y < 0 then Y := 0; with Control do SetBounds(X, Y, Width, Height); end; procedure FitRectToScreen(var Rect: TRect); var X, Y, Delta: Integer; begin X := GetSystemMetrics(SM_CXSCREEN); Y := GetSystemMetrics(SM_CYSCREEN); with Rect do begin if Right > X then begin Delta := Right - Left; Right := X; Left := Right - Delta; end; if Left < 0 then begin Delta := Right - Left; Left := 0; Right := Left + Delta; end; if Bottom > Y then begin Delta := Bottom - Top; Bottom := Y; Top := Bottom - Delta; end; if Top < 0 then begin Delta := Bottom - Top; Top := 0; Bottom := Top + Delta; end; end; end; procedure CenterWindow(Wnd: HWND); var R: TRect; begin GetWindowRect(Wnd, R); R := Rect((GetSystemMetrics(SM_CXSCREEN) - R.Right + R.Left) div 2, (GetSystemMetrics(SM_CYSCREEN) - R.Bottom + R.Top) div 2, R.Right - R.Left, R.Bottom - R.Top); FitRectToScreen(R); SetWindowPos(Wnd, 0, R.Left, R.Top, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER); end; procedure MergeForm(AControl: TWinControl; AForm: TForm; Align: TAlign; Show: Boolean); var R: TRect; AutoScroll: Boolean; begin AutoScroll := AForm.AutoScroll; AForm.Hide; TJvHack(AForm).DestroyHandle; with AForm do begin BorderStyle := bsNone; BorderIcons := []; Parent := AControl; end; AControl.DisableAlign; try if Align <> alNone then AForm.Align := Align else begin R := AControl.ClientRect; AForm.SetBounds(R.Left + AForm.Left, R.Top + AForm.Top, AForm.Width, AForm.Height); end; AForm.AutoScroll := AutoScroll; AForm.Visible := Show; finally AControl.EnableAlign; end; end; {$IFDEF WIN32} { ShowMDIClientEdge function has been copied from Inprise's FORMS.PAS unit, Delphi 4 version } procedure ShowMDIClientEdge(ClientHandle: THandle; ShowEdge: Boolean); var Style: Longint; begin if ClientHandle <> 0 then begin Style := GetWindowLong(ClientHandle, GWL_EXSTYLE); if ShowEdge then if Style and WS_EX_CLIENTEDGE = 0 then Style := Style or WS_EX_CLIENTEDGE else Exit else if Style and WS_EX_CLIENTEDGE <> 0 then Style := Style and not WS_EX_CLIENTEDGE else Exit; SetWindowLong(ClientHandle, GWL_EXSTYLE, Style); SetWindowPos(ClientHandle, 0, 0, 0, 0, 0, SWP_FRAMECHANGED or SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER); end; end; function MakeVariant(const Values: array of Variant): Variant; begin if High(Values) - Low(Values) > 1 then Result := VarArrayOf(Values) else if High(Values) - Low(Values) = 1 then Result := Values[Low(Values)] else Result := Null; end; {$ENDIF WIN32} { Shade rectangle } procedure ShadeRect(DC: HDC; const Rect: TRect); const HatchBits: array [0..7] of Word = ($11, $22, $44, $88, $11, $22, $44, $88); var Bitmap: HBITMAP; SaveBrush: HBrush; SaveTextColor, SaveBkColor: TColorRef; begin Bitmap := CreateBitmap(8, 8, 1, 1, @HatchBits); SaveBrush := SelectObject(DC, CreatePatternBrush(Bitmap)); try SaveTextColor := SetTextColor(DC, clWhite); SaveBkColor := SetBkColor(DC, clBlack); with Rect do PatBlt(DC, Left, Top, Right - Left, Bottom - Top, $00A000C9); SetBkColor(DC, SaveBkColor); SetTextColor(DC, SaveTextColor); finally DeleteObject(SelectObject(DC, SaveBrush)); DeleteObject(Bitmap); end; end; function ScreenWorkArea: TRect; {$IFNDEF WIN32} const SPI_GETWORKAREA = 48; {$ENDIF} begin if not SystemParametersInfo(SPI_GETWORKAREA, 0, @Result, 0) then with Screen do Result := Bounds(0, 0, Width, Height); end; function WindowClassName(Wnd: HWND): string; var Buffer: array [0..255] of Char; begin SetString(Result, Buffer, GetClassName(Wnd, Buffer, SizeOf(Buffer) - 1)); end; {$IFDEF WIN32} function GetAnimation: Boolean; var Info: TAnimationInfo; begin Info.cbSize := SizeOf(TAnimationInfo); if SystemParametersInfo(SPI_GETANIMATION, SizeOf(Info), @Info, 0) then {$IFDEF COMPILER3_UP} Result := Info.iMinAnimate <> 0 {$ELSE} Result := Info.iMinAnimate {$ENDIF} else Result := False; end; procedure SetAnimation(Value: Boolean); var Info: TAnimationInfo; begin Info.cbSize := SizeOf(TAnimationInfo); BOOL(Info.iMinAnimate) := Value; SystemParametersInfo(SPI_SETANIMATION, SizeOf(Info), @Info, 0); end; procedure ShowWinNoAnimate(Handle: HWND; CmdShow: Integer); var Animation: Boolean; begin Animation := GetAnimation; if Animation then SetAnimation(False); ShowWindow(Handle, CmdShow); if Animation then SetAnimation(True); end; {$ELSE} procedure ShowWinNoAnimate(Handle: HWND; CmdShow: Integer); begin ShowWindow(Handle, CmdShow); end; procedure SwitchToThisWindow(Wnd: HWND; Restore: Bool); far; external 'USER' index 172; {$ENDIF WIN32} procedure SwitchToWindow(Wnd: HWND; Restore: Boolean); begin if IsWindowEnabled(Wnd) then begin {$IFDEF WIN32} SetForegroundWindow(Wnd); if Restore and IsWindowVisible(Wnd) then begin if not IsZoomed(Wnd) then SendMessage(Wnd, WM_SYSCOMMAND, SC_RESTORE, 0); SetFocus(Wnd); end; {$ELSE} SwitchToThisWindow(Wnd, Restore); {$ENDIF} end; end; function GetWindowParent(Wnd: HWND): HWND; begin {$IFDEF WIN32} Result := GetWindowLong(Wnd, GWL_HWNDPARENT); {$ELSE} Result := GetWindowWord(Wnd, GWW_HWNDPARENT); {$ENDIF} end; procedure ActivateWindow(Wnd: HWND); begin if Wnd <> 0 then begin ShowWinNoAnimate(Wnd, SW_SHOW); {$IFDEF WIN32} SetForegroundWindow(Wnd); {$ELSE} SwitchToThisWindow(Wnd, True); {$ENDIF} end; end; {$IFDEF BCB} function FindPrevInstance(const MainFormClass: ShortString; const ATitle: string): HWND; {$ELSE} function FindPrevInstance(const MainFormClass, ATitle: string): HWND; {$ENDIF BCB} var BufClass, BufTitle: PChar; begin Result := 0; if (MainFormClass = '') and (ATitle = '') then Exit; BufClass := nil; BufTitle := nil; if (MainFormClass <> '') then BufClass := StrPAlloc(MainFormClass); if (ATitle <> '') then BufTitle := StrPAlloc(ATitle); try Result := FindWindow(BufClass, BufTitle); finally StrDispose(BufTitle); StrDispose(BufClass); end; end; {$IFDEF WIN32} function WindowsEnum(Handle: HWND; Param: Longint): Bool; export; stdcall; begin if WindowClassName(Handle) = 'TAppBuilder' then begin Result := False; PLongint(Param)^ := 1; end else Result := True; end; {$ENDIF} {$IFDEF BCB} function ActivatePrevInstance(const MainFormClass: ShortString; const ATitle: string): Boolean; {$ELSE} function ActivatePrevInstance(const MainFormClass, ATitle: string): Boolean; {$ENDIF BCB} var PrevWnd, PopupWnd, ParentWnd: HWND; {$IFDEF WIN32} IsDelphi: Longint; {$ELSE} S: array [0..255] of Char; {$ENDIF} begin Result := False; PrevWnd := FindPrevInstance(MainFormClass, ATitle); if PrevWnd <> 0 then begin ParentWnd := GetWindowParent(PrevWnd); while (ParentWnd <> GetDesktopWindow) and (ParentWnd <> 0) do begin PrevWnd := ParentWnd; ParentWnd := GetWindowParent(PrevWnd); end; if WindowClassName(PrevWnd) = 'TApplication' then begin {$IFDEF WIN32} IsDelphi := 0; EnumThreadWindows(GetWindowTask(PrevWnd), @WindowsEnum, LPARAM(@IsDelphi)); if Boolean(IsDelphi) then Exit; {$ELSE} GetModuleFileName(GetWindowTask(PrevWnd), S, SizeOf(S) - 1); if AnsiUpperCase(ExtractFileName(StrPas(S))) = 'DELPHI.EXE' then Exit; {$ENDIF} if IsIconic(PrevWnd) then begin { application is minimized } SendMessage(PrevWnd, WM_SYSCOMMAND, SC_RESTORE, 0); Result := True; Exit; end else ShowWinNoAnimate(PrevWnd, SW_SHOWNOACTIVATE); end else ActivateWindow(PrevWnd); PopupWnd := GetLastActivePopup(PrevWnd); if (PrevWnd <> PopupWnd) and IsWindowVisible(PopupWnd) and IsWindowEnabled(PopupWnd) then begin {$IFDEF WIN32} SetForegroundWindow(PopupWnd); {$ELSE} BringWindowToTop(PopupWnd); {$ENDIF} end else ActivateWindow(PopupWnd); Result := True; end; end; { Standard Windows MessageBox function } function MsgBox(const Caption, Text: string; Flags: Integer): Integer; begin Result := Application.MessageBox(PChar(Text), PChar(Caption), Flags); end; function MsgDlg(const Msg: string; AType: TMsgDlgType; AButtons: TMsgDlgButtons; HelpCtx: Longint): Word; begin Result := MessageDlg(Msg, AType, AButtons, HelpCtx); end; { Gradient fill procedure - displays a gradient beginning with a chosen } { color and ending with another chosen color. Based on TGradientFill } { component source code written by Curtis White, cwhite@teleport.com. } procedure GradientFillRect(Canvas: TCanvas; ARect: TRect; StartColor, EndColor: TColor; Direction: TFillDirection; Colors: Byte); var StartRGB: array [0..2] of Byte; { Start RGB values } RGBDelta: array [0..2] of Integer; { Difference between start and end RGB values } ColorBand: TRect; { Color band rectangular coordinates } I, Delta: Integer; Brush: HBrush; begin if IsRectEmpty(ARect) then Exit; if Colors < 2 then begin Brush := CreateSolidBrush(ColorToRGB(StartColor)); FillRect(Canvas.Handle, ARect, Brush); DeleteObject(Brush); Exit; end; StartColor := ColorToRGB(StartColor); EndColor := ColorToRGB(EndColor); case Direction of fdTopToBottom, fdLeftToRight: begin { Set the Red, Green and Blue colors } StartRGB[0] := GetRValue(StartColor); StartRGB[1] := GetGValue(StartColor); StartRGB[2] := GetBValue(StartColor); { Calculate the difference between begin and end RGB values } RGBDelta[0] := GetRValue(EndColor) - StartRGB[0]; RGBDelta[1] := GetGValue(EndColor) - StartRGB[1]; RGBDelta[2] := GetBValue(EndColor) - StartRGB[2]; end; fdBottomToTop, fdRightToLeft: begin { Set the Red, Green and Blue colors } { Reverse of TopToBottom and LeftToRight directions } StartRGB[0] := GetRValue(EndColor); StartRGB[1] := GetGValue(EndColor); StartRGB[2] := GetBValue(EndColor); { Calculate the difference between begin and end RGB values } { Reverse of TopToBottom and LeftToRight directions } RGBDelta[0] := GetRValue(StartColor) - StartRGB[0]; RGBDelta[1] := GetGValue(StartColor) - StartRGB[1]; RGBDelta[2] := GetBValue(StartColor) - StartRGB[2]; end; end; { Calculate the color band's coordinates } ColorBand := ARect; if Direction in [fdTopToBottom, fdBottomToTop] then begin Colors := Max(2, Min(Colors, HeightOf(ARect))); Delta := HeightOf(ARect) div Colors; end else begin Colors := Max(2, Min(Colors, WidthOf(ARect))); Delta := WidthOf(ARect) div Colors; end; with Canvas.Pen do begin { Set the pen style and mode } Style := psSolid; Mode := pmCopy; end; { Perform the fill } if Delta > 0 then begin for I := 0 to Colors do begin case Direction of { Calculate the color band's top and bottom coordinates } fdTopToBottom, fdBottomToTop: begin ColorBand.Top := ARect.Top + I * Delta; ColorBand.Bottom := ColorBand.Top + Delta; end; { Calculate the color band's left and right coordinates } fdLeftToRight, fdRightToLeft: begin ColorBand.Left := ARect.Left + I * Delta; ColorBand.Right := ColorBand.Left + Delta; end; end; { Calculate the color band's color } Brush := CreateSolidBrush(RGB( StartRGB[0] + MulDiv(I, RGBDelta[0], Colors - 1), StartRGB[1] + MulDiv(I, RGBDelta[1], Colors - 1), StartRGB[2] + MulDiv(I, RGBDelta[2], Colors - 1))); FillRect(Canvas.Handle, ColorBand, Brush); DeleteObject(Brush); end; end; if Direction in [fdTopToBottom, fdBottomToTop] then Delta := HeightOf(ARect) mod Colors else Delta := WidthOf(ARect) mod Colors; if Delta > 0 then begin case Direction of { Calculate the color band's top and bottom coordinates } fdTopToBottom, fdBottomToTop: begin ColorBand.Top := ARect.Bottom - Delta; ColorBand.Bottom := ColorBand.Top + Delta; end; { Calculate the color band's left and right coordinates } fdLeftToRight, fdRightToLeft: begin ColorBand.Left := ARect.Right - Delta; ColorBand.Right := ColorBand.Left + Delta; end; end; case Direction of fdTopToBottom, fdLeftToRight: Brush := CreateSolidBrush(EndColor); else {fdBottomToTop, fdRightToLeft } Brush := CreateSolidBrush(StartColor); end; FillRect(Canvas.Handle, ColorBand, Brush); DeleteObject(Brush); end; end; function MinimizeText(const Text: string; Canvas: TCanvas; MaxWidth: Integer): string; var I: Integer; begin Result := Text; I := 1; while (I <= Length(Text)) and (Canvas.TextWidth(Result) > MaxWidth) do begin Inc(I); Result := Copy(Text, 1, Max(0, Length(Text) - I)) + '...'; end; end; function GetAveCharSize(Canvas: TCanvas): TPoint; var I: Integer; Buffer: array [0..51] of Char; begin for I := 0 to 25 do Buffer[I] := Chr(I + Ord('A')); for I := 0 to 25 do Buffer[I + 26] := Chr(I + Ord('a')); GetTextExtentPoint(Canvas.Handle, Buffer, 52, TSize(Result)); Result.X := Result.X div 52; end; { Memory routines } function AllocMemo(Size: Longint): Pointer; begin if Size > 0 then Result := GlobalAllocPtr(HeapAllocFlags or GMEM_ZEROINIT, Size) else Result := nil; end; function ReallocMemo(fpBlock: Pointer; Size: Longint): Pointer; begin Result := GlobalReallocPtr(fpBlock, Size, HeapAllocFlags or GMEM_ZEROINIT); end; procedure FreeMemo(var fpBlock: Pointer); begin if fpBlock <> nil then begin GlobalFreePtr(fpBlock); fpBlock := nil; end; end; function GetMemoSize(fpBlock: Pointer): Longint; var hMem: THandle; begin Result := 0; if fpBlock <> nil then begin {$IFDEF WIN32} hMem := GlobalHandle(fpBlock); {$ELSE} hMem := LoWord(GlobalHandle(SelectorOf(fpBlock))); {$ENDIF} if hMem <> 0 then Result := GlobalSize(hMem); end; end; function CompareMem(fpBlock1, fpBlock2: Pointer; Size: Cardinal): Boolean; assembler; asm {$IFDEF WIN32} PUSH ESI PUSH EDI MOV ESI,fpBlock1 MOV EDI,fpBlock2 MOV ECX,Size MOV EDX,ECX XOR EAX,EAX AND EDX,3 SHR ECX,2 REPE CMPSD JNE @@2 MOV ECX,EDX REPE CMPSB JNE @@2 @@1: INC EAX @@2: POP EDI POP ESI {$ELSE} PUSH DS LDS SI,fpBlock1 LES DI,fpBlock2 MOV CX,Size XOR AX,AX CLD REPE CMPSB JNE @@1 INC AX @@1: POP DS {$ENDIF} end; {$IFNDEF COMPILER5_UP} procedure FreeAndNil(var Obj); var P: TObject; begin P := TObject(Obj); TObject(Obj) := nil; P.Free; end; {$ENDIF} { Manipulate huge pointers routines by Ray Lischner, The Waite Group, Inc. } {$IFDEF WIN32} procedure HugeInc(var HugePtr: Pointer; Amount: Longint); begin HugePtr := PChar(HugePtr) + Amount; end; procedure HugeDec(var HugePtr: Pointer; Amount: Longint); begin HugePtr := PChar(HugePtr) - Amount; end; function HugeOffset(HugePtr: Pointer; Amount: Longint): Pointer; begin Result := PChar(HugePtr) + Amount; end; procedure HMemCpy(DstPtr, SrcPtr: Pointer; Amount: Longint); begin Move(SrcPtr^, DstPtr^, Amount); end; procedure HugeMove(Base: Pointer; Dst, Src, Size: Longint); var SrcPtr, DstPtr: PChar; begin SrcPtr := PChar(Base) + Src * SizeOf(Pointer); DstPtr := PChar(Base) + Dst * SizeOf(Pointer); Move(SrcPtr^, DstPtr^, Size * SizeOf(Pointer)); end; {$ELSE} procedure __AHSHIFT; far; external 'KERNEL' index 113; { Increment a huge pointer } procedure HugeInc(var HugePtr: Pointer; Amount: Longint); assembler; asm MOV AX,Amount.Word[0] MOV DX,Amount.Word[2] LES BX,HugePtr ADD AX,ES:[BX] ADC DX,0 MOV CX,Offset __AHSHIFT SHL DX,CL ADD ES:[BX+2],DX MOV ES:[BX],AX end; { Decrement a huge pointer } procedure HugeDec(var HugePtr: Pointer; Amount: Longint); assembler; asm LES BX,HugePtr MOV AX,ES:[BX] SUB AX,Amount.Word[0] MOV DX,Amount.Word[2] ADC DX,0 MOV CX,OFFSET __AHSHIFT SHL DX,CL SUB ES:[BX+2],DX MOV ES:[BX],AX end; { ADD an offset to a huge pointer and return the result } function HugeOffset(HugePtr: Pointer; Amount: Longint): Pointer; assembler; asm MOV AX,Amount.Word[0] MOV DX,Amount.Word[2] ADD AX,HugePtr.Word[0] ADC DX,0 MOV CX,OFFSET __AHSHIFT SHL DX,CL ADD DX,HugePtr.Word[2] end; { When setting the Count, one might add many new items, which must be set to zero at one time, to initialize all items to nil. You could use FillChar, which fills by bytes, but, as DoMove is to Move, ZeroBytes is to FillChar, except that it always fill with zero valued words } procedure FillWords(DstPtr: Pointer; Size: Word; Fill: Word); assembler; asm MOV AX,Fill LES DI,DstPtr MOV CX,Size.Word[0] CLD REP STOSW end; { Fill Length bytes of memory with Fill, starting at Ptr. This is just like the procedure in the Win32 API. The memory can be larger than 64K and can cross segment boundaries } procedure FillMemory(Ptr: Pointer; Length: Longint; Fill: Byte); var NBytes: Cardinal; NWords: Cardinal; FillWord: Word; begin WordRec(FillWord).Hi := Fill; WordRec(FillWord).Lo := Fill; while Length > 1 do begin { Determine the number of bytes remaining in the segment } if Ofs(Ptr^) = 0 then NBytes := $FFFE else NBytes := $10000 - Ofs(Ptr^); if NBytes > Length then NBytes := Length; { Filling by words is faster than filling by bytes } NWords := NBytes div 2; FillWords(Ptr, NWords, FillWord); NBytes := NWords * 2; Dec(Length, NBytes); Ptr := HugeOffset(Ptr, NBytes); end; { If the fill size is odd, then fill the remaining byte } if Length > 0 then PByte(Ptr)^ := Fill; end; procedure ZeroMemory(Ptr: Pointer; Length: Longint); begin FillMemory(Ptr, Length, 0); end; // (rom) Ouch. so old DelForExp failed to format the indents procedure cld; inline($FC); procedure std; inline($FD); function ComputeDownMoveSize(SrcOffset, DstOffset: Word): Word; begin if SrcOffset > DstOffset then Result := Word($10000 - SrcOffset) div 2 else Result := Word($10000 - DstOffset) div 2; if Result = 0 then Result := $7FFF; end; function ComputeUpMoveSize(SrcOffset, DstOffset: Word): Word; begin if SrcOffset = $FFFF then Result := DstOffset div 2 else if DstOffset = $FFFF then Result := SrcOffset div 2 else if SrcOffset > DstOffset then Result := DstOffset div 2 + 1 else Result := SrcOffset div 2 + 1; end; procedure MoveWords(SrcPtr, DstPtr: Pointer; Size: Word); assembler; asm PUSH DS LDS SI,SrcPtr LES DI,DstPtr MOV CX,Size.Word[0] REP MOVSW POP DS end; procedure HugeMove(Base: Pointer; Dst, Src, Size: Longint); var SrcPtr, DstPtr: Pointer; MoveSize: Word; begin SrcPtr := HugeOffset(Base, Src * SizeOf(Pointer)); DstPtr := HugeOffset(Base, Dst * SizeOf(Pointer)); { Convert longword size to words } Size := Size * (SizeOf(Longint) div SizeOf(Word)); if Src < Dst then begin { Start from the far end and work toward the front } std; HugeInc(SrcPtr, (Size - 1) * SizeOf(Word)); HugeInc(DstPtr, (Size - 1) * SizeOf(Word)); while Size > 0 do begin { Compute how many bytes to move in the current segment } MoveSize := ComputeUpMoveSize(Word(SrcPtr), Word(DstPtr)); if MoveSize > Size then MoveSize := Word(Size); { Move the bytes } MoveWords(SrcPtr, DstPtr, MoveSize); { Update the number of bytes left to move } Dec(Size, MoveSize); { Update the pointers } HugeDec(SrcPtr, MoveSize * SizeOf(Word)); HugeDec(DstPtr, MoveSize * SizeOf(Word)); end; cld; { reset the direction flag } end else begin { Start from the beginning and work toward the end } cld; while Size > 0 do begin { Compute how many bytes to move in the current segment } MoveSize := ComputeDownMoveSize(Word(SrcPtr), Word(DstPtr)); if MoveSize > Size then MoveSize := Word(Size); { Move the bytes } MoveWords(SrcPtr, DstPtr, MoveSize); { Update the number of bytes left to move } Dec(Size, MoveSize); { Advance the pointers } HugeInc(SrcPtr, MoveSize * SizeOf(Word)); HugeInc(DstPtr, MoveSize * SizeOf(Word)); end; end; end; {$ENDIF} { String routines } { function GetParamStr copied from SYSTEM.PAS unit of Delphi 2.0 } function GetParamStr(P: PChar; var Param: string): PChar; var Len: Integer; Buffer: array [Byte] of Char; begin while True do begin while (P[0] <> #0) and (P[0] <= ' ') do Inc(P); if (P[0] = '"') and (P[1] = '"') then Inc(P, 2) else Break; end; Len := 0; while P[0] > ' ' do if P[0] = '"' then begin Inc(P); while (P[0] <> #0) and (P[0] <> '"') do begin Buffer[Len] := P[0]; Inc(Len); Inc(P); end; if P[0] <> #0 then Inc(P); end else begin Buffer[Len] := P[0]; Inc(Len); Inc(P); end; SetString(Param, Buffer, Len); Result := P; end; function ParamCountFromCommandLine(CmdLine: PChar): Integer; var S: string; P: PChar; begin P := CmdLine; Result := 0; while True do begin P := GetParamStr(P, S); if S = '' then Break; Inc(Result); end; end; function ParamStrFromCommandLine(CmdLine: PChar; Index: Integer): string; var P: PChar; begin P := CmdLine; while True do begin P := GetParamStr(P, Result); if (Index = 0) or (Result = '') then Break; Dec(Index); end; end; procedure SplitCommandLine(const CmdLine: string; var ExeName, Params: string); var Buffer: PChar; Cnt, I: Integer; S: string; begin ExeName := ''; Params := ''; Buffer := StrPAlloc(CmdLine); try Cnt := ParamCountFromCommandLine(Buffer); if Cnt > 0 then begin ExeName := ParamStrFromCommandLine(Buffer, 0); for I := 1 to Cnt - 1 do begin S := ParamStrFromCommandLine(Buffer, I); if Pos(' ', S) > 0 then S := '"' + S + '"'; Params := Params + S; if I < Cnt - 1 then Params := Params + ' '; end; end; finally StrDispose(Buffer); end; end; function AnsiUpperFirstChar(const S: string): string; var Temp: string[1]; begin Result := AnsiLowerCase(S); if S <> '' then begin Temp := Result[1]; Temp := AnsiUpperCase(Temp); Result[1] := Temp[1]; end; end; function StrPAlloc(const S: string): PChar; begin Result := StrPCopy(StrAlloc(Length(S) + 1), S); end; function StringToPChar(var S: string): PChar; begin {$IFDEF WIN32} Result := PChar(S); {$ELSE} if Length(S) = High(S) then Dec(S[0]); S[Length(S) + 1] := #0; Result := @(S[1]); {$ENDIF} end; function DropT(const S: string): string; begin if (UpCase(S[1]) = 'T') and (Length(S) > 1) then Result := Copy(S, 2, MaxInt) else Result := S; end; { Cursor routines } {$IFDEF WIN32} function LoadAniCursor(Instance: THandle; ResID: PChar): HCURSOR; { Unfortunately I don't know how we can load animated cursor from executable resource directly. So I write this routine using temporary file and LoadCursorFromFile function. } {$IFNDEF COMPILER3_UP} const RT_ANICURSOR = MakeIntResource(21); {$ENDIF} var S: TFileStream; Path, FileName: array [0..MAX_PATH] of Char; Rsrc: HRSRC; Res: THandle; Data: Pointer; begin Result := 0; Rsrc := FindResource(Instance, ResID, RT_ANICURSOR); if Rsrc <> 0 then begin OSCheck(GetTempPath(MAX_PATH, Path) <> 0); OSCheck(GetTempFileName(Path, 'ANI', 0, FileName) <> 0); try Res := LoadResource(Instance, Rsrc); try Data := LockResource(Res); if Data <> nil then try S := TFileStream.Create(StrPas(FileName), fmCreate); try S.WriteBuffer(Data^, SizeOfResource(Instance, Rsrc)); finally S.Free; end; Result := LoadCursorFromFile(FileName); finally UnlockResource(Res); end; finally FreeResource(Res); end; finally Windows.DeleteFile(FileName); end; end; end; {$ENDIF} function DefineCursor(Instance: THandle; ResID: PChar): TCursor; var Handle: HCURSOR; begin Handle := LoadCursor(Instance, ResID); {$IFDEF WIN32} if Handle = 0 then Handle := LoadAniCursor(Instance, ResID); {$ENDIF} if Handle = 0 then ResourceNotFound(ResID); for Result := 100 to High(TCursor) do { Look for an unassigned cursor index } if (Screen.Cursors[Result] = Screen.Cursors[crDefault]) then begin Screen.Cursors[Result] := Handle; Exit; end; DestroyCursor(Handle); raise EOutOfResources.Create(ResStr(SOutOfResources)); end; // (rom) changed to var var WaitCount: Integer = 0; SaveCursor: TCursor = crDefault; procedure StartWait; begin if WaitCount = 0 then begin SaveCursor := Screen.Cursor; Screen.Cursor := WaitCursor; end; Inc(WaitCount); end; procedure StopWait; begin if WaitCount > 0 then begin Dec(WaitCount); if WaitCount = 0 then Screen.Cursor := SaveCursor; end; end; { Grid drawing } // (rom) changed to var var DrawBitmap: TBitmap = nil; procedure UsesBitmap; begin if DrawBitmap = nil then DrawBitmap := TBitmap.Create; end; procedure ReleaseBitmap; far; begin if DrawBitmap <> nil then DrawBitmap.Free; DrawBitmap := nil; end; procedure WriteText(ACanvas: TCanvas; ARect: TRect; DX, DY: Integer; const Text: string; Alignment: TAlignment; WordWrap: Boolean {$IFDEF COMPILER4_UP}; ARightToLeft: Boolean = False {$ENDIF}); const AlignFlags: array [TAlignment] of Integer = (DT_LEFT or DT_EXPANDTABS or DT_NOPREFIX, DT_RIGHT or DT_EXPANDTABS or DT_NOPREFIX, DT_CENTER or DT_EXPANDTABS or DT_NOPREFIX); WrapFlags: array [Boolean] of Integer = (0, DT_WORDBREAK); {$IFDEF COMPILER4_UP} RTL: array [Boolean] of Integer = (0, DT_RTLREADING); {$ENDIF} var {$IFNDEF WIN32} S: array [0..255] of Char; {$ENDIF} B, R: TRect; I, Left: Integer; begin UsesBitmap; I := ColorToRGB(ACanvas.Brush.Color); if not WordWrap and (Integer(GetNearestColor(ACanvas.Handle, I)) = I) and (Pos(#13, Text) = 0) then begin { Use ExtTextOut for solid colors } {$IFDEF COMPILER4_UP} { In BiDi, because we changed the window origin, the text that does not change alignment, actually gets its alignment changed. } if (ACanvas.CanvasOrientation = coRightToLeft) and (not ARightToLeft) then ChangeBiDiModeAlignment(Alignment); {$ENDIF} case Alignment of taLeftJustify: Left := ARect.Left + DX; taRightJustify: Left := ARect.Right - ACanvas.TextWidth(Text) - 3; else { taCenter } Left := ARect.Left + (ARect.Right - ARect.Left) shr 1 - (ACanvas.TextWidth(Text) shr 1); end; {$IFDEF COMPILER4_UP} ACanvas.TextRect(ARect, Left, ARect.Top + DY, Text); {$ELSE} {$IFDEF WIN32} ExtTextOut(ACanvas.Handle, Left, ARect.Top + DY, ETO_OPAQUE or ETO_CLIPPED, @ARect, PChar(Text), Length(Text), nil); {$ELSE} ExtTextOut(ACanvas.Handle, Left, ARect.Top + DY, ETO_OPAQUE or ETO_CLIPPED, @ARect, StrPCopy(S, Text), Length(Text), nil); {$ENDIF} {$ENDIF} end else begin { Use FillRect and DrawText for dithered colors } {$IFDEF COMPILER3_UP} DrawBitmap.Canvas.Lock; try {$ENDIF} with DrawBitmap, ARect do { Use offscreen bitmap to eliminate flicker and } begin { brush origin tics in painting / scrolling. } Width := Max(Width, Right - Left); Height := Max(Height, Bottom - Top); R := Rect(DX, DY, Right - Left - {$IFDEF WIN32}1{$ELSE}2{$ENDIF}, Bottom - Top - 1); B := Rect(0, 0, Right - Left, Bottom - Top); end; with DrawBitmap.Canvas do begin Font := ACanvas.Font; Font.Color := ACanvas.Font.Color; Brush := ACanvas.Brush; Brush.Style := bsSolid; FillRect(B); SetBkMode(Handle, TRANSPARENT); {$IFDEF COMPILER4_UP} if (ACanvas.CanvasOrientation = coRightToLeft) then ChangeBiDiModeAlignment(Alignment); DrawText(Handle, PChar(Text), Length(Text), R, AlignFlags[Alignment] or RTL[ARightToLeft] or WrapFlags[WordWrap]); {$ELSE} {$IFDEF WIN32} DrawText(Handle, PChar(Text), Length(Text), R, AlignFlags[Alignment] or WrapFlags[WordWrap]); {$ELSE} DrawText(Handle, StrPCopy(S, Text), Length(Text), R, AlignFlags[Alignment] or WrapFlags[WordWrap]); {$ENDIF} {$ENDIF} end; ACanvas.CopyRect(ARect, DrawBitmap.Canvas, B); {$IFDEF COMPILER3_UP} finally DrawBitmap.Canvas.Unlock; end; {$ENDIF} end; end; {$IFDEF COMPILER4_UP} procedure DrawCellTextEx(Control: TCustomControl; ACol, ARow: Longint; const S: string; const ARect: TRect; Align: TAlignment; VertAlign: TVertAlignment; WordWrap: Boolean; ARightToLeft: Boolean); const MinOffs = 2; var H: Integer; begin case VertAlign of vaTopJustify: H := MinOffs; vaCenter: with TJvHack(Control) do H := Max(1, (ARect.Bottom - ARect.Top - Canvas.TextHeight('W')) div 2); else {vaBottomJustify} begin with TJvHack(Control) do H := Max(MinOffs, ARect.Bottom - ARect.Top - Canvas.TextHeight('W')); end; end; WriteText(TJvHack(Control).Canvas, ARect, MinOffs, H, S, Align, WordWrap, ARightToLeft); end; procedure DrawCellText(Control: TCustomControl; ACol, ARow: Longint; const S: string; const ARect: TRect; Align: TAlignment; VertAlign: TVertAlignment; ARightToLeft: Boolean); begin DrawCellTextEx(Control, ACol, ARow, S, ARect, Align, VertAlign, Align = taCenter, ARightToLeft); end; {$ENDIF} procedure DrawCellTextEx(Control: TCustomControl; ACol, ARow: Longint; const S: string; const ARect: TRect; Align: TAlignment; VertAlign: TVertAlignment; WordWrap: Boolean); const MinOffs = 2; var H: Integer; begin case VertAlign of vaTopJustify: H := MinOffs; vaCenter: with TJvHack(Control) do H := Max(1, (ARect.Bottom - ARect.Top - Canvas.TextHeight('W')) div 2); else {vaBottomJustify} begin with TJvHack(Control) do H := Max(MinOffs, ARect.Bottom - ARect.Top - Canvas.TextHeight('W')); end; end; WriteText(TJvHack(Control).Canvas, ARect, MinOffs, H, S, Align, WordWrap); end; procedure DrawCellText(Control: TCustomControl; ACol, ARow: Longint; const S: string; const ARect: TRect; Align: TAlignment; VertAlign: TVertAlignment); begin DrawCellTextEx(Control, ACol, ARow, S, ARect, Align, VertAlign, Align = taCenter); end; procedure DrawCellBitmap(Control: TCustomControl; ACol, ARow: Longint; Bmp: TGraphic; Rect: TRect); begin Rect.Top := (Rect.Bottom + Rect.Top - Bmp.Height) div 2; Rect.Left := (Rect.Right + Rect.Left - Bmp.Width) div 2; TJvHack(Control).Canvas.Draw(Rect.Left, Rect.Top, Bmp); end; destructor TJvScreenCanvas.Destroy; begin FreeHandle; inherited Destroy; end; procedure TJvScreenCanvas.CreateHandle; begin if FDeviceContext = 0 then FDeviceContext := GetDC(0); Handle := FDeviceContext; end; procedure TJvScreenCanvas.FreeHandle; begin if FDeviceContext <> 0 then begin Handle := 0; ReleaseDC(0, FDeviceContext); FDeviceContext := 0; end; end; procedure TJvScreenCanvas.SetOrigin(X, Y: Integer); var FOrigin: TPoint; begin SetWindowOrgEx(Handle, -X, -Y, @FOrigin); end; {$IFNDEF WIN32} { TBits } const BitsPerInt = SizeOf(Integer) * 8; type TBitEnum = 0..BitsPerInt - 1; TBitSet = set of TBitEnum; PBitArray = ^TBitArray; TBitArray = array [0..4096] of TBitSet; destructor TBits.Destroy; begin SetSize(0); inherited Destroy; end; procedure TBits.SetSize(Value: Integer); var NewMem: Pointer; NewMemSize: Integer; OldMemSize: Integer; begin if Value <> Size then begin NewMemSize := ((Value + BitsPerInt - 1) div BitsPerInt) * SizeOf(Integer); OldMemSize := ((Size + BitsPerInt - 1) div BitsPerInt) * SizeOf(Integer); if NewMemSize <> OldMemSize then begin NewMem := nil; if NewMemSize <> 0 then begin GetMem(NewMem, NewMemSize); FillChar(NewMem^, NewMemSize, 0); end else NewMem := nil; if OldMemSize <> 0 then begin if NewMem <> nil then Move(FBits^, NewMem^, Min(OldMemSize, NewMemSize)); FreeMem(FBits, OldMemSize); end; FBits := NewMem; end; FSize := Value; end; end; procedure TBits.SetBit(Index: Integer; Value: Boolean); begin if Value then Include(PBitArray(FBits)^[Index div BitsPerInt], Index mod BitsPerInt) else Exclude(PBitArray(FBits)^[Index div BitsPerInt], Index mod BitsPerInt); end; function TBits.GetBit(Index: Integer): Boolean; begin Result := Index mod BitsPerInt in PBitArray(FBits)^[Index div BitsPerInt]; end; function TBits.OpenBit: Integer; var I: Integer; B: TBitSet; J: TBitEnum; E: Integer; begin E := (Size + BitsPerInt - 1) div BitsPerInt - 1; for I := 0 to E do if PBitArray(FBits)^[I] <> [0..BitsPerInt - 1] then begin B := PBitArray(FBits)^[I]; for J := Low(J) to High(J) do begin if not (J in B) then begin Result := I * BitsPerInt + J; if Result >= Size then Result := Size; Exit; end; end; end; Result := Size; end; (* To create a metafile image from scratch, you must draw the image in a metafile canvas. When the canvas is destroyed, it transfers the image into the metafile object provided to the canvas constructor. After the image is drawn on the canvas and the canvas is destroyed, the image is 'playable' in the metafile object. Like this: MyMetafile := TMetafile.Create; with TJvMetafileCanvas.Create(MyMetafile, 0) do try Brush.Color := clRed; Ellipse(0,0,100,100); ... finally Free; end; Form1.Canvas.Draw(0,0,MyMetafile); { 1 red circle } To add to an existing metafile image, create a metafile canvas and play the source metafile into the metafile canvas. Like this: { continued from previous example, so MyMetafile contains an image } with TJvMetafileCanvas.Create(MyMetafile, 0) do try Draw(0,0,MyMetafile); Brush.Color := clBlue; Ellipse(100,100,200,200); ... finally Free; end; Form1.Canvas.Draw(0,0,MyMetafile); { 1 red circle and 1 blue circle } *) constructor TJvMetafileCanvas.Create(AMetafile: TMetafile; ReferenceDevice: HDC); var Temp: HDC; begin inherited Create; FMetafile := AMetafile; Temp := CreateMetafile(nil); if Temp = 0 then raise EOutOfResources.Create(ResStr(SOutOfResources)); Handle := Temp; FMetafile.Inch := Screen.PixelsPerInch; end; destructor TJvMetafileCanvas.Destroy; var Temp: HDC; KeepInch, KeepWidth, KeepHeight: Integer; begin Temp := Handle; Handle := 0; with FMetafile do begin KeepWidth := Width; KeepHeight := Height; KeepInch := Inch; Handle := CloseMetafile(Temp); Width := KeepWidth; Height := KeepHeight; Inch := KeepInch; end; inherited Destroy; end; { TResourceStream } constructor TResourceStream.Create(Instance: THandle; const ResName: string; ResType: PChar); var ResID: array [0..255] of Char; begin CreateFromPChar(Instance, StrPCopy(ResID, ResName), ResType); end; constructor TResourceStream.CreateFromID(Instance: THandle; ResID: Integer; ResType: PChar); begin CreateFromPChar(Instance, MakeIntResource(ResID), ResType); end; constructor TResourceStream.CreateFromPChar(Instance: THandle; ResName, ResType: PChar); var ResInfo: THandle; Handle: Integer; begin ResInfo := FindResource(Instance, ResName, ResType); if ResInfo = 0 then ResourceNotFound(ResName); Handle := AccessResource(Instance, ResInfo); if Handle < 0 then ResourceNotFound(ResName); inherited Create(Handle); FStartPos := inherited Seek(0, soFromCurrent); FEndPos := FStartPos + SizeOfResource(Instance, ResInfo); end; destructor TResourceStream.Destroy; begin if Handle >= 0 then FileClose(Handle); inherited Destroy; end; function TResourceStream.Write(const Buffer; Count: Longint): Longint; begin raise EStreamError.CreateRes(SWriteError); end; function TResourceStream.Seek(Offset: Longint; Origin: Word): Longint; begin case Origin of soFromBeginning: Result := inherited Seek(FStartPos + Offset, Origin) - FStartPos; soFromCurrent: Result := inherited Seek(Offset, Origin) - FStartPos; soFromEnd: Result := inherited Seek(FEndPos + Offset, soFromBeginning) - FStartPos; end; if Result > FEndPos then raise EStreamError.CreateRes(SReadError); end; function GetCurrentDir: string; begin GetDir(0, Result); end; // (rom) needs better implementation {$I-} function SetCurrentDir(const Dir: string): Boolean; begin ChDir(Dir); Result := IOResult = 0; end; {$ENDIF WIN32} {$IFDEF WIN32} procedure RaiseWin32Error(ErrorCode: DWORD); {$IFDEF COMPILER3_UP} var Error: {$IFDEF COMPILER6_UP} EOSError {$ELSE} EWin32Error {$ENDIF}; {$ENDIF} begin if ErrorCode <> ERROR_SUCCESS then begin {$IFDEF COMPILER3_UP} Error := {$IFDEF COMPILER6_UP} EOSError {$ELSE} EWin32Error {$ENDIF}.CreateFmt( {$IFDEF COMPILER6_UP} SOSError {$ELSE} SWin32Error {$ENDIF}, [ErrorCode, SysErrorMessage(ErrorCode)]); Error.ErrorCode := ErrorCode; raise Error; {$ELSE} raise EJVCLException.CreateFmt('%s (%d)', [SysErrorMessage(ErrorCode), ErrorCode]); {$ENDIF} end; end; { Win32Check is used to check the return value of a Win32 API function which returns a BOOL to indicate success. } {$IFNDEF COMPILER3_UP} function Win32Check(RetVal: Bool): Bool; var LastError: DWORD; begin if not RetVal then begin LastError := GetLastError; raise EJVCLException.CreateFmt('%s (%d)', [SysErrorMessage(LastError), LastError]); end; Result := RetVal; end; {$ENDIF COMPILER3_UP} function CheckWin32(OK: Boolean): Boolean; begin Result := OSCheck(Ok); end; {$ENDIF WIN32} {$IFNDEF COMPILER3_UP} function ResStr(Ident: Cardinal): string; begin Result := LoadStr(Ident); end; {$ELSE} function ResStr(const Ident: string): string; begin Result := Ident; end; {$ENDIF} { Check if this is the active Windows task } { Copied from implementation of FORMS.PAS } type PCheckTaskInfo = ^TCheckTaskInfo; TCheckTaskInfo = record FocusWnd: HWND; Found: Boolean; end; function CheckTaskWindow(Window: HWND; Data: Longint): WordBool; {$IFDEF WIN32} stdcall {$ELSE} export {$ENDIF}; begin Result := True; if PCheckTaskInfo(Data)^.FocusWnd = Window then begin Result := False; PCheckTaskInfo(Data)^.Found := True; end; end; function IsForegroundTask: Boolean; var Info: TCheckTaskInfo; {$IFNDEF WIN32} Proc: TFarProc; {$ENDIF} begin Info.FocusWnd := GetActiveWindow; Info.Found := False; {$IFDEF WIN32} EnumThreadWindows(GetCurrentThreadID, @CheckTaskWindow, Longint(@Info)); {$ELSE} Proc := MakeProcInstance(@CheckTaskWindow, HInstance); try EnumTaskWindows(GetCurrentTask, Proc, Longint(@Info)); finally FreeProcInstance(Proc); end; {$ENDIF} Result := Info.Found; end; function GetWindowsVersion: string; {$IFDEF WIN32} const sWindowsVersion = 'Windows %s %d.%.2d.%.3d %s'; var Ver: TOsVersionInfo; Platfrm: string[4]; begin Ver.dwOSVersionInfoSize := SizeOf(Ver); GetVersionEx(Ver); with Ver do begin case dwPlatformId of VER_PLATFORM_WIN32s: Platfrm := '32s'; VER_PLATFORM_WIN32_WINDOWS: begin dwBuildNumber := dwBuildNumber and $0000FFFF; if (dwMajorVersion > 4) or ((dwMajorVersion = 4) and (dwMinorVersion >= 10)) then Platfrm := '98' else Platfrm := '95'; end; VER_PLATFORM_WIN32_NT: Platfrm := 'NT'; end; Result := Trim(Format(sWindowsVersion, [Platfrm, dwMajorVersion, dwMinorVersion, dwBuildNumber, szCSDVersion])); end; end; {$ELSE} const sWindowsVersion = 'Windows%s %d.%d'; sNT: array [Boolean] of string[3] = ('', ' NT'); var Ver: Longint; begin Ver := GetVersion; Result := Format(sWindowsVersion, [sNT[not Boolean(HiByte(LoWord(Ver)))], LoByte(LoWord(Ver)), HiByte(LoWord(Ver))]); end; {$ENDIF WIN32} // (rom) moved to file end to minimize W- switch impact at end of function {$W+} function GetEnvVar(const VarName: string): string; var {$IFDEF WIN32} S: array [0..2048] of Char; {$ELSE} S: array [0..255] of Char; L: Cardinal; P: PChar; {$ENDIF} begin {$IFDEF WIN32} if GetEnvironmentVariable(PChar(VarName), S, SizeOf(S) - 1) > 0 then Result := StrPas(S) else Result := ''; {$ELSE} L := Length(VarName); P := GetDosEnvironment; StrPLCopy(S, VarName, 255); while P^ <> #0 do begin if (StrLIComp(P, {$IFDEF WIN32} PChar(VarName) {$ELSE} S {$ENDIF}, L) = 0) and (P[L] = '=') then begin Result := StrPas(P + L + 1); Exit; end; Inc(P, StrLen(P) + 1); end; Result := ''; {$ENDIF} end; {$W-} initialization {$IFDEF WIN32} finalization ReleaseBitmap; {$ELSE} AddExitProc(ReleaseBitmap); {$ENDIF} end.