给Source Insight做个外挂系列之六--“TabSiPlus”的其它问题
关于如何做一个Source Insight外挂插件的全过程都已经写完了,这么一点东西拖了一年的时间才写完,足以说明我是一个很懒的人,如果不是很多朋友的关心和督促,恐怕是难以完成了。许多朋友希望顺着本文的思路也作一个类似于TabSiPlus功能的Source Insight外挂插件,抱歉让他们等了这么长时间,看了本文或许能让大家消消气(大头在后面)。其实即使不是为了给Source Insight做外挂插件,本文的很多方法都可以用于给其它软件做外挂。
尽管本文介绍了做TabSiPlus外挂插件的完整过程,但是要做一个有使用价值的外挂插件还有很多细节要注意,首先是稳定,插入到Source Insight进程中的代码一定要考虑周到,仔细地测试所有分支,确保不能频繁地挂死Source Insight;其次,附加的功能一定不能干扰Source Insight的正常工作,比如窗口消息的处理;最后就是在界面上要能和Source Insight融为一体,插件创建的窗口一定不能覆盖Source Insight的窗口。
以上都是空话,现在用具体的例子来说几个细节,比如TabsiPlus提供了直接根据标签关闭文档窗口的功能,由于文档窗口创建的时候已经获取到窗口的句柄,所以TabsiPlus的第一个版本就使用DestroyWindow() API直接关闭了文档窗口,从外表看确实大到了效果,但是却隐藏了一个BUG,那就是虽然窗口被关闭了,但是Source Insight并不知道文档窗口被关闭了,相应的文件依然处于打开状态,如果文档修改过,这样关闭窗口甚至不会提醒用户保存文档。在自己的程序中关闭窗口当然直接DestroyWindow()就行了,但是既然你的代码是“寄人篱下”,就要按照“别人”的规矩来。通过Spy++观察Source Insight窗口的消息,发现Source Insight窗口只对WM_CLOSE消息会有正常的反映,也就是说Source Insight可能在OnClose()中处理了关闭文件和提示保存修改的操作(很奇怪DestroyWindow()后为什么没有触发Source Insight的OnClose()处理被调用,看来远程注入的代码确实有很多需要注意的地方),后来的版本使用SendMessage将一个WM_CLOSE消息发给文档窗口,这样就很好地解决了这个问题。
上面的问题还没完,让窗口消失就算是关闭了吗,有没有考虑窗口的Focus? 如果关闭某个拥有“焦点(Focus)”的子窗口,Windows会激活此焦点窗口的一个兄弟窗口,通常是上一个拥有焦点的窗口,这个相信使用Windows的人都知道,我也是这么认为的,但是,这一点在外挂中失灵了,在TabSiPlus的线程中,关闭当前拥有焦点的文档窗口后,其它的文档窗口标题栏竟然都是灰的,也就是Source Insight的MDIClient窗口没有选择上一个焦点窗口激活,怎么办?看看TabSiPlus中关闭文档窗口的代码:
void CTabBarsWnd::CloseSIWindow(CSiWindow*& pWindow)
{
ASSERT(pWindow);
HWND hPrevActive = NULL;
if(pGlobalActiveSIWindow != NULL && pWindow != pGlobalActiveSIWindow)
{
DebugTracing(gnDbgLevelNormalDebug,_T("CTabBarsWnd::CloseSIWindow() pGlobalActiveSIWindow = %x"),pGlobalActiveSIWindow);
hPrevActive = pGlobalActiveSIWindow->GetSafeHwnd();
m_iLockUpdates++;
}
pWindow->SendMessage(WM_CLOSE, 0, 0);//now close it!
if(hPrevActive != NULL)
{
::PostMessage(::GetParent(hPrevActive), WM_MDIACTIVATE,(WPARAM)hPrevActive, 0);
}
}
核心只有一句:
pWindow->SendMessage(WM_CLOSE, 0, 0);//now close it!
却要围绕它做很多事情。
再来看一个问题,有没有考虑过Tab标签栏上的标签与实际打开的文档窗口个数不一致的情况?虽然我们Hook可MDI_CREATE消息,但是依然有一些窗口创建是TabsiPlus插件无法感知的,比如Source Insight支持内置宏语言,通过宏进行窗口操作TabsiPlus插件无法感知,还有一种情况是Source Insight对于一些不激活的文档通常不是立即创建窗口,而是在激活的时候才创建窗口显示文档,当用户通过Windows菜单看到的已经打开的文件与你的Tab标签栏不一致会怎么想?没有好的办法,TabSiPlus使用一个定时器处理这种不一致,具体代码在CTabBarsWnd::OnTimer()中。
还有一个问题,如何安全地关闭外挂插件?有一种方法先关闭Source Insight,然后关闭加载器TabSiHost.exe,然后再打开Source Insight。让自己接受这种方案都很难,更何况别人,如果能够在插件中提供一个界面,通过用户选择可以直接退出插件就好了,实现这一点关键是Source Insight内部关闭Tab标签窗口后如何中止加载器TabSiHost.exe,如果不中止TabSiHost.exe,TabSiHost.exe会再次加载TabsiPlus.dll插件。TabsiPlus通过内核对象完成与TabSiHost.exe的同步:
void CTabBarsWnd::ShutDownTabSiPlus()
{
HANDLE hAnotherTabSiHostEvent = NULL;
LPCTSTR szGlobalKernelName = _T("Local//TabSiHostIsAlreadyRunning");
hAnotherTabSiHostEvent = CreateEvent( NULL, TRUE, FALSE, szGlobalKernelName );
DWORD dwer = GetLastError();
if(dwer == ERROR_ALREADY_EXISTS)
{
ResetEvent( hAnotherTabSiHostEvent );
}
::CloseHandle(hAnotherTabSiHostEvent);
g_pSiMDIClientWnd->SetManaging(false);
DestroyWindow();
}
还有,TabSiPlus内部窗口之前传递数据都是通过自定义消息进行的,原因就是Tab标签窗口与Source Insight的窗口是工作在不同的线程中的,在线程之间只有句柄是安全的,向窗口句柄发送消息要比直接操纵数据要安全。还有,当使用了Source Insight的查找字符串功能时,Source Insight会打开一个窗口显示搜索的结果,这个窗口的窗口类名和代码窗口一样,都是si_Sw,但是其窗口标题却和代码窗口的标题不一样,这个要区分。其它的细节还有很多,就不一样列举了,具体看代码吧。
罗嗦了半天,代码在哪里?本来想随本文一起上传的,但是这个Blog上传附件太麻烦,只好放到我的CSDN资源里了,大家可以到我的空间下载源代码。本文附带的代码是一份精简的TabSiPlus插件代码,为了大家理解代码,我去掉了全部装饰性的代码和附加功能代码,包括很多预防性代码,这样做地目的就是为了大家在学习源代码时能够将注意力集中在框架上而不是枝节琐事。尽管如此,这是一个完整的可工作的Tab标签栏,演示了本文写的全部内容。除了我的代码之外,源代码中还使用了一些自由代码,使用时请注意相关作者的权利要求。
代码的编译很简单,用VC 6.0打开直接Build就行了,为什么不升级到VC7 or VC8?其实我很懒。调试的时候注意相关的资源文件要在同一个目录中,TaiSiHost.exe的调试比较简单,直接加载就行了,调试TabSiPlus.dll比较麻烦,首先关闭已经打开的Source Insight程序,然后在Project Setting/Debug 窗口中设置“Executable for debug session:”为Source Insight的主程序,通常是Insight3.exe,再然后运行TabSiHost.exe,最后就可以按F5开始调试了。整个过程就是:按下F5后,VC根据调试设置启动insight3.exe,已经运行的TabSiHost.exe发现启动了Source Insight,就会远程代码注入到insight3.exe,于是insight3.exe就会加载TabSiPlus.dll,这样就可以调试了。
Source Insignt文件标签外挂:TabSiPlus的下载地址:
http://www.winmsg.com/download/tabsiplus.zip
给Source Insight做个外挂系列之六--“TabSiPlus”的其它问题的更多相关文章
- 给Source Insight做个外挂系列之三--构建外挂软件的定制代码框架
上一篇文章介绍了“TabSiPlus”是如何进行代码注入的,本篇将介绍如何构建一个外挂软件最重要的部分,也就是为其扩展功能的定制代码.本文前面提到过,由于windows进程管理的限制,扩展代码必须以动 ...
- 给Source Insight做个外挂系列之一--发现Source Insight
一提到外挂程序,大家肯定都不陌生,QQ就有很多个版本的去广告外挂,很多游戏也有用于扩展功能或者作弊的工具,其中很多也是以外挂的形式提供的.外挂和插件的区别在于插件通常依赖于程序的支持,如果程序不支持插 ...
- 给Source Insight做个外挂系列之五--Insight “TabSiPlus”
“TabSiPlus 外挂插件”主要有两部分组成,分别是“外挂插件加载器”和“插件动态库”.“插件动态库”完成Source Insight窗口的Hook,显示Tab标签栏,截获Source Insig ...
- 给Source Insight做个外挂系列之四--分析“Source Insight”
外挂的目的就是将代码注入到其它进程中,所以必须要有目标进程才能完成注入,而所谓的目标进程通常是某软件的一部分或者是全部,所以要对目标程序有深入地了解.一般外挂都是针对某个应用程序开发的,其装载.运行都 ...
- 给Source Insight做个外挂系列之二--将本地代码注入到Source Insight进程
上一篇文章介绍了如何发现正在运行的“Source Insight”窗口,本篇将介绍“TabSiPlus”是如何进行代码注入的.Windows 9x以后的Windows操作系统都对进程空间进行了严格的保 ...
- Source Insight 3.X 标签插件v1.0发布
Source Insight可以说是一款程序员必备的开发/阅读源码工具,美中不足的是SI没有标签栏,多个源码之间切换很不方便,于是我就乘闲暇之余写了该作品sihook:标签插件;不过严格意义上来说si ...
- Source Insight 插件
一提到外挂程序,大家肯定都不陌生,QQ就有很多个版本的去广告外挂,很多游戏也有用于扩展功能或者作弊的工具,其中很多也是以外挂的形式提供的.外挂和插件的区别在于插件通常依赖于程序的支持,如果程序不支持插 ...
- source insight 编程风格(持续更新)
1.字体Source Code Pro 出身于豪门Adobe,从名字上来看就知道是转为编码而生的.基本上也是拥有前面所提的编程字体的所有要素的.这个字体基本上具有编程字体所需的所有要素:等宽.支持Cl ...
- Linux下Source Insight的安装和汉化
原创文章,转载请注明出处. 工欲善其事,必先利其器.Source Insight绝对是阅读C和C++代码的利器,另外,Source Insight的体量很小,安装便捷,显示直观,比vim+cscope ...
随机推荐
- (转)CDN——到底用还是不用?
用CDN的七个理由 浏览器从服务器上下载css.js和图片等文件时都要和服务器连接,而大部分浏览器对同一个域名用于下载文件的并发连接数限制在4个,这意味着如果要下载第五个文件就必须等前四个文件中有一个 ...
- 25条提高iOS App性能的建议和技巧
这篇文章来自iOS Tutorial Team 成员 Marcelo Fabri, 他是 Movile 的一个iOS开发者. Check out his personal website or fol ...
- nginx.conf配置文件里的upstream加入健康检查
查看NGINX启用了那些模块: # ./nginx -V Tengine version: Tengine/ (nginx/) built by gcc (Red Hat -) (GCC) TLS S ...
- CSS3颜色渐变模式
1.线性渐变:linear-gradient 语法:<linear-gradient> = linear-gradient([ [ <angle> | to <si ...
- Linux网络管理1---(Linux配置IP地址,ifconfig、配置文件)
1.Linux配置IP 地址 ifconfig命令临时配置IP 地址 ifconfig命令,最常用的功能是查看本机的网络的配置状态(当然也可以配置网络,不过是暂时性的),直接输入ifconfig命令就 ...
- Struts2学习(一)
struts2 就是 web层开发框架,符合MVC模式 入门程序 创建web工程 导入jar包 下载struts2的jar包 struts-2.3.15.1-all 版本. 注意:在struts2开 ...
- 【dom4j xml】使用dom4j处理XML文件--测试过程遇到的问题
首先 关于dom4j的API,有如下: 当然 其中的实体引用有以下: 测试使用环境: 使用Maven搭建web环境,pom.xml文件配置如下: <project xmlns="ht ...
- 198个经典C#WinForm实例源码(超赞) 里面的例子 .sln 目录
\-窗体技巧\QQ窗体\QQFrm.sln; \-窗体技巧\仿XP系统的任务栏菜单\仿XP系统的任务栏菜单.sln; \-窗体技巧\向窗体中拖放图片并显示\向窗体中拖放图片并显示.sln; \-窗体技 ...
- Listener refused the connection with the following error 错误解决
原文地址 :http://blog.csdn.net/zajin/article/details/17753351 做个备份: 查询数据库当前进程的连接数: select count(*) from ...
- Pig基础学习【持续更新中】
*本文参考了Pig官方文档以及已有的一些博客,并加上了自己的一些知识性的理解.目前正在持续更新中.* Pig作为一种处理大规模数据的高级查询语言,底层是转换成MapReduce实现的,可以作为MapR ...