This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
|
Adding Internet Explorer Favorites to Your Application
Scott Roberts |
The Favorites menu is one of the most popular features of any browser. With the right code, you can access this list and enumerate the whole darned thing in your own program. |
It's hard to imagine surfing the Web
without accumulating a list of favorite
sites. Everyone has them. My favorite is
the Internet Client SDK support site, http://msdn.microsoft.com/workshop/essentials/inetsdk/inetsdk_map.asp. What would Web navigation be like if you couldn't save links to your favorite Web sites? If you have more than a few favorites, remembering and retyping all those long URL strings becomes a real chore.
That's where Microsoft® Internet Explorer 4.0 Favorites menu comes to the rescue. You undoubtedly know that the Favorites menu lets you save Web site addresses. You can even organize these favorites into separate folders so that they are easy to find. Then, when you want to navigate to a saved Web address, you just click on its shortcut from the Favorites menu. The Favorites menu also lets you update and organize your subscriptions. Obviously, this is the best thing since sliced bread. But what if you want to offer the same functionality in your applications? This is not a difficult task to accomplish, as I'll show you. If you've hosted the WebBrowser control in your applications, you've undoubtedly discovered that the Favorites menu is not offered through that component. The favorites features are implemented in shdocvw.dll (the home of the WebBrowser control), but the Favorites menu itself is implemented as part of the shell portion of the DLL, not the browser portion. (In Internet Explorer 4.0, the app is actually a shell that hosts the browser control inside it. Michael Heydt's article in this issue explains the WebBrowser control more fully.) The shell portion includes each and every part of the Favorites menu, from the Add to Favorites command to the actual favorites links. Shdocvw.dll implements a handful of COM interfacesIShellUIHelper, ISubscriptionMgr, and IShellLinkthat provide this functionality. Creating a Favorites menu similar to the one in Internet Explorer 4.0 is fairly straightforward. Among other things, shdocvw.dll provides interfaces whose methods provide the functionality of the Add to Favorites and Update Subscriptions menu items. Shdocvw.dll also exports two functions that give your app the functionality of the Add to Favorites and Organize Favorites commands. Implementing the equivalent of the Manage Subscriptions command is easy as well. Creating the menu items for the favorites themselves is a bit more complicated than you might expect. There is currently no interface that provides the favorites from which you can create the links portion of the menu. I'll explain how to implement those as well.
Add to Favorites
|
In addition to these options, you can change the name (as shown on the Favorites menu) under which the link will be stored. By default, Internet Explorer uses the page's title. This isn't always descriptive of the page's contents, so you may want to change this to something that makes it easy to find. Finally, you can choose a folder in which to store the favorite by pressing the Create In button. This button expands the Add Favorite dialog so you can choose an existing folder or create a new one.
So how can you invoke this dialog from your own application? There are two ways to do this. The first way to invoke the Add to Favorites menu item is by using the ShellUIHelper object. ShellUIHelper is implemented by the Windows® shell mainly to let developers using Visual Basic® access and script to some of the features available in the shell. Using this object to add a favorite from Visual Basic is very easy. Just set a reference to shdocvw.dll in your project, dim an object of type ShellUIHelper (using the New keyword to actually create the object), and call the object's AddFavorite method:
Dim suh as New ShellUIHelper
suh.AddFavorite "http://www.microsoft.com/mind", "MIND home"
If you want to use this object from Visual C++®, all you have to do is create an instance of ShellUIHelper and retrieve a pointer to IShellUIHelper. (The CLSID for ShellUIHelper and the IID for IShellUIHelper are defined in ExDisp.h, which comes with the Internet Client SDK.) Then call the AddFavorite method. Since this is the same call you'd make from Visual Basic, the method takes the same two input parameters: a string value that specifies the URL of the item to add to the Favorites folder, and an optional string value that represents the title of the item.
|
Note that DoAddToFavDlg takes a count of characters for the cchInitDir and cchFile parameters. To make this code work in a Unicode environment, I divide the size of the buffer by the size of one of its elements. This is done for any functions that take a count of characters as an input parameter.
Organize Favorites
|
Figure 4: Organize Favorites Dialog |
The Organize Favorites dialog is implemented in shdocvw.dll, which provides a DoOrganizeFavDlg exported function that you can call to invoke the dialog. DoOrganizeFavDlg takes two input parameters: a handle to the window that will own the dialog and a pointer to a string buffer that holds the location of the Favorites folder to be organized. Figure 5 shows code that invokes the Organize Favorites dialog from C++.
To use this function, you have to do the following:
Manage Subscriptions
|
Figure 6: Manage Subscriptions Dialog |
To implement the Manage Subscriptions functionality in your applications, you must do a couple of things. First, retrieve the location of the Subscriptions folder. Unfortunately, SHGetSpecialFolderPath does not currently support a Subscription folder flag and this location isn't kept anywhere in the registry, so you must retrieve this path yourself. For the purpose of this article, I'll assume that the Subscriptions folder is a subdirectory of the Windows directory. In future versions of Internet Explorer, this may not be the case.
The second step is to call ShellExecute to open the Subscriptions folder. The following MFC code shows how to implement the Manage Subscriptions menu item in your own application: |
|
Update All Subscriptions
|
Figure 7: Downloading Subscriptions |
Invoking the Downloading Subscriptions dialog in your application is easy. All you have to do is create an instance of the SubscriptionMgr object by calling CoCreateInstance with a CLSID of CLSID_SubscriptionMgr and ask for the ISubscriptionMgr interface. This CLSID is defined in the subsmgr.h header file that comes with the Internet Client SDK. This will return a pointer to the ISubscriptionMgr interface, from which you can call the UpdateAll method. That's it. The following code demonstrates how to invoke this dialog from an MFC-based application: |
|
Favorites
|
|
Second, you must retrieve a pointer to the desktop by using SHGetDesktopFolder: |
|
The desktop can be represented by an instance of the IShellFolder interface. A pointer to the desktop is needed so you can bind to the Favorites folder and iterate through it. Third, you must bind to the Favorites folder using the IShellFolder::BindToObject method. This method will return a pointer to an instance of the IShellFolder interface that represents the Favorites folder: |
|
Now that you have a pointer to a shell folder that represents the Favorites folder, you can start iterating through it and creating menu items for each
favorite that's stored there. Each time you encounter a new folder, you'll need to create a new submenu
on your own Favorites menu. Because this code
may be enumerating through subfolders below the Favorites folder and even through subfolders of
those subfolders, it's a good idea to recurse through these directories to create the Favorites menu. Since
this process is complex, I will only discuss the most important points. The complete code that demonstrates how to do this is contained in the IEFavMnu sample code. The first thing you must do when enumerating a special folder is call IShellFolder::EnumObjects. This method returns a pointer to an enumerator for item identifier lists. Since this is a standard enumerator object, you can simply call the Next method until it returns something other than NOERROR. Since it's an enumerator for an item identifier list, the Next method will return a PIDL representing the next item in the folder. After you retrieve a PIDL that represents a folder item, you must get the item's actual name with the IShellFolder::GetDisplayNameOf method. This method returns a STRRET structure that contains string values describing the item. The values contained in the STRRET structure depend on the value of the second parameter passed to GetDisplayNameOf. If you specify SHGDN_NORMAL, the STRRET structure will contain the display name of the item as it would be displayed on the menu or submenu. If you specify SHGDN_ FORPARSING, you'll get a name that can be resolved to the actual URL pointed to by the favorites item. You must store this URL in some data structure, such as an array, map, or linked list, so that your application can navigate to the correct URL when a favorite is chosen from the menu. All this may seem very confusing, but some code will help clarify things. Figure 8 contains the AddFavToMnu method that is part of the IEFavMnu sample. This code demonstrates how to enumerate the Favorites folder and add the items to the menu. If a folder is encountered, a new submenu is created. One thing to watch out for is channels, which look like folders when enumerated because they have the SFGAO_ FOLDER attribute. To avoid creating submenus for channels, check to see if the item's type name is Channel Shortcut. There are three different ways (hence three separate functions) to resolve a favorites item to its URL depending on whether the item is a Channel Shortcut, an Internet Shortcut, or a normal shell link. Since resolving an item involves a lot of code, I will not talk about it here. However, this code is included in the IEFavMnu sample. One thing I do in this code is check the szTypeName member of the SHFILEINFO structure to determine the type of the favorite. If you are worried about localization, you should check the extension of lpszFileName instead of checking szTypeName to determine the type of favorite you are processing. Internet shortcuts have a .url extension, while normal shell links have a .lnk (or possibly .pif) extension. Channel shortcuts have no extension at all. The code in Figure 8 builds the entire Favorites menu. This can potentially cause the startup time for your application to increase depending on the number of favorites you must process. Another drawback is that IEFavMnu recreates the Favorites menu each time a favorite is added or the favorites are organized. A more efficient way to create the Favorites menu is to create it popup by popup. In other words, create each popup menu only when it is needed. Since this article and the accompanying sample code just demonstrate how to create the Favorites menu, it is up to you to determine the most efficient method for your needs. |
Figure 9: The IEFavMnu Favorites Menu |
The IEFavMnu sample (shown in Figure 9) puts all these concepts to work. IEFavMnu is a basic MFC SDI application that hosts the WebBrowser control. It allows you to surf the Web just like Internet Explorer 4.x. (Well, sort of. Internet Explorer provides many more features.) As you can see from Figure 9, IEFavMnu has implemented every item on the Internet Explorer 4.0 Favorites menu.
Internet Explorer 5.0 Sneak Preview
|
Figure 10: New Organize Favorites Dialog |
The biggest proposed change is to the Organize Favorites dialog box (see Figure 10). In Internet Explorer 4.0 this is a standard Windows dialog box, but Internet Explorer 5.0 should sport an HTML-based dialog. The dialog should let you do the same things as its predecessor: move,
delete, and rename your favorites. It will also sort, import, export, and synchronize your favorites.
Subscriptions are expected to remain in Internet Explorer 5.0, but they will be known as offline content. Offline content is a more natural name for the feature, which is a means of downloading Web pages to view them offline. This is a big advantage if, for instance, you travel a lot and cannot be connected to the Internet at all times. One of the first things I noticed about the proposed Internet Explorer 5.0 Favorites menu was that the Manage Subscriptions and Update All Subscriptions menu items were renamed to Manage Offline Pages and Synchronize, respectively. Manage Offline Pages should work just like Manage Subscriptions. The Synchronize menu item should invoke a dialog like the one shown in Figure 11. This dialog displays all the items that you have selected for offline access. Using this dialog, you could set the download schedule for each of the items you specify. You could also specify different update options for different network connections. For instance, you could choose to synchronize offline pages when your computer is idle if you connect to the Internet through a LAN. Or you could choose to synchronize your pages at midnight if you connect to the Internet using a modem. |
Figure 11: New Synchronize Dialog |
Conclusion
By following the simple steps outlined here, you should be ready to upgrade your applications to include a Favorites menu similar to the one provided in Internet Explorer 4.0. Just a little knowledge of COM and C++ will go a long way. Plus, you've gotten a sneak preview of the planned Internet Explorer 5.0 Favorites menu. |
From the July 1998 issue of Microsoft Interactive Developer.