Entwickler-Ecke

Windows API - Message um Icons im Startmenü neu zu zeichnen...


FriFra - Sa 22.03.03 17:22
Titel: Message um Icons im Startmenü neu zu zeichnen...
Welche Message muss mein Programm senden, damit Windows die Icons im Startmenü neu lädt (z.B. das "windows beenden"-Bild)?
Bisher kann ich das Neuladen nur erzwingen, indem ich die explorer.exe abschiesse... diese Aktion erfordert allerdings einen anschliessenden Neustart von Windows, da danach div. Trayicons verschwunden sind


Delete - Sa 22.03.03 18:19

Warum ist das denn nötig? Eventuell kann man das Übel an der Wurzel packen und nicht an den Symptomen rumdoktern. :roll:


FriFra - Sa 22.03.03 19:29

Wieso rumdoktern? Ich schreibe div, Neuzuordnungen für die Icons im Startmenü in die Registry... anschliessend muss ich windows "nur noch" mitteilen, dass sich da etwas geändert hat!
Wie gesagt, nur durch "abschiessen" der explorer.exe lädt Windows diese Icons neu und genau dafür suche ich eine saubere Lösung.


Delete - Sa 22.03.03 19:42

Wie wäre es mit WM_SETTINGCHANGE?


FriFra - Sa 22.03.03 19:45

Windows98 reagiert darauf wunderbar... nur unter NT passiert nichts


Delete - Sa 22.03.03 19:48

Hast du auch die nötigen Rechte um in den Schlüssel zu schreiben?


FriFra - Sa 22.03.03 19:53

Ich bin Admin... Die Schlüssel sind auch alle geschrieben... nur "merkt" Windows eben nicht, dass im Startmenü neue Icons gezeigt werden sollen.., wie gesagt wenn ich den explorer crashe dann lädt er die icons

Für das "Windows beenden"-Bild sind es z.B. folgende Werte:
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\Shell Icons\27=c:\myicons\exit.ico,0
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\Shell Icons\27=c:\myicons\exit.ico,0


SMI - Sa 22.03.03 23:37

Microsoft schreibt in seiner KB, dass man die Datei c:\[windir]\shelliconcache wegzulöschen soll. Danach aktualisiert und regeneriert Windows seinen Iconcache wieder.

Andere möglichkeiten Direkt auf den Cache zuzugreifen steht hier:
http://www.geocities.com/SiliconValley/4942/iconcache.html

bzw. und hier
http://www.aha-soft.com/articons/faq/q18.htm

beschrieben.


SMI


FriFra - So 23.03.03 08:38

Danke! Der Tip von aha-soft.com funktioniert...

ScreenShot von WinNT4
user defined image

Ich habe den Code allerdings noch etwas anpassen müssen, da er nur sehr unvollständig (fehlende proceduren etc.) war:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
procedure TMain.RebuildIconCache;
var
  news, olds: string;
  sz: integer;
const
  sr_WindowMetrics = 'Control Panel\Desktop\WindowMetrics\';
  sr_ShellIconSize = 'Shell Icon Size';
  WaitCursor: TCursor = crHourGlass;
  WaitCount: Integer = 0;
  SaveCursor: TCursor = crDefault;
  function WindowsDir: string;
  var
    buffer: array[0..255of char;
  begin
    GetWindowsDirectory(@Buffer, SizeOf(buffer));
    Result := Buffer;
  end;
  function UpdateAllWindowsCallback(WHandle: HWnd; var Parm: Pointer): Boolean;
    stdcall;
  begin
    SendMessage(WHandle, WM_SETTINGCHANGE, 00);
    Result := True;
  end;
  procedure UpdateAllWindows;
  begin
    EnumWindows(@UpdateAllWindowsCallback, WM_SETTINGCHANGE);
  end;
  function GetIconCacheFile: string;
  begin
    Result := WindowsDir + 'ShellIconCache';
  end;
  procedure DeleteIconCache;
  var
    sfile: string;
  begin
    sfile := GetIconCacheFile;
    if fileexists(sfile) then
    begin
      if deletefile(sfile) = false then
        showmessage('Can not erase file: ' + sfile);
    end;
    // QueryRestartWindows;
  end;
  function RefreshActiveDesktop: boolean;
  const
    CLSID_ActiveDesktop: TGUID = '{75048700-EF1F-11D0-9888-006097DEACF9}';
  var
    ActiveDesktop: IActiveDesktop;
  begin
    try
      ActiveDesktop := CreateComObject(CLSID_ActiveDesktop) as IActiveDesktop;
      ActiveDesktop.ApplyChanges(AD_APPLY_ALL or AD_APPLY_FORCE);
      Result := true;
    except
      Result := false;
    end;
  end;
  procedure RefreshDesktop;
  var
    wnd: THandle;
    fl: boolean;
  begin
    fl := RefreshActiveDesktop;
    if fl = false then
    begin
      wnd := FindWindow('Progman''Program Manager');
      if wnd <> 0 then
        SendMessage(wnd, WM_COMMAND, $A0650)
      else
        UpdateAllWindows;
    end;
  end;
  function regreadstring(MyKey: HKey; MyValue: string): string;
  var
    reg: TRegistry;
    mp, mv: string;
  begin
    Result := '';
    mp := MyValue;
    if pos('\', mp) > 0 then
    begin
      while (copy(mp, length(mp), 1) <> '\'do
        mp := copy(mp, 1, length(mp) - 1);
      mp := copy(mp, 1, length(mp) - 1);
      mv := copy(MyValue, length(mp), length(MyValue));
      while (pos('\', mv) > 0do
        mv := copy(mv, 2, length(mv));
    end
    else
    begin
      mp := '';
      mv := '';
    end;
    try
      reg := TRegistry.Create;
      reg.RootKey := MyKey;
      reg.OpenKey(mp, false);
      if reg.ValueExists(mv) = true then
        Result := reg.ReadString(mv);
    finally
      FreeAndNil(reg);
    end;
  end;
  procedure regwritestring(MyKey: HKey; MyValue, NewValue: string);
  var
    reg: TRegistry;
    mp, mv: string;
  begin
    mp := MyValue;
    if pos('\', mp) > 0 then
    begin
      while (copy(mp, length(mp), 1) <> '\'do
        mp := copy(mp, 1, length(mp) - 1);
      mp := copy(mp, 1, length(mp) - 1);
      mv := copy(MyValue, length(mp), length(MyValue));
      while (pos('\', mv) > 0do
        mv := copy(mv, 2, length(mv));
    end
    else
    begin
      mp := '';
      mv := '';
    end;
    try
      reg := TRegistry.Create;
      reg.RootKey := MyKey;
      reg.OpenKey(mp, true);
      reg.WriteString(mv, NewValue);
    finally
      FreeAndNil(reg);
    end;
  end;
  procedure StartWait;
  begin
    if WaitCount = 0 then
    begin
      SaveCursor := Screen.Cursor;
      Screen.Cursor := WaitCursor;
    end;
    Inc(WaitCount);
  end;
  procedure StopWait;
  begin
    if WaitCount > 0 then
    begin
      Dec(WaitCount);
      if WaitCount = 0 then
        Screen.Cursor := SaveCursor;
    end;
  end;
begin
  Startwait;
  try
    deletefile(GetIconCacheFile);
    olds := regreadstring(HKEY_CURRENT_USER, sr_WindowMetrics +
      sr_ShellIconSize);
    sz := strtointdef(olds, 32);
    inc(sz);
    news := inttostr(sz);
    regwritestring(HKEY_CURRENT_USER, sr_WindowMetrics + sr_ShellIconSize,
      news);
    UpdateAllWindows;
    if olds = '' then
      olds := '32';
    regwritestring(HKEY_CURRENT_USER, sr_WindowMetrics + sr_ShellIconSize,
      olds);
    UpdateAllWindows;
    RefreshDeskTop;
  finally
    StopWait;
  end;
end;


Moderiert von user profile iconraziel: Code- durch Delphi-Tags ersetzt.


FriFra - Sa 29.03.03 15:29

:cry: Es funktioniert doch nicht zu 100%...
Auf NT Systemen ohne ActiveDesktop klappt alles, aber auf Systemen mit ActiveDesktop muss ich teilweise nach wie vor die explorer.exe abschiessen und neu starten.


kiwicht - Fr 20.06.03 07:40

wenn ich auf dem Desktop F5 drücke (ist ja bekanntlich Systemstandard für "aktualisieren"), dann wird der Hintergrund und die Icons ja auch aktualisiert... hilft das weiter?

Das funzt nämlich auch bei "ActiveDesktop"...

mfG


FriFra - Fr 20.06.03 08:23

nein


JayK - Mo 01.08.05 11:48

user profile iconkiwicht hat folgendes geschrieben:
wenn ich auf dem Desktop F5 drücke (ist ja bekanntlich Systemstandard für "aktualisieren"), dann wird der Hintergrund und die Icons ja auch aktualisiert... hilft das weiter?

*Alten Thread wieder ausgrab*
Nein tut es so nicht, weil die Icons ganz neu geladen werden müssen für sein vorhaben. Aktualisieren zeichnet sie höchstens neu und zwar aus dem Cache! Den muss man ja gerade aktualisieren.

Bei mir klappt die geänderte Prozedur von FriFra immer noch nicht:

In welcher Unit ist was drin?