Delphi-PRAXiS
Seite 3 von 3     123   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Hibernate und Standby erkennen (https://www.delphipraxis.net/81507-hibernate-und-standby-erkennen.html)

Sir Rufo 22. Jul 2016 12:59

AW: Hibernate und Standby erkennen
 
Adhoc sehe ich zwei Möglichkeiten:
  1. Stateless mit einem ClientDataSet (der Umbau wird aber wohl zu aufwändig sein)
  2. Eine statische Klasse die Tokens (Interface wegen ARC) herausgibt und beim ersten Token den Modus setzt und beim Verschwinden des letzten Tokens den Status wieder zurücksetzt (geringer Aufwand beim Einbau in das aktuelle Programm)

Auf die Schnelle mal dahingetippt
Delphi-Quellcode:
unit System.PowerManagement;

interface

uses
  System.Generics.Collections;

type
  TPowerModeOption = ( Display, System, Away );
  TPowerModeOptions = set of TPowerModeOption;

  IPowerManagementToken = interface
    [ '{F6326420-9BE9-4CAE-9EC8-0E6C4EE1B265}' ]
    function GetOptions( ): TPowerModeOptions;
    property Options: TPowerModeOptions read GetOptions;
  end;

  IPowerManagementService = interface
    procedure SetOptions( PowerModeOptions: TPowerModeOptions );
  end;

  PowerManagement = class sealed
  private type
    TInternalPowerManagementToken = class
    private
      FOptions: TPowerModeOptions;
    public
      constructor Create( Options: TPowerModeOptions );
      destructor Destroy; override;

      property Options: TPowerModeOptions read FOptions;
    end;

    TPowerManagementToken = class( TInterfacedObject, IPowerManagementToken )
    private
      function GetOptions( ): TPowerModeOptions;
    private
      FToken: TInternalPowerManagementToken;
    public
      constructor Create( Options: TPowerModeOptions );
      destructor Destroy; override;
    end;

    TNullService = class( TInterfacedObject, IPowerManagementService )
    private { IPowerManagementService }
      procedure SetOptions( PowerModeOptions: TPowerModeOptions );
    end;
  private
    class var _Service      : IPowerManagementService;
    class var _Tokens       : TList<TInternalPowerManagementToken>;
    class var _CurrentOptions: TPowerModeOptions;
    class constructor Create( );
    class destructor Destroy( );
    class procedure TokensNotify( Sender: TObject; const Item: TInternalPowerManagementToken; Action: TCollectionNotification );
  public
    class function GetToken( const PowerModeOptions: TPowerModeOptions ): IPowerManagementToken;
  end;

implementation

uses
{$IFDEF MSWINDOWS}
  System.PowerManagement.Win,
{$ENDIF}
  System.SysUtils;

{ PowerManagement.TPowerManagementToken }

constructor PowerManagement.TPowerManagementToken.Create( Options: TPowerModeOptions );
begin
  inherited Create( );
  if Options <> [ ]
  then
    FToken := TInternalPowerManagementToken.Create( Options );
end;

destructor PowerManagement.TPowerManagementToken.Destroy;
begin
  FToken.DisposeOf( );
  inherited;
end;

function PowerManagement.TPowerManagementToken.GetOptions: TPowerModeOptions;
begin
  if Assigned( FToken )
  then
    Result := FToken.Options
  else
    Result := [ ];
end;

{ PowerManagement }

class constructor PowerManagement.Create;
begin
{$IFDEF MSWINDOWS}
  _Service := TWindowsPowerManagementService.Create;
{$ELSE}
  _Service := TNullService.Create;
{$ENDIF}
  _Tokens         := TList<TInternalPowerManagementToken>.Create( );
  _Tokens.OnNotify := TokensNotify;
  _CurrentOptions := [ ];
end;

class destructor PowerManagement.Destroy;
begin
  _Service.SetOptions( [ ] );
  _Tokens.Free;
end;

class function PowerManagement.GetToken( const PowerModeOptions: TPowerModeOptions ): IPowerManagementToken;
var
  lToken: TPowerManagementToken;
begin
  lToken := TPowerManagementToken.Create( PowerModeOptions );
  Result := lToken;
end;

class procedure PowerManagement.TokensNotify(
  Sender   : TObject;
  const Item: TInternalPowerManagementToken;
  Action   : TCollectionNotification );
var
  lToken : TInternalPowerManagementToken;
  lOptions: TPowerModeOptions;
begin
  lOptions := [ ];

  for lToken in _Tokens do
    begin
      lOptions := lOptions + lToken.FOptions;
    end;

  if _CurrentOptions <> lOptions
  then
    begin
      _Service.SetOptions( lOptions );
      _CurrentOptions := lOptions;
    end;
end;

{ PowerManagement.TNullService }

procedure PowerManagement.TNullService.SetOptions( PowerModeOptions: TPowerModeOptions );
begin
  // do nothing
end;

{ PowerManagement.TInternalPowerManagementToken }

constructor PowerManagement.TInternalPowerManagementToken.Create( Options: TPowerModeOptions );
begin
  inherited Create;
  FOptions := Options;
  _Tokens.Add( Self );
end;

destructor PowerManagement.TInternalPowerManagementToken.Destroy;
begin
  _Tokens.Remove( Self );
  inherited;
end;

end.
Delphi-Quellcode:
unit System.PowerManagement.Win;

interface

uses
  Winapi.Windows,
  System.SysUtils,
  System.PowerManagement;

type
  TWindowsPowerManagementService = class( TInterfacedObject, IPowerManagementService )
  private { IPowerManagementService }
    procedure SetOptions( PowerModeOptions: TPowerModeOptions );
  end;

implementation

{ TWindowsPowerManagementService }

procedure TWindowsPowerManagementService.SetOptions( PowerModeOptions: TPowerModeOptions );
var
  esFlags: Cardinal;
  lResult: Cardinal;
begin
  esFlags := 0;

  if TPowerModeOption.Display in PowerModeOptions
  then
    esFlags := esFlags or ES_DISPLAY_REQUIRED;
  if TPowerModeOption.System in PowerModeOptions
  then
    esFlags := esFlags or ES_SYSTEM_REQUIRED;
  if TPowerModeOption.Away in PowerModeOptions
  then
    esFlags := esFlags or ES_AWAYMODE_REQUIRED;

  if esFlags <> 0
  then
    esFlags := esFlags or ES_CONTINUOUS;

  lResult := SetThreadExecutionState( esFlags );
  if lResult = 0
  then
    raise Exception.Create( 'Could not set ThreadExecutionState' );
end;

end.
Delphi-Quellcode:
unit Forms.MainForm;

interface

uses
  Winapi.Windows, Winapi.Messages,
  System.SysUtils, System.Variants, System.Classes, System.PowerManagement,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class( TForm )
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    CheckBox3: TCheckBox;
    SetModeButton: TButton;
    ClearModeButton: TButton;
    procedure ClearModeButtonClick( Sender: TObject );
    procedure SetModeButtonClick( Sender: TObject );
  private
    FToken: IPowerManagementToken;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ClearModeButtonClick( Sender: TObject );
begin
  FToken := nil;
end;

procedure TForm1.SetModeButtonClick( Sender: TObject );
var
  lOptions: TPowerModeOptions;
begin
  lOptions := [ ];

  if CheckBox1.Checked
  then
    lOptions := lOptions + [ TPowerModeOption.Display ];

  if CheckBox2.Checked
  then
    lOptions := lOptions + [ TPowerModeOption.System ];

  if CheckBox3.Checked
  then
    lOptions := lOptions + [ TPowerModeOption.Away ];

  FToken := PowerManagement.GetToken( lOptions );
end;

end.

mm1256 22. Jul 2016 16:48

AW: Hibernate und Standby erkennen
 
Danke @Sir Rufo für das Beispiel. Um auf Anhieb zu verstehen, wie du das meinst, muss ich erst mal meinen Kenntnisstand etwas vertiefen. Schöne Aufgabe für das Wochenende.

Zitat:

Zitat von Neutral General (Beitrag 1343189)
Ja gut aber WAS willst du denn machen? Wenn ein MDI-Child offen ist willst du Standby nicht verhindern, aber du willst auch kein Standby haben. :gruebel: Du musst dich für eins entscheiden.
Oder hoffst du auf eine Datenbankverbindung die den Standby überlebt? Keine Ahnung ob sowas geht, aber darauf würde ich nicht wetten.

Es ist so, wenn kein MDI aktiv ist, habe ich kein Problem damit, bei PBT_APMSUSPEND die Db-Connection zu schließen, und bei PBT_APMRESUMEAUTOMATIC (das kommt ja schon, wenn der User nur seine Maus bewegt) wieder zu verbinden. Wenn aber MDI- oder andere Fenster geöffnet sind, müsste ich mir den Zustand (offen/geschlossen), den Satzzeiger (DB-Cursor) und den Status (Browse, Edit usw.) aller offenen Datenbanken merken und anschließend wieder restaurieren. Dass ist sehr aufwändig, wenn nicht gar unmöglich. Die Datenbank (NexusDB) unterstützt auch einen Re-Connect, aber eben diese umfassende Restauration nicht, und dann kommt die Standby-Verhinderung ins Spiel.

Sir Rufo 22. Jul 2016 18:00

AW: Hibernate und Standby erkennen
 
@mm1256

Eigentlich ganz einfach:

In jeder Form-Instanz die jetzt den Ruhezustand doof finden würde, holst du dir einfach ein Token
Delphi-Quellcode:
FToken := PowerManagement.GetToken( [ TPowerModeOption.System ] );
.

Es ist egal ob du dir das Token holst, wenn die Instanz erzeugt wird, oder erst zum Zeitpunkt wenn du einen Ruhezustand-Kritischen Moment erreichst.

Wenn es der Form-Instanz dann wieder egal ist, ob das System in den Ruhezustand geht, dann einfach das Token auf
Delphi-Quellcode:
nil
setzen.

Die
Delphi-Quellcode:
PowerManagement
-Klasse sorgt nun dafür, dass der Modus ab einem Token eingeschaltet wird und auch wieder ausgeschaltet wird, wenn es kein Token mehr gibt.

mm1256 23. Jul 2016 10:52

AW: Hibernate und Standby erkennen
 
Vielen Dank Sir Rufo für die Erklärung! :thumb:

Jetzt hätte ich nur noch ein Problem zu lösen: Die Anwendung verwendet insgesamt (grob geschätzt) etwa 150 Formulare, aufgeteilt auf mehrere Module (Exen). Viele von den Formularen sind vererbt. Das reduziert zwar den Aufwand etwas, ist mir aber trotzdem noch etwas zu hoch. Aber, für ein kleineres Projekt in dem ich auch diese Anforderung habe, werde ich es mal ausprobieren!

Sir Rufo 23. Jul 2016 11:19

AW: Hibernate und Standby erkennen
 
Du kannst dir diese Funktionalität auch mit einer Unit hineinbringen
Delphi-Quellcode:
unit Vcl.BaseForm;

interface

uses
  System.PowerManagement,
  Vcl.Forms;

type
  TForm = class( Vcl.Forms.TForm )
  private
    FToken: IPowerManagementToken;
    function GetPowerModeOptions: TPowerModeOptions;
    procedure SetPowerModeOptions( const Value: TPowerModeOptions );
  protected
    function GetDefaultPowerMode( ): TPowerModeOptions; virtual;
    property PowerModeOptions: TPowerModeOptions read GetPowerModeOptions write SetPowerModeOptions;
  public
    procedure AfterConstruction; override;
  end;

implementation

{ TForm }

procedure TForm.AfterConstruction;
begin
  FToken := PowerManagement.GetToken( GetDefaultPowerMode( ) );
  inherited;
end;

function TForm.GetDefaultPowerMode: TPowerModeOptions;
begin
  Result := [ ];
end;

function TForm.GetPowerModeOptions: TPowerModeOptions;
begin
  Result := FToken.Options;
end;

procedure TForm.SetPowerModeOptions( const Value: TPowerModeOptions );
begin
  if PowerModeOptions <> Value
  then
    FToken := PowerManagement.GetToken( Value );
end;

end.
und diese Unit einfach nur noch nach der
Delphi-Quellcode:
Vcl.Forms
in die uses Liste aufnehmen. Dann brauchst du bei den Forms, die so etwas benötigen entweder nur die
Delphi-Quellcode:
GetDefaultPowerMode
zu überschreiben oder du setzt einfach den Wert der Eigenschaft
Delphi-Quellcode:
PowerModeOptions
.

;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:50 Uhr.
Seite 3 von 3     123   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz