Welcome to MSDN Blogs Sign in | Join | Help

Tony Schreiner's WebLog

Developer - IE | Vista. Fighting complexity for 9 years and counting.

Syndication

Don't Change System Settings to Perform a Computation

A post from Raymond Chen today reminds me of the first application compatibility issue I debugged (and fixed). At the time I was working on the MSN client and our team was on loan to load balance compatibility bugs for the release of Windows XP.

This application (which will remain nameless) had an alarm clock feature and the problem was that when you set the alarm on XP it would hang. After of slogging through retail assembly code for a while I finally found that whenever you set an alarm they would use SetTimeZoneInformation to temporarily change the system's time zone as part of an internal calculation, and then call it again to change it back. From the user's point of view it was fast enough that you never noticed.

That by itself wouldn't cause a hang. What caused the hang is that they also handled the WM_TIMECHANGE message, ostensibly to update the alarm if there was a system time or time zone change. While handling this message they called SetTimeZoneInformation to do their computation, which on XP caused the WM_TIMECHANGE notification to be sent again, leading to an asynchronous infinite loop.

The fix was to add a shim as part of the application compatibility functionality in Windows (from XP on, I believe), which provides a way to implement per-application compatibility workarounds without polluting the core Windows code base. The shim simply detected that a WM_TIMECHANGE was triggered by a call to SetTimeZoneInformation for this application and blocked the subsequent WM_TIMECHANGE notification.

Posted Wednesday, October 17, 2007 8:52 PM by tonyschr | 1 Comments

HD View - Gigapixel Images and More

Yesterday I stumbled across HD View which utilizes the very interesting new HD Photo format plus many other technologies to demonstrate how massive multi-GigaPixel images can be created and hosted on the web. It's a nice viewer reminiscent of Microsoft's 3D Virtual Earth and Google Earth -- the native code versions, not the web view -- but for generic large images.

The sample on the site is a 4+ GigaPixel image of Squamish Wall in Canada. According to the site this image was made using 800 images from a Canon 1DS Mark II, with a 100-400mm lens. The linked images such as this 360-degree panoramic view of Yosemite are also very impressive. If you have a fast machine notice how smoothly it adjusts the perspective in real-time as you go from being totally immersed in the 360-degree view to zooming out all the way.

But best of all, you can create your own! As an experiment I took a (very) random image from a visit to Rosarito, Mexico earlier this year and ran the hdmake.exe tool on it. It's not a GigaPixel panoramic so it's not as much fun, but even for normal photos I like the potential for sites such as Flickr: rather than clicking through several thumbnails of ever-increasing sizes until you get something that fills the monitor or you can see the detail, do it dynamically. Click here to see the image. Note that you'll need to accept the ActiveX control for HD View.

For some reason I couldn't get the tool to generate the XML (the errors aren't very descriptive), but it was easy enough to author manually:

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <imageset
    url="tiles/l_{l}/c_{c}/tile_{r}.wdp"
    levels="5"
    width="3456"
    height="2304"
    projection="perspective"
    thetaMin="0"
    thetaMax="0"
    phiMin="0"
    phiMax="0"
    rollPitchYaw="0 0 0"
    maxZoom="2"
  />
</root>

Now to go make some panoramas! :-)

Posted Monday, March 19, 2007 8:30 PM by tonyschr | 0 Comments

IE Automation & Tabs

A comment to one of my other posts asked about how to launch IE and open several additional tabs.

IE7 does not support specifying multiple URLs on the command line, but another way to do this is to use IE Automation to launch IE as an out-of-proc COM server and then call methods such as IWebBrowser2::Navigate2. While you can do this using C++ or any language that supports COM, the easiest is to use Windows Scripting Host.

First, create a 'lanuchie.js' file using your favorite text editor, add the following, and save:

var navOpenInBackgroundTab = 0x1000;
var oIE = new ActiveXObject("InternetExplorer.Application");
oIE.Navigate2("http://blogs.msdn.com");
oIE.Navigate2("http://blogs.msdn.com/tonyschr", navOpenInBackgroundTab);
oIE.Navigate2("http://blogs.msdn.com/oldnewthing", navOpenInBackgroundTab);
oIE.Navigate2("http://blogs.msdn.com/ericlippert", navOpenInBackgroundTab);
oIE.Visible = true;

Now from the command line you can do:

wscript.exe launchie.js

to open IE, navigate the first tab, and then open three background tabs.

One caveat: due to some IE features such as Protected Mode you will sometimes observe that the links are opened in an existing IE window.

Posted Friday, January 19, 2007 10:51 AM by tonyschr | 5 Comments

Blogs

My coworker Jeff Davis posted about IE7 and the cyclical nature of blogging, especially for those of us working on things that haven't yet been publicly announced. It includes a great ship analogy, and having been on the "critical path" for most of IE7 development (and before that having endured all my Longhorn Alpha work being scrapped (not for technical reasons)) mentally I think I'm still out on shore leave to a bit of an extent. ;-)

I tend to blog in bursts, with the prerequisite that I have ideas and I'm not suffering from writer's block. These days I have a list of at least a dozen topics queued up -- not including a bunch of overdue in-depth posts about IE7's tabbed browsing architecture -- so I just need to get to it, I guess.

Since you asked, other great blogs you should read are Coding Horror, Eric.Weblog(), and Fabulous Adventures in Coding.

Posted Tuesday, January 09, 2007 8:21 PM by tonyschr | 2 Comments

Menu Flickering / Toggling Redux - Any Ideas?

In a previous post I talked about a subtle bug between IE7 and the Office Handwriting recognition service that we discovered too late into IE7 to ship a work-around for, but described how end-users can fix this on their own.

However, a couple users have noticed a similar problem that even affects IE6 and other applications, so I thought I'd throw the question out there to see if anybody else knows the answer:

"I have been having the exact same problem for the last week with IE6. Like Jan above I do not have the "Handwriting Recognition" or "On-Screen Standard Keyboard" options under the "Details" tab. But I think this is greater than an IE problem because I get the menu flickering on all drop-downs in Windows. I just upgraded to IE7 and the problem remains. I cannot use my browser anymore and will have to change if there is no real fix. Any other ideas??"

(emphasis mine)

Any ideas?

Posted Tuesday, January 09, 2007 7:57 PM by tonyschr | 1 Comments

Client-side Code vs. Web 2.0

As a developer who specializes in client-side applications, I can't help but be amused and somewhat puzzled by some of the types of web-based applications people come up with. A great example are web sites that help resize and crop digital photos. There are actually a bunch of them out there; a few that were recently mentioned on digg.com (one of my favorite sites lately) include http://www.resizr.com/ and http://resizr.lord-lance.com/.

They seem to be missing the point. How could it possibly be better to upload a 5-10 megapixel image to a site (which can take several minutes per image even on a very fast connection, as upload speed is usually constrained much more than download speed), have the server resize it, and then download the resized image be better than using a client-side application to resize the image almost instantly, and with full interaction and nearly instant undo? Also, how can these sites afford the bandwidth costs?

Is this a usability issue, or has the world simply gone mad? :-)

Posted Tuesday, January 02, 2007 9:31 PM by tonyschr | 3 Comments

*Bloop!* - Wow, pop-up ads still exist!

One thing that amused me as I mindlessly surfed the web while stuck in my parents house due to the snowstorm in Colorado was the number of sites that still attempt to show pop-up advertisements -- sites like cnn.com and weather.com, not just shady sites. I'm left wondering... did they not get the memo that not only are pop-ups annoying, but also every web browser released in the past several years blocks them (longer if you count extensions, since IE6 didn't until XP SP2 (which everybody should have by now)).

I'm probably weird in that I keep the speakers on my PC on mute most of the time, both at home and work, but I had forgotten to mute the one on my laptop. *Bloop*...*Bloop*...*Bloop*.

Happy new year. :-)

Posted Monday, January 01, 2007 3:58 PM by tonyschr | 7 Comments

The Best Massively Multiplayer Real-time Online Game of All Time

Back in college, in 1996 (I believe) I frequently played the pre-release version of SubSpace, a massively multiplayer online game that was originally designed as a project to test the affects of lag over a modem. If I recall correctly, I first played using a 14.4k baud modem... and it worked. Here's a recent screen shot, Christmas themed because it's that time of the year:

 

Fast forward ten years, and despite being a 10-year old 2D game, the original company abandoning it, and enthusiests re-writing the client from scratch (!), it still has a fairly strong following. Sure, the graphics have been surpassed by 3D engines long ago, but as a top-down 2D game, they look as good as you could expect given the format, and at 1600x1200 I have no complaints.

To add to that, the problem great thing about SubSpace Continuum is that it not only has high replay value, but the controls are also designed in such a way that you can play the game and chat without switching modes or doing anything awkward. I don't play very often and I barely chat at all anymore, but it's still an ingenious and very natural system. I'm considering suggesting that future meetings between groups within IE take place in private zones using Continuum so that I am in a better position to annialate those who disagree with me. ;-)

One amusing thing is that even though I've joined and re-joined using different names over the years (I play for a few months and stop for a couple years), I still recognize some players from back when I originally played ten years ago. And yes, they are the same people; it's not a coincidence.

My only regret is that I never purchased a copy of SubSpace (although I didn't pirate it either; I just didn't play during the period it required a retail copy). This is one great game, and the developers deserved to be compensated appropriately.

Edit: I suppose I should give a link so that people can download and play SubSpace/Continuum: http://www.subspacedownloads.com, since it's free afterall.

Edit2 (sorry): The reason I added "Real-time" to the title is that I don't want to compare this to Tradewars, Yankee Trader, or any of the old BBS games quite yet. :-)

Posted Monday, December 11, 2006 10:29 PM by tonyschr | 2 Comments

Interface Smuggling

While I'm on the subject of COM and extension compatibility, another issue that affected a small number of extensions in IE7 involved passing an interface to a worker thread without first marshalling the interface using CoMarshalInterface() (or the longer and more convenient form, CoMarshalInterThreadInterfaceInStream()).

IE uses the uses the Single Threaded Apartment (STA) model for its UI threads, which in normal scenarios works like the following:

  • If you're on the same thread, calling a method on a COM object is the same as calling directly into the object through the vtable like an ordinary C++ class.
  • If you're on a different thread, all calls need to be marshaled back to the original thread (via. window messages) so that it's impossible for multiple threads to call into the object at the same time, and all calls originate from the same thread the object was instantiated on (i.e. some objects may use TLS).

If you create a worker thread and hand it a direct pointer to the object, it appears to work at first because it's all just memory; COM does not actively enforce its rules. However this breaks down quickly for a couple of reasons. Most obviously, STA objects are not designed to be thread safe. Passing a direct pointer to the object to a worker thread violates this assumption and will cause subtle bugs, hangs, and crashes.

But that's not what broke extensions between IE6 and IE7. In IE6 (and previous versions), developers often lucked out on the thread safety risk, but IE's new multithreaded architecture resulted in some public API calls needing to go across threads within Internet Explorer. In this scenario, when the pointer to the interface was smuggled onto a worker thread and then IE attempted to make an internal call through an internal pointer that had been marshaled for the non-worker thread, the call would fail with an error such as RPC_E_WRONG_THREAD.

In one case we managed to work around the problem (it was in a very popular extension) by changing our implementation for that specific API to use global/shared memory instead of internally requiring a cross-thread COM call. This of course isn't sustainable and it's not something we can do most of the time. If you're an extension developer please keep in mind that you might still be lucking out, even in IE7, so check your implementation to see if you're using multiple threads, especially if you pass IWebBrowser2 or similar interfaces to the other threads, and that you're marshalling interfaces correctly.

 

Fine print: This applies to the STA model; details for other threading models may vary. Also, never use the dreaded main threading model in IE extensions. Ever. Actually, it's a good idea not to use it outside of IE extensions too, unless you like reentrancy. :-)

Posted Monday, December 11, 2006 8:51 PM by tonyschr | 1 Comments

Spy vs. Spy: Revenge of the Tooltip

On Friday I talked about some of the problems with unbalanced CoInitialize() and CoUninitialize() calls and how to debug an unbalanced CoUninitialize inside IE7. At the end I mentioned that using IInitializeSpy in an extension to "fix" an unbalanced init or uninit was a bad thing and to never do it. Here's one story that illustrates why.

In the late stages of IE7 beta testing a coworker found that IE7 on XP would sometimes hang when sending messages through Outlook Web Access. At first the problem was very difficult to reproduce, but eventually we caught it under a debugger and found out that an unbalanced CoInitialize() call was causing COM to do cleanup while holding the loader lock, leading to a deadlock (as described in Friday's post).

But how could this be? On XP IE7 still uses IInitilaizeSpy to force this into balance, and then does the final CoUninitialize() right at the end of the threadproc! It should be impossible for there to be an unbalanced init in this scenario.

After a lot of debugging we found that in scenarios where IE hung, there was an additional spy loaded in the process, and when IE would attempt its final uninit the spy would jump in and call CoInitialize() again. No matter how late or how many times IE called CoUninitialize(), it would always bump it back up and out of balance.

The component doing this was part of the alternative Input Method Editor (IME), which is used for things such as entering Japanese characters. It's not installed on an English XP build by default, which is one reason this was hard to track down. Years ago, to work-around an application compatibility issue, they decided to leverage IInitializeSpy to fix an unbalanced CoUninitialize().

After more investigation we found that the IME component called CoInitialize() from their spy if there were any other top-level windows still visible on that thread. IE closes its normal windows well before the end of the threadproc, but in the OWA scenario it turned out that if you hovered over the "Send" button until the tooltip showed, and then sent the message, that tooltip window would stick around until the end of the threadproc and cause the IME component to do the extra CoInitialize(), triggering the hang.

The brilliant counterplan we devised to combat their spy was to hide all windows on the thread before calling the final CoUninitialize(). This way the IME component stops hooking the windows and won't call CoInitialize() to force the thread out of balance.

Posted Monday, December 11, 2006 10:11 AM by tonyschr | 0 Comments

Space Shuttle Analogies

First, congratulations to everybody who contributed to the successful launch of the space shuttle Discovery this evening. I watched online via. NASA TV and it's been a long time since I've watched a "live" liftoff.

In some recent meetings people have been making analogies between the space shuttle and complex software such as Windows and Internet Explorer. Whenever this happens I can't help but think of Richard P. Feynman's observations about the Challenger accident. A detailed account is part of the book What Do You Care What Other People Think?, which, along with Surely You're Joking, Mr. Feynman!, I highly recommend reading.

The summary of his investigation is available online and definitely worth a read. An interesting excerpt:

    The usual way that such engines are designed (for military or civilian aircraft) may be called the component system, or bottom-up design. First it is necessary to thoroughly understand the properties and limitations of the materials to be used (for turbine blades, for example), and tests are begun in experimental rigs to determine those. With this knowledge larger component parts (such as bearings) are designed and tested individually. As deficiencies and design errors are noted they are corrected and verified with further testing. Since one tests only parts at a time these tests and modifications are not overly expensive. Finally one works up to the final design of the entire engine, to the necessary specifications. There is a good chance, by this time that the engine will generally succeed, or that any failures are easily isolated and analyzed because the failure modes, limitations of materials, etc., are so well understood. There is a very good chance that the modifications to the engine to get around the final difficulties are not very hard to make, for most of the serious problems have already been discovered and dealt with in the earlier, less expensive, stages of the process.

    The Space Shuttle Main Engine was handled in a different manner, top down, we might say. The engine was designed and put together all at once with relatively little detailed preliminary study of the material and components. Then when troubles are found in the bearings, turbine blades, coolant pipes, etc., it is more expensive and difficult to discover the causes and make changes. For example, cracks have been found in the turbine blades of the high pressure oxygen turbopump. Are they caused by flaws in the material, the effect of the oxygen atmosphere on the properties of the material, the thermal stresses of startup or shutdown, the vibration and stresses of steady running, or mainly at some resonance at certain speeds, etc.? How long can we run from crack initiation to crack failure, and how does this depend on power level? Using the completed engine as a test bed to resolve such questions is extremely expensive. One does not wish to lose an entire engine in order to find out where and how failure occurs. Yet, an accurate knowledge of this information is essential to acquire a confidence in the engine reliability in use. Without detailed understanding, confidence can not be attained.

    A further disadvantage of the top-down method is that, if an understanding of a fault is obtained, a simple fix, such as a new shape for the turbine housing, may be impossible to implement without a redesign of the entire engine.

Posted Saturday, December 09, 2006 6:15 PM by tonyschr | 3 Comments

My Toolbar or BHO is Causing IE7 on Vista to Crash on Close. Help!

During the development of IE7, one problem we discovered was that a small number of extensions have unbalanced CoInitialize() or CoUninitialize() calls. On IE6 they sometimes lucked out, but due to architectural changes in IE7 these would cause crashes, hangs, or erratic behavior.

Unbalanced CoInitialize() calls seem harmless enough at first glance. During shutdown COM will detect this and do the missing uninits. However, one problem is that on XP it does this while holding the loader lock! If the destruction of any of the objects triggers a cross-thread COM call (or a SendMessage), or any similar scenario where another piece of code needs to acquire the loader lock at this time, the application will deadlock.

Unbalanced CoUninitialize() calls lead to a different sort of problem: if code does too many of them it will cause COM to clean up the apartment on that thread early, and after that point all cross-thread COM calls involving that thread will fail. This usually leads to erratic behavior, as objects that need to talk to each other can no longer do so.

As a workaround, IE7 initially leveraged IInitializeSpy to detect both types of out-of-balance initializations, and fix them on the fly. After all, since we're the application and we know that COM needs to stay initialized for the entire duration of the thread, none of the inits or uninits in between really matter.

Unfortunately, life isn't that simple. It turned out that using IInitializeSpy in this way was slightly hacky and we had a couple issues with it causing conflicts with other behavior. In addition, using IInitializeSpy would perpetuate the problem for future versions because now developers (both internal and external) could be sloppy with the inits and uninits without obvious consequenses.

On XP the balancing is still done; for various reasons both are needed. However, on Vista both are turned off by default. For the unbalanced CoInitialize() calls COM no longer does cleanup while holding the loader lock. For the unbalanced CoUnitialize() calls we decided that crashing early to help developers detect the problem was preferable to subtle bugs and erratic behavior.

So, how do you debug this if it's happening to you? In this example I took the Hello World BHO sample and added a spurious CoUninitialize() call to the SetSite(NULL) implementation.

 

First, I recommend installing the Microsoft Debugging Tools. You can probably accomplish all of this through Visual Studio or some other debugger, but it's easier to talk through this way.

The next step is to launch IE under the debugger and set the symbols to Microsoft's public symbol server so you can see what's going on and, later, set breakpoints.

C:\Program Files\Internet Explorer>cdb iexplore.exe

. . .
0:000> .sympath SRV*c:\publicsymbols*
http://msdl.microsoft.com/download/symbols
Symbol search path is: SRV*c:\publicsymbols*http://msdl.microsoft.com/download/symbols
0:000> .reload

. . .

Now, run the scenario which triggers the crash on close, close IE. If this is the issue, you will see something like the following:

(1c18.1140): Unknown exception - code 800401fd (first chance)
(1c18.1140): Unknown exception - code 800401fd (first chance)
(1c18.1140): Unknown exception - code 800401fd (!!! second chance !!!)
eax=02d5f968 ebx=002bef74 ecx=00342208 edx=6efba36b esi=00342208 edi=00000000
eip=7709b09e esp=02d5f968 ebp=02d5f9b8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
kernel32!RaiseException+0x58:
7709b09e c9 leave
0:004> .lastevent
Last event: 1c18.1140: Unknown exception - code 800401fd (!!! second chance !!!)
debugger time: Fri Dec 8 16:48:47.924 2006 (GMT-8)
0:004> !error 800401fd
Error code: (HRESULT) 0x800401fd (2147746301) - Object is not connected to server
0:004> k
ChildEBP RetAddr
02d5f9b8 6f0acad0 kernel32!RaiseException+0x58
02d5f9d0 6eff15c3 IEFRAME!CShellBrowser2::_CrashOnTabToFrameCommunicationSevered+0x14
02d5f9f0 6efb98d4 IEFRAME!CShellBrowser2::_DoFinalCleanup+0x15e
02d5fa10 6efb9ad9 IEFRAME!CShellBrowser2::_OnConfirmedClose+0xad
02d5fa24 6efb9a12 IEFRAME!CShellBrowser2::OnClose+0x109
02d5fa8c 770c3833 IEFRAME!CTabWindow::_TabWindowThreadProc+0x1ec
02d5fa98 7787a9bd kernel32!BaseThreadInitThunk+0xe
02d5fad8 00000000 ntdll!_RtlUserThreadStart+0x23

IE forces a crash in this scenario by raising a non-continuable exception with the HRESULT of the error code returned when a cross-thread COM call unexpectedly failed. The stack, conveniently readable due to public symbols, makes it even more obvious what's going on.

Now that we have confirmed this is indeed the cause of the crash, the next step is to restart IE and put a breakpoint in COM to see what call is causing the apartment to get torn down early. We do this by setting a breakpoint on ole32!ApartmentUninitialize and re-running the scenario:

0:000> .sympath SRV*c:\publicsymbols*http://msdl.microsoft.com/download/symbols
Symbol search path is: SRV*c:\publicsymbols*http://msdl.microsoft.com/download/symbols
0:000> .reload

. . .

0:000> bp ole32!ApartmentUninitialize
0:000> g

. . .
Breakpoint 0 hit
eax=004e4620 ebx=7706064c ecx=00000000 edx=00000000 esi=02b1f994 edi=00000000
eip=76f8a5bc esp=02b1f968 ebp=02b1f97c iopl=0 nv up ei ng nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000282
ole32!ApartmentUninitialize:
76f8a5bc 8bff mov edi,edi
0:004> k
ChildEBP RetAddr
02b1f964 76f8ad7e ole32!ApartmentUninitialize
02b1f97c 76f89d98 ole32!wCoUninitialize+0x88
02b1f998 77963951 ole32!CoUninitialize+0x71
02b1f9a4 779648d9 IMM32!CtfImmCoUninitialize+0x34
02b1f9ac 76f77f25 IMM32!ISPY_PostUninitialize+0x51
02b1f9c8 76f89c3b ole32!NotifyInitializeSpies+0x6a
*** WARNING: Unable to verify checksum for c:\Proj\TestBho1\TestBho1\Debug\TestBho1.dll
02b1f9ec 02c32b59 ole32!CoUninitialize+0x98
02b1facc 6efce448 TestBho1!CHelloWorldBHO::SetSite+0xb9
02b1faec 6efdebe2 IEFRAME!IUnknown_SetSite+0x33

02b1fb00 6efa790c IEFRAME!CIEFrameAutoProp::_VariantClear+0x26
02b1fb08 6efa78e9 IEFRAME!CIEFrameAutoProp::~CIEFrameAutoProp+0xa
02b1fb14 6efa78cb IEFRAME!CIEFrameAutoProp::`scalar deleting destructor'+0xd
02b1fb20 6efce5ac IEFRAME!CIEFrameAuto::_ClearPropertyList+0x19
02b1fb48 6efcfbf2 IEFRAME!CIEFrameAuto::SetOwner+0x184
02b1fb64 6efbdc22 IEFRAME!CBaseBrowser2::OnDestroy+0x88
02b1fb70 6efbdc41 IEFRAME!CCommonBrowser::OnDestroy+0x21
02b1fb80 6efcfb61 IEFRAME!CShellBrowser2::OnDestroy+0xf
02b1fb98 6efac10c IEFRAME!CBaseBrowser2::WndProcBS+0xb8
02b1fbb4 6efaba1d IEFRAME!CCommonBrowser::WndProcBS+0x2a
02b1fc1c 6efbac5c IEFRAME!CShellBrowser2::WndProcBS+0x18f

Ah ha! From the stack we can see that our test BHO with the bogus call to CoUninitialize() in the SetSite() implementation triggered the apartment to get torn down.

Now, it isn't always this easy. If this doesn't lead you to the problem I recommend doing some code inspection around places where your extension (knowingly) calls CoInitialize() and CoUninitialize(), and see if there are any edge cases where they could get out of balance.

If that’s not sufficient, or you have to do explicit matching to understand the root cause, you can put breakpoints on both the init and unint in the debugger, run through the simplest scenario that causes the crash, and then analyze the debug output. I usually set the following breakpoints:

bp ole32!CoInitializeEx “~.;k;g”
bp ole32!CoUninitialize “~.;k;g”

at the initial breakpoint, and let it go until the exception is hit. These will trace all of the calls. Then, in a text editor you can chop out all the calls from threads not on the thread that crashed and start matching them up. (Most of the calls will be obvious noise.) Make sure you either log to a file or have a large buffer.

To close, I want to call out that your extension should never, ever attempt to implement IInitializeSpy to compensate for an unbalanced init or uninit. First, you don't own the threadproc, and second it leads to nothing but trouble. In a future post I'll talk about an example. :-)

Posted Friday, December 08, 2006 5:42 PM by tonyschr | 7 Comments

IE7 Tabbed Browsing Q & A

I'm working on some long-overdue posts about tabbed browsing, but before I get too deep into them what I'd like to know most is: what do you want to know about IE7's tabbed browsing implementation?

If you have questions, please post them as comments. For the smaller questions I may reply as a comment, but the bigger questions will be answered as future blog posts. In the end I plan to wrap everything up in a "FAQ" for future reference.

Please keep in mind that I have to use a certain amount of discretion in answering the questions, and I can't really talk about future releases, but I'll do the best I can.

My expertise is mainly in the underlying architecture/implementation, but if you have UI-specific questions I'll ask my colleague if I don't know the answers.

Finally, if there are things you'd like to see in future versions, feel free to comment on those too.

Posted Wednesday, December 06, 2006 11:27 PM by tonyschr | 34 Comments

IE7 Menu Flickering / Toggling Glitch

Just before we shipped IE7 we heard sporadic reports of a "Heisenbug" where users would click a tab or click in the address bar, and the IE window would start shaking (or "flickering", or "menus bouncing up and down", depending on how users described it). We researched the bug and contacted some end users, but it remained a mystery until an employee on another team reported the issue and we were able to do some local debugging.

To make a long story short, it turned out to be a issues between IE7's multi-threaded design, the auto-hide menus, and an optional "Office Handwriting" component which provides an on-screen keyboard that doesn't get installed with the default settings. When the user clicks a tab (or performs certain other UI operations) the on-screen keyboard would detect that a UI thread is losing focus and uses SendInput() to synthesize the Alt-Up keystroke (along with several others). Alt-Up is the signal in IE to give focus to the menus, auto-expanding them if needed. This new focus change would then be detected by the on-screen keyboard, resulting in it sending another Alt-Up keystroke which, under the right circumstances, causes the cycle to repeat until the user clicks outside the IE window.

My understanding is that this component isn't widely used anymore (it's not the same on-screen keyboard that Tablet PC uses), and of the people I've been in contact with who reported this problem, none of them were actually using the functionality it provides. Fortunately it's easy to disable. From the IE7 Release Notes:

To work around this problem, disable the On-Screen Keyboard component of the Handwriting Recognition Service:

  1. Click Start, and then click Control Panel.
  2. Click Regional and Language Options.
  3. Click the Languages tab.
  4. Click the Details button.
  5. Under Handwriting Recognition select On-Screen Standard Keyboard.
  6. Click Remove.
  7. Under Handwriting Recognition select On-Screen Symbol Keyboard.
  8. Click Remove.
  9. Click OK twice to save and exit changes.
  10. Restart Internet Explorer 7.

(BTW: I'm not really blaming the on-screen keyboard for having this behavior; it's just an unexpected interaction. Coincidenally, years ago I wrote a piece of software similar to Synergy/Multiplicity which does a similar thing to prevent keys from getting "stuck" down if you had a key pressed while moving the mouse between machines. But it didn't break IE7. ;-) )

Posted Wednesday, December 06, 2006 10:52 PM by tonyschr | 12 Comments

Bringing the Menus to the Top in IE7

In the IE7 Beta 2 Preview the UI element that hosts menus and 3rd party toolbars is located between the navigation bar and tabs. However, in this release there's a registry key which you can set to move this to the top of the window instead:

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Toolbar\WebBrowser]
"ITBar7Position"=dword:00000001

You can also turn off the menu auto-hide functionality by checking Tools -> Toolbars -> Classic Menus from the Command Bar.

Disclaimer: This is not an official feature at this time and may not be available in the future.

One minor request: If you think you want to use this key please try it both ways with your toolbars and menus configured how you like them, especially if you use the Links bar and 3rd party toolbars. Also, yes I'm very aware that some people who previously did heavy toolbar customization in IE6 have concerns about the customizability of IE7. I hope this will help a bit, but if you just came here to flame please make it constructive. That will maximize your chances of getting heard. Ok, that's two requests. :-)

Posted Tuesday, January 31, 2006 8:14 PM by tonyschr | 19 Comments

More Posts Next page »
Page view tracker