git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.jvcl@12 7f62d464-2af8-f54e-996c-e91b33f51cbe
3032 lines
81 KiB
ObjectPascal
3032 lines
81 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: 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.
|
|
|