How do I hide a window without blocking on it?


A customer was working on improving their application startup performance. They found that if their application was launched immediately after a fresh boot, the act of dismissing their splash screen was taking over 5% of their boot time. Their code removed the splash screen by calling Show­Window(hwndSplash, SW_HIDE). They suspect that the splash screen thread has, for some reason, stopped responding to messages, and while an investigation into that avenue was undertaken, a parallel investigation into reducing the cost of hiding the splash screen was also begun.

One of the things they tried was to remove the WS_EX_TOOL­WINDOW style and call ITaskbarList::DeleteTab(hwndSplash) but they found that it wasn't helping.

The reason it wasn't helping is that editing the window style generates WM_STYLE­CHANGING/WM_STYLE­CHANGED messages to the target window, and now you're back where you started.

A better way is to use Show­Window­Async(hwndSplash, SW_HIDE). The -Async version of the Show­Window function is the Send­Notify­Message version of Show­Window: If the window belongs to another thread group, then it schedules the operation but does not wait for it to complete.

Comments (35)
  1. Arlie says:

    If only they would just ditch the splash screen entirely.  They're a total waste of resources, and they just get in the way.  I cringe every time I see some god-awful splash screen, because I know how much memory it is wasting.  Most of them are a bitmap, so there's the memory for the bitmap.  Very often they are semi-translucent images, so the image has an alpha channel, and now the compositor has to do extra work to handle the translucency and Z-order constraints.  And on most systems, the image must be copied from system memory to video memory, so there's an entire extra copy of it.  Most systems have significantly less video memory than system memory, so the system probably had to evict something else (something more useful!) from video memory in order to accommodate the image.

    A complete waste of time and resources.  I understand why apps do it, but really a better fix is to have the shell (Explorer) indicate to the user that an app is being launched.  Yes, this is a feature request, and I know how high the bar is for feature requests.  But come on — OS X showed how to do a decent job of this.

  2. Dan Bugglin says:

    Don't forget splash screens that animate.

  3. Brian says:

    @Arlie: Windows 7 will display a version of an application's progress bar within the application's taskbar icon.  This could probably be leveraged to do what you suggest without additional changes by Microsoft.

    MSDN's guidelines for Metra splash screens: msdn.microsoft.com/…/hh465338.aspx

  4. Chris B says:

    Splash screens aren't always bad… If a program takes a long time to load, I like having a splash screen come to indicate that the computer is trying to respond to my request. I like what Office 2010 did to make them minimizable so if it gets in the way, you can at least dismiss it. That said, splash screens should not noticeably impact the load time of an app. That defeats the purpose entirely.

  5. John Schroedl says:

    Nice tip! I didn't know about ShowWindowAsync()

  6. No One says:

    Re: Splash screens

    If the splash screen isn't always-on-top then I don't mind it.  If I can set it so that the splash screen is opened up behind other windows that'd be great.  That way if I want to wait for Firefox to reticulate its splines I can.  If I want to keep working on something while Firefox reticulates its splines I can.  I even like the Metro guidelines for splash screens.

    I don't get all this hatred for splash screens — yes, they are often done horribly wrong, but if done right they can be a great aid to UX without much cost.  A –nointo flag on the exe to avoid the splash screen would allay the problems that most people have with them though.

  7. 640k says:

    Many splash screens are actually topmost. Pure evil.

  8. Adrian says:

    Eliminate ALL the splash screens!

    Put the branding in the application itself.  Impress your users with a fast startup time rather that applying a splash screen bandaid to your embarrassingly slow initialization.

  9. Rob says:

    @Brian: While your proposed solution could potentially work for a program already pinned to the taskbar, it presents a few hurdles.  The first is that a taskbar icon doesn't generally appear until an application's first top-level window appears, except for pinned icons which have a different appearance (no block vs. block).  You then have the problem of who is responsible for reporting the application's load progress.  Obviously the Shell team can't do it, so the app itself has to report load progress.  That being said, it probably then becomes more of a headache than it's worth, leading us right back to putting up a splash screen.  :)

  10. AsmGuru62 says:

    I once worked on a team for a project where it has 118 DLLs (statically linked, of course) — startup time ~45sec.

  11. Gabe says:

    As annoying as splash screens are, what's the alternative? A blank window where it looks like you can act but really can't is certainly not a better user exerience. While some splash screens are purely unnecessary (put there just for branding), others are extremely expensive to do better than.

  12. John says:

    What are we arguing about here?  Are all splash screens bad or just the annoying ones?  If the program's startup time can not be improved (as is sometimes the case when 3rd party frameworks or components are involved), I at least want some kind of feedback that something is happening.  An unobtrusive splash screen would serve that purpose.

  13. Tod says:

    I remember using KDE3 on Knoppix about 5 years ago. It showed a bouncing ball with the icon of the application being launched next to the cursor.

    Sadly half of the applications were broken and didn't launch at all, leading to frustrated waiting until the animation timed out. But that's a different issue.

  14. Walter says:

    do Windows belong to threads or to "thread groups" as you call them, and if the latter, what is a thread group?

    [Windows belong to threads, and threads belong to thread groups. (Therefore, windows belong indirectly to thread groups.) I discussed thread groups in my "Five things every Win32 programmer should know" talk. -Raymond]
  15. Mark says:

    Windows does something a bit similar, except that the busy cursor does not have the application icon, but is generic.

  16. Anonymous Coward says:

    When you show a splash screen, you're saying these things:

    * Our ego is huge.

    * Your time and your life are unimportant.

    * Our software is bloated and our programmers incompetent.

    * And we're proud of it.

    Burn all splash screens.

  17. Danny says:

    @Adrian and all other splash haters that don't use their single neuron when saying "get rid of ALL.." – try sell a application which has resources over VPN in different location in the world, the light takes ~70 ms to travel from Los Angeles to Moscow, or do open a Excel file from Moscow while the resource is shared on a HDD in LA. Then talk again. I like splash screens that shows the feedback – your "get rid of ALL" statement(s)…well marry that neuron so you'll double your IQ.

  18. cheong00 says:

    @AsmGuru62: How do you static link a DLL? I think static link means the code in .LIB get placed in the EXE file directly.

    118 .LIB files doesn't necessary mean long load time if static linked, because when doing static linking, functions that's not used won't be put into the EXE file.

  19. Joshua says:

    I suspect it actually is possible, but why you'd want to do it I have no clue. If the offset of functions within the dll change, you're broken. Link dynamically with dlls.

  20. meh says:

    I think he meant implicit DLL linking, also known as a static load: msdn.microsoft.com/…/9yd93633.aspx

  21. @cheong00:

    As meh said, this is refering to linking against the import library at compile time and then statically loading the DLL. This is just another of those interesting terms that people use. Obviously, the converse of this is dynamic linking. I guess it is helpful to be aware of these quirky terms at times.

    Of course, statically loading 118 DLLs will cause slow down if all 118 DLLs do strange things in their DllMain functions.

  22. mpz says:

    A splash screen that is contained within the application's actual window (client area) is perfectly acceptable (in other words, bring up the "real" application window immediately, even if it can't be interacted with (the splash "screen" communicates to the user that the application is still loading)). Just don't make it a separate window and DO NOT make it topmost. That is grounds for immediate uninstall in my books.

    (The reason why I'd prefer splash "screens" in the application window is because it's highly annoying when an application that is not focused, brings up its main window and steals focus even though I was doing something completely different, waiting for the application to launch..)

  23. Thomas says:

    @Gabe:

    "As annoying as splash screens are, what's the alternative?"

    Improve application load time? Make it load on demand instead of everything at startup?

    Slow startup is a symptom that should be addressed – not put a big fat sticker on it.

  24. BC_Programming says:

    Some of my applications involve actions such as compiling scripts, enumerating .NET assemblies for implementations of interfaces and derivations of certain abstract classes, loading images and sounds, as well as acting on a number of options provided as part of the settings of the application. The Splash screen provides feedback during this process in the form of a progress bar (that is the entire splash changing colour horizontally as well as the win7 taskbar progressbar). If a problem occurs it can stop and provide a diagnostic log that I can use to help them with the issue. It  is animated as well and uses a bitmap, but the purpose is to "distract" the user for the 6-10 seconds for startup. It appears instantly, and if the user switches to another application it doesn't try to usurp the focus.

    I hate programs that don't provide <any> feedback during initialization and give you a single generic error when anything bad happens, so I made mine provide clear feedback when something goes south by showing the progress and displaying any error traces visually in addition to automatically writing log files for inspection.

  25. @BC_Programming says:

    >Some of my applications involve actions such as compiling scripts, enumerating .NET assemblies for implementations of interfaces and derivations of certain abstract classes, loading images and sounds, as well as acting on a number of options provided as part of the settings of the application<<

    Because you are in .NET, you should let the runtime lazy-load all this. .NET makes it very easy and safe to implement "initialization on first use": By defining "static readonly" members having the initilization value produced by a function.

  26. Brian says:

    AsmGuru62: I hope you guys at least rebased the dlls.

  27. AsmGuru62 probably linked against the LIB files for the DLLs as normal.  To compare, he could have asked the linker to delay-load these DLLs, which would have probably made a significant difference.

    On the other hand, if the program actually has to call code from each of these DLLs on startup, then some more work is probably in order.

  28. David Walker says:

    @Danny, you could tone it down a bit.  There's no reason to be abusive!

  29. AsmGuru62 says:

    I wish I worked alone on that one.

    I was just a consultant for a few outsourcers. :-)

    118 DllMains indeed would do some cool and slow stuff.

    So, we needed the splash, because of the slow startup.

    Rebasing is a good idea, but I think system itself does it.

    When XP starts an EXE – it caches the DLLs final loaded address, so next

    startups for the same EXE (with the same timestamp) would be faster.

    This effect however lasts until next reboot (or the new build, so EXE will be modified).

    Splash screen was made on a different thread, so it can be dismissed by user if user is annoyed for some reason.

  30. Klimax says:

    I'd say bind. (LibreOffice/Openoffice can be sped up that way – AFAIK ~50%) Sounds like that project could use that as well. Warning: some compilers can produce binaries in such way that bind can break them. (notably GCC)

  31. Simon R says:

    For bad splash screens – how about the Visual Studio 2010 one? VS takes long enough to load that it arguably needs a splash screen – but the problem is the splash screen itself often doesn't appear until a second or so after you've launched VS, which defeats the point of having it!  If I had a penny for every time I've started two instances of VS because the delayed splash screen on the first instance made me think it wasn't launching, so I clicked to launch it again.

  32. Adrian says:

    @Danny:  Just bring up the app's main window in a non-editable state until the resources become available.  What if I started the app by mistake.  Why should I have to wait for bloated resources from Moscow just to close the app?

    A splash screen just consumes additional resources for branding.  And it's not the kind of branding you want.  I only remember the splash screens from the slow starting app.

  33. Gabe says:

    Adrian: What if the app doesn't know how to draw the window without those resources?

  34. Veltas says:

    @BC_Programming

    It  is animated as well and uses a bitmap, but the purpose is to "distract" the user for the 6-10 seconds for startup. It appears instantly, and if the user switches to another application it doesn't try to usurp the focus.

    MSDN has something to say about animated splash screens.

    msdn.microsoft.com/…/aa511284

  35. ender says:

    MSDN has something to say about animated splash screens.

    Office team didn't get that memo.

Comments are closed.

Skip to main content