为什么我的tb_insertbutton消息导致comctl32投掷
Why is my TB_INSERTBUTTON message causing comctl32 to throw?
我正在尝试将一个附加按钮添加到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
它正在失败,因为您发送了一条包含在过程边界上的指针的消息。请注意您通过地址的事实:
LRESULT insertButtonResult = SendMessage(hWndToolbar, TB_INSERTBUTTON, 0,
(LPARAM)&buttonToAdd);
该最终参数是您的流程地址地址空间中的一个地址。但是收件人是一个不同的过程,您通过的地址在另一个过程的地址空间中没有任何意义。
例如,WM_SETTEXT
的一些消息将其有效载荷通过系统编组为另一个过程。但是TB_INSERTBUTTON
不属于该类别。TB_INSERTBUTTON
的规则之一是,您通过的指针在拥有收件人窗口的过程中具有含义。
您可以使用VirtualAlloc
,WriteProcessMemory
等解决此问题,以在其他过程中分配并写入内存。
警告说,这是正确的任务。特别是这两个过程是否具有相同的位置非常重要。结构的布局在32和64位之间不同。确保您发送正确布局的最简单方法是以与目标过程相同的位置编译过程。
到目前为止,做类似此类操作的最简单方法是在目标过程中。如果您要编写插件,那么您就不必处理任何这些问题,也将能够使用正式支持的API进行扩展。
正如雷蒙德(Raymond)所说的那样,您正在尝试的是很危险,您会很好地了解他的建议。
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- 如何为模板化对象创建模板向量?VS正在投掷C3203
- 为什么这个程序对投掷不做任何事情?
- 在放松试验块期间,通过投掷破坏者而导致这种怪异的行为
- 如果make_shared/make_unique可以投掷bad_alloc,为什么不为它设置一个尝试捕捉块?
- Poco Websocket投掷错误的URL例外.为什么
- 删除QDOMNODE投掷
- 尝试,投掷,接住功能
- Cython投掷语法错误
- 地图清除投掷异常
- 将向量对象存储在共享指针投掷错误中
- C 可选与投掷
- 在给定表达式的情况下返回对类型的引用时出错:“cond ?*这个 : 投掷()'
- 向int64_t投掷双倍,而不会丢失信息
- 当用户提供空命令行值时,如何投掷错误
- 辩论者如何设法打破任何投掷
- 构造函数和高级异常投掷C
- 在功能中捕获并投掷语句
- C++ 编写一个程序,提示用户以数字形式输入一个人的出生日期(投掷/接球)
- 为什么我的tb_insertbutton消息导致comctl32投掷