AttachThreadInput is like taking two threads and pooling their money into a joint bank account, where both parties need to be present in order to withdraw any money

Consider this code:

// Code in italics is wrong
   foregroundThreadId = ::GetWindowThreadProcessId(::GetForegroundWindow(), 0); 
   myThreadId = GetCurrentThreadId(); 
   if (foregroundThreadId != myThreadId) 
       AttachThreadInput(foregroundThreadId, myThreadId, TRUE); 

If you try to step over the Attach­Thread­Input call in the debugger, both the debugger and the application being debugged will freeze. Why is that?

This should look familiar because it's basically the same code that I warned you about several years ago. The code grabs the current foreground window and attaches its input state to the current thread. Now you're in trouble.

Remember dual-signature bank accounts? These were bank accounts that required the signatures of both account holders in order to make a withdrawal. It can work out fine if the two parties trust each other with a shared bank account and can coordinate their actions so that when one of them needs money, it can go to the other and say, "Hey, can you sign this withdrawal slip? I need some money." (Another use case for dual-signature bank accounts was a parent wanting to monitor their child's spending.)

Attach­Thread­Input tells the window manager, "Please take these two threads and put all their money in a dual-signature bank account."

In the case above, the code said, "See that random person being served by the bank teller? Please take all my money and all his money and put them into a dual-signature bank account."

As you can imagine, this is a bad idea, both for you and for the other person. You cannot withdraw any money until you can somehow track down that random person and get him to sign the withdrawal form. And it's not like you have any relationship with that person—you don't even know his name!—so the only chance you have is to go down to the bank and hang out there hoping that the other guy will show up to make a withdrawal as part of his normal course of business, and then you can say, "Hey, you there! Sign this for me, will ya?"

The other person is in a similar predicament. When he goes to the bank to make a withdrawal, the teller will say, "I'm sorry, sir, but your money is in a dual-signature account, and your withdrawal slip has only one signature on it." He's stuck doing the same thing that you do: Whenever he wants to withdraw money, he has to go to the bank and hang around hoping that you will show up eventually.

bank account input queue

money input

go to the bank check the message queue

In this case, what happened was that the code grabbed the debugger and said, "Okay, we now have a dual-signature bank account!" And now you're stuck. The debugger cannot withdraw any money because it is waiting for you to go to the bank. But you can't go to the bank because you're broken into the debugger. Result: Nobody gets any money.

This is why you shouldn't grab random people in the bank and unilaterally create dual-signature bank accounts with them.

Reminder: Attaching input queues is not a Get Out of Jail Free card. It's a Get Into the Same Jail card.

Comments (29)
  1. Hm, it works. But there must be any message, addressed to the Window of the application being debugged, which blocks the input queue. But which one could that be? The Thread of the application being debugged should not receive any messages simply during the call of AttachThreadInput. (The Debugger does not reach the BringWindowToTop call)

    [Focus change messages, probably. -Raymond]
  2. Thank you for your super fast answer.

    So my assumption was correct, that the reason for the block is that the Debugger cannot retrieve any of its messages, because he cannot bypass a message which is addressed to the application?

    (Read all of your blog-entries associated to this topic, during this week. Big thanks for all of them, at this point)

  3. I'm a little more concerned with "why is this app doing all kinds of wacky stuff to try to get to be the foreground window." What's so special about this app that it should get to be the foreground window?

  4. What d'ya mean the bank is out of money??! says:

    This post reminds me of a Simpson's reference… A building society must prove robust against imps. In this case I assume the operating system as a whole copes quite well.

  5. Joshua says:

    [Focus change messages, probably. -Raymond]

    I think I'll remember this next time I have to disrupt debuggers. I'd love to see the look on the guy's face when his debugger hangs.

  6. parkrrrr says:

    @Joshua: This guy, at least, is using ntsd -d to debug your process and won't even blink.

  7. Ivan says:

    Why the hang often happens if the second application is not a debugger? Of course, in theory the second app is not designed to handle attached thread input, so anything can happen. But what are actual reasons for hang, if, for example, the second app is just showing message box at the time of BringWindowToTop call? You know, all this AttachThreadInput-related stuff is there, in code samples, only to steal focus from 3rd-party apps, and it is not clear why _sometimes_ they are not handling it well.

    [I thought I spent a whole week discussing this. See "Get into the same jail free". -Raymond]
  8. DWalker says:

    Re bank tellers and withdrawing money:  Remember, analogies are like feathers on a snake.  :-)

  9. Sven2 says:

    Why is this dangerous trick of AttachThreadInput so popular to get focus? Wouldn't it be much cleaner to just do something like CreateRemoteThread({SetForegroundWindow(mywindow)}) in the application that currently has focus?

  10. Myria says:

    The biggest lesson of Raymond's blog has always been to not touch stuff that isn't yours.  Don't mess with other programs – keep to yourself.  Relying upon the precise behavior of another application is bad news.

    CreateRemoteThread is far more of a hack than AttachThreadInput.  You're injecting assembly code at that point.

    As for annoying debuggers, good reverse engineers won't be fazed at all.  They can just make the AttachThreadInput API do nothing anyway.

  11. Joshua says:

    @Myria: I've got something worse for him. You see, you warn once with a blatent goaway, then you play nasty.

  12. parkrrrr says:

    And then all of the people who have legitimate reasons to be debugging your application, like those of us who attempt to pay your taxes for you by adding the accessibility you couldn't be bothered with, shrug our shoulders and counsel our customers to buy literally anything else.

    I'm looking at you, popular voice chat application with overly-paranoid developers and a new corporate parent who should know better.

  13. Gabe says:

    I think you can refine the analogy by adding that you're taking a random stranger and forcing them at gunpoint to put your savings into a joint dual-signature account, whereupon you're arrested for using the gun. At that point, you cannot get your money out because you've been arrested and the stranger can't get his money out either because you've been arrested.

    The stranger can't even bail you out to get your signature, because in order to get the bail money he needs your signature!

  14. Christian says:

    I really don't like programs to steal focus and I have no plan to ever write one.

    But this "forbidden" topic is somewhat interesting. In the linked posts there was much talk about SwitchToThisWindows, but allegedly that function does not magically bring an obnoxious application to the front and it minds focus rules.

    Can someone confirm that this crazy, dangerous method of using AttachThreadInput is "the forbidden trick" that those programs use to get to the front and steal focus? Or do they just turn the protection off in the registry temporary (which is the well known global state for local solution problem)

    If indeed AttachThreadInput+BringWindowToTop is the secret trick, then clearly the crowd who say that it must not ever be talked about can have a piece of mind: Only really crazy software would do that (which means 90% of it ;-) )

  15. Jan Ringoš says:

    [John Doe] What if the foreground window's application is running at a higher integrity level?

    I, for one, wrote myself a simple program, that waits until some period of idleness elapses, and then starts cycling between console windows, movie-style. Except it works only until the period, where it is allowed to set foreground window, elapses. I couldn't find a way how to do that the proper way, so it sits between my suspended projects waiting if it ever will be resurrected. Yes, I do often use several console windows with different output.

  16. Nitpick: both the application being debugged and the *application in the foreground* will freeze. (This is very likely, but not certainly, the debugger.)

    [I'm walking through the specific scenario where you are debugging the application ("If you try to step over the Attach­­Thread­­Input call in the debugger"), so it is implied that the debugger is the foreground window. -Raymond]
  17. > Jan Ringos

    If your simple program is the foreground window, it can set any other app to the foreground window. So one solution would be to have it include itself in the cycle, refreshing its "allowed to set foreground window" privileges.

  18. Joshua says:

    > SwitchToThisWindow … does not magically bring … application to the front

    I'm told it used to prior to XP. (End-run in 98, ME, 2000).

  19. John Doe says:

    @Sven2, is thread injection any cleaner?

    What if the foreground window's application is running at a higher integrity level?

    Or again, what's so special about any application that it requires to interrupt whatever you're doing in such way? You may be typing a password, or simply a message/phrase, followed by Return and *BAM*, you've just clicked the default button of whatever was it that got in your way.

  20. Hello Raymond,

    Sorry for misusing your Blog – Comment List as a chat, but i would be grateful if you would answer my question to you within comment no. 3. That bothered me yesterday all evening.

  21. @Allgaeuer says:

    Didn't you claim to have read the answer already right after asking the question?

  22. No, i am absolutly uncertain about my assumption, that any message, addressed to the Window of the application being debugged, is (for sure) the reason for the unresponding Windows. I took up my interest to this topic just to express my gratitude.

    I also don't understand the question of Ivan. I mean, the "Get Into the Same Jail card"-article states that the thread which owns the forground Window has to process is WM_ACTIVATE message. There is no reason why an application which shows a message box should be unable to do this. Even if there is a modal dialog, the thread still has to pump messages within the routine… :(

  23. Neil says:

    Of course, there are much easier ways to hang your debugger. Copying from the debuggee and accidentally pasting into the debugger is the way I normally fail.

  24. DWalker says:

    @Gabe:  That was good… maybe you could work a getaway driver in there somehow.  :-)

  25. Joshua says:

    @Jan Ringoš: I would have told you to change the setting "prevent applications from stealing focus" but a Google search tells me that option was removed from the code starting in Windows 7.

  26. John Doe says:

    @Jan Ringoš, you see, that's no different from the stated problem. Yet again, what's so special about your application?

    The chance that the user will press Return by about the time your application steals the focus is still (relatively) huge. Imagine, he/she might be reading the text in a message box, deciding what to do before doing anything (your idle time), then do it (just a tiny bit after you stole focus and got ahead of everything else).

    The taskbar will blink if you use SetForegroundWindow, just use it and let the user decide when he/she wants to switch to it.

    If you're doing some nuclear power plant monitoring and controlling system, then you should have physical bright almost blinding lights of various colors and loud almost deafening speakers for things that really *really* REALLY require your attention.

    Or turn the computer almost "unusable", to the point where it's a kiosk and you probably shouldn't have much problem with focus (or chat applications, for that matter).

    @Allgaeuer, if two threads share the same input queue, any generic message pumping loop will most likely block when the other thread blocks. There's no "for sure" that the block is due to shared input queues, but Of Course™, you can debug the debugger to confirm it.

    @Neil, good point. An application might have a handler for when the current clipboard's content is requested. When pasting from a debugged application that is suspended, pasting will block until the debugged application is resumed. If you paste in the debugger, you can't resume.

  27. kme says:

    So how did debugging work in older versions of Windows where there was just one global input queue?

  28. @kme:

    Not very well, from what I remember…

  29. Joshua says:

    @kme: I'm pretty sure there was in the 16 bit days some kind of way for the system to notice because it didn't hang up my 16 bit debugger to step into the message loop, put breakpoints in WndProc, etc.

Comments are closed.

Skip to main content