Longhorn Fusion file patches for Windows 7

For the Longhorn Fusion project, I created a series of system file patches to help theme Windows 7 closer to the Longhorn look.

Longhorn Fusion file patches for Windows 7

For the Longhorn Fusion project, I created a series of system file patches to help theme Windows 7 closer to the Longhorn look. A common hack back then was to set the the scaling to 97 DPI - this would trigger the larger sizes of the next commonly supported scaling option (120 DPI) but mostly keep fairly close to the 96 DPI sizes. It did still cause several side effects though, and while it (sort-of) worked for navigation buttons, it didn't for the start button, so I worked on patching the system files to provide the larger sizes directly at 96 DPI.

These were announced via the Longhorn Fusion page via DeviantArt. The reversed samples below are based on the AMD64 compile of Windows 7 Post-SP1 rollup (6.1.7601.24214.win7sp1_ldr_escrow.180801-1700), though these broadly should be applicable to all RTM and patch versions of Windows 7. Originally I used IDA Professional to reverse engineer this, but when writing it up for this article, I've used Cutter.

Windows Explorer - Start Button sizing

The first modification (announced here) was to explorer.exe. This was the first problem that I tackled. The hardcoded sizing in the Windows 7 taskbar very much made certain assumptions, and particularly for Longhorn themes, the difficulty was that it very much assumed a squarer shape for the start button.

CStartButton::GetSizeAndFont

This is the method which determines the size of the visible button. In Windows 7, the start button is in fact a separate window positioned above the taskbar. The relevant code is this part:

cmp edi, 0x78 ; compare current DPI to 120
jge 0x10005cda7 ; jump if greater than or equal to 120 (125%)
; we're not going to follow this branch, we're assuming 96 DPI
; it also has branches for 144 DPI (150%) and 192 DPI (200%)
; these follow a similar structure and can be similarly edited

mov ecx, 0x36; set overall button height to 54px
...
move ecx, 7; set the "overhang" to 7px
; this moves the top of the button to 7px above the superbar
; 54px total size - (2 x 7px overhang) = 40px - the default superbar size
; adjusting these values will adjust the size / positioning of the button

CTray::v_WndProc

The one complication you may run into though is that the taskbar actually still paints a "legacy" start button within the taskbar window itself. Usually this is hidden because the Windows 7 start button is larger and not transparent and so covers it up entirely. This was a problem for Fusion which used a translucent button. You can modify this function to prevent this from being painted.

Cutter actually had some issue picking up this function, but you can still find the relevant part of the code by looking for calls to CTray::_DrawBackupStartButton.

test byte [rsi + 0x60], r12b
jne 0x100034e43; skip the following call if the field doesn't match the value
; this is the part you will modify - swap this jump out for different one
mov rdx, rbx
mov rcx, rsi
; these push the arguments for the call below
call CTray::_DrawBackupStartButton
; this call paints the start button onto the taskbar itself

Explorer Frame - Backwards / Forwards button sizing

After submitting the start button patch to the Longhorn Fusion project, a request was made to look at supporting larger navigations in Explorer at 96 DPI. The previous workaround was to set the system to 97 DPI.

This worked because ExplorerFrame changed it's behaviour based on an internal "IsHighDPI" function, which essentially returned true whenever the DPI was higher than 96 DPI (in contrast to the start button example we looked at before, which explicitly supports several DPI values and uses them as a lower threshold).

However, it was not without side effects (anything that properly supported DPI scaling would get a lot of slightly out visual parts or become blurry as scaled to very fractional values), and with the Start Button supporting 96 DPI explicitly, the desire was to match this with the navigation buttons. Once complete, this signalled the end of the 97 DPI hack within the Longhorn Fusion team (announced here).

CTravelBand::_ThemeTravelBand

This is all contained within a single function, though you likely need to adjust this in several places. There are two determining factors for the size: Is this "High DPI" (>96 DPI) and is the Classic theme enabled

This code handles setting the width:

call IsHighDPI
neg eax
sbb ecx, ecx
; this is probably not the easiest code to understand because
; it uses a common VC++ compiler optimisation to avoid branching
; essentially, if IsHighDPI is true, then ecx will be -1 else 0
and ecx, 0x11 ; bitwise and to set ecx to 17 if IsHighDPI
add ecx, 0x46 ; unconditionally add 70 to ecx
; this has the effect of setting the width to (0 + 70) = 70px for "low DPI"
; and setting the width to (17 + 70) = 87px for "high DPI"

This code handles setting the height:

call IsHighDPI
test eax, eax
mov eax, 0x26 ; set the height to 38px
jne 0x7ff54026476 ; if high DPI, skip the following line
mov eax, 0x20 ; set the height to 32px
; in the x86 (32-bit) version I did previously, these checks were
; the other way round - it set 20px and then set 38px if high DPI
; this is purely a function of the optimising compiler

This sets the size for the individual buttons. In some variants of Windows 7, it's a separate function called CTravelBand::_SetButtonImages but in this sample, it seems this function was inlined into the _ThemeTravelBand function:

call IsHighDPI
neg eax
sbb r8d, r8d
; using the same trick mentioned earlier, we do a branchless conditional set
and r8d, 7 ; bitwise and to set r8d to 7 if High DPI is true, 0 otherwise
add r8d, 0x1B ; unconditionally add 27 to r8d
; this gives us a size of 27px for Low DPI, 34px for High DPI
; this is used for both the width and height of the button
; the bounds for these buttons must be square