Thursday, December 27, 2007

why doesn't the favicon for my site appear in IE7?

This is a re-posting of a post originally published on 2007-03-01. The original can be found here. This version has been updated to match what is currently reality.

When I was at Microsoft, I was the developer tasked with fixing the Favicon story for IE7. The original IE6 behavior was to download the favicon once--when a user made a site a Favorite. I do not want to go too deep into the details of how this craziness works, but the key piece of information to understanding why it seemed so broken is this: a mapping between the url of the site the url for the site's Favicon would be stored in IE's History database and the actually bits of the icon would be stored in the temporary Internet files folder. Thus, if you cleared your history or your cache, or the item expired out of either one, the icon would be gone forever.

Fast-forward to IE7. It has been over two (three?) years since IE6 shipped. We want to implement tabbed browsing, and we want the tabs to display the correct Favicons. So I updated the Favicon code to always download the icon on a first visit. The code also remembers if there is no Favicon (404) or it was invalid in some way (ExtractIcon() failed).

Here is a Mini-Faq (with one bonus question at the end) that I wrote while I was at Microsoft:

Q: How do I make a favicon appear for my site in IE7?
A: There are two ways. The first is to put a file in the root of your domain called favicon.ico. The second is to use a <link> tag with the rel="shortcut icon" value and the href value set to the URL for the Icon you wish to display.

Q: How often does IE download the favicon?
A: IE will download the icon when a user first visits the site. The icon is stored in the Temporary Internet Files folder on the client machine. Additional metadata about the favicon is stored in the user's Url History database. If either store is cleared, or items relating to the favicon have naturally expired, then the icon will be downloaded again on the next visit. If more than one page (or site) shares the same favicon, it is only downloaded once. IE takes great pains to download the icon as few times as possible to reduce load on the server.

Q: I see the wrong favicon for some sites I visit. How do I fix this?
A: If the history database has become corrupted in some way, this can happen. The simplest solution is just to use Delete Browsing History (on the Tools menu) to clear the cache and the history store.

Q: I put a favicon.ico on my site as you described, but it still doesn't appear.
A: It must actually be a .ico (an Icon) file. Bitmaps, pngs, gifs, etc, will not work. IE7 will download your favicon to the Temporary Internet Files folder and call ExtractIcon() on the file. If this fails, we will show the default icon instead of your favicon.

Q: I verified that my favicon really is an icon, but it still doesn't appear.
A: Since IE loads your icon out of the Temporary Internet Files folder, it must be able to actually store it there. If you are setting the no-cache directive for the icon file, then IE will not be able to display your icon and will display the default icon instead. You can use Fiddler to verify.

Q: How do I create a different favicon for every page on my site?
A: Put a different tag on each page, pointing to a different icon.

Q: I changed my site's favicon to a different icon, but the old one still shows in IE. How do I force IE to update?
A: If you just put the favicon.ico file in the root of your domain, IE doesn't have any way of knowing if it changed. To force an update, you need to use a tag and point to a different filename than you previously used. The current filename is compared against the known filename stored in the Url History database. When IE sees the filename has changed, it will download your new icon. Alternatively, you can ask your users to clear their history and cache (Tools->Internet Options->Delete Browsing History), which will also force IE to download the new file.

Q: What is still broken?
A: Two things: (1) If you specify an alternate location via <link> tag, the href member must be fully-qualified and does not respect the <base> tag. (2) The <link> tag must have "shortcut icon" as the rel value, but this is in violation of the W3C spec that says whitespace in the rel tag denotes a list of values. IE treats "shortcut icon" as a single value. Luckily this still works for other browsers who see "shortcut" and ignore it and only pay attention to the "icon" string.

That should cover most of the questions I've received about favicons in IE7. If you have more questions, feel free to ask.

Wednesday, December 5, 2007

the importance of context: security and the dom

This is a re-posting of a post originally published on 2004-07-22. The original can be found here. This version has been updated to match what is currently reality.

Almost every navigation in Internet Explorer results in a flurry of security checks. Many of these checks are fairly obvious things, such as checking the URL of the current location (the context URL) and the pending navigation's destination URL to see if their zones, domains, protocols, etc are the same, different, acceptable, etc. When I worked on Internet Explorer, I spent a significant amount of time debugging strange combinations and ways of navigating. I will not bore you with the details; my goal is to emphasize the importance of context. I will mainly speak to the Internet Explorer Pop-up Blocker's dependence on the context URL.

The Pop-up Blocker is dependent on the context URL. When the page attempts to open a new window, the HTML rendering engine queries the Pop-up Blocker. The Pop-up Blocker looks in the white list to see if this page is exempt from new window management. If, for some reason, the context URL provided is NULL, then obviously it cannot be matched to a domain in the white list.

So let us examine the following:
var oSpan = document.createElement("span");
oSpan.innerHTML =
"<a href="http://www.blogger.com/" target="'_blank'">Microsoft.com</a>";

When the anchor causes the browser to navigate, it will see the _blank and attempt to open a new window. This attempt will have to be verified by Pop-up Blocker. But the span is not parented to anything, thus it has no context. Elements with no context get the default context, which is about:blank, which confers no rights.

The moral of this story is always remember to parent your dynamically created elements to something in the document:

document.appendChild(oSpan);


It's been pointed out that the W3C specification says something about what should happen here and that IE does something wrong (or fails to do something). That may be the case. I was not responsible for the code the implemented the DOM.

Furthermore, adding about:blank to your white list doesn't work either, since it has no domain and the whitelist requires domains.

Tuesday, December 4, 2007

how to cleanly start and stop explorer.exe

This is a re-posting of a post originally published on 2004-07-22. The original can be found here. This version has been updated to match what is currently reality.

When you are developing Shell Extensions, sometimes you want to be able to cleanly start a new instance of explorer.exe without picking up all the environment variables of whatever command window you've got running (since environment is inherited). Similarly, you may want to shut down explorer.exe cleanly so that it releases its references on your dll--generally so that you can swap in a new version.

Cleanly Starting Explorer

The trick is to hold down CTRL while you select New Task. This will automagically launch an new instance of Explorer.

CTRL+SHIFT+ESC->File->CTRL+New Task (Run...)

Cleanly Shutting Down Explorer on Windows XP

The way to tell Explorer to shut down is to say you want to shutdown the machine, but then cancel in a special way:

Start->Shutdown->CTRL+ALT+SHIFT+Cancel

Cleanly Shutting Down Explorer on Windows Vista

During development of Windows Vista, they changed the way shutdown worked. They got rid of the shutdown dialog and replaced it with better options on the Start menu. Thus the way to cleanly shutdown Explorer had to change. Now you do some magic right on the start menu itself.

Start->CTRL+SHIFT+Right Click [on some empty space]->Exit Explorer

When you CTRL+SHIFT+Right Click on the empty space, a context menu appears with a clearly labeled option for shutting down explorer.exe.

Sunday, December 2, 2007

the internet explorer pop-up manager and your webbrowser control host

This is a re-posting of a post originally published on 2004-01-26. The original can be found here. This version has been updated to match what is currently reality.

Overview
With the introduction of Windows XP Service Pack 2, Internet Explorer 6 (and up) introduced a built-in pop-up window manager. If your program is going to host the webbrowser control, you may or may not want the pop-up blocker's functionality. This post will describe how to alter, override or enable the pop-up blocker's functionality for application.

Implement INewWindowManager
The basic Implement INewWindowManager. The webbrowser control will QueryInterface its site for this method. You should implement this in the same place you (would) implement IDocHostUIHandler.

When webbrowser control detects a new window is being requested, it will call the EvaluateNewWindow() method on the interface. Just about any method for opening a new window should trigger this call. What follows is boiler-plate for various scenarios:

I Do Not Want Any Pop-up Management
This is the easy case, since pop-up management is opt-in. Simply do nothing. The webbrowser control will query you for INWM. If the query fails, no pop-up management will occur. This decision was made so that applications that already exist would not have to change when Windows XP Service Pack 2 shipped.

I Want Exactly What Internet Explorer Does
This is easy too. Simply implement INWM::ENW() and return E_NOTIMPL. You will get all the same functionality, including checking against the user's white list and action according to the user's preferences.

CMyObject::EvaluateNewWindow(...)
{
return E_NOTIMPL;
}
When the webbrowser control sees the failure code, it will fall back to the default pop-up management.

I Want My Own Logic
Implement INWM::ENW() and use the parameters to decide whether or not to block the new window. Return S_FALSE to block the window and S_OK to allow it:

CMyObject::EvaluateNewWindow(...)
{
HRESULT hr = S_OK;
if (/* your logic here */)
{
hr = S_FALSE;
}
else if (/* more of your logic here */)
{
hr = S_FALSE;
}
// ... and so on ...

// Now update your UI.
switch(hr)
{
case S_OK:
OnPopupNotBlocked(...);
break;

case S_FALSE:
OnPopupBlocked(...);
break;
}

return hr;
}
Developer's Note
I will admit right now, this is the first public interface I ever designed. I was young and stupid and the Interface was not subject to a lot of review by people with more expertise. If I was doing it all over again, I would probably not have done it this way. But it works.