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

前端之家收集整理的这篇文章主要介绍了c – 为什么我的TB_INSERTBUTTON消息导致comctl32抛出?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我试着 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,(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 __int64,__int64)    Unknown
comctl32.dll!CToolbar::s_ToolbarWndProc(struct HWND__ *,__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,(LPARAM)&buttonToAdd);

最后一个参数是进程地址空间中的一个地址.但收件人是一个不同的进程,而您通过的地址在其他进程的地址空间中没有意义.

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

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

要警告,这是一个有点困难的任务.无论两个过程是否具有相同的位,特别重要的是重要.结构的布局在32位和64位之间不同.确保发送正确布局的最简单方法是以与目标进程相同的位置来编译进程.

到目前为止,最简单的做这样的方法是在目标过程之内.如果您要编写一个插件,那么您不必处理任何这些问题,也可以使用正式支持的API进行扩展.

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

猜你在找的C&C++相关文章