WPF Performance and .NET Framework Client Profile

WPF performance and .NET Framework Client Profile related blogs provided by Jossef Goldberg.

Splash Screen To Improve WPF Application Perceived Cold Startup Performance

Splash Screen To Improve WPF Application Perceived Cold Startup Performance

  • Comments 20

Technorati Tags: ,,


Note: The original sample had a dependency on milcore.dll  (which was renamed to Wpfgfx_v0300.dll  in .Net 3.5 Sp1) so it did not work on .Net 3.5 Sp1 or later. On Jan,13, 2009 I update the sample not to depend on milcore.dll (it now uses Marshal.Release instead). I also updated the Resource compile command.
For 3.5 Sp1 it is recommended hat you simply use the new built-in Splash Screen APIs. (See
blog).

Summary:

As was mentioned in the Improving WPF applications Startup Time blog, disk IO has huge affect on application cold start time.

When a WPF application is launched for the first time after reboot, it needs to access the disk to load many of Common Language Runtime (CLR) and WPF code pages that otherwise may be present in the OS memory manager's standby list.

One of suggestions mentioned in that blog, was to add a splash screen that will show as-soon-as-possible and will be followed by the main WPF app window once the code on the start up path is executed. This will present the user with some quick UI and will improve the overall user-perceived responsiveness of your application.

This blog provides a basic sample that demonstrates how this can be done.

The main idea is to use as little as possible managed code during startup and to use interop to display as-quickly-as-possible an unmanaged Win32 windows on the screen.

The sample provided shows a static image in that first Splash window but your application can display anything it wants (maybe as series of images to adversities some of the application features).

The sample code allows you to select either a .BMP or a .PNG image. These images are compiled into a win32 (.rc) resource file.

Why PNG vs. BMP ?

The advantage of using a .PNG image over .BMP for your splash screen is that you will have better control on your Splash UI (for example, provide transparency if combined with UpdateLayeredWindow() API [which is not used in this sample]) and also will reduce the overall size of your app. Therefore, it will improve performance by decreasing the coldstart and application deployment time .

In this sample the PNG version of the app is about 7 times smaller than the BMP one (560Kb vs. 76Kb)

Unlike other samples that uses GDI+, this sample uses WIC (Windows Imaging Components) to process the .PNG image (see code in CreateBitmapBits() ).

Using WIC to process .PNG requires 7 additional DLLs (in addition to what the .BMP version requires) that are loaded at startup (milcore.dll, oleaut32.dll, psapi.dll, WindowsBase.dll, System.dll, WindowsCodecs.dll and xpsp2res.dll)

At first look this may appear costly, however, these DLLs are required anyway by a typical WPF app, so the time spent on loading these DLLs is not wasted and the overall startup performance should not decrease.

Another approach is to use GDI+ to process the .PNG image, however, this approach is not recommended as will load the GDI+ DLLs which are not required by a typical WPF application and therefore will increase the overall startup time.

By the default the sample is set to use .PNG resource. To change and use a .BMP, perform the following steps:

1) Simply undefined the “USE_PNG” from the ‘Pre Build Events’ define in the ‘Build Event’ project property page.

E.g. do: "$(DevEnvDir)..\tools\bin\rc.exe" /u USE_PNG /i "$(DevEnvDir)..\..\vc\PlatformSDK\Include" /r "$(ProjectDir)win32res.rc"

image

2) Remove the ‘USE_PNG’ ‘Conditional compilation symbols’ from the ‘Build’ project property page.

image

Here are the steps I took to create this sample:

1. We create a win32 resource file. For example:

img1

2. The Win32 window uses a Win32 resource file that is built using a custom pre-build event in the project build. In Visual Studio 2005 we add a pre-build event and use a resource compiler to compile the resource file . The following command is used. You may need to adjust the paths to your system:

img2

3. In the code, we first override the application Main method.

img3

4. We read either the PNG or BMP image from the app resource. In the PNG case we used the WIC Interop API to covert the PNG image to a bitmap format bits.

image

5. We then create a win32 window using pInvoke.

image

6. We then override the Application class we override the InitializeComponent() method and load the application main window. Notice that we no longer have an Application XAML file

image

Results and summary:

Examining the modules (a good tool to do so is the Process Explorer) that are loaded by the win32 splash window and then by the main WPF application window can explain why the splash window starts up much faster than the main WPF window. You can easily see that in the .BMP case, the WPF main app window loads 21 additional modules.

In addition to slowness because of disk IO, when the WPF platform starts it needs to perform some initialization which causes additional delay to application startup time. For example, when WPF starts for the first time it needs to launch the PresentationFontCache service as well as to initialize the DirectX device among other things.

The splash window technique can really help end-users with an improved perceived startup time and give the impression that the app is more responsive.

Testing on my (slow) XP machine after reboot (coldstart), the Splash screen appeared after ~2-3 sec while the main application windows appeared after ~13 seconds, a significant 11 sec improvement.

Improving the startup time of WPF application is something that Microsoft is working very hard to improve in coming versions. Until such improvements are built-in the platform, it is recommended that you use the Splash screen technique as well as some of the other ideas mentioned in the Improving WPF applications Startup Time blog.

Download Location:

You can download the sample from here.

Note:

As mentioned in this article , you can expect that Windows accelerators (in specific Prefetch and Superfetch ) will approve application startup time depends on how frequently the user uses the WPF application or other managed apps

Special thanks to Adam Smith who helped review this blog.

 

Attachment: SplashScreenSample_1_10_2009.zip
Leave a Comment
  • Please add 4 and 5 and type the answer here:
  • Post
  • made some small bug fixes to my WPF Calculator sample app (that is/was already included in the .Net 3

  • hey, i had this working but I upgraded my project to vs2008.  There is no rc.exe in the tools bin folder or anywhere in the Visual Studio 9.0 tree.  I also did not see it in the vs2008 sdk - any ideas?  Should I just use the rc.exe in vs2005?

    thanks,

    Dan

  • When I create a png file with rounded corners and transparent background the background of the corners on the splash becomes black. Any idea why this happens?

    Best regards,

    Jesper

  • Mint bizonyára hallottátok már, megjelent a .net 3.5 SP1 első bétája, vele a

  • Anybody have a working version for Visual studio 2008? This does not working with it since the rc.exe is missing

  • Having same issue here with sample not working on VS2008.  I have tried using rc.exe for VS2005 but this does not do it.

  • On my PC, with VS 2008 and the Windows 6.0A SDK,

    1. rc.exe is in "Microsoft SDKs\Windows\v6.0A\bin\rc.exe"

    2. the SDK include directory is "Microsoft SDKs\Windows\v6.0A\Include"

    3. sal.h is in "Microsoft Visual Studio 9.0\VC\include"

    The pre-build event line, with hard-coded paths, looks like this:

    Microsoft SDKs\Windows\v6.0A\Include" /i "C:\Program Files\Microsoft Visual Studio 9.0\VC\include

  • That last line got clipped.

    "C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\rc.exe"  /d USE_PNG  /i "C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include" /i "C:\Program Files\Microsoft Visual Studio 9.0\VC\include"  /r "$(ProjectDir)win32res.rc"

    Now the sample works with VS2008. Thanks!

  • Excellent, thanks. Works for me now.

  • Add the WS_EX_TOOLWINDOW flag to keep the splash window from showing up on the taskbar.

    private const uint WS_EX_TOOLWINDOW = 0x00000080;

    _splashScreenHwnd = CreateWindowEx(

    CS_HREDRAW | CS_VREDRAW | WS_EX_TOOLWINDOW,

    etc.

  • Summary: To improve the perception of a more responsive startup experience many WPF applications added

  • Hi,

    I was recently told that MILCore is legitimately removed (also seen this in person) by the .net 3.5 SP1 installer on XP. Basically want to make sure you are aware anyone using this code just entered a world of hurt if they distributed on XP.

    Is there an explanation of why you felt MilCore.dll dependency was required for the png loading of the splash?

    what are the side effects if you just remove MILCore dependency entirely and let the common runtime handle the garbage collection or use the Marshal.Release() on the pointers?

    Any help would be much appreciated.

    Thanks,

    D

  • As D. mentioned , since this sample has a dependency on milcore.dll  (which was renamed to Wpfgfx_v0300.dll  in .net 3.5 Sp1) it will not work on recently .net 3.5 Sp1.

    For 3.5 Sp1 it is recommended hat you simply use the new built in Splash Screen APIs. (See this blog: http://blogs.msdn.com/jgoldb/archive/2008/08/12/what-s-new-in-wpf-3-5-sp1-splash-screen-to-improve-perceived-startup-perf.aspx)

    The sample was written well before the decision to rename MILCore.dll in 3.5 Sp1 was made.    

    I’ll try to fix the sample so that it does not depend on milcore.dll.

    Jossef.

  • A simple solution would be to allow the CLR to make the Release calls itself and handle the reference counts. (you would just remove any part of the sample that contains reference to milcore)

    D

  • It appears after inspecting the memory usage with swapping the call for Marshal.Release that using Marshal.Release may be more robust.

    I did speak with someone from msft and they seemed to be under the impression however that the CLR would take care of the interface references in this case.

    D

Page 1 of 2 (20 items) 12