AppsInit.pas
上传用户:yj_qiu
上传日期:2022-08-08
资源大小:23636k
文件大小:25k
源码类别:

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(Application Initialization Unit)
  3.  (C) 2003-2007 George "Mirage" Bakhtadze
  4.  The source code may be used under either MPL 1.1 or LGPL 2.1 license. See included license.txt file <br>
  5.  Unit contains application initialization and maintenance classes
  6. *)
  7. {$Include GDefines.inc}
  8. unit AppsInit;
  9. interface
  10. uses
  11.   TextFile,
  12.   BaseTypes, Basics, BaseMsg, OSUtils,
  13.   Windows, Messages, ShellAPI;
  14. const
  15.   WM_NOTIFYTRAYICON = WM_USER + 1;
  16. type
  17.   // Windows message handling callback
  18.   TWndProc = function (WHandle: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
  19.   // Possible application option flags
  20.   TStarterOption = ({ Without this option the starter will create a working directory for the application in current user's documents directory (usally within "my documents" folder")
  21.                       If the option is included the directory with the application's .exe file will be used as working directory. Not recommended under Windows Vista. }
  22.                     soSingleUser,
  23.                     // If this option is included current directory will be not changed by the starter, else it will be changed to working directory
  24.                     soPreserveDir);
  25.   // Application option flag set
  26.   TStarterOptions = set of TStarterOption;
  27.   { Application starter base class
  28.     The class manages application startup process, creates window, forwards windows messages, etc }
  29.   TAppStarter = class                                     // ToDo: Make it independent from OS
  30.   private
  31.     FTerminated, FActive: Boolean;
  32.     WindowProc: TWndProc;
  33.   protected
  34.     // Application window style
  35.     FWindowStyle: Cardinal;
  36.     // Application window handle
  37.     FWindowHandle: Cardinal;
  38.     // Application name
  39.     FProgramName,
  40.     // Application .exe file name
  41.     FProgramExeName,
  42.     // Application .exe directory
  43.     FProgramExeDir,
  44.     // Application working directory
  45.     FProgramWorkDir: string;
  46.     // Application version string
  47.     FProgramVersionStr: string[16];
  48.     // Returns <b>True</b> if the application is terminated
  49.     function GetTerminated: Boolean; virtual;
  50.     // Windows message handler
  51.     function ProcessMessage(Msg: Longword; wParam: Integer; lParam: Integer): Integer; virtual;
  52.     // This method should be overridden to do command line parameters parsing
  53.     procedure ParseParamStr; virtual;
  54.     // This method should be overridden for variables custom initialization
  55.     procedure Init; virtual;
  56.   public
  57.     // Determines if message handling is needed. <b>True</b> by default.
  58.     HandleMessages: Boolean;
  59.     // Determines if a default window message handler should be called
  60.     CallDefaultMsgHandler: Boolean;
  61.     // A message handler to forward Window messages to
  62.     MessageHandler: TMessageHandler;
  63.     // Time to sleep in milliseconds when the application is not active (60 default)
  64.     InactiveSleepAmount: Integer;
  65.     // Create and setup an application with the given name. If <b>AWindowProc</b> is <b>nil</b> a default procedure will be used.
  66.     constructor Create(const AProgramName: string; AWindowProc: TWndProc; Options: TStarterOptions);
  67.     // Immediate termination
  68.     destructor Destroy; override;
  69.     // Set <b>Terminated</b> flag. Normally the application will be terminated as soon as possible.
  70.     procedure Terminate; virtual;
  71.     // Returns <b>True</b> if another instance of the application is already rinning. If <b>ActivateExisting</b> is <b>True</b> the other instance will be activated.
  72.     function isAlreadyRunning(ActivateExisting: Boolean): Boolean; virtual; abstract;
  73.     // Should be called each application cycle. Usally overridden to perform message processing. Returns negate value of @Link(Terminated) property.
  74.     function Process: Boolean; virtual; abstract;
  75.     // Prints an error information
  76.     procedure PrintError(const Msg: string; ErrorType: TLogLevel); virtual; abstract;
  77.     // Application name
  78.     property ProgramName: string read FProgramName;
  79.     // Application .exe file name
  80.     property ProgramExeName: string read FProgramExeName;
  81.     // Application .exe directory including trailing path delimiter
  82.     property ProgramExeDir: string read FProgramExeDir;
  83.     // Application working directory including trailing path delimiter
  84.     property ProgramWorkDir: string read FProgramWorkDir;
  85.     // Application window style
  86.     property WindowStyle: Cardinal read FWindowStyle;
  87.     // Application window handle
  88.     property WindowHandle: Cardinal read FWindowHandle;
  89.     // <b>True</b> if the application's window is currently active
  90.     property Active: Boolean read FActive;
  91.     // <b>True</b> if the application is terminated
  92.     property Terminated: Boolean read GetTerminated write FTerminated;
  93.   end;
  94.   // Screen saver specific implementation of @Link(TAppStarter)
  95.   TScreenSaverStarter = class(TAppStarter)
  96.   private
  97.     MutexWindowHandle: hWnd;
  98.     Rect: TRect;
  99.     ParamChar: Char;
  100.     FWindowClassName: string;
  101.     FParentWindow: hWnd;
  102.     FPreviewMode: Boolean;
  103.     FMoveCounter: Integer;
  104.   protected
  105.     // Current window class
  106.     WindowClass: TWndClass;
  107.     // Windows message handler
  108.     function ProcessMessage(Msg: Longword; wParam: Integer; lParam: Integer): Integer; override;
  109.     // This method should be overridden to do parameters parsing
  110.     procedure ParseParamStr; override;
  111.   public
  112.     // Create and setup a screen saver with the given name. If <b>AWindowProc</b> is <b>nil</b> a default procedure will be used.
  113.     constructor Create(const AProgramName: string; AWindowProc: TWndProc; Options: TStarterOptions);
  114.     destructor Destroy; override;
  115.     // Runs the screen saver. If <b>APreviewMode</b> is <b>True</b> the screen saver will run in preview window.
  116.     procedure Run(APreviewMode: Boolean); virtual;
  117.     // Calls system routine to request password
  118.     procedure SetPassword; virtual;
  119.     // Calls system routine to ask user for password and returns <b>True</b> if no password needed or user enter correct password
  120.     function QueryPassword: Boolean; virtual;
  121.     // Shows a configuration window. Usally called from OS screen saver setup dialog
  122.     procedure Configure; virtual;
  123.     // Prints an error information
  124.     procedure PrintError(const Msg: string; ErrorType: TLogLevel); override;
  125.     // <b>True</b> if the screen saver is running in preview mode
  126.     property PreviewMode: Boolean read FPreviewMode;
  127.   end;
  128.   // Win32 implementation of @Link(TAppStarter)
  129.   TWin32AppStarter = class(TAppStarter)
  130.   private
  131.     FWindowClassName: string;
  132.   protected
  133.     // Current window class
  134.     WindowClass: TWndClass;
  135.     // Windows message handler
  136.     function ProcessMessage(Msg: Longword; wParam: Integer; lParam: Integer): Integer; override;
  137.     // Should be override for custom window settings
  138.     procedure InitWindowSettings(var AWindowClass: TWndClass; var ARect: BaseTypes.TRect); virtual;
  139.   public
  140.     constructor Create(const AProgramName: string; AWindowProc: TWndProc; Options: TStarterOptions);
  141.     destructor Destroy; override;
  142.     { Returns <b>True</b> if another instance of the application (currently, an application with the same window class name) is already rinning.
  143.       If <b>ActivateExisting</b> is <b>True</b> the other instance will be activated. }
  144.     function isAlreadyRunning(ActivateExisting: Boolean): Boolean; override;
  145.     // Performs win32 messages processing
  146.     function Process: Boolean; override;
  147.     procedure PrintError(const Msg: string; ErrorType: TLogLevel); override;
  148.     // Application's window class name
  149.     property WindowClassName: string read FWindowClassName;
  150.   end;
  151.   // Starter class for a Win32 application with an icon in system tray
  152.   TTrayAppStarter = class(TWin32AppStarter)
  153.   private
  154.     TrayIcon: TNotifyIconData;
  155.   protected
  156.     // Windows message handler
  157.     function ProcessMessage(Msg: Longword; wParam: Integer; lParam: Integer): Integer; override;
  158.   public
  159.     // Adds an icon to system tray and returns <b>True</b> if success
  160.     function AddTrayIcon: Boolean;
  161.     // Removes an icon to system tray
  162.     procedure RemoveTrayIcon;
  163.     destructor Destroy; override;
  164.   end;
  165. implementation
  166. uses SysUtils;
  167. type
  168.   TVerifySSPassFunc = function(Parent: hWnd): Bool; StdCall;
  169.   TChgPassAFunc = function(A: PChar; Parent: hWnd; B, C: Integer): Integer; StdCall;
  170. var
  171.   CurrentStarter: TAppStarter;
  172. function StdWindowProc(WHandle: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
  173. begin
  174.   if (CurrentStarter = nil) or (CurrentStarter.WindowHandle = 0) or (CurrentStarter.FTerminated) then begin
  175. //    Log.Log('*** <Default> Message: ' + Format('%D, %D, %D', [Msg, wParam, lParam]), lkError);
  176.     Result := DefWindowProc(WHandle, Msg, wParam, lParam)
  177.   end else begin
  178. //    Log.Log('*** Message: ' + Format('%D, %D, %D', [Msg, wParam, lParam]), lkError);
  179.     CurrentStarter.CallDefaultMsgHandler := True;
  180.     Result := CurrentStarter.ProcessMessage(Msg, wParam, lParam);
  181.     if CurrentStarter.CallDefaultMsgHandler then Result := DefWindowProc(WHandle, Msg, wParam, lParam);
  182.   end;
  183. end;
  184. { TAppStarter }
  185. function TAppStarter.GetTerminated: Boolean;
  186. begin
  187.   Result := FTerminated;
  188. end;
  189. function TAppStarter.ProcessMessage(Msg: Longword; wParam, lParam: Integer): Integer;
  190. begin
  191.   if Assigned(MessageHandler) then MessageHandler(WMToMessage(Msg, wParam, lParam));
  192.   Result := 1;
  193. end;
  194. procedure TAppStarter.ParseParamStr;
  195. begin
  196. end;
  197. procedure TAppStarter.Init;
  198. begin
  199. end;
  200. constructor TAppStarter.Create(const AProgramName: string; AWindowProc: TWndProc; Options: TStarterOptions);
  201. var ExeExt: string;
  202. begin
  203.   CurrentStarter := Self;
  204.   FProgramName := AProgramName;
  205.   ExeExt := ExtractFileExt(ParamStr(0));
  206.   FProgramExeName := LowerCase(ExtractFileName(ParamStr(0)));
  207.   if ExeExt <> '' then FProgramExeName := Copy(ProgramExeName, 1, Length(ProgramExeName) - Length(ExeExt));
  208.   FProgramExeDir := IncludeTrailingPathDelimiter(ExtractFileDir(ParamStr(0)));
  209.   FProgramWorkDir := '';
  210.   if not (soSingleUser in Options) then begin
  211.     FProgramWorkDir := IncludeTrailingPathDelimiter(GetSysFolder(sfPersonal)) + ProgramExeName;
  212.     if not DirectoryExists(ProgramWorkDir) then
  213.       if not CreateDir(ProgramWorkDir) then begin
  214.         Log.Log(ClassName + '.Create: Can''t create directory "' + ProgramWorkDir + '"', lkError);
  215.         FProgramWorkDir := '';
  216.       end;
  217.   end;
  218.   if ProgramWorkDir = '' then FProgramWorkDir := FProgramExeDir;
  219.   if not (soPreserveDir in Options) then SetCurrentDir(ProgramWorkDir);
  220.   WindowProc := AWindowProc;
  221.   Init;
  222.   Terminated := False;
  223.   if isAlreadyRunning(True) then begin
  224.     Log.Log(ClassName + '.Create: Application instance is already running', lkError);
  225.     Terminated := True;
  226.   end;
  227.   InactiveSleepAmount := 60;
  228.   FActive := GetActiveWindow = WindowHandle;
  229. end;
  230. destructor TAppStarter.Destroy;
  231. begin
  232.   Terminate;
  233.   inherited;
  234. end;
  235. procedure TAppStarter.Terminate;
  236. begin
  237.   FTerminated := True;
  238. end;
  239. { TWin32AppStarter }
  240. function TWin32AppStarter.ProcessMessage(Msg: Longword; wParam, lParam: Integer): Integer;
  241. begin
  242.   Result := inherited ProcessMessage(Msg, wParam, lParam);
  243.   case Msg of
  244.     WM_CLOSE: begin
  245.       Result := 0; Terminated := True;
  246.     end;
  247.     WM_ACTIVATEAPP: begin
  248.       if (wParam and 65535 = WA_ACTIVE) or (wParam and 65535 = WA_CLICKACTIVE) then FActive := True;
  249.       if wParam and 65535 = WA_INACTIVE then FActive := False;
  250.     end;
  251.   end;
  252. end;
  253. procedure TWin32AppStarter.InitWindowSettings(var AWindowClass: TWndClass; var ARect: BaseTypes.TRect);
  254. begin
  255. end;
  256. constructor TWin32AppStarter.Create(const AProgramName: string; AWindowProc: TWndProc; Options: TStarterOptions);
  257. const SizePercent = 50;
  258. var
  259.   ScreenX, ScreenY: Integer;
  260.   WinRect: BaseTypes.TRect;
  261. begin
  262.   inherited;
  263.   FWindowStyle := WS_OVERLAPPED or WS_CAPTION or WS_THICKFRAME or WS_MINIMIZEBOX or WS_MAXIMIZEBOX or WS_SIZEBOX or WS_SYSMENU;
  264. //  WindowStyle := WS_OVERLAPPEDWINDOW{ or WS_SYSMENU or WS_MINIMIZEBOX or WS_MAXIMIZEBOX or WS_SIZEBOX};
  265.   WindowClass.style := 0;//CS_VREDRAW or CS_HREDRAW or CS_OWNDC;
  266.   if @AWindowProc = nil then
  267.     WindowClass.lpfnWndProc := @StdWindowProc else
  268.       WindowClass.lpfnWndProc := {$IFNDEF FPC}@{$ENDIF}AWindowProc;
  269.   WindowClass.cbClsExtra := 0;
  270.   WindowClass.cbWndExtra := 0;
  271.   WindowClass.hIcon := LoadIcon(hInstance, 'MAINICON');
  272.   WindowClass.hCursor := LoadCursor(WindowClass.hInstance*0, IDC_ARROW);
  273.   WindowClass.hInstance := HInstance;
  274.   WindowClass.hbrBackground := 0;//GetStockObject(WHITE_BRUSH);
  275.   WindowClass.lpszMenuName := nil;
  276.   FWindowClassName := 'TAWindowClass(' + AProgramName + ')';
  277.   WindowClass.lpszClassName := PChar(FWindowClassName);
  278.   if RegisterClass(WindowClass) = 0 then begin
  279.     Log.Log('TWin32AppStarter.Create: Window class registration failed', lkFatalError);
  280.     Exit;
  281.   end;
  282.   ScreenX := GetSystemMetrics(SM_CXSCREEN);
  283.   ScreenY := GetSystemMetrics(SM_CYSCREEN);
  284.   if ScreenX = 0 then ScreenX := 640;
  285.   if ScreenY = 0 then ScreenY := 480;
  286.   WinRect := GetRectWH((ScreenX - ScreenX * SizePercent div 100) div 2, (ScreenY - ScreenY * SizePercent div 100) div 2,
  287.                        ScreenX * SizePercent div 100, ScreenY * SizePercent div 100);
  288.   InitWindowSettings(WindowClass, WinRect);
  289.   FWindowHandle := Windows.CreateWindow(WindowClass.lpszClassName, PChar(AProgramName), FWindowStyle,
  290.                                         WinRect.Left, WinRect.Top, WinRect.Right-WinRect.Left, WinRect.Bottom-WinRect.Top,
  291.                                         0, 0, HInstance, nil);
  292.   if FWindowHandle = 0 then begin
  293.     Log.Log('TWin32AppStarter.Create: Window creation failed', lkFatalError);
  294.     Exit;
  295.   end;
  296.   ShowWindow(FWindowHandle, SW_NORMAL);
  297.   HandleMessages := True;
  298. end;
  299. procedure TWin32AppStarter.PrintError(const Msg: string; ErrorType: TLogLevel);
  300. begin
  301.   case ErrorType of
  302.     lkInfo:       MessageBox(WindowHandle, PChar(Msg), 'Information', MB_ICONINFORMATION);
  303.     lkWarning:    MessageBox(WindowHandle, PChar(Msg), 'Warning',     MB_ICONWARNING);
  304.     lkError:      MessageBox(WindowHandle, PChar(Msg), 'Error',       MB_ICONERROR);
  305.     lkFatalError: MessageBox(WindowHandle, PChar(Msg), 'Fatal error', MB_ICONSTOP);
  306.   end;
  307.   Log.Log(Msg, ErrorType);
  308. end;
  309. destructor TWin32AppStarter.Destroy;
  310. begin
  311.   if WindowHandle <> 0 then DestroyWindow(WindowHandle);
  312.   if not UnRegisterClass(PChar(WindowClassName), hInstance) then
  313.   if Log <> nil then Log.Log('Error unregistering window class: ' + GetOSErrorStr(GetLastError), lkError);
  314.   inherited;
  315. end;
  316. function TWin32AppStarter.isAlreadyRunning(ActivateExisting: Boolean): Boolean;
  317. var h: HWND;
  318. begin
  319.   h := FindWindow(PChar(WindowClassName), nil);
  320.   Result := h <> 0;
  321.   if Result and ActivateExisting then begin
  322. //    SetActiveWindow(h);
  323.     SetForegroundWindow(h);
  324.     PostMessage(h, WM_NOTIFYTRAYICON, 0, WM_LBUTTONDOWN);
  325.   end;
  326.   {$IFDEF DEBUGMODE}
  327.   if Result and ActivateExisting then PostMessage(h, WM_NOTIFYTRAYICON, 0, WM_LBUTTONDOWN);
  328.   SetWindowPos(h, HWND_TOP, GetSystemMetrics(SM_CXSCREEN) div 2, 0, GetSystemMetrics(SM_CXSCREEN) div 2, GetSystemMetrics(SM_CYSCREEN)*2 div 3, SWP_NOACTIVATE{ or SWP_NOSIZE});
  329.   Result := False;
  330.   {$ENDIF}
  331. end;
  332. function TWin32AppStarter.Process: Boolean;
  333. var Msg: tagMSG;
  334. begin
  335.   if HandleMessages then begin
  336.     if (PeekMessage(Msg, WindowHandle, 0, 0, PM_REMOVE)) then begin
  337.       repeat
  338.         with Msg do begin
  339.           if message = WM_QUIT then Terminated := True;
  340.           if (message = WM_KEYDOWN) or (message = WM_KEYUP) or (message = WM_SYSKEYDOWN) or (message = WM_SYSKEYUP) then TranslateMessage(Msg);
  341.         end;
  342.         DispatchMessage(Msg);
  343.       until not PeekMessage(Msg, WindowHandle, 0, 0, PM_REMOVE);
  344.     end else if not Active then begin
  345.       if InactiveSleepAmount >= 0 then begin
  346.         Sleep(InactiveSleepAmount);
  347.   //      Log.Log('sleeping...');
  348.       end;
  349.       FActive := GetActiveWindow = WindowHandle;
  350.     end;
  351.   end;
  352.   Result := not Terminated;
  353. end;
  354. { TTrayAppStarter }
  355. function TTrayAppStarter.AddTrayIcon: Boolean;
  356. const
  357.   TrayMsg = 'Click to restore ';
  358.   MsgMaxLength = 64;
  359. var i, len: Integer; Title: PChar;
  360. begin
  361.   with TrayIcon do begin
  362.     cbSize := SizeOf(TNotifyIconData);
  363.     {$IFDEF FPC} HWnd := WindowHandle; {$ELSE} Wnd := WindowHandle; {$ENDIF}
  364.     uID := 1;
  365.     uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP;
  366.     uCallBackMessage := WM_NOTIFYTRAYICON;
  367.     hIcon := WindowClass.hIcon;
  368.     szTip := TrayMsg;
  369.     Getmem(Title, MsgMaxLength*4);       // Reserve memory for a unicode string
  370.     if GetWindowText(WindowHandle, Title, MsgMaxLength-1) = 0 then begin
  371.       FreeMem(Title);
  372.       Title := PChar(WindowClassName);
  373.     end;
  374.     if Length(Title) + Length(TrayMsg) < MsgMaxLength then
  375.       Len := Length(Title) else
  376.         Len := MsgMaxLength-Length(TrayMsg);
  377.     for i := 1 to Len do szTip[i+Length(TrayMsg)-1] := Title[i-1];
  378.     FreeMem(Title);
  379.   end;
  380.   Result := Shell_NotifyIcon(NIM_ADD, PNotifyIconData(@TrayIcon));
  381. end;
  382. procedure TTrayAppStarter.RemoveTrayIcon;
  383. begin
  384.   Shell_NotifyIcon(NIM_DELETE, PNotifyIconData(@TrayIcon));
  385. end;
  386. function TTrayAppStarter.ProcessMessage(Msg: Longword; wParam, lParam: Integer): Integer;
  387. begin
  388.   Result := inherited ProcessMessage(Msg, wParam, lParam);
  389.   case Msg of
  390.     WM_NOTIFYTRAYICON: if lParam = WM_LBUTTONDOWN then begin
  391.       RemoveTrayIcon;
  392.       ShowWindow(WindowHandle, SW_SHOW);
  393.       ShowWindow(WindowHandle, SW_RESTORE);
  394.     end;
  395. //    WM_ERASEBKGND, WM_PAINT: Result := 1;//DefWindowProc(WHandle, Msg, WParam, LParam);
  396.     WM_SIZE{, WM_CANCELMODE}: begin
  397.       if wParam = SIZE_MINIMIZED then begin
  398.         if AddTrayIcon then ShowWindow(WindowHandle, SW_HIDE);
  399.         FActive := False;
  400.       end;
  401.     end;
  402.   end;
  403. end;
  404. destructor TTrayAppStarter.Destroy;
  405. begin
  406.   RemoveTrayIcon;
  407.   inherited;
  408. end;
  409. { TScreenSaverStarter }
  410. function PreviewThreadProc(Data : Integer) : Integer; StdCall;
  411. begin
  412.   Sleep(1000);
  413.   Result := 0; Randomize;
  414.   ShowWindow(CurrentStarter.WindowHandle, SW_SHOW); UpdateWindow(CurrentStarter.WindowHandle);
  415.   repeat
  416.     InvalidateRect(CurrentStarter.WindowHandle, nil, False);
  417.     Sleep(30);
  418.   until CurrentStarter.Terminated;
  419.   PostMessage(CurrentStarter.WindowHandle, wm_Destroy, 0, 0);
  420. end;
  421. constructor TScreenSaverStarter.Create(const AProgramName: string; AWindowProc: TWndProc; Options: TStarterOptions);
  422. begin
  423.   inherited;
  424.   GetWindowRect(GetDesktopWindow, Rect);
  425.   ParseParamStr;
  426.   Run(FParentWindow <> 0);
  427. {  if (cc = 'C') Then RunSettings
  428.   Else If (cc = 'P') Then RunPreview
  429.        Else If (cc = 'A') Then RunSetPassword
  430.             Else RunFullScreen;}
  431. end;
  432. procedure TScreenSaverStarter.ParseParamStr;
  433. var s: string;
  434. begin
  435.   s := ParamStr(1);
  436.   if (Length(s) > 1) then begin
  437.     Delete(s, 1, 1); { delete first char - usally "/" or "-" }
  438. //    S[1] := UpCase(S[1]);
  439.     ParamChar := UpCase(s[1]);
  440.   end;
  441.   if (ParamChar = 'P') then begin
  442.     FParentWindow := StrToIntDef(ParamStr(2), 0);
  443.     GetWindowRect(FParentWindow, Rect);
  444.   end else FParentWindow := 0;
  445.   if (ParamChar = 'C') then Configure;
  446. end;
  447. procedure TScreenSaverStarter.Run(APreviewMode: Boolean);
  448. var Dummy: Cardinal;
  449. begin
  450.   FPreviewMode := APreviewMode;
  451.   FMoveCounter := 10;
  452.   WindowClass.style := 0; //CS_VREDRAW or CS_HREDRAW or CS_OWNDC;
  453.   WindowClass.lpfnWndProc := {$IFNDEF FPC}@{$ENDIF}WindowProc;
  454.   WindowClass.cbClsExtra := 0;
  455.   WindowClass.cbWndExtra := 0;
  456.   WindowClass.hIcon := LoadIcon(hInstance, 'MAINICON');
  457.   WindowClass.hCursor := LoadCursor(WindowClass.hInstance*0, IDC_ARROW);
  458.   WindowClass.hInstance := HInstance;
  459.   WindowClass.hbrBackground := 0;//GetStockObject(WHITE_BRUSH);
  460.   WindowClass.lpszMenuName := nil;
  461.   FWindowClassName := 'TAWindowClass(' + ProgramName + ')';
  462.   WindowClass.lpszClassName := PChar(FWindowClassName);
  463.   if RegisterClass(WindowClass) = 0 then begin
  464.     Log.Log('TScreenSaverStarter.Create: Window class registration failed', lkFatalError); 
  465.     Exit;
  466.   end;
  467.   if (FParentWindow <> 0) then begin
  468.     FWindowStyle  := WS_CHILD or WS_VISIBLE or WS_DISABLED;
  469.     FWindowHandle := CreateWindow(WindowClass.lpszClassName, WindowClass.lpszClassName, FWindowStyle, 0, 0, Rect.Right-Rect.Left, Rect.Bottom-Rect.Top, FParentWindow, 0, hInstance, nil);
  470.     MutexWindowHandle := 0;//CreateWindow(WindowClass.lpszClassName, 'Mutex', WS_DISABLED, -10, -10, 1, 1, 0, 0, hInstance, nil);
  471. //    SetWindowPos(MutexWindowHandle, 0, -10, -10, 1, 1, SWP_HIDEWINDOW or SWP_NOACTIVATE);
  472.   end else begin
  473. //    WindowStyle := WS_OVERLAPPED or WS_CAPTION or WS_THICKFRAME or WS_MINIMIZEBOX or WS_MAXIMIZEBOX or WS_SIZEBOX or WS_SYSMENU;
  474.     FWindowStyle  := Cardinal(WS_VISIBLE or WS_POPUP);
  475.     FWindowHandle := CreateWindow(WindowClass.lpszClassName, nil{WindowClass.lpszClassName},
  476.                                  FWindowStyle, 0, 0,
  477.                                  Rect.Right-Rect.Left, Rect.Bottom-Rect.Top, 0, 0, hInstance, nil);
  478.     {$IFNDEF DEBUGMODE}
  479.     SetWindowPos(WindowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOREDRAW);
  480.     {$ENDIF}    
  481.   end;
  482. // ShowWindow(CurrentStarter.WindowHandle, SW_SHOW); UpdateWindow(CurrentStarter.WindowHandle);
  483.   if FPreviewMode then OSUtils.ShowCursor;
  484. //  if PreviewMode then CreateThread(nil, 0, @PreviewThreadProc, nil, 0, Dummy);
  485.   if not FPreviewMode then SystemParametersInfo(SPI_SCREENSAVERRUNNING, 1, @Dummy, 0);
  486. end;
  487. procedure TScreenSaverStarter.SetPassword;
  488. var
  489.   Lib: THandle;
  490.   ChgPassAFunc: TChgPassAFunc;
  491. begin
  492.   Lib := LoadLibrary('MPR.DLL');
  493.   if Lib > 0 Then begin
  494.     ChgPassAFunc := TChgPassAFunc(GetProcAddress(Lib,'PwdChangePasswordA'));
  495.     if (@ChgPassAFunc <> nil) then ChgPassAFunc('SCRSAVE', StrToInt(ParamStr(2)), 0, 0);
  496.     FreeLibrary(Lib);
  497.   end;
  498. end;
  499. function TScreenSaverStarter.QueryPassword: Boolean;
  500. var
  501.   Key: hKey;
  502.   D1, D2: Integer; { two dummies }
  503.   Value: Integer;
  504.   Lib: THandle;
  505.   VerifySSPassFunc: TVerifySSPassFunc;
  506. begin
  507.   Result := True;
  508.   if RegOpenKeyEx(HKEY_CURRENT_USER, 'Control PanelDesktop', 0, KEY_READ,Key) = ERROR_SUCCESS then begin
  509.     D2 := SizeOf(Value);
  510.     if RegQueryValueEx(Key, 'ScreenSaveUsePassword', nil, @D1, @Value, @D2) = ERROR_SUCCESS then begin
  511.       if Value <> 0 then begin
  512.         Lib := LoadLibrary('PASSWORD.CPL');
  513.         if Lib > 0 then begin
  514.           VerifySSPassFunc := TVerifySSPassFunc(GetProcAddress(Lib,'VerifyScreenSavePwd'));
  515.           AdjustCursorVisibility(True);
  516.           if @VerifySSPassFunc <> nil then Result := VerifySSPassFunc(FParentWindow);
  517.           AdjustCursorVisibility(False);
  518.           FMoveCounter := 10; { reset again if password was wrong }
  519.           FreeLibrary(Lib);
  520.         end;
  521.       end;
  522.     end;
  523.     RegCloseKey(Key);
  524.   end;
  525. end;
  526. procedure TScreenSaverStarter.Configure;
  527. begin
  528.   MessageBox(WindowHandle, 'There is no settings yet.'#13#10#13#10'You can use Q/W/E/S/Z/C keys to control view angle', 'Info', MB_OK);
  529.   Terminated := True;
  530. end;
  531. procedure DrawSingleBox;
  532. {var
  533.   PaintDC  : hDC;
  534.   Info     : TPaintStruct;
  535.   OldBrush : hBrush;
  536.   X,Y      : Integer;
  537.   Color    : LongInt;
  538.   WndRect: TRect;}
  539. begin
  540. {  PaintDC := beginPaint(CurrentStarter.WindowHandle, Info);
  541.   GetWindowRect(CurrentStarter.WindowHandle, WndRect);
  542.   X := Random(WndRect.Right); Y := Random(WndRect.Bottom);
  543.   Color := RGB(Random(255),Random(255),Random(255));
  544.   OldBrush := SelectObject(PaintDC,CreateSolidBrush(Color));
  545.   RoundRect(PaintDC,X,Y,X+Random(WndRect.Right-X),Y+Random(WndRect.Bottom-Y),20,20);
  546.   DeleteObject(SelectObject(PaintDC,OldBrush));
  547.   EndPaint(CurrentStarter.WindowHandle, Info);}
  548. end;
  549. function TScreenSaverStarter.ProcessMessage(Msg: Longword; wParam, lParam: Integer): Integer;
  550. begin
  551.   Result := inherited ProcessMessage(Msg, wParam, lParam);
  552.   case Msg of
  553.     WM_NCCREATE: begin Result := 1; Exit; end;
  554.     WM_DESTROY: begin Result := 1; PostQuitMessage(0); Terminated := True; end;
  555. //    WM_PAINT: DrawSingleBox; { paint something }
  556.     WM_KEYDOWN: ;//if not PreviewMode then Finished := True;//AskPassword;
  557.     WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN, WM_MOUSEMOVE: begin
  558.       if (not FPreviewMode) then begin
  559.         Dec(FMoveCounter);
  560.        if (FMoveCounter <= 0) then Terminated := True;//AskPassword;
  561.       end;
  562.     end;
  563.     WM_CLOSE: begin Result := 1; Terminated := True; end;
  564.     WM_SHOWWINDOW: if wParam = 0 then Terminated := True;
  565.     WM_ACTIVATEAPP, WM_ACTIVATE, WM_NCACTIVATE: if not FPreviewMode then begin
  566.       if wParam and 65535 = WA_INACTIVE then Terminated := True;
  567.     end;
  568.     WM_SYSCOMMAND: begin
  569.       CallDefaultMsgHandler := False;
  570.       case wParam and $FFF0 of
  571.         SC_CLOSE: ;//Finished := True;
  572.         SC_SCREENSAVE: ;
  573.         else CallDefaultMsgHandler := True;
  574.       end;
  575.     end;
  576.   end;
  577. end;
  578. procedure TScreenSaverStarter.PrintError(const Msg: string; ErrorType: TLogLevel);
  579. begin
  580.   Log.Log(Msg, ErrorType);
  581. end;
  582. destructor TScreenSaverStarter.Destroy;
  583. var Dummy: Cardinal;
  584. begin
  585. //  if not PreviewMode then
  586.   SystemParametersInfo(SPI_SCREENSAVERRUNNING, 0, @Dummy, 0);
  587.   AdjustCursorVisibility(True);
  588.   if MutexWindowHandle <> 0 then DestroyWindow(MutexWindowHandle);
  589.   if WindowHandle <> 0 then DestroyWindow(WindowHandle);
  590.   UnRegisterClass(PChar(FWindowClassName), hInstance);
  591.   inherited;
  592. end;
  593. end.