Don’t just grab the foreground window and host UI on it


I was asked to look at an application compatibility bug in a program from a major vendor. But that's actually irrelevant; what I'm writing about today has nothing to do with application compatibility. That's just what drew my attention to the program in the first place.

At some point during the install, the setup program encountered an error and wanted to display an error message. When it called DialogBox to display the error message, it didn't pass the setup program's main window as the hwndParent. Instead it passed GetForegroundWindow(). They chose the wrong owner for modal UI. (I've also seen people try GetTopWindow(0).)

It so happened that the foreground window was Task Manager, since I had switched to Task Manager to look at various statistics of their installer as it ran.

I hope you can see where this is going.

They passed Task Manager as their modal owner, and since modal dialog boxes disable the owner, they ended up disabling Task Manager. (Meanwhile, their main setup program remained enabled, so I could have clicked on the Cancel button if I wanted to, which would have led to the "stack without support" problem.)

Now I can't terminate their broken setup program from Task Manager since they inadvertently disabled Task Manager.

But why did the programmers choose to use the foreground window anyway?

One possibility is the programmer's version of the politician's fallacy.

  • We must pass a window.
  • The foreground window is a window.
  • Therefore, we must pass it.

Another possibility is that they did this on purpose in order to ensure that their error message steals focus. Because their program is the most important program in the history of mankind.

Unfortunately, I see this a lot. People who think their program is so important that they will abuse the rest of the system in order to get what they want instead of just waiting their turn. Of course, these people also fail to realize that setting a window as the owner for UI creates its own problems. As already noted, you disabled a random program. What's more, you've now attached the two input queues and tied your fates together. If the program that owns the foreground window stops responding to messages, then your program will also stop responding to messages.

But primarily it's just rudeness. You took somebody else's window and started acting as if you owned the place. It's like looking up somebody's address in the phone book and using it as your own. That's not your house, and that's not your window.

Comments (58)
  1. Anonymous says:

    Hilarious! …That’s not your house, and that’s not your window. Classic. Thanks for the laugh

  2. Anonymous says:

    I’ve seen these mistakes in the making.  I think Raymond is attributing to malice what was probably incompetance (or ignorance).  The devs probably found themselves in a place where they needed to display an error and didn’t have the window handle of the installer’s main window.  The architecture was probably too complex to pass the parameter all the way down the call stack (or perhaps even to another process).

    Somebody probably stumbled upon the idea of using GetForegroundWindow and didn’t think it through.  99% of users probably don’t switch tasks during an install, so it might not have occurred to the devs that the foreground window might be anything other than their application.  Ignorant, sure, but not necessarily arrogant.

    Assuming that fixing the architecture wasn’t feasible at the time, what would have been the right way to get the proper window handle?  GetActiveWindow?  FindWindow?

  3. CGomez says:

    Not to mention that many times the install would not encounter an error, and the rude code would not run.

    I think most developers I have ever encountered don’t really understand how Windows works… at all (not asking for Raymond’s level of expertise, even).  If you described the behavior above to them, they would simply say: "That’s a bug in Windows.  It can’t recognize that I want my own foreground window." or "There should be an easier API to get my own top window, then" or "Windows is too complicated because MSFT is a monopolist."

    I really don’t think I’m making any of these answers up… and the list is not complete.

  4. Anonymous says:

    > I think Raymond is attributing to malice what was probably incompetance (or ignorance).  

    I would agree with Adrian 100%, having written a few programs when I started out that where all modal and stole window focus from everywhere. I approached the development like my software was only software that would need to run on the machine, in retrospect it was a combination of pressure to deliver and incompetance that did it.

    Would I do it today, hell no!

    Chen is 100% correct, its damn rude!/

  5. Anonymous says:

    Under what circumstances is it a Good Thing for one program to use another program’s window as the parent for DialogBox?

    I’m curious, because I can’t think of any possible case; and yet, if there weren’t, there would have been nothing to stop MS disallowing this usage (eg. silently converting the window handle to NULL in this case). The general MS strategy seems to be to preserve potential bug-causing scenarios if the correct behaviour of an application might depend on them. This is good; but I’m wondering what “correct behaviour” would depend on cross-process DialogBox().

    [Consider two programs which are working together to display what appears to the user as one application. This happens a lot more than you think. -Raymond]
  6. Mike Dimmick says:

    In general, when you call DialogBox, you’re doing it in response to some event that you’ve received on a particular window. The obvious window to pass to DialogBox/MessageBox as the owner for the dialog is the window that received the event!

    If you have a worker thread doing the work while your UI thread is showing a progress window of some sort, you have to have the window handle of the progress window to inform it of progress. Well, if you’ve programmed it sanely, you do – you call PostMessage with a custom window message to inform it of progress, and when the process is complete. If you need to show an error, you send a message back to the progress window that tells it to raise a message box.

  7. Mike Dimmick says:

    @Adam: unfortunately most of the people who have these problems would never open the book.

    Books I would recommend to anyone who actually wanted to learn the technology rather than just guess: "Programming Windows" (Petzold), "Programming Applications for Microsoft Windows, 4th Edition" (Richter), "Windows Internals, 4th Edition" (Russinovich & Solomon). If you’re going to write a server application, also read "Programming Server-Side Applications for Microsoft Windows" (Richter & Clark). All very useful if you’re going to be writing .NET applications too, because you still have Windows underneath – Windows Forms largely uses the standard Windows controls and common controls library.

  8. Anonymous says:

    I see this is an inexperience thing. Hey, my installer’s running, so that’s what the user is looking at, right? They wouldn’t be running the installer if it weren’t on top. (Except for all the exceptions!) I would have made the same mistake if you asked me to write an installer two years ago. Heck, I might have made the same mistake next week if I hadn’t been reading this.

    I won’t argue that the books cited aren’t good and useful but you can’t just read them and come out an expert. You have to read, write programs for practice, and make mistakes to gain experience and eventually write less-buggy programs.

  9. Anonymous says:

    Arrg I can remember back during the 98 beta when it first came up in the beta newsgroups about disabling the ability to steal focus in the OS altogether. Ahh it was a grand dream. Nothing ticks me off worse than to be typing away at 80wpm and blammmo some app has to toss up a dialog right in the middle of some important point. Let alone when your blissfully coding along and this happens, since a lot of the time I write and code with my eyes shut (touch typing is grand) then I don’t always even know its happened. That said, I guess I shouldn’t be typing up a 30 line vb or vfp utility while installing software..

  10. Anonymous says:

    Somebody probably stumbled upon the idea of

    using GetForegroundWindow and didn’t think it

    through.  99% of users probably don’t switch

    tasks during an install,

    Calling BS on that one. I want to see the raw data here.

    Installers are long and slow. There’s no way in hell 99% of people stop everything they were doing to wait for the installer to finish it’s long and slow process. "Sorry, Bob, I didn’t respond to your IM because the World of Warcraft installer was only on disk 2, and god forbid I switch apps to reply to you."

    Unless you’ve done usability tests that show this, you (the programmer of this installer) should make NO assumptions about what users do while your app is running.

    One of my hugest pet peeves is installer programs that create a giant window that takes over the whole screen to show a teeny progress bar in the middle. Actually, one of my hugest pet peeves is that all programs don’t just use .msi installers which work well all the time instead of their crazy third-party installers that don’t.

    Another huge pet peeve is applications that steal focus. Not going to name name, as per blog rules, but I installed a anti-virus product recently that stole focus from my IM windows three times in a row to inform me that it was updating itself. Sure, anti-virus updates are important, but they’re not THAT important. It could easily have been a notification manager thing. (Tons of apps do this… try putting a DVD in an OS X machine while typing something. It’ll steal your focus twice, with just enough gap in-between to switch back to the window you want.)

  11. Anonymous says:

    Of course, this begs the question of why the installer dialog is able to disable another app in the first place. Isn’t it part of the responsibility of the OS to give programs an isolated space to work? I’m sure there’s lots of Win16 history and compatibility that limits the options, but then let’s give the poor programmer a break–it may not be ignorance or malice but just struggling with design flaws of the environment.

    [There are legitimate reasons for one program to disable another program’s window (e.g. as I noted in a previous comment). Windows assumes that programmers know what they are doing. -Raymond]
  12. Anonymous says:

    This is actually a subset of the whole ‘my application is the most important thing in the world’ class of UI problems.

    User applications should force themselves to the foreground, approximately never.  

    OS applications should only force themselves to the foreground in the case of critical notifications.

    And in any case, if you force yourself to the foreground, don’t put any one-key shortcut keys or default action on the dialog.

    This is probably my biggest pet peeve in the XP UI.  I’m not running vista anywhere yet so I don’t know if that’s changed.

  13. Anonymous says:

    How long until we get serious, as a profession, about building systems that don’t allow applications to stomp all over each other and core functionality in this fashion?

    [If you prevent programs from doing stupid things, then you also prevent them from doing clever things. -Raymond]
  14. Anonymous says:

    I vote ignorance. The programmer needed a window handle but did not have one handy (deep in a call stack or InstallScript) and thought that the foreground window must be the installer – wrong answer.

    The deeper problem is that it is too easy to get a reference to a different application and mess it up.

  15. Anonymous says:

    Maybe I just don’t understand the issue, but isn’t this a security issue for the Task Manager?  I would think that if an application can interfere with Task Manager, it becomes very difficult to kill a misbehaving program. Of course, at that point the user has already run the offending program, so the battle is already somewhat lost.

    Or is there something else I’m missing?

  16. Anonymous says:

    Adam: "So, would MS really lose that many sales of Visual Studio by selling it for $330 and including a decent tutorial – Programming Windows – with it?"

    Expecting MS to include a book to teach you to program makes as much sense as expecting the manufacturer of a woodworking lathe to send a trainer to your workshop to show you how to turn a piece of wood into a table leg. Or the rifle manufacturer to send a marksman to your house to make sure you know how to shoot safely.

    Just because you provide the tools doesn’t mean you have to teach someone to use them. The end-user has that responsibility.

  17. Mike Dunn says:

    ATL makes this mistake all too easy to do when you call DoModal. The param to DoModal is the window to use as the dialog’s owner, and it defaults to GetActiveWindow(). If you just write "DoModal()" it will usually work, except in the cases when it doesn’t.

    I ran into this a while ago, I had a worker thread doing some long operations (on the order of minutes), and if it hit an error, it posted a message to the main thread saying "show error message #123 now". The trouble was that the user probably minimized the app or switched away in the intervening time, and the call to DoModal() could end up using some other app’s window for the owner. Since I started in MFC, I was used to calling DoModal() with no params and having it Just Work. Not so in ATL.

  18. Anonymous says:

    KenW: Some manufacturers do, some don’t. My Whirlpool oven, for example, came with some excellent instructions on how to bake, my most recent camera had some really good information on how to take pictures.

    Raymond’s life might be a lot easier (in ten years) if more of the documentation clearly stated which routines were commonly used and which were uncommon, which were "safe" and which were "dangerous"

  19. Anonymous says:

    @Mike Dunn: On its own, the call to GetActiveWindow was not the problem.  From the MSDN documentation:

    "The GetActiveWindow function retrieves the window handle to the active window attached to the calling thread’s message queue."

    So as you can see GetActiveWindow does not return a window from another application.  It may however return an unexpected window (or none) from your application.  It all depends on which thread you call it on.

  20. Anonymous says:

    Myron: No, it isn’t a security issue – Raymond had an entry about this not many days ago. When you run the installer, you’re trusting that application to  make changes to your system, which might well include disabling (or indeed replacing: at least one free MS tool we may or may not be allowed to name offers this facility) taskmgr. For that matter, the installation could involve replacing some or all of the operating system (think service pack or OS upgrade)…

    One exception to that is that if the tool is able to disable the Secure Attention Key (aka ctrl-alt-del), you may have violated the security model (to prevent imposters taking the place of the login screen) – this is why virtual machine software can’t normally intercept ctrl-alt-del to pass to virtual machines instead of the host: the OS won’t allow them to.

  21. Anonymous says:

    CGomez, don’t forget that old staple "Microsoft’s apps aren’t screwed up like my apps because they use witchcraft^H^H^Hsecret APIs."

  22. Anonymous says:

    Nothing ticks me off worse than to be typing away at 80wpm and blammmo some app has to toss up a dialog right in the middle of some important point.

    The recent irritation was the system update stuff on my laptop (corp install, etc). MS has decided to pop up a dialog and steal my focus out of the blue, and it’s highly likely that I’ll be typing (like now) when that happens. Hit the wrong key and the system reboots.

    What’s needed is, as you say, removing the ability to steal focus. This is what makes X style window managers so cool – you demand focus and the manager slaps you down.

  23. Anonymous says:

    There should have been a flag on every window/process which could prevent the window from getting rogue children from other processes.

  24. Anonymous says:

    Adam: Microsoft does offer an instruction manual, it’s called MSDN Library and it includes Visual Studio documentation.  It’s available online:

    http://msdn2.microsoft.com/library/

    and as a free download:

    http://www.microsoft.com/downloads/details.aspx?FamilyID=b8704100-0127-4d88-9b5d-896b9b388313&DisplayLang=en

    I really can’t believe it could take someone ages to learn the basics of Windows programming if they serious about learning and not just doing it as a hobby.  Maybe that argument was valid 15 years ago, but with the amount of information available (for free) on the internet your argument is pathetic.  You can lead a horse to water, but you can’t make him drink.

  25. Anonymous says:

    [There are legitimate reasons for one program to disable another program’s window (e.g. as I noted in a previous comment). Windows assumes that programmers know what they are doing. -Raymond]

    A system that trusts its users to not misbehave can never be secure. No amount of articles educating programmers to not abuse the OS will help. If it can be abused, it will be.

  26. Anonymous says:

    I really can’t believe it could take someone ages to learn the basics of Windows programming if they serious about learning and not just doing it as a hobby.

    The thing you’re missing is that some people are doing this as a side job for their office or that they don’t really care – it works, sort of, so why waste time reading books? MS people tend to be driven and care about personal development. In fact, most people I’ve met professionally are like this, but there are always George Costanzas in the world, and some of them write code.

  27. Anonymous says:

    CGomez > I think that might come down to most Windows devs not being able to find decent documentation on how to write Windows programs from scratch. (The Visual Studio wizards probably have something to do with this, but that’s another beef).

    Yes, MSDN has a lot of reference material. But a good tutorial on how everything works? I’ve never really found one in the MSDN bits that come with VS. Not one goes through everything and is easy to read. If it’s there, it’s completely lost amongst all the other cra^H^H^Hdocumentation that’s there, and needs (IMHO) to be made a *lot* more prominent.

    So, what is a good book on how it all works? Scratch that, what is the *best* book on how Windows works, that all Windows programmers should start to read before they write their first line of Windows code?

    (If I’m missing something in MSDN that’s been available in most versions of VC/VS released, please someone shout loud. If anyone knows where I should have been looking to already know without doubt what the best book is for learning Win32 programming, also shout loud)

    I do keep hearing that "Programming Windows" by Charles Petzold is pretty good. Which is published by MS Press. So, how about MS supply a dead-tree copy of PW5 with each copy of Visual Studio. List price is $59.99[0], but from the links on that page it’s available for as little as $35.99. Assuming that MS are still making quite a bit on that, they could probably write it off for $30 or even less if they bundled it with something else.

    So, how much is Visual C? Um, OK, Visual Studio standard edition? Well, it looks to me like about $300[1]

    So, would MS really lose that many sales of Visual Studio by selling it for $330 and including a decent tutorial – Programming Windows – with it? Or even lost that much money selling the combination for £300 and taking a £30 hit on each copy of VS?

    And do you really think it wouldn’t make much difference to the general understanding of windows, and therefore the general level of competence of windows programmers?

    [0] http://www.microsoft.com/mspress/books/2344.aspx

    [1] http://www.microsoft.com/products/info/product.aspx?view=22&pcid=760b0bb0-dd48-425e-ab41-653b5b60216e&crumb=catpage&catid=515c9859-958b-4433-b4f9-91f37258ca2f#HowToBuy

  28. Anonymous says:

    I agree, it’s insane that the current desktop is open season to any app which wants to mess around.

    So what if there are legitimate uses? Do you remove the lock from your front door just because your friends visit frequently?

    There needs to be at least some simple defense that would prevent these n00bs from making these mistakes in the first place.

  29. Anonymous says:

    Mike > Really? I had that problem for ages when starting to write windows programs, and it took me ages to find out about PW and some of the other good books. Most of the book shops near me were mostly stocked with "Learn MFC programming in 21 days" or something like that, a few of which turned out to be awful. After some suggestions from other places that also turned out to be bad, I pretty much gave up.

    I myself ended up, for quite some time, just shotgun debugging and shotgun *writing* to try and figure out how to get something barely working. With only an API reference, but no good guidance on how to string things together or how stuff was actually meant to *work*, I ended up doing stuff like the above for a while.

    And a lot of programmers at other companies I worked for were much the same. The thorough tutorials or background information just never seemed to be around.

    I don’t know. Does that spark some recognition with anyone else who reads this blog? Or did you all figure out which other good resources you needed to get hold of straight away, without spending $$$ on some really useless books?

  30. Anonymous says:

    I agree that there exist programs that need to grab other programs’ windows and operate on them.

    However, this is an exceptional case — no programm needs to *accidentially* grab another program’s window. Also, it poses a large security risk.

    This is a place where an ACL system is needed. To cooperating programs should be able to grant each other access to their windows; a "super user programm" (such as task manager, or a debugger) might have special "root rights". But a garden variety end user application should never have such rights, nor need them.

  31. Anonymous says:

    @KenW: I don’t think anybody’s arguing that Microsoft would somehow be *obliged* to teach people how to program, just that the world might be that much better off if they included a book with VS. That’s not even in the same league as hiring personal instructors.

    And I’m only half-kidding if I say that an inept programmer can do more damage with Visual Studio than an inept rifleman can with his rifle. It’s certainly true if we’re only considering economic damage.

  32. Anonymous says:

    I don’t want them to teach me how to program, I’d figured that one out for command line programs some time before. But how Windows works? I’d have thought that might be kind of important.

    Anyway, it must be an odd world you live in where nothing comes with an instruction manual. Did you last mobile phone not come with one? Did your DVD player? What about your car? And the interfaces to those are a couple of orders of magnitude simpler than the Windows API I’d figure.

    *shrug* Guess it is just me then.

  33. Anonymous says:

    I think if those developer don’t bother search the net for the materials, does it help even if you deliver the right book directly to their home. I bet most of them will at best read a few pages, then put it on the bookshelves and never bother to read it again (the reference of the book’s existence automatically be GC-ed in their main memory).

  34. Anonymous says:

    >> If the program that owns the foreground window stops responding to messages, then your program will also stop responding to messages.

    Can anyone explain this to me a little bit more? I believe both windows will be in different threads with different message pumps, so blocking parent messsage pump should not affect popup’s pump.

  35. Anonymous says:

    not for nothing, but what’s the point of allowing one app to stall another?  this is a problem in the dialog api and the windows api in general.  

  36. Anonymous says:

    >>> [If you prevent programs from doing stupid things, then you also prevent them from doing clever things. -Raymond]

    Can you say that again please!!!

    I’m fed up with a world that fights that stated ideal.

    I cannot coun’t the number of times I’ve written "Rude Code", and I am happy to accept it. If it puts me in the bad books I’ll happily accept that.

    I don’t do it on purpose. In fact I hope that I’m able to remove the majority of examples before they become a problem, but I can’t guarantee it to anyone. Not least myself.

    There is one precious thing in life, not just software, and that is the possiblility of an open outcome. It’s too easy to constrain anything in life to a set of closed outcomes. That generic fight is worth significant hardship.

    What impresses me most is that the statement comes from a significant representative of Microsoft.

    The point of being able to stall another app, is that until you have the need, you don’t know that it’s a clear case for prevention.

    Certainly if you have a bunch of processes that operate in synchronisation with a master process, an ideal way to terminate those processes is to halt them and clean them up from the outside. Were all data associated with shared memory this would be perfectly feasible, and IMO valid. If said process were composed of multiple threads, it would actually represent a very fast, efficient and safe approach to the exit problem.

    One could argue that there is a similar case for the protection of global memory, with a process scope. My rationale for being against such an uncontolled situation is simple. If you are attempting to debug a process, then there is probably something wrong with it. If there is something wrong with the code being debugged, has it damaged the debugger?

    Those who have developed on embedded computers, with merely a hardware bootloader for company will know how difficult it can be to debug a system where the program counter has become compromised.

  37. Anonymous says:

    Raymond’s being psychic again – I first encountered this phenomenon just this week, while debugging a well known UK-based accounting system.

    My guess is it’s from some sample code, since I can’t see anything to stop people passing NULL as the hWnd to MessageBox.  Or does passing NULL make people uneasy?

  38. Anonymous says:

    [quote]that applies to any parameter to any function, not just
    window handles. Should we add that to all functions? “HeapFree: Since
    this function frees the memory pointed to by the lpMem parameter, the
    pointer you pass here must be one for which all existing references
    belong to code that understands that the memory will no longer be
    valid.”[/quote]

    Can you pass other processes’ handles to HeapFree()? NOW you are scaring me.

    I must agree with others here. I’ve been programming Windows since
    3.0, and I always assumed that you can only mess with your own handles;
    at most, with the handles from other threads in your same process.
    Being light in parameter validation and letting apps do very funky
    things with their own resources is fine (if you want to live the rest
    of your life in backwards compatibility hell), but when you let one app
    mess with resources owned by another, any expectations of security are
    gone.

    [If they are being intentionally malicious, then
    that won’t stop them. They’ll just inject code into the target process
    and do it there. -Raymond
    ]
  39. Anonymous says:

    <i>If you prevent programs from doing stupid things, then you
    also prevent them from doing clever things. -Raymond</I>

    But you also prevent them from doing malicious things. You assume
    that every programmer has the best intentions. The amount of virii,
    especially for the Win32 platform, shows differently. An application
    should at least need admin privileges for accessing windows that don’t
    belong to them, or at least for windows that belong to the OS.

    [You’re all missing historical perspective. -Raymond]
  40. Anonymous says:

    “Adam: Microsoft does offer an instruction manual, it’s called MSDN Library and it includes Visual Studio documentation.  It’s available online:”

    Um, yeah, I am aware of that, and I did already point it out.

    But, as I said, I couldn’t find a decent tutorial in MSDN on how the different bits of the Windows API fit together, or enough on what it does behind the scenes to be able to figure out *why* some naieve approaches to some problems (as detailed many times by Raymond in this very blog) won’t work.

    API references are sucky tutorials.

    Taking this example, knowing what GetForegroundWindow() or GetTopWindow() do, what arguments they take and what their return values are, as documented in the API reference, is not enough info to know *when* to (and when *not* to) use them.

    So, if such a tutorial does exist in the copy of MSDN that comes with VS, one that takes you through the basics of Windows programming from the message loop onwards, without going through MFC and the application wizards that hide all that away, I never found it. Please, where is it? How are you supposed to find it?

    And is it really that easy to read on the computer screen where you’re trying to code as you follow it, instead of being open on your desk next to the keyboard?

    [The issue isn’t GetForegroundWindow() or GetTopWindow(). It’s grabbing some window that doesn’t belong to you and doing UI with it. If anywhere, the remark would be in MessageBox, DialogBox, any function that accepts a window parameter, with something like “Note: Since this function will do stuff to the window parameter you pass here, it goes without saying that the window you pass here must be one that is prepared to have those things done to it.” But that applies to any parameter to any function, not just window handles. Should we add that to all functions? “HeapFree: Since this function frees the memory pointed to by the lpMem parameter, the pointer you pass here must be one for which all existing references belong to code that understands that the memory will no longer be valid.” -Raymond]
  41. Anonymous says:

    aahhhg.. thousands of programs are doing this.  It works most of the time because the command that launched the dialog box was started by a mouse click, or a keyboard shortcut which implies that the main app window is the foreground window.

    I think this creeps up in all large applications that where dialog boxes are implemented in DLLs by various teams.

    If I remember correctly, I can also happen in MFC when the module state is NULL or something of that sort, in which case MFC itself calls GetForegroundWindow for AfxGetMainWnd()

    The code is wrong, not rude, but many of the scenario when it fails in common apps falls into edge case category.   I’d be more at ease however if the default behaviour of the API was to return HWND for the current process only, and the apps that really need HWND from other potentially other processes would have to be forced to use another API that is specifically just for that.

  42. Anonymous says:

    ‘Aargh’: Requiring admin privileges might sound reasonable to you (aside from the problem that any Win 95/98/Me app will have been developed with no concept of ‘admin’ rights in the first place) – until you think about any sort of process interaction. Automation tools? Accessibility apps like screen readers? Remote control tools?

    Even wearing my non-developer hat I’ve had to interact programmatically with windows which weren’t my own (installing printer drivers, for one thing).

    Not to mention that a lot of inter-program communication takes places via “windows” – not visible ones, necessarily, but still window messages and handles. It might be interesting to try disabling inter-process window messages for a few minutes, just to see what happens – but I doubt you’d want to try using the resulting system!

    [There’s a program you use every day that requires access to other processes’ windows: The taskbar. (In order to move focus between apps when you click on their buttons, among other things.) Or are you saying that Explorer must run with admin privs? -Raymond]
  43. Anonymous says:

    Having written a number of installers myself, I think I know why the wrong window handle was used.

    I would guess that the installer is running a helper utility that in turn calls GetForegroundWindow(), in order to display a modal window with the installer as the parent.

    The person writing that code probably never thought that the user might switch away from the installer while it was running, and the testers probably never included it as a test case. Therefore the buggy code made its way out the door, and Raymond managed to find it.

    One option would be to use FindWindow to get the installer’s window based on its title. Another option would be to use EnumWindows to find a window with a given string in the title.

    A better option would be to pass the window handle to the helper util. However, this may not have been done because either: (a) the installer doesn’t have a way of getting the main window’s handle; (b) the developer didn’t look hard enough to find the functions to do (a); (c) the developer couldn’t figure out how to pass the window handle to the app; (d) the developer was too lazy to do any of the above and something else that seemed to work.

    In any case, there were options available that could have been used but weren’t.

  44. Anonymous says:

    James Schend said: "One of my hugest pet peeves is installer programs that create a giant window that takes over the whole screen to show a teeny progress bar in the middle. Actually, one of my hugest pet peeves is that all programs don’t just use .msi installers which work well all the time instead of their crazy third-party installers that don’t."

    I worked with Windows Installer technology around the time that Windows Installer 1.2 was released. That thing was an absolute nightmare.

    I spent close to 9 months just getting the product to install correctly most of the time, and then about another 3 months trying to dig into customer log files when installs didn’t work.

    I also had to code numerous hacks, just to get the MSI installer to do the nice things we’d added to the previous InstallShield installer. (For example, if one of our product’s services had been stopped, it wouldn’t be restarted on an upgrade.)

    We used MSI for just one major version of one of our products. For the next major release we switched back to (a newer version of) InstallShield and had the installer rewritten and working correctly in about 3 weeks.


    The point I’m trying to make here is that it’s possible to write a good installer using something other than Windows Installer. It’s also possible to write a bad Windows Installer package. Don’t blame the technology when it’s the developer at fault.

  45. Centaur says:

    @Jamie

    One option would be to use FindWindow to get the

    installer’s window based on its title. Another option

    would be to use EnumWindows to find a window with a

    given string in the title.

    And then you have to modify and recompile the helper application for each language version of the installer. And woe unto the user if he/she happens to have a window with a similar title.

    No, the main application must pass its window handle to the slave explicitly as a command line parameter, a function argument, or in a shared memory block whose ID is somehow explicitly passed to the slave. Any AI-based way to discover the master window handle is a perversion and should be seen as a sign that the design is wrong.

  46. Anonymous says:

    [If you prevent programs from doing stupid things, then you also prevent them from doing clever things. -Raymond]

    That applies to more than just programs, of course ;-)

  47. Anonymous says:

    [If you prevent programs from doing stupid things, then you also prevent them from doing clever things. -Raymond]

    That applies to more than just programs, of course ;-)

  48. Anonymous says:

    @Centaur

    [Quote]And then you have to modify and recompile the helper application for each language version of the installer. And woe unto the user if he/she happens to have a window with a similar title.[/Quote]

    No you need not to recompile.. You abiviously know your window class name, (if you don’t know the thirdparty parent installer class name, then you can very well spy it, and use it).

    Any org for that matter needs a witty tester (prefferably an integration tester and an acceptence tester). 90% of these bugs can be resolved if you have a good tester who can do all ODD things with your application, he need not to know the technology but should act as mischievously as possible.

  49. Anonymous says:

    Only a few months ago I almost made the same stupid mistake that Raymond’s story is all about: I wanted to show a MessageBox from a custom action DLL that did some non-trivial things beforehand (something you simply couldn’t do with WiX) and then would decide to show a MessageBox or not. Since we have a lot of knowledgeable commenters on Raymond’s story here: Can anyone tell me how to properly determine the HWND of the MSI installer running the setup that eventually invokes a custom action DLL? I ended up using FindWindow("MsiDialogCloseClass", NULL)… which I find quite suboptimal, to say the least. Maybe the author of the setup program that Raymond is talking about had the same issue?

  50. Anonymous says:

    "The deeper problem is that it is too easy to get a reference to a different application and mess it up."

    To go back and change history, in the rare cases where you need to reference a different application’s window, you should have to pass a flag that means "I know it’s not my window, but I want to access it anyway".

    If you don’t pass this flag, you can’t get another application’s window.  

    But that’s changing history.  (The new cross-window restrictions in Vista might have been a good place to add this.)

  51. Anonymous says:

    Raymond… Adam is looking for a tutorial.  He is absolutely right that reference documentation is a poor way to find a high-level overview of “how to do things”, and how all the bits fit together.

    Your non-serious suggestions to add silly disclaimers to every topic doesn’t mean that he’s wrong.  A “Getting started programming with Windows” article in MSDN would be nice.  Or even a book :-)

    [There are plenty of books on Windows programming to choose from. MSDN is more of a reference than a tutorial. -Raymond]
  52. Anonymous says:

    [There’s a program you use every day that requires access to other processes’ windows: The taskbar. (In order to move focus between apps when you click on their buttons, among other things.) Or are you saying that Explorer must run with admin privs? -Raymond]

    Explorer is an integral part of the system. I don’t see why it shouldn’t be allowed to have more power than fred-app over there. Although it probably can’t be changed lest every program in existance stop working. But it would be nice to have the system and the apps seperated a bit.

    [Okay, fine, if not Explorer, then the Windows XP Alt+Tab or Virtual Desktop powertoys. Any program that manipulates other windows would be affected. -Raymond]
  53. Anonymous says:

    Centaur said: "And then you have to modify and recompile the helper application for each language version of the installer. And woe unto the user if he/she happens to have a window with a similar title."

    More often than not, the window title contains the name of the application being installed. It may be relatively slow, but you could enumerate all top-level windows and find the one that contains your product name.

    Also, as mentioned by Adarsha, you can get the window class name and find that (e.g. by using Spy++). There’s bound to be some combination of the two that can be used to locate the correct window with minimal fuss, and no need to recompile for different locales.

  54. Anonymous says:

    Ah yes, Assumptions. It’s an installer, it must be the foreground window…  It’s windows, Explorer.exe MUST be running … and so on.

    The Scripting Guys actually just published in the August Technet mag a solution for determining who’s logged onto a computer based on determining the owner of the "Explorer.exe" process.  Apparently nobody told them there are alternative shells out there — Explorer might not even be running.

    I think grabbing the foreground window is a noob mistake, not a conscious decision.  The MSDN documentation for GetForegroundWindow doesn’t actually mention the possibility that the returned window handle might belong to another app.

  55. Anonymous says:

    Joel "Jaykul" Bennett said: "The MSDN documentation for GetForegroundWindow doesn’t actually mention the possibility that the returned window handle might belong to another app."

    Does the MSDN library really have to spell that out? The first part of the function description says:

    "The GetForegroundWindow function returns a handle to the foreground window (the window with which the user is currently working)."

    Doesn’t it logically follow that if the user has switched to another application (e.g. browsing the web while an installer does its thing), then the user is working in that window, and therefore that window’s handle will be returned?

  56. Dean Harding says:

    Explorer is an integral part of the system. I don’t see why it shouldn’t be allowed to

    have more power than fred-app over there.

    By the way, if you give explorer "more power" then authors of explorer.exe shell replacement apps would complain (see, for example, http://lsdev.org/ or http://www.geoshell.org/ etc)

  57. Xepol says:

    Sounds more like a design flaw in windows itself that you can do stuff like this.  It certainly breaks the concept of process isolation.

    This is yet another symptom of the design flaws that make malware so easy to write on windows.

    [Yeah, how dare programs communicate with each other. -Raymond]
  58. Anonymous says:

    [Yeah, how dare programs communicate with each other. -Raymond]

    Indeed. It’s not just "manipulating" windows in the obvious sense (as happened here), either: there are plenty of interactions involving access to another process’s windows – drag and drop, cut and paste, bits of OLE/COM as I recall, and I think the Win3.1 method of creating application icons (talking to progman.exe) will do too. Disable that lot – or restrict it to admin only – and your new "improved" Windows system won’t get very many users.

    Joel: you’re right that there may not be any instances of Explorer.exe running – but worse, there may be more than one, with different owners, even on a single-user system – you can fire up an Explorer window running as Administrator or LocalSystem while logged in (and running explorer.exe as your shell) as another user. It’s a horribly broken technique, however you look at it!

    Xepol: yeah, stupid Windows developers allowing communication. Do you avoid spam by deleting all your e-mail unread, too? Process isolation doesn’t mean prohibiting IPC outright, just limiting it to clearly defined interfaces and having ACLs where appropriate – and this is one of those interfaces. Incidentally, Vista tightens these restrictions somewhat with the Integrity Levels – no help here, of course, because an application installer will probably end up with High level anyway, but helpful elsewhere.

Comments are closed.