【问题标题】:Why is my TB_INSERTBUTTON message causing comctl32 to throw?为什么我的 TB_INSERTBUTTON 消息导致 comctl32 抛出?
【发布时间】:2014-01-31 15:05:29
【问题描述】:

我正在尝试add an additional button into a toolbar in Internet Explorer

我认为实现是直截了当的,目前正在使用此代码:

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 );

发送消息时,Internet Explorer 将在 90% 的情况下崩溃(10% 的情况下,工具栏上的按钮有点损坏),但以下情况除外:

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

鉴于结果不一致,我假设存在某种内存布局问题。所以我尝试改为发送TB_INSERTBUTTONA(我的应用程序默认为TB_INSERTBUTTONW),但这对问题没有影响。

我还尝试了我的应用程序的 32 和 64 版本,两者的结果相同。

我看了一下iexplore.exe的调用栈,长这样:

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
...

我发现这有点有趣,因为我假设顶部的方法将数据从我的输入结构复制到内部结构中并且出现了问题。但是我的输入数据结构有什么问题?

源代码本身可在 GitHub 上获取:https://github.com/oliversalzburg/ie-button

【问题讨论】:

  • 附注 - 这是尝试开放黑盒 Microsoft 技术的一部分,因此任何人都可以轻松地免费创建 IE 扩展,而不必使用闭源专有技术。
  • 请注意,IE 将来可能会决定更改工具栏技术,或者可能会更改其窗口层次结构,因此工具栏位于不同的位置。 (过去都发生过。)此代码依赖于 IE 的未记录行为,您需要明确说明您的程序依赖于它,以便您的客户知道他们在做什么。
  • @RaymondChen 你当然是对的。这是针对 SE 中另一个问题的开放技术努力,我们一次找出一个 IE 版本(IE9-IE11 可能是一个非常好的开始)。人们很难开发在 IE 上运行的扩展,这一事实令人震惊。
  • 您故意编写的代码很可能在 IE 的每个主要版本中都被破坏,这无济于事。任何使用你的库的人都有很大的机会不在 IE 的下一个主要版本上工作。我认为这会使为 IE 编写扩展变得更加困难,而不是更容易。 (每次发布新版本的 IE 时,您都必须重写您的扩展。) IE 已经有一个文档化且受支持的扩展模型。使用它。
  • @RaymondChen 当然。理想的情况是 IE 允许这样做,编写这样的框架确实需要对每个版本的 IE 进行更新(没有什么可以说它甚至只是主要版本 afaik)。这个想法是为已经提供此功能的封闭源工具提供替代方案,类似于 Chrome、Safari 和 Firefox 允许的功能。如果我们创建一个如何 的知识库,开发人员可以自己构建这类东西并适应不同版本的 IE。如果你知道如何在 IE 的扩展模型中做到这一点,请说出来!

标签: c++ winapi managed-c++


【解决方案1】:

失败是因为您发送的消息包含跨进程边界的指针。请注意您传递了一个地址这一事实:

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

最后一个参数是进程地址空间中的一个地址。但是收件人是不同的进程,你传递的地址在其他进程的地址空间中没有任何意义。

某些消息,例如WM_SETTEXT,将由系统将其有效负载编组到其他进程。但TB_INSERTBUTTON 不属于该类别。 TB_INSERTBUTTON 的规则之一是你传递的指针在拥有接收者窗口的进程中是有意义的。

您可以通过使用VirtualAllocWriteProcessMemory 等在其他进程中分配和写入内存来解决此问题。

请注意,要正确完成这项任务有些困难。特别是这两个进程是否具有相同的位数非常重要。结构的布局在 32 位和 64 位之间有所不同。确保发送正确布局的最简单方法是使用与目标进程相同的位数来编译进程。

到目前为止,执行此类操作的最简单方法是在目标进程中。如果您要编写一个插件,那么您将不必处理任何这些问题,并且还可以使用官方支持的 API 进行扩展。

正如雷蒙德所说,你的尝试相当危险,你最好听从他的建议。

【讨论】:

  • 主要问题是 IE 允许通过在单独进程上运行的 BHO(浏览器帮助对象)扩展它。支持性框架实现了这一点——但对于想要构建开源跨浏览器扩展的外行开发人员来说,这很难做到。
  • 我听到你的声音响亮而清晰。我自己并不是特别喜欢以非标准方式修改应用程序 UI。但我认为这是一个有趣的挑战。所以,谢谢:)
  • 正如雷蒙德所说,你正在尝试的是相当危险的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多