|
Antwort |
Olli
(Gast)
n/a Beiträge |
#1
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 SHGetSetSettings() und das Flag SSF_STARTPANELON sowie Setzen oder Löschen des Bits fStartPanelOn in der SHELLSTATE-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:
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 SHGetSetSettings() 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.
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] 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:
Da Delphi keine Bitfelder unterstützt, mußte ich die Bits für fStartPanelOn explizit setzen und holen.
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; 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 ... |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs 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
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |