A box of four fancy C++ Windows tricks

This article presents four useful code snippets, solving four common coding problems

Introduction

When I cleaned up my harddisk lately, I found some ancient text files I created a long time ago. One of them contained "coding tips" and code fragments concerning problems I had to solve during the development of some of my applications.

Whenever I found a solution for a specific problem, I pasted the corresponding code into the text file, and now, dozens of self-made applications later, I know what stuff you will run into over and over again:

How do I prevent an application from showing up in the taskbar?

How do I start an application minimized without "flickering"?

How do I prevent my application from being started multiple times?

How do I get rid of this annoying "Gridlines-Scrolling" bug in my custom CListctrl?

I present the answers here and hope they come along handy for you and your application; maybe this article even helps saving some of your valuable time.

So here we go…

1. Preventing an application from showing up in the taskbar

Years ago, a friend of mine came up with the idea for a small digital clock hovering above all other windows with adjustable transparency. I started coding and quickly ran into two major problems: first, the clock application (based on CDialog) showed up in the taskbar and second, its window was also accessible via ALT-TAB.

I tried several approaches to get around these problems, and finally found the solution presented below. The trick for "hiding" your application is quite simple: the main dialog window is attached to an "invisible" parent window. That's all, and it's perfectly preventing my clock application from showing up in the taskbar or being accessible via ALT-TAB ever since.

Here is the default code generated by MSVC for any new CDialog based application:

So, to make your dialog "taskbar-resistent", just use the init method shown below. If you also want to prevent the user from accessing your window using the ALT-TAB taskswitch mechanism, just make your dialog a TOOL window using the MSVC property editor.

2. Starting an application minimized without flickering

To start an application minimized (e.g. appearing directly in the tray area), the common way to do this is calling ShowWindow(SW_HIDE) as soon as possible, preferably directly after the call to CDialog::OnInitDialog().

This surely does the trick, but every now and then, you will see your main dialog window flickering for a fraction of a second before it is finally hidden or sent to the tray area.

This is because the basic window has already been created when CDialog::OnInitDialog() returns, and its default behaviour is to appear on screen (in fact, this is what windows were made for).

A few years from now, when computers operate faster than light, you'll get rid of this annoying flickering automatically, because your Operating System will then hide your window before you even start the corresponding application.

But for now, just add this OnWindowPosChanging() handler to your application:

You can also declare an optional boolean member variable (m_bDlgVisible in this example), which is initialized to true in the constructor and gets toggled in the corresponding SendToTray() and RestoreFromTray() functions. This way, I can track the current window state (IsWindowVisible() would also work) for different purposes.

Note: Adding this message handler to your code will not make your computer operate faster than light.

3. Avoiding multiple starts of your application

So you finally coded it, this ultimate application, only to find your beta testers launching it a hundred times, rendering your database useless because your function calls are not MT safe? Well, how about this little code snippet that allows only one instance of your application running at a time.

There is more than one approach to check if your application's already running or not. You could, for example, read in the list of running processes on startup and see if you can find your application more than once. But this is kind of overkill and, even more important, it's not cool.

It's more efficient (and cool) to create a system-wide unique object (called a "mutex") and check if it already exists when your program starts. If it does exist, all that's left to do then is to exit the recently started instance…et voilà!

As an option, you can also broadcast a custom message and grab the HWND of the responding application to perform other magic tricks.

Let's do it

The code shown below tries to grab the HWND of the running instance to bring its parent window to front. This is optional, but probably exactly what you're looking for, so I included the code lines required to to this.

If you don't need this kind of hocus pocus, you can quietly exit the recently started instance and be at peace.

But we want it nice, so first of all, create your own custom message; you do this in the main instance .h file:

And there it is, your ultimate application, blocking any of your beta tester's attempts to start it more than once!

4. Solving the XP gridlines problem

You've probably seen it all before: using a custom CListCtrl in report mode with gridlines enabled causes (under XP) the control to mess up its content as soon as you start scrolling up or down. This is a bug confirmed bei M$, but it looks like it won't be fixed…so here's the workaround.

The gridlines scrolling bug only applies to systems that have the Smooth Scrolling feature enabled, but you can't go wrong adding (or modifying) the OnVScroll() handler of the CListCtrl(s) in question:

That was easy! We're just forcing an additional redraw to get things right. If you think it's a waste of valuable CPU time to redraw the control even with Smooth Scrolling disabled, then this might come in handy:

This will set bIsEnabled to true when Smooth Scrolling is enabled on a particular XP system. You can then pass this value on to the OnVScroll() handler to decide if the control should be redrawed or not.

Points of Interest

And that was my box of tricks…I'm not quite sure if any of the topics have already been discussed on this site. Anyway, now they're all together here, and it would be cool if you find them useful.

History

This is the very first version of this article, and probably the last one, too, and there's no version number. In fact, there never was one.

Share

About the Author

The first thing I did when I was born in 1966 was to start crying. For years, this was my favorite hobby, until I got my first computer in 1981. I then continued crying until I finally mastered 65xx assembler. I learned to smile then, and that's what I've been doing ever since.

Comments and Discussions

It's been nice of you to share your attemp
for achieving a non-multi-instance application.
I am using a MDI-MFC app. In my case,
the portion of your code for
restoring the app. window SIMPLY DOESN'T WORK...
What could be wrong?

If your window doesn't do what you want it to do, like showing up in the foreground, it's most likely because you're sending a wrong message...or a correct message, but you're supplying wrong parameters. I found this was the case all the time I tried to signal my application to bring up the main window.

You could try some low-cost debugging by simply throwing in a few AfxMessageBoxes before you send the message, so you can see everything's okay except the message -- or the message handler.

Enjoy the show

--Jörg

-----------------------------------------
There are three kinds of people:
Those who can count and those who cannot.