IE 4.0 Shell Toolbar Extension mechanism

Overview:

IE 3.0 introduced the internet toolbar (or "coolbar") which is suitable for browsing, which is quite different from the Win95 shell's explorer toolbar. This two different toolbar was not a problem until we integrates the browser functionality into the explorer in IE 4.0. First, we tried it with two separate toolbars (from which the user can choose), but we've received many negative feedback against it from users. It became clear for us that we need to merge two toolbar into one. This document describes a proposed toolbar extension mechanism which allows us to have a single toolbar which is suitable for both with shell type folders (directories, my computer, control panel) and web pages.

Since we need to achieve this in a very short development time frame, it's very important to know exactly what are our goals:

Mechanism:

UI negotiation will be performed between a shell view (IShellView) and a shell browser (IShellBrowser). We introduce one new interface (IExplorerToolbar) to perform UI negotiation, one new service GUID (SID_SExplorerToolbar) to help finding the service, and use one existing interface (IOleCommandTarget from ActiveX document interfaces) to invoke commands.

  1. When a shell view is being UIActivated, it gets the IExplorerToolbar interface to the toolbar by calling IServiceProvider::QueryService with SID_SExplorerToobar.
  2. Then, when the shell browser gets created, it calls IExplorerToolbar::SetCommandTarget with the following parameters:
    SetCommandTarget(IUnknown* punkCmdTarget, const GUID* pguidButtonGroup, DWORD dwFlags);
    punkCmdTarget is the IOleCommandTarget interface to it's command target interface
    pguidButtonGroup is a unique GUID to identify the group of buttons
    dwFlags specifies which bands in the coolbar should be visible and how many lines of text the toolbar should have..
    Calling SetCommandTarget will establish a direct connection from the toolbar to the shell view (or its sub-component).
  3. Then, it calls IExplorerToolbar::AddButtons (typically) multiple times to add buttons to the toolbar. It specifies its command ID (to be passed to IOleCommandTarget along with pguidButtonGroup), glyphs (normal and highlighted) and button text (to be displayed right below the button). AddButton takes a GUID as an argument (the same GUID to be passed to SetCommandTarget), but it won't be used in this version -- it's for future enhancement.
  4. Above negotiation will give enough information for the toolbar to display those additional buttons. Those buttons will be enabled or disabled based on the return value from IOleCmdTarget::QueryStatus.
  5. When the user moves the mouse over to one of those buttons, the toolbar calls IOleCmdTarget::QueryStatus to get the tooltip text (which is longer than the button text).
  6. When the user clicks one of those buttons, the toolbar calls IOleCmdTarget::Exec. To make it easy to implement a pull-down menu effect, it passes the position of the button's left-bottom corner in screen coordinate.

 

Interface:

DECLARE_INTERFACE_(IExplorerToolbar, IUnknown)
{

// *** IExplorerToolbar methods ***
HRESULT SetCommandTarget(IUnknown* punkCmdTarget, const GUID* pguidCmdGrp, DWORD dwFlags);

// Std buttons are Stop, Home, Refresh, ...
HRESULT AddStdBrowserButtons();

HRESULT AddButtons(const GUID * pguidButtonGroup, UINT nButtons, LPTBBUTTON lpButtons);
HRESULT AddString(const GUID * pguidButtonGroup, HINSTANCE hInst, UINT uiResID, LRESULT * pOffset);
HRESULT GetButton(const GUID * pguidButtonGroup, UINT uiCommand, LPTBBUTTON lpButton);
HRESULT GetState(const GUID * pguidButtonGroup, UINT uiCommand, UINT * pfState);
HRESULT SetState(const GUID * pguidButtonGroup, UINT uiCommand, UINT fState);

// uiBMPType (BITMAP_NORMAL, BITMAP_HOT, BITMAP_DISABLED

// Offset of the glyphs in the toolbar are returned in pOffset.
HRESULT AddBitmap(const GUID * pguidButtonGroup, UINT uiBMPType, UINT uiCount, TBADDBITMAP * ptb,
LRESULT * pOffset, COLORREF rgbMask);

// The size of Glyphs Coolbar expects
HRESULT GetBitmapSize(UINT * uiID);

// Not supported

HRESULT SendToolbarMsg(GUID * pguidButtonGroup, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT * plRes);

};

Cook book for new clients:

  1. Call SetCommandTarget () to register the it's IOleCmdTarget and guidButtonGroup
  2. Call GetBitmapSize() to find out the size coolbar expects for the Bitmaps
  3. Call AddBitmaps giving HINST of the DLL and the resource ID or the Glyphs. This will return the Glyph offset
  4. Call AddStrings giving HINST of the DLL and the resource ID or the Strings. This will return the String offset
  5. AddButtons() specifying appropriate Glyph and String offsets
  6. Use GetButton(), GetState(), SetState() to manipulate the buttons
  7. Ensure that IOleCmdTarget::QueryStatus is supported. It will be called to get button states and tooltip strings
  8. Ensure that IOleCmdTarget::Exec is supported. It will be called when the user clicks on a button.