views:

298

answers:

1

If I add a WindowEvents_WindowActivated handler to my Visual Studio 2005 Macros EnvironmentEvents module, I get a weird side-effect: when I click from one window to another in Visual Studio, that click is treated as a double click.

So for instance, I put the focus in an editor window and click a file in Solution Explorer, and the file opens.

Or I put the focus in the Toolbox and click in an editor window, and the word I click on gets selected. In most cases, when a single-click causes a window to activate, that click is being treated as a double-click.

This happens even with an empty event handler:

Private Sub WindowEvents_WindowActivated(ByVal GotFocus As EnvDTE.Window, _
                                         ByVal LostFocus As EnvDTE.Window) _
                                         Handles WindowEvents.WindowActivated
    ' Do nothing.
End Sub

I want to use the WindowActivated event to do cool stuff, but this is a killer. Has anyone seen this before and worked around it? (I know I could use a timer and poll for the current window, but yuck.)

+2  A: 

I do not have this problem. Most likely the WindowActivated event is being fired twice. This usually happens when another process steals focus, such as another add-in, from the activated window then the window is re-activated. You can duplicate the behavior you are experiencing by adding a MsgBox call within the WindowActivated event.

AMissico
I think you're right about it being a focus/activation problem, but the circumstances are weird. The difference between working and failing seems to be calling a native function via P/Invoke. My macro was calling SetWindowText, which causes the problem. Remove that call, and it's fine. How it got into a state where an empty handler caused it to fail, I don't know - I can't reproduce that now. I know the VS Macros runtime environment lives in a separate process, so maybe there's something about using P/Invoke that makes that process get the focus. (The handler is only called once, BTW.)
RichieHindle
Remarks for SetWindowText states, "To set the text of a control in another process, send the WM_SETTEXT message directly instead of calling SetWindowText." I seem to remember reading something many years ago about SetWindowText causing a process to capture the focus...blah...blah...blah. Maybe I can find a reference. But the above statement might be a clue.
AMissico
Does the SetWindowText result in Zero, but still sets the text?
AMissico
`SetWindowText` returns True, and sets the caption. `SendMessage(..., WM_SETTEXT, ...)` also returns true, but doesn't set the caption. I've seen that note in the documentation, and in my experience it's backwards - `SetWindowText` does the magic of copying the new caption string into the other process's address space, but `WM_SETTEXT` doesn't, at least not always. Anyway, *both* APIs cause the mystery double-click effect.
RichieHindle
"SetWindowText returns True..." True or Zero and Non-Zero? There is a difference.
AMissico
Then the other process must be at fault. Does it do anything after setting text? Is this reproducible on other machines? I do not see this as a bug in WindowActivate. Are you using the Visual Studio SDK for development of this "macro"? I don't thing it is a macro because you are calling API.
AMissico
Lastly what are values of event parameters GotFocus, and LostFocus. I expect they will be correct.
AMissico
By "True" I mean "non-zero". The other process is Visual Studio itself; my macro is setting the caption for the Visual Studio main window. It *is* a macro - I'm calling APIs via P/Invoke. `GotFocus` and `LostFocus` are correct (but I'm not sure that's relevant?). I've tried it on two machines and it goes wrong on both. I can reproduce it with a single-line WindowActivated macro that does this: `SetWindowText(DTE.MainWindow.HWnd, "Hello world!")` (note that that Visual Studio will immediately overwrite the new caption with its default one in most cases; that's a different problem. 8-)
RichieHindle
Okay, 1) it is a macro and not an add-in. 2) Relevant only so I eliminate that fact. 3) Reproducible. 4) You are using SetWindowText because DTE.MainWindow.Caption is not working. 5) The double event does not happen in all cases, such as moving between Output and Code windows. 6) If you set a breakpoint in the activate event, the double activation does not occur. 7) Have you tried this in an add-in?
AMissico
@AMissico: First let me apologise for not accepting your answer, and hence inadvertently denying you the bounty on this question. This was due to my reading and believing erroneous information in the SO FAQ. I've raised a bug report about it here: http://meta.stackoverflow.com/questions/20094/bounty-rules-please-fix-the-faq If there were some way I could award you the bounty after the fact, I would, but I suspect there isn't. I can only apologise.
RichieHindle
I haven't tried it in an add-in, no. That's a good suggestion - if it is a problem with different processes getting the focus, doing it in an addin ought to cure it. I'll give that a try (but I won't be able to do so until next week).
RichieHindle
Not really interested in "bounty". It is more for amusement. I mean...I turned down the Microsoft offer to be one of the first MVP when the started the program, all those years ago. :O) Besides, it would ruin my "reputation" graph.
AMissico
@AMissico: OK, that's good to hear. More good news: it all works perfectly from an add-in. Many thanks! (Now if only I could Accept your answer I would, but thanks again to the bizarre bounty system, I can't.)
RichieHindle
I figured an add-in would work because setting a breakpoint worked. You are welcome and good luck.
AMissico
Have you tried PostMessage, instead of SendMessage?
AMissico
Good suggestion, but PostMessage still causes the problem. I'm happy to use an addin.
RichieHindle