If the user invokes a command by typing an accelerator key or selecting a menu item, Windows calls IContextMenu::InvokeCommand. CBandObj does the same MFC routing as for initializing the menu, so the command magically arrives at your ON_COMMAND handlers in the usual way.
When the user closes your band, Windows calls IDockingWindow::CloseDW. CBandObj sends a WM_CLOSE and—poof—your window is gone. But the CBandObj object lives on until Windows releases it. It's all very straightforward and logical—if you use TRACE!
Band Object Bugaboos
What I've just described is the vanilla operation of a basic band object. But in the real world, nothing ever works quite the way it's supposed to, so it's time to let you know the things Mama didn't tell you.
The docs say a desk band needs IPersistStream to save any persistent data. What data? My trace diagnostics reveal that, in the case of desk bands, Explorer doesn't even query for IPersistStream, though it does query for IPersistStreamInit. So what's IPersistStream for? A comment buried in some Microsoft sample code explains the deal: IPersistStream is required to let the user drag the desk band off the task bar, as in Figure 2. If you don't want or need this feature, you don't have to implement IPersistStream.
TRACE also reveals that Windows queries for IOleCommandTarget and IDiscardableBrowserProperty. The latter is an interface I can really love; it has no functions! How can an interface have no functions? IDiscardableBrowserProperty is just a way to tell Internet Explorer, "It's OK to toss my properties if you visit another page. They're expendable." For more information, see "Discardable Properties for Your Web Pages in Internet Explorer 4.0" in the MSDN™ Library.
Finally, TRACE again reveals that Windows queries for yet another interface, the secret interface {EA5F2D61-E008-11CF-99CB-00C04FD64497}. This ID doesn't appear in any document, source file or registry entry I can find. If you know what this interface does, please contact your local authorities.
When you first create your desk band, you may have trouble getting Windows to recognize it. For info and comm bands, all you have to do is restart Internet Explorer. The same is true for Explorer, the only trick there being you have to Ctrl-Alt-Del to kill it. But when I recently got a new machine with Windows 98 Second Edition installed, my desk band mysteriously stopped working. No matter how many times I registered the DLL and killed and rekilled Explorer, my band refused to appear. The same thing happened on Windows 2000.
After much fretting and frustration, and nearly throwing my brand-new $2700 18" liquid crystal monitor out the window, I called my trusty editor (this is where it helps to have connections). He relayed the problem to the friendly Redmondtonians, who promptly pointed me to Knowledge Base article Q214842, which explains the mystery. Windows 2000 (and apparently also Windows 98 Second Edition) keeps a category cache that it refreshes only "if it senses that an installation application is run or if the cache location in the registry is not present." Windows "senses" an installation. Is it psychic? The article goes on to explain two ways to make Explorer rebuild its category cache: install from a program named setup.exe or install.exe (psychic powers explained—is that hokey or what?) or delete the registry key HKEY_CLASSES_ROOT/Component Categories/ {00021492-0000-0000-C000-000000000046}/Enum, which is the cache. ({00021492...} is CATID_DeskBand.) I modified BandObj.rgs to always delete this key. Problem solved. But you still have to restart the shell to make Windows generate a new cache.
The next problem seemed like three problems, but they were all caused by the same bug. Whenever I tried to recompile my code, I got "Cannot open MyBands.dll for writing." Apparently Explorer keeps its band objects alive as long as it's running. Internet Explorer does the same thing: when the user hides and shows your band, Internet Explorer calls IDockingWindow::HideDW and ShowDW. Internet Explorer doesn't release the object until it quits. In the case of desk bands, this means you have to Ctrl-Alt-Del again with every build cycle. Annoying, but not a big deal.
When I tried to debug my desk band using the technique in the Visual C++® Knowledge Base article "HOWTO: Debug a Windows Shell Extension" (the Ctrl+Alt+Shift trick, then run the debugger with explorer.exe as the debug process), I couldn't because I always ended up with a lock on my DLL. This time you have to reboot—yuck! Fortunately, I hate debugging anyway. I much prefer TRACE. But the one or two times I resorted to debugging, I had to use a system-level debugger.
When I first implemented MyBands, it failed to remember which search engine the user had selected. That's because I was saving the state in my object's destructor—but the destructor was never called because, as I just told you, Windows doesn't destroy the object, it only closes the window. So I moved my save code to PostNcDestroy, which fixed the problem. But wait a minute. If the object is still alive even after the user closes it, there should be no need to save settings because they should still be there in memory, right?
All these little problems were caused by one big problem, revealed instantly by the TRACE output: every time you hide or show a desk band, Explorer creates a new band object. It never releases the old one! Let's see. If CMyDeskBand is 916 bytes, and I have 128MB of RAM, how many times do I have to hide or show before Windows runs out of memory? The Redmondtonians acknowledge their booboo and assure it'll soon be fixed.
While I'm on the subject of booboos, I told you at the outset there are three kinds of bands. Well, I lied. There's a fourth kind: tool bands. My head is spinning just trying to keep all the terminology straight. A tool band lives in the Internet Explorer rebar. The Radio in Internet Explorer 5.0 is an example of a tool band. (You didn't know Internet Explorer has a radio now? That's nothing; 6.0 may even have HDTV.)
Writing a tool band is easy. It's just an info/comm band with a special registration; add your band's class ID (GUID) as a string under HKEY_LOCAL_MACHINE/Software/ Microsoft/Internet Explorer/Toolbar. I modified BandObj.rgs to add this value, and called it ExplrBar.rgs. Then, I modified MyBands.rc to use it. |