A better WPF splash screen

by StefanOlson 27. November 2008 10:07

Further Update: there was a bug relating to the splash screen start application not correctly closing. This has now been fixed and you can download it here

Update: Thanks to all of those who have pointed out that it didn't work correctly on windows XP, I have now fixed this and you can download it here

WPF 3.5 Service Pack 1 introduced a new splash screen feature which was supposed to provide a splash screen whilst the program loads.  Unfortunately it has a number of faults:

  1. Although the splash screen class uses native code within it, it is actually part of the .net framework so a large part of the framework has to load before the splash screen can be displayed.  This still provides a substantial period of time, particularly on cold boots where the user doesn't have any indication that your application is loading.
  2. The splash screen will display images stored in resources in either an application or a dll.  In my application I need to load the splash screen from an image at runtime.  I have submitted a suggestion on connect that this feature should be added.
  3. There is a bug in the splash screen code, that in certain cases where a user may shift focus away from the splash screen, the splash screen will throw an exception causing the application to crash.  I have submitted this issue as a bug on connect, but Microsoft seem to have ignored my attempts to reopen it, so it is anyone's guess it will be fixed in the update to the service pack due early next year
  4. Because it is not set to be on top, the splash screen can disappear below your application.
The last three issues could have been avoided, had the splash screen been part of the beta of the service pack.  It was not available until the final release, so we were unable to comment on these issues or even discover them prior to that.

Recently, Bradley Grainger on the Logos Bible Software Code Blog posted a series on how to build a splash screen in native code.  His solution is to build an executable which displays the splash screen using native code and then runs your WPF application.  This resolves problem number one because it starts much more quickly than the .net framework and makes it clear to the user what is going on.  Of course it also resolves problem number 3 because it doesn't have the same code is .net is using.  However it does not address problem number 2, and his code was posted without a compilable version, he just posted snippets of code in his blog.

Since I needed to solve my splash screen problems, I built Bradley’s code into a new Visual C++ application and made a few improvements including being able to display images not in the resources, being always on top, and fading out the splash screen like WPF does when it no longer needs to be displayed.

The source code can be downloaded here

The code is available under the same licence as the original.

To test it for yourself, after you have downloaded the code, run splashscreenstarter.exe in the root folder.  If you want to see how it works in a real world application, this video shows you how we use it in our virtual tour viewer.

So, if you wish to use it in your own application, what do you do?  You can modify the splashscreenstarter project.  Generally you should only need to change this line of code in splashscreenstarter.cpp:

CSplashScreen splash(
        hInstance, 
        // Length of time in milliseconds to display splashscreen fading 
        3000, 
        // Specifies the way to load the image for the splashscreen 
        // To load from the resources, as we have done here, provide the 
        // resource name and the resource type name.  We have used a jpg.
        // If you use a PNG, its opacity should be honored to allow you 
        // to display partially transparent splashscreens.
        // To edit the resources in a C++ application go to the resource 
        // view tab
        // To load from a file use this line instead, where filename is the file
        // you wish to load:
        // new CFileImageLoader(filename), 
        new CResourceImageLoader(MAKEINTRESOURCE(IDR_SPLASH), _T("JPG")),
        // Application prefix.  This will be added to the event name so there are no 
        // conflicts between applications.
        _T("SplashScreenStarter"), 
        // File name of your executable to run.  The extension does not need to be .exe.  
        // If you want to stop your users from starting your application without displaying
        // the splashscreen you could use a different extension.
        // Is assumed it is in the same folder as this program 
        // If it is not you can call splash.SetFullPath
        _T("SplashScreenTester.exe") 
        ) ;

You will need to replace the image used for the splashscreen which is stored in startuppic.jpg.  You'll also want to replace the icon with the application icon you are using.

Then in your WPF application class (app.xaml.cs):

protected override void OnStartup(StartupEventArgs e)
{
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Loaded,
        (DispatcherOperationCallback)delegate { CloseSplashScreen(); return null; },
        this);
    base.OnStartup(e);
}

private void CloseSplashScreen()
{
    // signal the native process (that launched us) to close the splash screen
    using (var closeSplashEvent = new EventWaitHandle(false,
        EventResetMode.ManualReset, "CloseSplashScreenEventSplashScreenStarter"))
    {
        closeSplashEvent.Set();
    } 
}

Notes that the event name, CloseSplashScreenEventSplashScreenStarter, includes the prefix from above at the end of it.  If you use a different prefix you will need to modify this.

If you wish to close the splash screen at any each time without fading it you can call this code:

static protected void CloseSplashScreenWithoutFade()
{
    // signal the native process (that launched us) to close the splash screen
    using (var closeSplashEvent = new EventWaitHandle(false, 
        EventResetMode.ManualReset, "CloseSplashScreenWithoutFadeEventSplashScreenStarter"))
    {
        closeSplashEvent.Set();
    }
}

Hopefully this code will help you to create a more responsive application. If you have any questions or comments, please feel free to contact me.

…Stefan

Tags:

WPF

Comments

12/2/2008 3:12:27 AM #

Pingback from mgalinks.wordpress.com

2008 December 02 - Links for today « My (almost) Daily Links

mgalinks.wordpress.com

12/5/2008 4:51:49 AM #

Hi Stefan,

Glad you found the code useful, and thanks for packaging it up in a downloadable project. I've updated my post to link back here for those who want a convenient way to get all the code.

Bradley

Bradley Grainger

12/16/2008 8:58:31 AM #

Hi Stefan,

I've downloaded your zip and tried the splashscreenstarter.exe in the root.

It seems no image is showing after running it for me. I see the starter.exe in my taskmanager as well as tester.exe.  After a few seconds the starter closes as expected, but no splash image.  Is this intended?

/JP

JP Chow

12/16/2008 9:44:08 AM #

JP,

No, not the intention. What operating system are you running on?

...Stefan

StefanOlson

12/16/2008 10:27:27 AM #

I'm running Windows XP SP3 with latest .Net 3.5 and VS2008.

I've also been running your distributed code in debug mode. The starter.exe will load my WPF app, but again no splash is being shown.

JP Chow

12/16/2008 12:43:13 PM #

I'll try and look into it over the next week or to see if I can repeat it on XP.

StefanOlson

1/5/2009 8:18:29 PM #

Hi

I also tried the code. All works fine, besides the image that does not show up.
I also tried to use direct filename:
new CFileImageLoader(_T("C:\\WPF\\WPFSplashTest\\bin\\Release\\Splash01.png")),

And it even does not compile...

I also work with XP

Thanks
John

Jonathan

1/6/2009 5:39:45 AM #

I'm having a similar problem to JP Chow above on the same configuration.  I played around a little and ended up removing the blending from the UpdateLayeredWindow() (now ULW_OPAQUE) and that allowed it to work - but obviously without the blending.

HankM

HankM

1/7/2009 7:57:46 AM #

Thanks to those who have reported that the image doesn’t appear correctly under Windows XP, the resolution for this is very simple, just call:
memset (&m_blend, 0, sizeof(m_blend));

In the splash screen constructor (the joys of C++! Smile).

I have re-uploaded an updated source and binary build.  You can find and at the top of this page.

...Stefan

StefanOlson

1/9/2009 2:12:22 AM #

Anyway to get a C# version?  New to programing so I have no idea how to convert one language to another.

Bryan Krossley

2/17/2009 10:57:21 PM #

Trackback from Stefan Olson's Blog

Virtual Tour Viewer beta available

Stefan Olson's Blog

5/3/2009 12:00:15 AM #

Code will not compile when trying load an image from a file using CFileImageLoader.  Could you post some working code?  This is otherwise a really nice program.

Nicole

5/27/2009 6:19:51 AM #

Thanks for useful code.

Small bug: If you mouseclick on splash screen during the fadeout, SplashScreenStarter.exe stays in memory until you terminate it from task manager.

Victor Laskin

6/4/2009 2:32:00 AM #

I've also seen the mouse-click problem.  And staying in memory prevents you from restarting the application.  Not a problem for me but certainly for my not-particularly-technical user base.

Simon

6/4/2009 7:57:00 AM #

@Nicole,

To use CFileImageLoader. Just add this line to the includes section at the top of the file:
#include "FileImageLoader.h"

...Stefan

StefanOlson

6/4/2009 9:01:59 AM #

@Victor,@Simon,

I apologize, this bug has been fixed, I thought that the updated code have been uploaded, but in fact it hasn't. I have now uploaded the update that fixes this problem.

...Stefan

StefanOlson

6/4/2009 9:02:38 AM #

@Nicole,

the update to the source code today includes the FileImageLoader.h default.

...Stefan

StefanOlson

6/4/2009 8:48:31 PM #

Thanks, Stefan.  This code is wonderful.

What would have to be done to draw controls or text on top of the layered window?

Nick

6/7/2009 12:56:25 PM #

@Nick,

You could possibly try creating some controls in CSplashScreen::SetSplashImage, but it may not be too easy.

I'd certainly be interested in hearing how you achieved it if you can get it to work.

...Stefan

StefanOlson

7/4/2009 10:39:26 AM #

Fantastic! Exactly what I was looking for!

@Nick,

I would interested in the code you come up with to overlay text.
It would be very useful to be able to overlay version and license information on top of the splash screen...



Cameron

7/9/2009 8:05:11 PM #

Hi Stefan,

I looked at the code and your idea is great.
I think that in order to make it a multi projects utility, it would have been better to pass both the app name and the splash screen image at the command line of the shortcut.
This way, you can use it for different projects without having to recompile the code every time.

Raz

Raz Davidovich

7/10/2009 9:58:55 AM #

Raz,

Yes, that is certainly a possibility, we do something very similar for our virtual tour viewer, where we calculate the file name based on the Command Line parameters.  However, the reason that is not the default is because most people want to be able to double-click on their application to start it, and in this case the only way to start it would be via a start menu command.

... Stefan

StefanOlson

7/11/2009 7:06:00 AM #

Hi Stephan,

Will it be possible for you to post the changes needs to be made to the C++ code to support that functionality ?
I want to pass the EXE file name and the Image file name at the command line, using some kind of separator (like ; for example) between them.
I program mostly with .NET platform and don't use C++ much...
Thanks!!

Raz

Raz Davidovich

7/25/2009 11:09:31 PM #

How would I adopt this code for my pure native codebase? For example, I'm looking for something like this...

CSplashScreen splashScreen(2000);    // Sets the fade time to 2 seconds.

...   // Do more variable initialization.

splashScreen.Show();    // Show the splash screen.

// Lengthy setup here.

splashScreen.Hide();    // Fade out over 2 seconds.

This method won't start up another application, rather it will just show a splash screen until I dismiss it in the same application.

Clark

8/5/2009 7:34:14 PM #

Hi,
  Sometimes this is just an image file and other times it might show you the progress of the app loading, or even something else. Well now WPF applications can have a simple splash screen for free. This only applies to WPF since I tested it with Forms and it did not work at all. Well on to the coding....

tin whiskers

8/12/2009 2:03:28 AM #

Pingback from devcomponents.com

Denis Basaric: DevComponents Blog  » Blog Archive   » 12 Tips To Speed-up Your Windows Forms Applications

devcomponents.com

8/27/2009 3:03:28 AM #

Can I use it in a WinFroms application? What code should I write inside my app for closing the splash?

Cornel

10/2/2009 1:06:58 AM #

How can I use this in Winformsn not WPF?

Riaan

10/2/2009 6:40:29 AM #

Tim, Cornel,

You can use it in Winforms. You would need to use the same code to notify the splash screen that it needs to close.

...Stefan

StefanOlson

3/11/2010 1:23:19 AM #

Stefan,

On windows 7, the WPF application which gets invoked from Splash screen is running into issues while rendering images. Whereas the same works perfectly fine on Windows VISTA and XP.

Any clues?

-Sangam

Sangam

9/21/2010 2:07:56 AM #

This code is great.
I found a way to draw text on top of the splash screen. It is probably not the nicest way but it works:
1. in the function CreateSplashWindow() I create another layered window with hwndSplash as the parent window handle.
2. create a window procedure for this window that draw the text in it using the command TextOut under the WM_PAINT event in the window proc.
3. made the new child window transparent using -SetLayeredWindowAttributes

So, what I got is another window which is the child of the splash screen and is all transparent except the text. This window is shown on top of the splash.

the next thing is to get the text to flash or change slowly to indicate loading time. I am trying to "animate" the dots in "Loading . . .".

Itai Barami

9/29/2010 10:37:07 PM #

I would interested in the code you come up with to overlay text.
It would be very useful to be able to overlay version and license information on top of the splash screen...

Ira Riklis

5/3/2011 8:02:33 PM #

In app.xaml.cs you would have to add the folowing lines
using System.Threading;
using System.Windows.Threading;
or fully qualify the Dispatcher and EventWaitHandler objects.

I also have a question: If I set the SplashScreenStarter as startup project, is it then possible to enter debugging and hit breakpoints etc in the .net wpf project that is being started from the SplashScreenStarter?  (Otherwise we would just have to keep the main project as startup until compiling for distribution).

Thank you for a great piece of code! It's a pity that the built-in splash screen function is not usable. So once again Stefan: thank you!

Andreas Jansson

5/5/2011 3:37:52 AM #

Hello Stefan,
(we have the same name! ;) )

Have you tried CResourceImageLoader on an x64 project?
In my build it seems the LPCTSTR returned by MAKEINTRESOURCE are not valid, and the CreateStreamOnResource fails...

Thanks for your attention,
Stefano

http://www.onthetabletop.eu/

Stefano

5/5/2011 7:47:21 AM #

@Andreas

Personally, I build the splash screen starter separately and only use it in the actual distribution, I never see it during development.  This makes things simpler, because I don't need to see the splash screen.

...Stefan

StefanOlson

5/5/2011 7:50:23 AM #

@Sangam,

I have not noticed any problems rendering images on Windows 7. I run Windows 7 for all my development and have not seen anything like that.

...Stefan

StefanOlson

5/5/2011 7:51:55 AM #

@Stefano

No, I haven't tried it as an x64 project. Maybe someone else has and can assist you.

...Stefan

StefanOlson

8/23/2011 2:04:28 AM #

Hi

There are 2 download links at the top of the article, same name and zip file size - are they identical?

thanks

Paul Eden

8/23/2011 6:40:26 AM #

@Paul,

The top one is the latest one.

StefanOlson

8/23/2011 8:19:44 PM #

That's great - many thanks.

paul

Paul Eden

Add comment




biuquote
  • Comment
  • Preview
Loading



About the author

Stefan Olson is the Managing Director of Olson Software.  He has been developing software using Microsoft Technologies for nearly 20 years.

He is currently working on building the next generation Virtual Tour software in WPF and Silverlight for www.palacevirtualtours.com.