10

I'm trying to add an additional button into a toolbar in Internet Explorer.

I assumed the implementation to be straight forward, and am currently using this code:

TBBUTTON buttonToAdd;
ZeroMemory( &buttonToAdd, sizeof( TBBUTTON ) );
buttonToAdd.iBitmap = 1;
buttonToAdd.idCommand = 1;
buttonToAdd.fsState = TBSTATE_ENABLED;
buttonToAdd.fsStyle = BTNS_BUTTON|BTNS_AUTOSIZE;

LRESULT insertButtonResult = SendMessage( hWndToolbar, TB_INSERTBUTTON, 0, (LPARAM)&buttonToAdd );

When the message is sent, Internet Explorer will crash 90% of the time (10% of the time, I get a somewhat broken button on the toolbar) with the following exception:

Unhandled exception at 0x000007FEFB97DDFA (comctl32.dll) in iexplore.exe: 0xC000041D: An unhandled exception was encountered during a user callback.

Given that the results aren't consistent, I assumed some sort of memory layout issue. So I tried to send TB_INSERTBUTTONA instead (my application defaults to TB_INSERTBUTTONW), but that has no effect on the issue.

I also tried both 32 and 64 builds of my application, both have the same result.

I took a look at the callstack of iexplore.exe, which looks like this:

comctl32.dll!CToolbar::TBInputStruct(struct _TBBUTTONDATA *,struct _TBBUTTON const *)   Unknown
comctl32.dll!CToolbar::TBInsertButtons(unsigned int,unsigned int,struct _TBBUTTON *,int)    Unknown
comctl32.dll!CToolbar::ToolbarWndProc(struct HWND__ *,unsigned int,unsigned __int64,__int64)    Unknown
comctl32.dll!CToolbar::s_ToolbarWndProc(struct HWND__ *,unsigned int,unsigned __int64,__int64)  Unknown
user32.dll!UserCallWinProcCheckWow()   Unknown
user32.dll!DispatchClientMessage() Unknown
user32.dll!__fnDWORD() Unknown
ntdll.dll!KiUserCallbackDispatcherContinue()   Unknown
user32.dll!NtUserPeekMessage() Unknown
user32.dll!PeekMessageW()  Unknown
...

I found that somewhat interesting, because I'm assuming the method at the top copies data from my input structure into an internal structure and something goes wrong. But what's wrong with my input data structure?

The source code itself is available on GitHub at: https://github.com/oliversalzburg/ie-button

Community
  • 1
  • 1
Oliver Salzburg
  • 21,652
  • 20
  • 93
  • 138
  • Side note - This is part of an attempt to make a black-box Microsoft technology open so anyone can create IE extensions easily for free rather than have to use closed-source proprietary technologies. – Benjamin Gruenbaum Jan 31 '14 at 15:06
  • 6
    Note that IE may decide to change tool bar technology in the future, or it may change its window hierarchy so the toolbar is in a different place. (Both have happened in the past.) This code relies on undocumented behavior of IE, and you need to make it clear that your program relies on it so that your customers know what they are in for. – Raymond Chen Jan 31 '14 at 15:12
  • @RaymondChen you are of course correct. This is for an open technology effort in the other question in SE, we figure it out one IE version at a time (IE9-IE11 can be a really good start). The fact it's so hard for people to develop extensions that run on IE is astonishing. – Benjamin Gruenbaum Jan 31 '14 at 15:13
  • That you are intentionally writing code that is highly likely to break at every major revision of IE doesn't help matters. Anybody who uses your library will have a significant chance of not working at the next major version of IE. I would think this counts as making it harder to write extensions for IE, not easier. (You have to rewrite your extension each time a new version of IE comes out.) IE already has a documented and supported extension model. Use it. – Raymond Chen Jan 31 '14 at 15:18
  • @RaymondChen of course. The ideal thing would be for IE to allow this, writing such a framework would indeed require an update for every version of IE (there is nothing to say that it'll even only be major ones afaik). The idea is to provide an alternative to closed source tools that already provide this functionality which is similar to what Chrome, Safari and Firefox allow. If we create a knowledge base of _how_ to do this developers could build this sort of thing themselves and adapt to different versions of IE. If you know how to do this within IE's extension model please say so! – Benjamin Gruenbaum Jan 31 '14 at 15:19
  • @BenjaminGruenbaum You seem to assert that IE does not have a documented extension model. Am I understanding you correctly. – David Heffernan Jan 31 '14 at 15:22
  • @DavidHeffernan No, IE has a model (which I've been unable to find a solid book or reference on) with Browser Helper Objects. I have just been unable to find _how_ to do this in IE. The closest thing I've found talked about IE3. Since you're well... David Heffernan if you could shed some light on the _right_ way to do [this](http://stackoverflow.com/questions/21364178/add-browser-action-button-in-internet-explorer-bho) we would be very very very very grateful. It's being done today by frameworks like Crossrider . – Benjamin Gruenbaum Jan 31 '14 at 15:25
  • @RaymondChen Any help on the _right_ way to accomplish this would of course be very, very, very appreciated from you. – Benjamin Gruenbaum Jan 31 '14 at 15:30
  • @BenjaminGruenbaum I have no experience of IE extension but as I understand it, it is well-documented and capable – David Heffernan Jan 31 '14 at 16:20
  • @IInspectable: That was a reference to existing cross-browser extension development frameworks which provide the functionality that is being discussed here. – Oliver Salzburg Jan 31 '14 at 16:24
  • @IInspectable I've read through that - the rest of my BHO is pretty straightforward. I have been unable to find any information relating to the [this question](http://stackoverflow.com/questions/21364178/) which __seems__ pretty straightfoward. I have been unable to find that documented interface - if you know about anything about it, please _do_ go ahead and answer that question. I'm getting pretty tired of people telling me how 'simple' and well documented it is but not providing any solution or reference of how to accomplish or progress with it. – Benjamin Gruenbaum Jan 31 '14 at 16:25
  • The implementation is straight forward. Since you are somewhat unused to dealing with criticism I assume you made a copy of the link I posted earlier. It explains, among other things, how to create an Explorer Bar, and add buttons to it. Important detail here: This is **your** toolbar, and you are free to do with it as you please. You cannot safely hijack someone else's toolbar. For one thing, it fails the "what if someone else did this" test. – IInspectable Jan 31 '14 at 17:01
  • @IInspectable First of all - I'm not the one who flagged your other comment. Second, I've already _read_ the link you posted earlier - it does not explain how to accomplish anything like placing a button where frameworks like http://crossrider.com do (they've done it for example see http://crossrider.com/developer/demo). It doesn't have to be "_their_ toolbar" like you put it, I'm just trying to place the button next to it. I have a legitimate use case for this. – Benjamin Gruenbaum Jan 31 '14 at 18:46
  • [This tutorial explains how to add a toolbar button to the Windows Internet Explorer user interface](http://msdn.microsoft.com/en-us/library/aa753588(v=vs.85).aspx). – Raymond Chen Jan 31 '14 at 20:54
  • @RaymondChen Thank you, however - this is nothing like what Crossrider (and other various frameworks) do. Adding the button there is a useful way to interact with add-on users and several extension vendors do this. We can not find any way to do it. (That is, add a toolbar to the left of the Home screen and _not_ in toolbar that slices a chunk from the usable browser space the user has). If you could help us accomplish that by any chance I would be very grateful. If this is something Microsoft does _not_ want us to do and is a violation of some design vision or ToC _please_ let us know. – Benjamin Gruenbaum Jan 31 '14 at 21:14
  • That mini-toolbar is not part of the extensibility model as far as I'm aware. Any modifications to the mini-toolbar would be unsupported and may stop working at any time without warning. – Raymond Chen Feb 01 '14 at 07:04
  • @RaymondChen thank you, a 'no' answer is still much better than uncertainty. It's very frustrating (and third party closed frameworks get away with it) - but it is what it is. – Benjamin Gruenbaum Feb 01 '14 at 19:43

1 Answers1

7

It is failing because you are sending a message that contains a pointer across a process boundary. Note the fact that you pass an address:

LRESULT insertButtonResult = SendMessage(hWndToolbar, TB_INSERTBUTTON, 0, 
    (LPARAM)&buttonToAdd);

That final parameter is an address in your processes address space. But the recipient is a different process and the address you pass has no meaning in the address space of the other process.

Some messages, for instance WM_SETTEXT, will have their payloads marshalled to the other process by the system. But TB_INSERTBUTTON does not fall into that category. One of the rules of TB_INSERTBUTTON is that the pointer you pass has meaning in the process that owns the recipient window.

You can resolve this by using VirtualAlloc, WriteProcessMemory, etc. to allocate and write to memory in that other process.

Be warned that this is a somewhat difficult task to get right. In particular it matters greatly whether or not the two processes have the same bitness. The layout of the struct differs between 32 and 64 bit. The easiest way for you to make sure you send the right layout is to compile your process with the same bitness as the target process.

By far the easiest way to do something like this is to be inside the target process. If you were to write a plugin then you would not have to deal with any of these issues and would also be able to use officially supported APIs for extension.

As Raymond says, what you are attempting is rather dangerous and you would do well to heed his advice.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • The main issue with this is that IE allows extending it through BHOs (browser helper objects) that run on a separate process. Propitiatory frameworks accomplish this - but for the layman developer who wants to build an open source cross-browser extension, this is very hard to do. – Benjamin Gruenbaum Jan 31 '14 at 15:16
  • I hear you loud and clear. I'm not particularly fond of modifying an application UI in non-standard ways myself. But I thought this was a fun challenge. So, thanks :) – Oliver Salzburg Jan 31 '14 at 15:27
  • As Raymond says, what you are attempting is rather dangerous – Sergey Efimov Feb 21 '21 at 15:06