Windows Desktop Hintergrundfarbe ändern bzw. Registrywert einlesen

Dalai

Grand Admiral Special
Mitglied seit
14.06.2004
Beiträge
7.420
Renomée
262
Standort
Meiningen, Thüringen
Hallo Leute,

ich weiß gar net so richtig, wie ich mein Problem beschreiben soll, aber ich versuchs einfach mal.
Ich denke doch, dass einige Leser hier das Programm BgInfo (www.sysinternals.com/Utilities/BgInfo.html) kennen.
Nun kann man ja in diesem Prog einiges einstellen, unter anderem auch eine andere Hintergrundfarbe für den Windows-Desktop.

Nun zum Problem: Mithilfe welcher Mittel mach ich sowas selbst? Ich vermute, dass BgInfo wahrscheinlich WinAPI-Fkt. benutzt. Aber welche sind das ???

Ich hab schon ne ganze Menge im Netz gefunden, unter anderem, wie man die Desktopsymbole neu einlesen lassen kann, also der IconCache neu aufgebaut wird (Wert in der Registry ändern, Windows-API-Funktion SendMessageTimeout benutzen, Wert wieder zurück und nochmal die Windows-API-Fkt. ausführen) oder auch, dass man den Dateinamen eines Hintergrundbilds einfach in die Registry schreiben kann und dann den Befehl "rundll32 shell32.dll,Control_RunDLL UpdatePerUserSystemParameters" ausführt und schon wird das neue Bild geladen.

Aber wie verändere ich die Hintergrundfarbe des Desktops?

Achso:
Programmiersprache ist mir im Wesentlichen egal, ich bevorzuge Delphi, benutze C++ sehr ungern, Java fällt aus (benötigt leider die JVM), VB muss nicht sein, AutoIt und Windows-Batchdateien gehen auch :)

Ich hoffe mal, dass klar ist, was ich meine, falls nicht, dann bitte einfach fragen ;)
Ich kann mich bei diesem Problem net so richtig ausdrücken...

Danke im Voraus an alle Helfer
MfG Dalai


PS: Hintergrund der ganzen Sache ist unter anderem, dass ich NetExec (www.netexec.de , Multiuser-Switching auch auf NT/2000) benutze und dort die Hintergrundfarbe des Desktops nach Beenden eines zweiten Desktops nicht immer wiederhergestellt wird.
 
Schau Dir mal das API SetSysColors an.
 
Schau Dir mal das API SetSysColors an.
Danke, das hatte ich auch schon benutzt, aber die Farbe bleibt leider nicht erhalten, wenn sich der Benutzer abmeldet.
Das ist also nicht das, was BgInfo macht...

Ich weiß jetzt leider nicht mehr, ob die Farbe beim Aktualisieren mit F5 erhalten blieb, oder einfach wieder zurückgesetzt wurde...

MfG Dalai
 
Man könnte mit RegMon und FileMon versuchen rauszufinden wo Windows das Zeugs hinschreibt wenn man es über die Anzeigeeigenschaften ändert.
 
Man könnte mit RegMon und FileMon versuchen rauszufinden wo Windows das Zeugs hinschreibt wenn man es über die Anzeigeeigenschaften ändert.
Man kann diese Programme verwenden, aber in dieser Sache ist das nicht nötig :-)
Die Einstellungen werden unter HKCU\Control Panel\Colors (für die Farben des derzeitigen Schemas) sowie HKCU\Control Panel\Appearance (die Schemen selbst) gespeichert.

Aber hilft das weiter?
Ich meine, auslesen ist ja kein Problem; selbst auf der Konsole per "reg query <reg_pfad>" geht das, aber was mache ich mit den Werten (bzw ist es ja nur der Wert "Background" in Control Panel\Colors)?

MfG
 
Kann sein, dass ich nen Blackout hab, aber was genau ist das Problem? Du änderst die Werte in der Registry (mittels RegSetValueEx und Konsorten) und sendest dann am besten per SendMessageTimeout/HWND_BROADCAST ein WM_SYSCOLORCHANGE. Das sollte theoretisch funktionieren.
 
Ich hab jetzt folgende Implementation:

Code:
uses windows, messages;

const
  KEY_NAME = 'Control Panel\Colors';

var meinwert: string;

procedure _BroadcastChanges;
var
  success: DWORD;
begin
  SendMessageTimeout(HWND_BROADCAST,
                     WM_SETTINGCHANGE,
//                     WM_SYSCOLORCHANGE,
                     SPI_SETNONCLIENTMETRICS,
//                     0,
//                     NULL,
                     Integer(PChar(KEY_NAME)),
                     SMTO_ABORTIFHUNG,
                     10000,
                     success);
end;

begin
  RegGetString(HKEY_CURRENT_USER, 'Control Panel\Colors\Background', meinwert);
  Sleep(500);
  RegSetString(HKEY_CURRENT_USER, 'Control Panel\Colors\Background', '0 0 0');
  //Sleep(500);
  _BroadcastChanges;
  Sleep(2500);
  RegSetString(HKEY_CURRENT_USER, 'Control Panel\Colors\Background', meinwert);
  _BroadcastChanges;
end.

Die Funktionen RegGetString und RegSetString hab ich von http://www.swissdelphicenter.ch/torry/showcode.php?id=2008 (damit ich mich nicht mit dem Einrichten von Buffern und dem ganzen Kram auseinandersetzen muss).

Der Wert wird korrekt in die Registry geschrieben (nachgeschaut mit regedit -> deswegen auch die 2,5 Sekunden Sleep), aber es hat null Wirkung! Man sieht zwar, dass er den Desktop aktualisiert (flackert kurz), aber die Farbe ändert sich nicht.

MfG Dalai

EDIT: in der uses-Klausel fehlt ein minireg, es muss also heißen
Code:
uses windows, messages, minireg;
 
Zuletzt bearbeitet:
Wenn ein Druck auf F5 den erwünschten Effekt hat, könnte man diesen Code nutzen, um ein gedrücktes F5 zu simulieren. Das ist zwar nicht sonderlich elegant, dürfte aber die einfachste Lösung sein.
 
Wenn ein Druck auf F5 den erwünschten Effekt hat...
Nein, das hat leider genau wie mein Code oben keinen Effekt. Wär nur ein Druck auf F5 nötig, könnte ich mich damit abfinden ;)

Hab ja auch schon andere Implementationen gesehn, die einen Druck auf F5 simulieren, aber das nutzt mir wie gesagt alles nix, leider.

MfG Dalai
 
Okay, nächster Ansatz. :)
Der Desktop ist letzten Endes ein ListView. Du könntest mal versuchen, das Fensterhandle dieses ListViews zu ermitteln und ihm dann ein LVM_SETBKCOLOR senden.

Oder sende mal das WM_SYSCOLORCHANGE direkt an das ListView.

/edit2: Auch könntest Du mal das _BroadcastChanges in diesen Code ändern:
SendMessageTimeout(HWND_BROADCAST,
WM_SYSCOLORCHANGE,
0,
0,
SMTO_ABORTIFHUNG,
10000,
success);
 
Danke, das hatte ich auch schon benutzt, aber die Farbe bleibt leider nicht erhalten, wenn sich der Benutzer abmeldet.
Das ist also nicht das, was BgInfo macht...
Was passiert eigentlich, wenn Du SetSysColors nutzt UND die Werte in der Registry änderst?
 
Oder sende mal das WM_SYSCOLORCHANGE direkt an das ListView.
Du meinst so?

Code:
procedure _BroadcastChanges;
var
  success: DWORD;
begin
  SendMessageTimeout(FindWindow('Progman', 'Program Manager'),
                     WM_SYSCOLORCHANGE,
                     0,
                     0,
                     SMTO_ABORTIFHUNG,
                     10000,
                     success);
end;

/edit2: Auch könntest Du mal das _BroadcastChanges in diesen Code ändern:
SendMessageTimeout(HWND_BROADCAST,
WM_SYSCOLORCHANGE,
0,
0,
SMTO_ABORTIFHUNG,
10000,
success);
Ich hatte beides erfolglos probiert: WM_SYSCOLORCHANGE und WM_SETTINGCHANGE
 
Zuletzt bearbeitet:
Nein, das ListView hat die Fensterklasse SysListView32. Ich habe zur Ermittlung des Handles folgenden Code gefunden:
Code:
function GetDesktopListViewHandle: THandle; var
  s: String; 
begin
  Result := FindWindow('ProgMan', nil);   
  Result := GetWindow(Result, GW_CHILD);
  Result := GetWindow(Result, GW_CHILD); 
  SetLength(s, 40);
  GetClassName(Result, PChar(s), 39);
  if PChar(s) <> 'SysListView32' then 
    Result := 0; 
end;
Dummerweise ist der Code für Windows 98 und ich bezweifle, dass er unter Win2000 läuft, da es dort glaube ich schon gar kein ProgMan-Fenster mehr gibt.
Ich hatte beides erfolglos probiert: WM_SYSCOLORCHANGE und WM_SETTINGCHANGE
Mir ging es mehr um die Parameter 3 und 4.

Nachtrag: Das Handle, welches vom API GetDesktopWindow() geliefert wird, ist zwar nicht das ListView, aber anscheinend kann man es als solches behandeln, sprich man kann ihm anscheinend ListView-Nachrichten (LVM_*) senden.
 
Dummerweise ist der Code für Windows 98 und ich bezweifle, dass er unter Win2000 läuft, da es dort glaube ich schon gar kein ProgMan-Fenster mehr gibt.
Doch, läuft einwandfrei unter Windows 2000, dort gibt es dieses Fenster noch (sieht man wunderbar mit AU3Info.exe aus dem AutoIt-Package).

EDIT: also mit "läuft" meine ich, er lässt sich ausführen :-)

Mir ging es mehr um die Parameter 3 und 4.
Die sind im Moment beide auf 0, keine Änderung der Lage...

MfG Dalai
 
Doch, läuft einwandfrei unter Windows 2000, dort gibt es dieses Fenster noch (sieht man wunderbar mit AU3Info.exe aus dem AutoIt-Package).
Gut. Und wenn Du jetzt die Werte in der Registry änderst und zusätzlich dem ListView eine LVM_SETBKCOLOR-Nachricht sendest?
EDIT: also mit "läuft" meine ich, er lässt sich ausführen :-)
Und es gibt auch ein Handle != 0 zurück, nehme ich an.

Teste auch mal was passiert, wenn Du die Werte in der Registry änderst und zusätzlich SetSysColors aufrufst.
Mit dem Ändern der Registry machst Du die Farbe Session-übergreifend persistent und mit SetSysColors änderst Du die Farbe für die laufende Session. Soweit die Theorie...
 
Und es gibt auch ein Handle != 0 zurück, nehme ich an.
Ja, ist (auf verschiedenen Rechnern) immer ungleich Null.

Den Rest (SetSysColors und LVM_SETBKCOLOR) werde ich probieren, aber nicht mehr "heute" ... ;)

MfG Dalai
 
Ich hab jetz mal versucht, das LVM_SETBKCOLOR mithilfe dieser Funktion an das LietView zu senden:
Code:
SendMessage(GetDesktopWindow, LVM_SETBKCOLOR, 0, 0);
Tja, leider sagt der Delphi-Compiler, dass er das LVM_SETBKCOLOR nicht kennt...

Das Nutzen einer neueren Version als Delphi 5 fällt flach, nur um dieses "Popelproblem" zu lösen... Das muss doch mit vergleichsweise geringen Mitteln zu lösen sein?!

MfG Dalai
.
.
Edit:
Tja, leider sagt der Delphi-Compiler, dass er das LVM_SETBKCOLOR nicht kennt...

Asche auf mein Haupt...
Man sollte die CommCtrl mit einbinden... ;-)

MfG Dalai
.
.
Edit:
Ein Teilerfolg hat sich eingestellt:
Code:
procedure _BroadcastChanges;
  SendMessageTimeout(GetDesktopListViewHandle,
                     LVM_SETBKCOLOR,
                     0,
                     0,
                     SMTO_ABORTIFHUNG,
                     10000,
                     success);

  SendMessageTimeout(GetDesktopListViewHandle,
                     WM_SYSCOLORCHANGE,
                     0,
                     0,
                     SMTO_ABORTIFHUNG,
                     10000,
                     success);
end;

RegGetString(HKEY_CURRENT_USER, 'Control Panel\Colors\Background', meinwert);
RegSetString(HKEY_CURRENT_USER, 'Control Panel\Colors\Background', '0 0 0');
_BroadcastChanges;
RegSetString(HKEY_CURRENT_USER, 'Control Panel\Colors\Background', meinwert);
_BroadcastChanges;

Dieser Code ändert die Hintergrundfarbe auf schwarz. Soweit so gut, ABER sobald ich aufm Desktop F5 drücke, zack, is wieder die Ursprungsfarbe da.
Zumal er die Farbe ja selbst wieder zurücksetzen müsste, denn der Code schreibt ja den ursprünglichen Wert wieder in die Registry.

MfG Dalai

EDIT: Wieso wird meine Antwort als EDIT des letzten Post behandelt? Ich hab unten auf "Antworten" geklickt und net auf "Ändern"!
 
Zuletzt bearbeitet:
Code:
RegGetString(HKEY_CURRENT_USER, 'Control Panel\Colors\Background', meinwert);
RegSetString(HKEY_CURRENT_USER, 'Control Panel\Colors\Background', '0 0 0');
_BroadcastChanges;
RegSetString(HKEY_CURRENT_USER, 'Control Panel\Colors\Background', meinwert);
_BroadcastChanges;

Dieser Code ändert die Hintergrundfarbe auf schwarz. Soweit so gut, ABER sobald ich aufm Desktop F5 drücke, zack, is wieder die Ursprungsfarbe da.
Welchen Wert hat denn 'meinwert'?
EDIT: Wieso wird meine Antwort als EDIT des letzten Post behandelt? Ich hab unten auf "Antworten" geklickt und net auf "Ändern"!
Schreibt jmd. 2 Posts hintereinander und liegen diese weniger als 10 Stunden auseinander, werden sie zu 1 Post zusammengefasst. Das verhindert versehentliche Doppelposts und macht Spammern das Leben schwer.
 
Welchen Wert hat denn 'meinwert'?
Öhm, irgendeiner, der in der Registry steht, also z.b. hier "64 40 64" (ist ein String).
Der Wert wird ja mit
Code:
RegGetString(HKEY_CURRENT_USER, 'Control Panel\Colors\Background', meinwert);
gesetzt, also in 'meinwert' geschrieben.

Schreibt jmd. 2 Posts hintereinander und liegen diese weniger als 10 Stunden auseinander, werden sie zu 1 Post zusammengefasst. Das verhindert versehentliche Doppelposts und macht Spammern das Leben schwer.
Ah, ok, das ist sinnvoll, wenn auch net schön in diesem Fall.

MfG Dalai
 
Öhm, irgendeiner, der in der Registry steht, also z.b. hier "64 40 64" (ist ein String).
Der Wert wird ja mit
Code:
RegGetString(HKEY_CURRENT_USER, 'Control Panel\Colors\Background', meinwert);
gesetzt, also in 'meinwert' geschrieben.
Und welche Farbe soll das ListView am Ende haben und welche hat es nach einem F5?
 
Und welche Farbe soll das ListView am Ende haben und welche hat es nach einem F5?
Haben soll das ListView (der Desktop) die Farbe, die ich setze mit
Code:
RegSetString(HKEY_CURRENT_USER, 'Control Panel\Colors\Background', '0 0 0');
in diesem Fall also schwarz, wobei man dort eine beliebige Farbe eintragen kann.
Nach einem F5 bekommt der Desktop wieder die vorhergehende Farbe, also die vor dem Setzen einer Farbe (in diesem Fall also schwarz).

Eine Sache ist mit allerdings noch aufgefallen: Die Hintergrundfarbe der Schrift der Icons (Arbeitsplatz etc) wird nicht mit geändert! Es ändert sich also nur die Farbe des restlichen Desktops. BgInfo macht das also irgendwie noch anders...
Zumal es bei BgInfo ja auch so ist, dass die gesetzte Farbe in der Vorschau des "Eigenschaften von Anzeige"-Dialogs zu sehen ist.
Das wird sich mit SetSysColors und dem Eintragen des Farbwerts in die Registry nicht erreichen lassen *vermut*

Man muss irgendwie veranlassen, dass das System diesen Registry-Eintrag neu einliest.

MfG Dalai
 
Na Du setzt doch aber den Registry-Wert sofort wieder von schwarz auf 'meinwert'?! Mach das mal nicht und schau was dann passiert.

Ansonsten gehen mir die Ideen aus.
 
Na Du setzt doch aber den Registry-Wert sofort wieder von schwarz auf 'meinwert'?!
Das ist richtig bzgl. des oben geposteten Code.

Mach das mal nicht und schau was dann passiert.
Es passiert genau dasselbe, mit F5 kommt die eigentliche Farbe (64 40 64) zurück.
Ich hab auch das Gefühl, dass die Farbe eben nicht komplett gesetzt wird für den gesamten Desktop, denn wie ich gerade geschrieben hab, bleibt die Hintergrundfarbe der Schrift der Icons dieselbe, egal, welche Farbe der restliche Desktop verpasst bekommt.

MfG Dalai

EDIT: Ansonsten muss ich doch mal den Autor von BgInfo anschreiben und dort versuchen zu erfahren, wie er das gemacht hat...
 
Ich hab auch das Gefühl, dass die Farbe eben nicht komplett gesetzt wird für den gesamten Desktop, denn wie ich gerade geschrieben hab, bleibt die Hintergrundfarbe der Schrift der Icons dieselbe, egal, welche Farbe der restliche Desktop verpasst bekommt.
Das ListView hat den Stil LVS_EX_REGIONAL, d. h. der Hintergrund des Controls wird vom dahinterliegenden Fenster gezeichnet. Evt. lässt sich darüber etwas machen. Allerdings würde das sicherlich nicht das Problem lösen, dass der Anzeige-Dialog die falsche Farbe anzeigt.
Vermutlich ist es wirklich das beste, den Autor von BgInfo zu fragen.
 
Das ListView hat den Stil LVS_EX_REGIONAL, d. h. der Hintergrund des Controls wird vom dahinterliegenden Fenster gezeichnet. Evt. lässt sich darüber etwas machen.
*grübel* Das find ich gar nicht in der WinAPI-Hilfe. Google spuckt auch net grade hilfreiches aus...
Was und wie kann man damit was anfangen?

Allerdings würde das sicherlich nicht das Problem lösen, dass der Anzeige-Dialog die falsche Farbe anzeigt.
Das wird wohl das Problem sein und bleiben, leider...

MfG Dalai
 
Zurück
Oben Unten