Bildschirmschoner unter Windows blockieren

Hallo.

Gibt es eine Möglichkeit, dass ein Programm den Bildschirmschoner blockiert, so dass dieser nicht nach dem Timeout anspringt? Ich möchte den dabei aber nicht ganz deaktivieren, stattdessen soll der Bildschirmschoner wieder aktiv sein, wenn mein Programm nicht läuft. Wie bekomme ich das hin?

Danke für die Hilfe,

Sebastian.

Nachtrag
Ganz vergessen:
Das ganze soll mit Delphi 7 funktionieren (zur Not auch Delphi 2005) und unter möglichst allen NT-basierten Windows-Versionen (also 2000, XP, 2003, Vista, …)

Hallo Sebastian,

Wie bekomme ich das hin?

Setze eine Private-Variable des Typs Byte auf die Form, z.B.

type
 TForm1 = class(TForm)
...
private
 ScreenSaverActive: Byte;
...

Diese dient dazu, die Benutzereinstellung auszulesen und zu speichern, damit nach Programmende wieder alles wie vorher ist.
Dann kannst Du z.B. im FormShow die Bildschirmschoner-Einstellung auslesen und ihn deaktivieren, falls er aktiv ist. Beim Programmende setzt Du wieder alles in seinen ursprünglichen Zustand.

procedure TForm1.FormShow(Sender: TObject);
begin
 SystemParametersInfo(SPI\_GETSCREENSAVEACTIVE, 0, @ScreenSaverActive, 0) ;
 if ScreenSaverActive \> 0 then
 SystemParametersInfo(SPI\_SETSCREENSAVEACTIVE, 0, nil, 0);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 SystemParametersInfo(SPI\_SETSCREENSAVEACTIVE, ScreenSaverActive, nil, 0);
end;

Schönen Gruß,
Rudy

Hallo.

Wie bekomme ich das hin?

Setze eine Private-Variable des Typs Byte auf die Form, z.B.

type
TForm1 = class(TForm)

private
ScreenSaverActive: Byte;

Diese dient dazu, die Benutzereinstellung auszulesen und zu
speichern, damit nach Programmende wieder alles wie vorher
ist.
Dann kannst Du z.B. im FormShow die
Bildschirmschoner-Einstellung auslesen und ihn deaktivieren,
falls er aktiv ist. Beim Programmende setzt Du wieder alles in
seinen ursprünglichen Zustand.

procedure TForm1.FormShow(Sender: TObject);
begin
SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0,
@ScreenSaverActive, 0) ;
if ScreenSaverActive > 0 then
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, nil, 0);
end;

procedure TForm1.FormClose(Sender: TObject; var Action:
TCloseAction);
begin
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,
ScreenSaverActive, nil, 0);
end;

Ok soweit, ich habe zwar kein Form, weil das eine Konsolenanwengung ist, aber das Prinzip ist klar. Aber wenn jemand den Prozess des Programs über den Taskmanager beendet, dann wird die Einstellung auch nicht wieder zurückgesetzt?
Wie machen das z.B. einige Videoplayer? Wenn da ein Video läuft, springt der Bildschirmschoner nicht an, obwohl er laut Windows noch aktiv ist. Kann man sowas auch mit Deplhi hinbekommen?

Sebastian.

Hallo Sebastian,

Ok soweit, ich habe zwar kein Form, weil das eine
Konsolenanwengung ist, aber das Prinzip ist klar.Aber wenn
jemand den Prozess des Programs über den Taskmanager beendet,
dann wird die Einstellung auch nicht wieder zurückgesetzt?

Wenn der Prozess gekillt wird, dann hat das ungeahnte Folgen - da gibt es im selben Prozess keine Möglichkeit noch etwas zu tun. Deshalb auch die Warnung vom Taskmanager, wenn man das macht - es kann zu Systeminstabilität führen. CTRL_C, CTRL_CLOSE, etc. im ConsoleCtrlHandler abzufangen wird da wohl nicht reichen.

Wie machen das z.B. einige Videoplayer? Wenn da ein Video
läuft, springt der Bildschirmschoner nicht an, obwohl er laut
Windows noch aktiv ist. Kann man sowas auch mit Deplhi
hinbekommen?

Die Win32-Videoplayer, die ich kenne, sind keine Konsolenanwendungen :smile: Wahrscheinlich fangen die meisten den Windows-Message WM_SYSCOMMAND ab und blockieren sozusagen den Bildschirmschoner ‚passiv‘. Bevor Windows den Bildschirmschoner aktiviert, sendet es die Nachricht WM_SYSCOMMAND mit dem Wert SC_SCREENSAVE im WParam an die aktuell aktive Anwendung - dann reicht es den Message abzufangen und message.result auf 0 zu setzen; schon aktiviert Windows den Bildschirmschoner nicht mehr. Wenn die Anwenung inaktiv ist, hat dies aber keine Wirkung. Wenn Du das in einer Konsolenanwendung hinbekommst, dann sollte es kein Problem sein ^^.

Bei Multitier-Datenbankanwendungen mache ich immer einen Service, um zu entdecken, ob eine Instanz der Anwendung abgebrochen wurde - also beim Start wird zum Service verbunden; wenn die Anwendung abstürzt, abbricht oder beendet wird verliert die Anwendung die Verbindung zum Service - das kann ich dann im Service abfangen und beispielsweise von zur Laufzeit dieser Instanz eingeführte Locks auf Datensätze wieder freigeben.

Schönen Gruß,
Rudy

Hallo.

Ok soweit, ich habe zwar kein Form, weil das eine
Konsolenanwengung ist, aber das Prinzip ist klar.Aber wenn
jemand den Prozess des Programs über den Taskmanager beendet,
dann wird die Einstellung auch nicht wieder zurückgesetzt?

Wenn der Prozess gekillt wird, dann hat das ungeahnte Folgen -
da gibt es im selben Prozess keine Möglichkeit noch etwas zu
tun. Deshalb auch die Warnung vom Taskmanager, wenn man das
macht - es kann zu Systeminstabilität führen.

Das ist natürlich klar.

Wie machen das z.B. einige Videoplayer? Wenn da ein Video
läuft, springt der Bildschirmschoner nicht an, obwohl er laut
Windows noch aktiv ist. Kann man sowas auch mit Deplhi
hinbekommen?

Die Win32-Videoplayer, die ich kenne, sind keine
Konsolenanwendungen :smile:

OK, die, die ich kenne, auch nicht. Aber vielleicht geht deren Vorgehen ja auch in Konsolenanwendungen.

Wahrscheinlich fangen die meisten den
Windows-Message WM_SYSCOMMAND ab und blockieren sozusagen den
Bildschirmschoner ‚passiv‘. Bevor Windows den
Bildschirmschoner aktiviert, sendet es die Nachricht
WM_SYSCOMMAND mit dem Wert SC_SCREENSAVE im WParam an die
aktuell aktive Anwendung - dann reicht es den Message
abzufangen und message.result auf 0 zu setzen; schon aktiviert
Windows den Bildschirmschoner nicht mehr. Wenn die Anwenung
inaktiv ist, hat dies aber keine Wirkung.

Hm, es wäre natürlich schön, wenn das auch geht, wenn das Programm im Hintergrund läuft.

Vielleicht muss ich doch anders vorgehen. Wofür ich das ganze brauche:
Ich habe mir ein Programm geschrieben, dass zu einem per Parameter bestimmbaren Zeitpunkt den Rechner runterfährt. Als Ersatz für den shutdown-Befehl von Windows, weil der ja nur mit Administratorrechten will. Das Problem ist, dass mein Programm den Rechner nur runterfährt, wenn nicht der Bildschirmschoner aktiv ist.
Ist der Bildschirmschoner aktiv, geht folgender Befehl schief:

LookupPrivilegeValue(nil, 'SeShutdownPrivilege', tp.Privileges[0].Luid);

Wenn ich also den Bildschirmschoner nicht deaktiviert bekomme, hast du eine Idee, wie ich es hinbekomme, dass ich trotz aktivem Bildschirmschoner runterfahren kann?

Sebastian.

Hallo Sebastian,

Deshalb auch die Warnung vom Taskmanager, wenn man das
macht - es kann zu Systeminstabilität führen.

Das ist natürlich klar.

Imo könntest Du das auch akzeptieren, der Nutzer muss schließlich wissen, was er tut, wenn er einen Prozess runterschießt. Du fängst die CTRL-Messages für Logoff, Shutdown, Close etc. ab und stellst da die Einstellung wieder her. In der Registry legst Du Dir einen Schlüssel an, der beim ordnungsgemäßen Herunterfahren zurückgestellt wird, und kannst so rausfinden, ob Du beim nochmaligen Start des Programms den Zustand vor dem Absturz wiederherstellen musst.

Hm, es wäre natürlich schön, wenn das auch geht, wenn das
Programm im Hintergrund läuft.

Das funktioniert nicht so einfach. Eine Möglichkeit wäre, die Funktion in eine DLL auszulagern und einen System-Weiten Hook einzubringen der WM_SYSCOMMAND abfängt und dann irgendwas macht, um den Screensaver zu deaktivieren - aber davon halte ich nicht viel, weil das ziemlich dünnes Eis ist, auf dem man sich da bewegt. Da reicht schon irgendeine andere Anwendung, die Hooks verwendet und CallNextHook() nicht aufruft und es funktioniert nicht mehr. Wie sich das genau verhält, wenn man die Anwendung killt, weiß ich nicht, müsste man testen.

Wenn ich also den Bildschirmschoner nicht deaktiviert bekomme,
hast du eine Idee, wie ich es hinbekomme, dass ich trotz
aktivem Bildschirmschoner runterfahren kann?

Dein eigentliches Problem bleibt der Bildschirmschoner - aber im Grunde stört der Dich doch nicht, bis Du herunterfährst, oder? Wäre es nicht ausreichend, einfach den Bildschirmschoner beenden, falls er aktiv geworden ist, kurz bevor Du die Maschine herunterfährst? Das würde mir als Nutzer auch freundlicher erscheinen. Unter Win95 kein Problem (WM_CLOSE), bei NT-basierten Systemen ist das etwas anders zu realisieren, aber Microsoft hat dafür sogar eine Doku geschrieben: http://support.microsoft.com/default.aspx?scid=kb;en…

Schönen Gruß,
Rudy

Hallo.

Deshalb auch die Warnung vom Taskmanager, wenn man das
macht - es kann zu Systeminstabilität führen.

Das ist natürlich klar.

Imo könntest Du das auch akzeptieren, der Nutzer muss
schließlich wissen, was er tut, wenn er einen Prozess
runterschießt.

Das ist natürlich ein gutes Argument.

Dein eigentliches Problem bleibt der Bildschirmschoner - aber
im Grunde stört der Dich doch nicht, bis Du herunterfährst,
oder? Wäre es nicht ausreichend, einfach den Bildschirmschoner
beenden, falls er aktiv geworden ist, kurz bevor Du die
Maschine herunterfährst? Das würde mir als Nutzer auch
freundlicher erscheinen. Unter Win95 kein Problem (WM_CLOSE),
bei NT-basierten Systemen ist das etwas anders zu realisieren,
aber Microsoft hat dafür sogar eine Doku geschrieben:
http://support.microsoft.com/default.aspx?scid=kb;en…

Da würde dann aber die Passwort-Eingabe auftauchen, wenn ich das richtig verstehe. Und das wäre dann auch nicht so ganz das, was ich bräuchte.

Scheinbar ist es wirklich am besten, den Bildschirmschoner einfach zu deaktivieren und direkt vor dem Runterfahren wieder zu aktivieren. Und falls das Programm anderweitig beendet wird, eben auch wieder zu aktivieren. Wenn jetzt jemand den Prozess killt, bleibt der Bildschirmschoner halt abgeschaltet.

Sebastian.

Hallo Sebastian,

http://support.microsoft.com/default.aspx?scid=kb;en…

Da würde dann aber die Passwort-Eingabe auftauchen, wenn ich
das richtig verstehe. Und das wäre dann auch nicht so ganz
das, was ich bräuchte.

Das habe ich nicht ausgetestet, in der Doku steht das nicht explizit - aber wäre irgendwie logisch, hab gar nicht mehr daran gedacht, dass sich der Bildschirmschoner mit der Sperrung der Arbeitsstation verbinden lässt (das verwende ich nie). Einen Versuch wäre es allemal wert.

Scheinbar ist es wirklich am besten, den Bildschirmschoner
einfach zu deaktivieren und direkt vor dem Runterfahren wieder
zu aktivieren. Und falls das Programm anderweitig beendet
wird, eben auch wieder zu aktivieren. Wenn jetzt jemand den
Prozess killt, bleibt der Bildschirmschoner halt abgeschaltet.

Finde ich auch akzeptabel und weniger riskant als das Anhängen von Hooks an Prozessen, wenn das mit dem Beenden des Screensavers nicht klappt. Du änderst damit nur temporär ein Flag in der Registry. Allerdings muss der Nutzer dann auch drauf aufmerksam gemacht werden, dass der Bildschirmschoner nicht mehr seine Arbeitsstation sperrt, weil er nicht anspringen wird. Was passiert übrigens, wenn man die Station manuell sperrt?

Schönen Gruß,
Rudy

Hallo.

http://support.microsoft.com/default.aspx?scid=kb;en…

Da würde dann aber die Passwort-Eingabe auftauchen, wenn ich
das richtig verstehe. Und das wäre dann auch nicht so ganz
das, was ich bräuchte.

Das habe ich nicht ausgetestet, in der Doku steht das nicht
explizit

Auf der verlinkten Seite steht das eigentlich:
—Zitat—
Note that if a screen saver password is set, the following code brings up the password dialog box, prompts the user for a password, and then actually terminates the screen saver application.
—Zitat Ende—

Was passiert übrigens, wenn man die Station
manuell sperrt?

Dann funktioniert das Runterfahren genausowenig. Zumindest unter Windows XP.

Sebastian.

Hi Sebastian,

http://support.microsoft.com/default.aspx?scid=kb;en…

Das habe ich nicht ausgetestet, in der Doku steht das nicht
explizit

Auf der verlinkten Seite steht das eigentlich:

Stimmt, hatte ich trotz nochmaligen Lesens übersehen - ich schiebs mal auf die Affenhitze. ^^

Was passiert übrigens, wenn man die Station
manuell sperrt?

Dann funktioniert das Runterfahren genausowenig. Zumindest
unter Windows XP.

Ist dann das Sperren der Station nicht irgendwie wie der Bildschirmschoner selbst? Also will sagen, dass wenn man ein Passwort and den Bildschirmschoner anbringt, macht man das ja aus Sicherheitsgründen. Man kann als Entwickler nun entscheiden, ob man diese Möglichkeit von vornherein ausschließt durch blockieren des Bildschirmschoners, oder man lässt dem Nutzer die Wahl. Persönlich wäre mir zweiteres lieber, das garantiert leider nicht die Funktion des Programms in allen Fällen. Da ist nun Kreativität gefragt - ich glaube wir sind nun alle Möglichkeiten durchgegangen :smile:

Schönen Gruß,
Rudy

Hallo.

http://support.microsoft.com/default.aspx?scid=kb;en…

Das habe ich nicht ausgetestet, in der Doku steht das nicht
explizit

Auf der verlinkten Seite steht das eigentlich:

Stimmt, hatte ich trotz nochmaligen Lesens übersehen - ich
schiebs mal auf die Affenhitze. ^^

Ja, diese Hitze. Schrecklich. Aber in 2 Monaten fängt ja der Herbst an…

Was passiert übrigens, wenn man die Station
manuell sperrt?

Dann funktioniert das Runterfahren genausowenig. Zumindest
unter Windows XP.

Ist dann das Sperren der Station nicht irgendwie wie der
Bildschirmschoner selbst? Also will sagen, dass wenn man ein
Passwort and den Bildschirmschoner anbringt, macht man das ja
aus Sicherheitsgründen.

Stimmt.

Man kann als Entwickler nun
entscheiden, ob man diese Möglichkeit von vornherein
ausschließt durch blockieren des Bildschirmschoners, oder man
lässt dem Nutzer die Wahl. Persönlich wäre mir zweiteres
lieber, das garantiert leider nicht die Funktion des Programms
in allen Fällen.

Genau das ist das Problem.

Da ist nun Kreativität gefragt - ich glaube
wir sind nun alle Möglichkeiten durchgegangen :smile:

Bliebe nur die Möglichkeit, dass das Programm den Shutdown auch initiieren kann, wenn der Bildschirmschoner läuft. Aber das klappt ja leider nicht.
Naja, muss ich mich halt mit dem begnügen, was funktioniert.

Danke,
Sebastian.

Hi Sebastian,

guckst Du z.B.
http://msdn.microsoft.com/library/default.asp?url=/l…

So geht´s auch ganz ohne Tricks. Es gibt auch noch eine spezielle Seite zum An-/Ausschalten des Screensavers über das System-Object. Habe die dummerweise nicht gefunden. Gib mal in der MS KB „Screensaver“ ein und such ein bißchen.

HTH

Tim

Hallo.

guckst Du z.B.
http://msdn.microsoft.com/library/default.asp?url=/l…

So geht´s auch ganz ohne Tricks.

Hm, muss ich aber auch später wieder aktivieren, oder geht das von selbst? Auf der Seite steht jedenfalls nichts davon, dass das automatisch geht.

Es gibt auch noch eine
spezielle Seite zum An-/Ausschalten des Screensavers über das
System-Object. Habe die dummerweise nicht gefunden. Gib mal in
der MS KB „Screensaver“ ein und such ein bißchen.

Da habe ich leider nichts passendes gefunden.
Ich habe jetzt die Variante von Rudy mit SystemParametersInfo genommen und dann einen ConsoleCtrlHandler eingebaut, der beim Beenden des Programms den Bildschirmschoner wieder aktiviert, falls er vorher aktiviert war.

Sebastian.