This has taken me many days of trial and error, but I've found solutions
(more or less) to my own questions.
If you don't want the explanation but just some working code,
I'll release a component in the near future (well, during the next
month), which allows you to add BHOs and toolbar buttons to IE.
I'll let you all know when it's done. Full src and demos will be
available.
As for the questions:
-------------------------------------------
> 1) I'd like my button to be a dropdown button (with menuitems),
> rather than a simple pushbutton.
This article describes how to do it:
http://msdn.microsoft.com/library/en-us/dhtmltechcol/cols/dnwebteam/w...
(see Magic Lantern section).
However, you have to modify the sample somewhat to make the
check/uncheck feature work. Here's the code I use in the Exec method,
after the various AppendMenu calls:
GetCursorPos(pt);
hWndToolbar := WindowFromPoint(pt);
// Get number of buttons on the toolbar this button belongs to
nButtonCount := SendMessage(hWndToolbar, TB_BUTTONCOUNT, 0, 0);
OldButtonStyle := SendMessage(hWndToolbar, TB_GETSTYLE, 0, 0);
// Find this button by finding which of the buttons is under the cursor
nTargetButton := -1;
ScreenToClient(hWndToolbar, pt);
for I := 0 to nButtonCount -1 do
begin
if SendMessage(hWndToolbar, TB_GETITEMRECT, I, Integer(@rect)) <> 0 then
if PtInRect(rect, pt) then
begin
nTargetButton := I;
Break;
end;
end;
if nTargetButton <> -1 then
begin
tbbi.idCommand := 1111; // Needs to have a unique value for various
TB_XXX messages to work
SendMessage(hWndToolbar, TB_SETCMDID, nTargetButton, tbbi.idCommand);
SendMessage(hWndToolbar, TB_SETSTYLE, 0, OldButtonStyle or
TBSTYLE_CHECKGROUP);
// Make the button appear pressed
SendMessage(hWndToolbar, TB_CHECKBUTTON, tbbi.idCommand, Integer(True));
end;
......
// Display and track the menu
......
if nTargetButton <> -1 then
begin
// Make the button appear not pressed
SendMessage(hWndToolbar, TB_CHECKBUTTON, tbbi.idCommand,
Integer(False));
SendMessage(hWndToolbar, TB_SETSTYLE, 0, OldButtonStyle);
end;
And here are the vars you'll need:
var
hWndToolbar: HWND;
tbbi: TBBUTTONINFO;
pt: TPoint;
rect: TRect;
nButtonCount, nTargetButton: Integer;
OldButtonStyle: Integer;
uses
Windows, CommCtrl;
Still, the button is not a real dropdown button - it doesn't have an
arrow, and it's too narrow. The solution to this would be to not use
IOleCommandTarget and instead simply make the BHO implement
IDispatch, then call TB_ADDBUTTONS and TB_ADDBITMAP
in the IDispatch.SetSite method. The problem with this approach is
you need the handle to the toolbar, which we so far have found
by using a hack.
I'll look more into this problem. I suppose it's possible to find
the toolbar handle somehow.
-------------------------------------------
> 2) I'd like to change the icon of the button. I don't mean the "hot"
> and "cold" icons, which depend on whether the mouse cursor hovers over the
> button. I mean I'd like to change the button icon when some other
> condition
> occurs, like a change in the current web page.
This is indeed possible. I tried many different approaches but found
only one way to make it work.
The hWndToolbar and idCommand parameters correspond to the
hWndToolbar and tbbi.idCommand vars from before.
procedure ChangeButtonImage(hWndToolbar: HWND; idCommand: Integer);
var
AddedBitmap, AddedHotBitmap: Integer;
hIml, hImlHot: HIMAGELIST;
hBmp, hBmpHot: HBITMAP;
begin
// Load bitmaps from resource file
hBmp := LoadBitmap(HInstance, PChar(1616));
hBmpHot := LoadBitmap(HInstance, PChar(16162));
// Get imagelists of toolbar
hIml := SendMessage(hWndToolbar, TB_GETIMAGELIST, 0, 0);
hImlHot := SendMessage(hWndToolbar, TB_GETHOTIMAGELIST, 0, 0);
// Cold icon
AddedBitmap := ImageList_Add(hIml, hBmp, 0);
SendMessage(hWndToolbar, TB_CHANGEBITMAP, idCommand,
MakeLParam(AddedBitmap, 0));
// Hot icon
AddedHotBitmap := ImageList_Add(hImlHot, hBmpHot, 0);
SendMessage(hWndToolbar, TB_CHANGEBITMAP, idCommand,
MakeLParam(AddedHotBitmap, 0));
// Clean up
DeleteObject(hBmp);
DeleteObject(hBmpHot);
end;
-------------------------------------------
That's all, folks.
Troels