WhiteUnicorn |
| |
#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 > | |
|
| ||
Anastasija aka WhiteUnicorn |
LiveJournal PhotoFile |
|
|