为什么我的TB_INSERTBUTTON消息导致comctl32抛出?

 fedfedfv_249 发布于 2023-01-30 10:17

我正在尝试在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这个看起来像这样的callstack :

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

1 个回答
  • 它失败了,因为您发送的消息包含跨进程边界的指针.请注意您传递地址的事实:

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

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

    例如WM_SETTEXT,某些消息将由系统将其有效负载编组到另一个进程.但TB_INSERTBUTTON不属于那一类.其中一条规则TB_INSERTBUTTON是您传递的指针在拥有收件人窗口的进程中具有意义.

    您可以通过使用VirtualAlloc,WriteProcessMemory等来解决此问题,以便在该其他进程中分配和写入内存.

    请注意,要做到这一点,这是一项有点困难的任务.特别重要的是,这两个过程是否具有相同的位数.结构的布局在32位和64位之间不同.确保发送正确布局的最简单方法是使用与目标进程相同的位数编译进程.

    到目前为止,做这样的事情的最简单方法是进入目标进程.如果您要编写插件,则不必处理任何这些问题,也可以使用官方支持的API进行扩展.

    正如雷蒙德所说,你所尝试的是相当危险的,你会听从他的建议.

    2023-01-30 10:19 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有