|
|
|
| |
|
| #WhiteUnicorn/ StartPage/ Documentation/DelphiFAQ > |
|
| |
First, a brief overview of what a screen saver is. For a more complete overview, consult the MSDN (Microsoft Developers Network), books and articles on the subject. There are also web sites with screen saver information and source code.
A screen saver is just an executable that has an extension of SCR instead of EXE. In Delphi 3, you can set this using the $E compiler directive.
A screen saver can be launched in several ways:
A couple of things to look out for when it comes to the little preview window:
As you know a screen saver has to respond to mouse events and key presses. When you don't have a password, it should simply shut down. When you have a password set, it should ask for the password. You'll see this as part of the SSave unit (see SSave.pas below).
One final note before we create the screen saver:
OK, now let's go ahead and create the screen saver!
**********
SSetup.pas
**********
unit Ssetup;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, ExtCtrls, Buttons, Spin, ExtDlgs;
type
TSetup = class(TForm)
Ball1Box: TGroupBox;
Label3: TLabel;
xPos1: TSpinEdit;
yPos1: TSpinEdit;
xVel1: TSpinEdit;
yVel1: TSpinEdit;
Label5: TLabel;
Size1: TSpinEdit;
Label7: TLabel;
Label4: TLabel;
Label8: TLabel;
Random1: TCheckBox;
OKButton: TBitBtn;
CancelButton: TBitBtn;
TestButton: TBitBtn;
procedure TestButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure OKButtonClick(Sender: TObject);
procedure CancelButtonClick(Sender: TObject);
procedure Random1Click(Sender: TObject);
procedure Size1Change(Sender: TObject);
private
{ Private declarations }
Loading : Boolean;
public
{ Public declarations }
end;
var
Setup: TSetup;
implementation
uses
SSave, Globals;
{$R *.DFM}
procedure TSetup.TestButtonClick(Sender: TObject);
begin
DefRandom := Random1.Checked;
DefSize := Size1.Value;
DefPosX := xPos1.Value;
DefPosY := yPos1.Value;
DefVelX := xVel1.Value;
DefVelY := yVel1.Value;
TestMode := True;
Scrn := TScrn.Create(Application);
Scrn.LoadingApp := True;
Scrn.Left := -1000;
Scrn.Top := -1000;
Scrn.Width := 0;
Scrn.Height := 0;
Scrn.ShowModal;
Scrn.Free;
SetFocus;
TestMode := False;
end;
procedure TSetup.FormCreate(Sender: TObject);
begin
Loading := True;
end;
procedure TSetup.FormActivate(Sender: TObject);
begin
if Loading then begin
Loading := False;
ReadIniFile;
Size1.Value := DefSize;
xPos1.Value := DefPosX;
yPos1.Value := DefPosY;
xVel1.Value := DefVelX;
yVel1.Value := DefVelY;
Random1.Checked := DefRandom;
xPos1.MinValue := (DefSize*SpotSize div 2)+1;
xPos1.MaxValue := Screen.Width-(DefSize*SpotSize div 2);
yPos1.MinValue := (DefSize*SpotSize div 2)+1;
yPos1.MaxValue := Screen.Height-(DefSize*SpotSize div 2);
end;
end;
procedure TSetup.OKButtonClick(Sender: TObject);
begin
DefRandom := Random1.Checked;
DefSize := Size1.Value;
DefPosX := xPos1.Value;
DefPosY := yPos1.Value;
DefVelX := xVel1.Value;
DefVelY := yVel1.Value;
WriteIniFile;
Close;
end;
procedure TSetup.CancelButtonClick(Sender: TObject);
begin
Close;
end;
procedure TSetup.Random1Click(Sender: TObject);
var
NewColor : TColor;
begin
NewColor := clWindow;
with Random1 do begin
if Checked then
NewColor := clBtnFace;
DefRandom := Checked;
Size1.Enabled := not Checked;
xPos1.Enabled := not Checked;
yPos1.Enabled := not Checked;
xVel1.Enabled := not Checked;
yVel1.Enabled := not Checked;
end;
Size1.Color := NewColor;
xPos1.Color := NewColor;
yPos1.Color := NewColor;
xVel1.Color := NewColor;
yVel1.Color := NewColor;
end;
procedure TSetup.Size1Change(Sender: TObject);
begin
xPos1.MinValue := (Size1.Value*SpotSize div 2)+1;
xPos1.MaxValue := Screen.Width-(Size1.Value*SpotSize div 2);
yPos1.MinValue := (Size1.Value*SpotSize div 2)+1;
yPos1.MaxValue := Screen.Height-(Size1.Value*SpotSize div 2);
xPos1.Value := xPos1.Value;
yPos1.Value := yPos1.Value;
end;
end.
**********
SSetup.dfm
**********
object Setup: TSetup
Left = 260
Top = 188
BorderIcons = []
BorderStyle = bsDialog
Caption = 'Simple Saver Setup'
ClientHeight = 145
ClientWidth = 345
Font.Charset = DEFAULT_CHARSET
Font.Color = clBlack
Font.Height = -12
Font.Name = 'Arial'
Font.Style = []
Position = poScreenCenter
ShowHint = True
OnActivate = FormActivate
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 15
object Ball1Box: TGroupBox
Left = 8
Top = 8
Width = 329
Height = 89
Caption = 'Settings'
TabOrder = 0
object Label3: TLabel
Left = 72
Top = 40
Width = 30
Height = 15
Caption = 'x-pos'
end
object Label5: TLabel
Left = 8
Top = 40
Width = 23
Height = 15
Caption = 'Size'
end
object Label7: TLabel
Left = 136
Top = 40
Width = 30
Height = 15
Caption = 'y-pos'
end
object Label4: TLabel
Left = 200
Top = 40
Width = 24
Height = 15
Caption = 'x-vel'
end
object Label8: TLabel
Left = 264
Top = 40
Width = 24
Height = 15
Caption = 'y-vel'
end
object xPos1: TSpinEdit
Left = 72
Top = 56
Width = 57
Height = 24
MaxLength = 4
MaxValue = 9999
MinValue = 0
TabOrder = 2
Value = 0
end
object yPos1: TSpinEdit
Left = 136
Top = 56
Width = 57
Height = 24
MaxLength = 4
MaxValue = 9999
MinValue = 0
TabOrder = 3
Value = 0
end
object xVel1: TSpinEdit
Left = 200
Top = 56
Width = 57
Height = 24
MaxLength = 4
MaxValue = 10
MinValue = -10
TabOrder = 4
Value = 0
end
object yVel1: TSpinEdit
Left = 264
Top = 56
Width = 57
Height = 24
MaxLength = 4
MaxValue = 10
MinValue = -10
TabOrder = 5
Value = 0
end
object Size1: TSpinEdit
Left = 8
Top = 56
Width = 57
Height = 24
MaxLength = 4
MaxValue = 4
MinValue = 1
TabOrder = 1
Value = 1
OnChange = Size1Change
end
object Random1: TCheckBox
Left = 8
Top = 16
Width = 97
Height = 17
Caption = 'Randomize'
TabOrder = 0
OnClick = Random1Click
end
end
object OKButton: TBitBtn
Left = 8
Top = 104
Width = 73
Height = 33
Caption = 'Ok'
Font.Charset = DEFAULT_CHARSET
Font.Color = clBlack
Font.Height = -12
Font.Name = 'Arial'
Font.Style = []
ParentFont = False
TabOrder = 1
OnClick = OKButtonClick
Kind = bkOK
end
object CancelButton: TBitBtn
Left = 136
Top = 104
Width = 73
Height = 33
Font.Charset = DEFAULT_CHARSET
Font.Color = clBlack
Font.Height = -12
Font.Name = 'Arial'
Font.Style = []
ParentFont = False
TabOrder = 2
OnClick = CancelButtonClick
Kind = bkCancel
end
object TestButton: TBitBtn
Left = 264
Top = 104
Width = 73
Height = 33
Caption = 'Test'
Font.Charset = DEFAULT_CHARSET
Font.Color = clBlack
Font.Height = -12
Font.Name = 'Arial'
Font.Style = []
ParentFont = False
TabOrder = 3
OnClick = TestButtonClick
Glyph.Data = {
76010000424D7601000000000000760000002800000020000000100000000100
0400000000000001000000000000000000001000000010000000000000000000
800000800000008080008000000080008000808000007F7F7F00BFBFBF000000
FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00333333000000
033333FFFF77777773F330000077777770333777773FFFFFF733077777000000
03337F3F3F777777733F0797A770003333007F737337773F3377077777778803
30807F333333337FF73707888887880007707F3FFFF333777F37070000878807
07807F777733337F7F3707888887880808807F333333337F7F37077777778800
08807F333FFF337773F7088800088803308073FF777FFF733737300008000033
33003777737777333377333080333333333333F7373333333333300803333333
33333773733333333333088033333333333373F7F33333333333308033333333
3333373733333333333333033333333333333373333333333333}
NumGlyphs = 2
end
end
*********
SSave.pas
*********
unit Ssave;
interface
uses WinTypes, WinProcs, Graphics, Forms, Messages, Classes, Controls,
ExtCtrls, StdCtrls, SysUtils;
type
TScrn = class(TForm)
Image1: TImage;
procedure FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormCreate(Sender: TObject);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure FormActivate(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
Mouse : TPoint;
procedure StartSaver(var WinMsg : TMessage); message WM_USER+1;
procedure StopSaver(var WinMsg : TMessage); message WM_USER+2;
procedure GetPassword;
procedure Trigger(Sender : TObject; var Done : Boolean);
public
{ Public declarations }
LoadingApp : Boolean;
end;
var
Scrn : TScrn;
DesktopBitmap : TBitmap;
implementation
uses
CodeSpot, Globals, Registry;
const
IgnoreCount : Integer = 0;
{$R *.DFM}
procedure CursorOff;
begin
ShowCursor(False);
end;
procedure CursorOn;
begin
ShowCursor(True);
end;
procedure TScrn.StartSaver(var WinMsg : TMessage);
begin
DrawSpot;
end;
procedure TScrn.StopSaver(var WinMsg : TMessage);
begin
GetPassword;
end;
procedure TScrn.GetPassword;
var
MyMod : THandle;
PwdFunc : function (Parent : THandle) : Boolean; stdcall;
SysDir : String;
NewLen : Integer;
MyReg : TRegistry;
OkToClose : Boolean;
begin
if (SSMode <> ssRun) or TestMode then begin
Close;
Exit;
end;
IgnoreCount := 5;
OkToClose := False;
MyReg := TRegistry.Create;
MyReg.RootKey := HKEY_CURRENT_USER;
if MyReg.OpenKey('Control Panel\Desktop',False) then begin
try
try
ShowCursor(True);
if MyReg.ReadInteger('ScreenSaveUsePassword') <> 0 then begin
SetLength(SysDir,MAX_PATH);
NewLen := GetSystemDirectory(PChar(SysDir),MAX_PATH);
SetLength(SysDir,NewLen);
if (Length(SysDir) > 0) and (SysDir[Length(SysDir)] <> '\') then
SysDir := SysDir+'\';
MyMod := LoadLibrary(PChar(SysDir+'PASSWORD.CPL'));
if MyMod = 0 then
OkToClose := True
else begin
PwdFunc := GetProcAddress(MyMod,'VerifyScreenSavePwd');
if PwdFunc(Handle) then
OkToClose := True;
FreeLibrary(MyMod);
end;
end
else
OkToClose := True;
finally
ShowCursor(False);
end;
except
OkToClose := True;
end;
end
else
OkToClose := True;
MyReg.Free;
if OkToClose then
Close;
end;
procedure TScrn.Trigger(Sender : TObject; var Done : Boolean);
begin
PostMessage(Handle,WM_USER+1,0,0);
end;
procedure TScrn.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
GetPassword;
end;
procedure TScrn.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
if IgnoreCount > 0 then begin
Dec(IgnoreCount);
Exit;
end;
if (Mouse.X = -1) and (Mouse.Y = -1) then begin
Mouse.X := X;
Mouse.Y := Y;
end
else
if (Abs(X-Mouse.X) > 2) and (Abs(Y-Mouse.Y) > 2) then begin
Mouse.X := X;
Mouse.Y := Y;
GetPassword;
end;
end;
procedure TScrn.FormCreate(Sender: TObject);
begin
LoadingApp := True;
end;
procedure TScrn.FormActivate(Sender: TObject);
var
Dummy : Boolean;
begin
if LoadingApp then begin
LoadingApp := False;
Scrn.Color := clBlack;
Scrn.Top := 0;
Scrn.Left := 0;
Scrn.Width := Screen.Width;
Scrn.Height := Screen.Height;
InitSpot;
Mouse.X := -1;
Mouse.Y := -1;
Application.OnIdle := Trigger;
SetWindowPos(Handle,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE + SWP_NOMOVE);
SystemParametersInfo(SPI_SCREENSAVERRUNNING,1,@Dummy,0);
CursorOff;
Scrn.Visible := True;
SetCapture(Scrn.Handle);
end;
end;
procedure TScrn.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
GetPassword;
end;
procedure TScrn.FormClose(Sender: TObject; var Action: TCloseAction);
var
Dummy : Boolean;
begin
SystemParametersInfo(SPI_SCREENSAVERRUNNING,0,@Dummy,0);
Application.OnIdle := nil;
ReleaseCapture;
CursorOn;
end;
end.
*********
SSave.dfm
*********
object Scrn: TScrn
Left = 314
Top = 376
HorzScrollBar.Visible = False
BorderIcons = [biSystemMenu]
BorderStyle = bsNone
ClientHeight = 130
ClientWidth = 457
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -13
Font.Name = 'System'
Font.Style = []
OnActivate = FormActivate
OnClose = FormClose
OnCreate = FormCreate
OnKeyDown = FormKeyDown
OnMouseDown = FormMouseDown
OnMouseMove = FormMouseMove
PixelsPerInch = 96
TextHeight = 16
object Image1: TImage
Left = 0
Top = 0
Width = 457
Height = 130
Align = alClient
Visible = False
end
end
***********
Globals.pas
***********
unit Globals;
interface
type
TSSMode = (ssSetPwd,ssPreview,ssConfig,ssRun);
const
SSMode : TSSMode = ssRun;
TestMode : Boolean = False;
Section = 'Screen Saver.Simple Screen Saver';
SpotSize = 50;
DefSize : Integer = 2;
DefPosX : Integer = 51;
DefPosY : Integer = 51;
DefVelX : Integer = 1;
DefVelY : Integer = 1;
DefRandom : Boolean = True;
procedure ReadIniFile;
procedure WriteIniFile;
implementation
uses
IniFiles;
procedure ReadIniFile;
var
IniFile : TIniFile;
begin
IniFile := TIniFile.Create('CONTROL.INI');
DefSize := IniFile.ReadInteger(Section,'Size1',DefSize);
DefPosX := IniFile.ReadInteger(Section,'PosX1',DefPosX);
DefPosY := IniFile.ReadInteger(Section,'PosY1',DefPosY);
DefVelX := IniFile.ReadInteger(Section,'VelX1',DefVelX);
DefVelY := IniFile.ReadInteger(Section,'VelY1',DefVelY);
DefRandom := IniFile.ReadBool(Section,'Rand1',DefRandom);
IniFile.Free;
end;
procedure WriteIniFile;
var
IniFile : TIniFile;
begin
IniFile := TIniFile.Create('CONTROL.INI');
IniFile.WriteInteger(Section,'Size1',DefSize);
IniFile.WriteInteger(Section,'PosX1',DefPosX);
IniFile.WriteInteger(Section,'PosY1',DefPosY);
IniFile.WriteInteger(Section,'VelX1',DefVelX);
IniFile.WriteInteger(Section,'VelY1',DefVelY);
IniFile.WriteBool(Section,'Rand1',DefRandom);
IniFile.Free;
end;
end.
************
CodeSpot.pas
************
unit Codespot;
interface
uses
WinTypes, WinProcs, Graphics, Forms, Controls, Classes, Sysutils, Dialogs;
var
zx, zy : Integer;
cx, cy,
vx, vy,
d : Real;
Picture : HBitmap;
procedure InitSpot;
procedure DrawSpot;
implementation
uses
SSave, Globals;
procedure InitSpot;
begin
Randomize;
if not TestMode then
ReadIniFile;
zx := Screen.Width;
zy := Screen.Height;
d := (Random(4)+1)*SpotSize;
cx := Random((zx div 2)-Round(d)-1)+1;
cy := Random(zy-Round(d)-1)+1;
vx := Random(2)+1;
vy := Random(2)+1;
if Random(2) = 0 then
vx := -vx;
if Random(2) = 0 then
vy := -vy;
if not DefRandom then begin
d := DefSize*SpotSize;
cx := DefPosX-d/2;
cy := DefPosY-d/2;
vx := DefVelX;
vy := DefVelY;
end;
Scrn.Image1.Picture.Bitmap := DesktopBitmap;
Picture := Scrn.Image1.Picture.Bitmap.Handle;
end;
procedure DrawSpot;
var
WinDC, MemDC : HDC;
Rgn1, Rgn3 : HRgn;
begin
WinDC := GetDC(Scrn.Handle);
MemDC := CreateCompatibleDC(WinDC);
SelectObject(MemDC,Picture);
if ((cx+vx <= 0) or (cx+d+vx >= zx)) then
vx := -vx;
if ((cy+vy <= 0) or (cy+d+vy >= zy)) then
vy := -vy;
cx := cx+vx;
cy := cy+vy;
Rgn3 := CreateRectRgn(0,0,zx,zy);
Rgn1 := CreateEllipticRgn(Round(cx),Round(cy),
Round(cx+d),Round(cy+d));
CombineRgn(Rgn3,Rgn3,Rgn1,RGN_DIFF);
FillRgn(WinDC,Rgn3,GetStockObject(BLACK_BRUSH));
SelectObject(WinDC,Rgn1);
BitBlt(WinDC,0,0,zx,zy,MemDC,0,0,SRCCOPY);
DeleteObject(Rgn3);
DeleteObject(Rgn1);
DeleteDC(MemDC);
ReleaseDC(Scrn.Handle,WinDC);
end;
end.
**********
Simple.dpr
**********
program Simple;
uses
Forms,
SysUtils,
Windows,
Graphics,
Classes,
Ssave in 'SSave.pas' {Scrn},
Codespot in 'CodeSpot.pas',
Ssetup in 'SSetup.pas' {Setup},
Globals in 'Globals.pas';
{$E SCR}
{$R *.RES}
var
MySem : THandle;
Arg1,
Arg2 : String;
DemoWnd : HWnd;
MyRect : TRect;
MyCanvas : TCanvas;
x, y,
dx, dy : Integer;
MyBkgBitmap,
InMemBitmap : TBitmap;
ScrWidth,
ScrHeight : Integer;
SysDir : String;
NewLen : Integer;
MyMod : THandle;
PwdFunc : function (a : PChar; ParentHandle : THandle; b, c : Integer) :
Integer; stdcall;
begin
Arg1 := UpperCase(ParamStr(1));
Arg2 := UpperCase(ParamStr(2));
if (Copy(Arg1,1,2) = '/A') or (Copy(Arg1,1,2) = '-A') or
(Copy(Arg1,1,1) = 'A') then
SSMode := ssSetPwd;
if (Copy(Arg1,1,2) = '/P') or (Copy(Arg1,1,2) = '-P') or
(Copy(Arg1,1,1) = 'P') then
SSMode := ssPreview;
if (Copy(Arg1,1,2) = '/C') or (Copy(Arg1,1,2) = '-C') or
(Copy(Arg1,1,1) = 'C') or (Arg1 = '') then
SSMode := ssConfig;
if SSMode = ssSetPwd then begin
SetLength(SysDir,MAX_PATH);
NewLen := GetSystemDirectory(PChar(SysDir),MAX_PATH);
SetLength(SysDir,NewLen);
if (Length(SysDir) > 0) and (SysDir[Length(SysDir)] <> '\') then
SysDir := SysDir+'\';
MyMod := LoadLibrary(PChar(SysDir+'MPR.DLL'));
if MyMod <> 0 then begin
PwdFunc := GetProcAddress(MyMod,'PwdChangePasswordA');
if Assigned(PwdFunc) then
PwdFunc('SCRSAVE',StrToInt(Arg2),0,0);
FreeLibrary(MyMod);
end;
Halt;
end;
MySem := CreateSemaphore(nil,0,1,'SimpleSaverSemaphore');
if ((MySem <> 0) and (GetLastError = ERROR_ALREADY_EXISTS)) then begin
CloseHandle(MySem);
Halt;
end;
Application.Initialize;
if SSMode = ssPreview then begin
DemoWnd := StrToInt(Arg2);
while not IsWindowVisible(DemoWnd) do
Application.ProcessMessages;
GetWindowRect(DemoWnd,MyRect);
ScrWidth := MyRect.Right-MyRect.Left+1;
ScrHeight := MyRect.Bottom-MyRect.Top+1;
MyRect := Rect(0,0,ScrWidth-1,ScrHeight-1);
MyCanvas := TCanvas.Create;
MyCanvas.Handle := GetDC(DemoWnd);
MyCanvas.Pen.Color := clWhite;
x := (ScrWidth div 2)-16;
y := (ScrHeight div 2)-16;
dx := 1;
dy := 1;
MyBkgBitmap := TBitmap.Create;
with MyBkgBitmap do begin
Width := ScrWidth;
Height := ScrHeight;
end;
MyBkgBitmap.Canvas.FillRect(Rect(0,0,ScrWidth-1,ScrHeight-1));
InMemBitmap := TBitmap.Create;
with InMemBitmap do begin
Width := ScrWidth;
Height := ScrHeight;
end;
while IsWindowVisible(DemoWnd) do begin
InMemBitmap.Canvas.CopyRect(MyRect,MyBkgBitmap.Canvas,MyRect);
InMemBitmap.Canvas.Draw(x,y,Application.Icon);
MyCanvas.CopyRect(MyRect,InMemBitmap.Canvas,MyRect);
Sleep(10);
Application.ProcessMessages;
if (x = 0) or (x = (ScrWidth-33)) then
dx := -dx;
if (y = 0) or (y = (ScrHeight-33)) then
dy := -dy;
x := x+dx;
y := y+dy;
end;
MyBkgBitmap.Free;
InMemBitmap.Free;
MyCanvas.Free;
CloseHandle(MySem);
Halt;
end;
DesktopBitmap := TBitmap.Create;
with DesktopBitmap do begin
Width := Screen.Width;
Height := Screen.Height;
end;
BitBlt(DesktopBitmap.Canvas.Handle,0,0,Screen.Width,Screen.Height,
GetDC(GetDesktopWindow),0,0,SrcCopy);
if SSMode = ssConfig then begin
Application.CreateForm(TSetup, Setup);
end else
Application.CreateForm(TScrn,Scrn);
Application.Run;
DesktopBitmap.Free;
CloseHandle(MySem);
end.
|
| |
|
| #WhiteUnicorn/ StartPage/ Documentation/DelphiFAQ > |
|
| |
|
| ||
|
|
|
|
|
| ||