我认为这个实现是直截了当的,目前我正在使用这个代码:
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进行扩展.
正如雷蒙德所说,你所尝试的是相当危险的,你会很好地听从他的建议.