AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Code-Bibliothek Library: Windows API / MS.NET Framework API XP-Stil oder klassisch? Startpanel konfigurieren ...
Thema durchsuchen
Ansicht
Themen-Optionen

XP-Stil oder klassisch? Startpanel konfigurieren ...

Ein Thema von Olli · begonnen am 24. Aug 2005
Antwort Antwort
Olli
(Gast)

n/a Beiträge
 
#1

XP-Stil oder klassisch? Startpanel konfigurieren ...

  Alt 24. Aug 2005, 15:09
Moin,

ich habe in den letzten 3 Wochen immer wieder etwas für das Projekt Xpy (auf SF.net) ausgeforscht. Und zwar wie man den klassischen/XP-Stil des Startpanels bei XP umstellt und dem Explorer dann auch mitteilt, daß es diese Änderung gab - jedoch ohne ihn zu killen! Und da ich mir einmal diese Arbeit gemacht habe, will ich euch das Ergebnis natürlich nicht vorenthalten. Um es vorweg zu sagen, herausgefunden habe ich es durch RE-Techniken (RE == Reverse Engineering).

Die Einstellungen werden gemacht wie das nunmal dokumentiert ist. Über MSDN-Library durchsuchenSHGetSetSettings() und das Flag SSF_STARTPANELON sowie Setzen oder Löschen des Bits fStartPanelOn in der MSDN-Library durchsuchenSHELLSTATE-Struktur. Darauf werde ich also nicht eingehen, weil dies wunderbar dokumentiert ist.

Obwohl man diese Flags nun also setzen oder löschen kann, bleibt noch ein Problem: wie bringt man dem Explorer bei, daß sich das Flag geändert hat? Nunja, ohne da einen Blick in den "Quelltext" (also das Disassemblat ) des Explorers zu werfen, geht da leider nix ... bei den vielen Fensternachrichten die er schickt, ist man auch verloren. Was habe ich also gemacht? Meine sympathische Freundin IDA ausgepackt und mir das ganze mit ihrer Hilfe angeschaut. Nach der statischen Analyse war ich dann am Code angelangt welcher vom Konfigurationsdialog der Taskbar aus aufgerufen wird. Dort gab es eine Funktion, welche ich ApplyStartmenuConfigSettings() genannt habe, die die Radiobuttons auslas, überprüfte ob es Beschränkungen gab (namentlich SHRestricted(REST_NOSTARTPANEL)) und danach den Wert auslas und dann entsprechend des Dialogs setzte. Außerdem wurden beim Setzen noch 2 Nachrichten an mir unbekannte Fenster gepostet. Da man die so schlecht rausbekommt mit einer statischen Analyse, habe ich meinen guten Kumpel WinDbg gebeten mir zu helfen. Das tat er dann auch indem er sich mit einem gewagten Sprung an die Fersen von explorer.exe heftete (engl. "attach"), während ich den Konfigurationsdialog bediente. Da ich ja durch die statische Analyse schon wußte wonach ich suchte, war es relativ einfach es zu finden. Zuerst ein BPX auf PostMessageW() um dann "Apply" im Dialog zu drücken. Den Callstack überprüft um zu meiner Funktion ("ApplyStartmenuConfigSettings") zu finden, Singlestep durch und voila, da waren sie. Schnell auf dem Stack rumgelungert und geguckt welche Werte übergeben werden ... aha 00080100 und 000200a2. Spy++ ausgepackt und angeworfen, Handlewerte eingegeben und ermittelt, welches Handle welcher Fensterklasse entspricht. Die Kandidaten lagen ja schon auf der Hand, aber da Blindflug blöde ist, machen wir's natürlich vorbildlich und pedantisch:
- 00080100 "Progman"
- 000200a2 "Shell_TrayWnd"

Hier mal meine kommentierte Version der Funktion aus IDA (nur der wichtigere Teil):
Code:
jz     short [b]AlreadySet[/b]
lea    eax, [esi+esi]
xor    eax, [ebp+sst.RestFlags]
push   TRUE           [color=gray]; Set mask, not just retrieve it[/color]
and    eax, 2          [color=gray]; fStartPanelOn[/color]
xor    [ebp+sst.RestFlags], eax
push   ebx            [color=gray]; 200000h == SSF_STARTPANELON[/color]
lea    eax, [ebp+sst]
push   eax            [color=gray]; Pointer to SHELLSTATE[/color]
call   edi ; SHGetSetSettings
push   0               [color=gray]; lParam[/color]
push   0               [color=gray]; wParam[/color]
push   [u]WM_USER + 60h[/u]  [color=gray]; Msg == WM_USER + 0060[/color]
push   hProgman       [color=gray]; hWnd == "Progman"[/color]
call   [color=blue]ds:PostMessageW[/color]

[b]AlreadySet:[/b]            [color=gray]; CODE XREF: ApplyStartmenuConfigSettings+5Fj[/color]
push   0               [color=gray]; lParam[/color]
push   0               [color=gray]; wParam[/color]
push   [u]WM_USER + 0Dh[/u]  [color=gray]; Msg == WM_USER + 000D[/color]
push   hTrayWnd       [color=gray]; hWnd == "Shell_TrayWnd"[/color]
call   [color=blue]ds:PostMessageW[/color]
Und siehe da, die Lösung liegt wunderschön auf der Hand. Man suche sich das Fenster der Klasse "Shell_TrayWnd" (i.e. die Taskbar) und poste an dieses die Nachricht WM_USER+$0D um eine Änderung bekanntzugeben. Dies wird im o.g. Code immer gemacht, sogar wenn der Wert nicht gesetzt wird! Wurde der Wert mithilfe MSDN-Library durchsuchenSHGetSetSettings() geändert, wird an das Fenster der Klasse "Progman" (i.e. den Desktop) die Nachricht WM_USER + $60 gepostet um ihm mitzuteilen sich zu aktualisieren.

Während ersteres dazu dient der Taskbar mitzuteilen, daß sich ihr Stil geändert hat, dient letzteres (an den Desktop) dazu die Elemente "Arbeitsplatz", "Netzwerkumgebung" usw. zu verstecken (XP-Stil) oder anzuzeigen (klassischer Stil), je nach der neuen Einstellung. Da zu vermuten stand, daß der Code in der explorer.exe von Windows 2003 ähnlich aussieht, habe ich mir den auch angeguckt und er ist fast identisch (Suche nach 0x460 == WM_USER + 0x60). Die Nachrichten sind aber die gleichen und das ist das wichtige!

Hier nun das Resultat in Delphi:
Delphi-Quellcode:
type
  SHELLSTATE = record
    Flags1: DWORD;
(*
    BOOL fShowAllObjects : 1;
    BOOL fShowExtensions : 1;
    BOOL fNoConfirmRecycle : 1;

    BOOL fShowSysFiles : 1;
    BOOL fShowCompColor : 1;
    BOOL fDoubleClickInWebView : 1;
    BOOL fDesktopHTML : 1;
    BOOL fWin95Classic : 1;
    BOOL fDontPrettyPath : 1;
    BOOL fShowAttribCol : 1; // No longer used, dead bit
    BOOL fMapNetDrvBtn : 1;
    BOOL fShowInfoTip : 1;
    BOOL fHideIcons : 1;
    BOOL fWebView : 1;
    BOOL fFilter : 1;
    BOOL fShowSuperHidden : 1;
    BOOL fNoNetCrawling : 1;
*)

    dwWin95Unused: DWORD; // Win95 only - no longer supported pszHiddenFileExts
    uWin95Unused: UINT; // Win95 only - no longer supported cbHiddenFileExts

    // Note: Not a typo! This is a persisted structure so we cannot use LPARAM
    lParamSort: Integer;
    iSortDirection: Integer;

    version: UINT;

    // new for win2k. need notUsed var to calc the right size of ie4 struct
    // FIELD_OFFSET does not work on bit fields
    uNotUsed: UINT; // feel free to rename and use
    Flags2: DWORD;
(*
    BOOL fSepProcess: 1;
    // new for Whistler.
    BOOL fStartPanelOn: 1;      //Indicates if the Whistler StartPanel mode is ON or OFF.
    BOOL fShowStartPage: 1;      //Indicates if the Whistler StartPage on desktop is ON or OFF.
    UINT fSpareFlags : 13;
*)

  end;
  LPSHELLSTATE = ^SHELLSTATE;

const
  SSF_SHOWALLOBJECTS = $00000001;
  SSF_SHOWEXTENSIONS = $00000002;
  SSF_HIDDENFILEEXTS = $00000004;
  SSF_SERVERADMINUI = $00000004;
  SSF_SHOWCOMPCOLOR = $00000008;
  SSF_SORTCOLUMNS = $00000010;
  SSF_SHOWSYSFILES = $00000020;
  SSF_DOUBLECLICKINWEBVIEW = $00000080;
  SSF_SHOWATTRIBCOL = $00000100;
  SSF_DESKTOPHTML = $00000200;
  SSF_WIN95CLASSIC = $00000400;
  SSF_DONTPRETTYPATH = $00000800;
  SSF_SHOWINFOTIP = $00002000;
  SSF_MAPNETDRVBUTTON = $00001000;
  SSF_NOCONFIRMRECYCLE = $00008000;
  SSF_HIDEICONS = $00004000;
  SSF_FILTER = $00010000;
  SSF_WEBVIEW = $00020000;
  SSF_SHOWSUPERHIDDEN = $00040000;
  SSF_SEPPROCESS = $00080000;
  SSF_NONETCRAWLING = $00100000;
  SSF_STARTPANELON = $00200000;
  SSF_SHOWSTARTPAGE = $00400000;


procedure SHGetSetSettings(var lpss: SHELLSTATE; dwMask: DWORD; bSet: BOOL) stdcall; external 'shell32.dll';

procedure SwitchStartpanelXP(xpstyle: Boolean);
var
  lpss: SHELLSTATE;
  bIsXPstyle: Boolean;
begin
  ZeroMemory(@lpss, sizeof(lpss));
  // Retrieve current style
  SHGetSetSettings(lpss, SSF_STARTPANELON, False);
  // Check the current style
  bIsXPstyle := (lpss.Flags2 and 2) = 2; // fStartPanelOn
  // If a change occurred
  if (bIsXPstyle <> xpstyle) then
  begin
    // If the user wants XP style then set it, else reset it
    if (xpstyle) then
      lpss.Flags2 := 2 // fStartPanelOn = 1
    else
      lpss.Flags2 := 0; // fStartPanelOn = 0
    // Set new style
    SHGetSetSettings(lpss, SSF_STARTPANELON, True);
    // Notify desktop of the change
    PostMessage(FindWindow('Progman', nil), WM_USER + $60, 0, 0);
  end;
  // Notify taskbar
  PostMessage(FindWindow('Shell_TrayWnd', nil), WM_USER + $0D, 0, 0);
end;
Da Delphi keine Bitfelder unterstützt, mußte ich die Bits für fStartPanelOn explizit setzen und holen.

Hinweis: Eigentlich sollte man noch mit SHRestricted(REST_NOSTARTPANEL) testen (auf Rückgabe ungleich 0), ob der moderne Stil gesetzt werden darf. Dies ist aber im Grunde nur Kosmetik und ich überlasse es dem geneigten Leser dies selbst zu implementieren

Nicht vergessen: Unit Messages und Windows einbinden. Schön wäre noch, wenn jemand hier sagen könnte, ab welcher Delphiversion die Funktion SHGetSetSettings() direkt unterstützt wird, da sie bei mir (D3 und D4) noch nicht deklariert war, logisch, da erst Windows 2000 sie kannte

Viel Spaß ... und an IDA ...
  Mit Zitat antworten Zitat
Antwort Antwort

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:53 Uhr.
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