最近作者用
20
天写了一个小软件,在
csdn
的
Bcb
论坛和
chinabcb
发表,得到了大家的支持,并有很多朋友询问是否可以公开源代码,作者其实也不是一个保守的人,以前就公开了自己的游戏源代码,但后来这个游戏被别人盗用,还那他当共享软件收费,我非常生气,也算有了教训,这次作者在短期之内是不会公开源代码了,但面对那么多网友的支持,作者认为有责任写一些东西来帮助广大
bcber
爱好者共同进步,所以就写了这篇开发手记,希望对初学者有一定帮助,如果你是高手,就当我班门弄斧好了。
如果你还没有见过
MySpy
,你可以从
http://www.chinabcb.com/bbs/viewtopic.php?t=6445
下载,这个地址需要你注册登录才能看到下载地址,否则只有介绍。
作者不打算介绍整个开发过程,就拿出问的最多的问题来介绍一下吧:
1.
如何将图标保存为真彩色图标的?
其实,这本来不改算是个问题,但在
Bcb
和
Delphi
里这可真是一个非常难解决的问题,不知大家是否知道,
Bcb
和
Delphi
的
TIcon
类保存的图标仅支持
16
色,这样不管是
256
色还是真彩色的图标,都只能用
16
色来显示,这样的保存结果不要也罢,作者曾一度想放弃保存图标的功能,但最后还是没有这样做,那么作者是怎么解决的呢?
首先作者想到了
Internet
,既然我有这样的问题,那么世界上肯定还有其他人遇到了这样的问题,去
google
上应该可以找到其他人解决问题的方法,作者花了一个下午的时间,在各大
Delphi
站点、
faq
、控件区都没有找到合适的解决方法,最后在一个日本网战上找到了一个
TIconEx
,从几个认识的中文里,我猜出了这个东西正好是我要的
,
我立刻开着快车把他下了下来,很可惜没有源代码,日本人真
tmd
的讨厌,怀着对日本人无限的愤怒之情,我把那个
TIconEx
扔进了垃圾箱。
看来他山之石是借不出来了,那么作者只好从底层出发寻找解决方案了,从这个地址
http://www.csdn.net/dev/format/
,作者找到了
Icon
的文件格式和一段微软工程师写的例子代码,作者用了一个晚上来研究这个
Icon
格式和工程师的代码,明白后,作者决定把他用
Bcb
封装起来,因为原来的代码是用
c
语言编写的,而作者是个
oo
爱好者,所以作者决定把他类化然后加入了从
HICON
保存文件的代码(原来的只能从模块中抽取出来保存)。
代码是写完了,但是把他用到
Bcb
还真是不容易,不过这已经不是技术问题了,大家如果有兴趣就自己试一试吧,对了,上面介绍
Icon
格式的文章是英文的,如果作者有时间了,会把他翻译成为中文的,那篇文章写的相当好。
2.
如何
HOOK
?
HOOK
在
MySpy
里是用的最多的技术,从获取密码到截获系统的消息都是
HOOK
技术,可以说这个技术已经不是什么技术了,网上随便一个编程站点都可以找到相关介绍资料,但截获系统消息的还是比较麻烦的,作者就介绍一下它吧。
截获系统消息无非是安装系统钩子
WH_CALLWNDPROC
、
WH_CALLWNDPROCRET
和
WH_GETMESSAGE
,为什么要安装这么多,因为系统消息有很多不同的类型,有
Send
,
Post
还有处理消息返回也是需要截获的,当然如果你对系统菜单也感兴趣,还需要安装
WH_SYSMSGFILTER
钩子,因为这是一个系统范围的钩子,所以必须编写成为
DLL
,而核心代码也不过就是:
LRESULT CALLBACK MsgHookProc1(int nCode, WPARAM wParam,LPARAM lParam)
{
if (nCode>=0)
{
CWPSTRUCT* mm=(CWPSTRUCT*)lParam;
MsgData data;
data.msg=mm->message;
data.wparam=(int)mm->wParam;
data.lparam=(int)mm->lParam;
data.type=1;
data.result=0;
COPYDATASTRUCT copydata;
copydata.dwData=0;
copydata.cbData=sizeof(MsgData);
copydata.lpData=&data;
if(mm->hwnd==HookStruct->HookedWnd)
{
SendMessage(HookStruct->ParentWnd,WM_COPYDATA,0,(LPARAM)©data);
}
}
return(CallNextHookEx(HookStruct->MsgHook1,nCode,wParam,lParam));
}
可以看到作者是使用
WM_COPYDATA
向
MySpy
发送通知消息的,上面是其中一个
HOOK
的回调函数,其他类似。
MySpy
收到
WM_COPYDATA
消息后,会将
lParam
参数转换成为
MsgData
,而这个结构体封装了关于该消息全部有用的信息,就等着
MySpy
处理了。
HOOK
其实真的很简单,就是调试麻烦,作者在调试过程中,至少死机
10
多次,如果使用
Win9x
系统,可能你就光死机了。
到此你可能认为写个截获消息的功能就算完成了,如果你注意
MySpy
的话,并对
Win32API
有一定了解,你会发现,我们得到的消息是个整数的
id
,而我们不可能只给用户显示个
id
,我们需要
WM_XXX
这个的友好表示,但
API
里并没有提供把整数
id
转换成为友好字符串的函数,这该如何解决呢?作者最后使用了一个记录文件,文件格式如下:
0x0000 WM_NULL
0x0001 WM_CREATE
0x0002 WM_DESTROY
0x0003 WM_MOVE
0x0005 WM_SIZE
0x0006 WM_ACTIVATE
……
有了这个文件,查找对应的友好字符串就简单了,而且扩展这个记录文件非常容易,你可以加入你已知
id
的对应字符串。关键在于查找效率,这个也不难,排序后快速查找再合适不过了。到现在,作者也不知道我的解决方法是不是最好的,还请各位赐教?
3.
如何得到网页上的元素,并取得他的相关信息?
这个问题还是有一点难度的,特别对于不懂
COM
的人,这个问题就更难了。
想要操作
HTML
首先要得到
IHtmlDocument2
接口,这个接口是
IE4.0
以上提供用来专门与
Html
交互的
COM
对象表露的,如果我们用
asp
或
JavaScript
来操作
Html
,非常简单,当然得到网页里的元素也非常简单,而使用
Bcb
这样的开发工具来操作
Html
,没有微软的帮助恐怕是不行(至少作者不知道),还好微软确实提供了这方面的支持。这个支持就是
OLEACC.DLL
。
这个
DLL
的功能很多,其中之一就是从
HWND
得到关联的
COM
对象的接口,那么代码到底是什么样的呢?
CComPtr<IAccessible> spAccess;
hr=AccessibleObjectFromWindow(hwnd,0,IID_IAccessible,(void**) &spAccess);
if ( SUCCEEDED(hr) )
{
CComPtr<IServiceProvider> spServiceProv;
hr=spAccess->QueryInterface(IID_IServiceProvider,(void**)&spServiceProv);
if(hr==S_OK)
{
CComPtr<IHTMLWindow2> spWin;
hr=spServiceProv->QueryService(IID_IHTMLWindow2,IID_IHTMLWindow2,(void**)&spWin);
if(hr==S_OK)
spWin->get_document(&pDoc2);
}
}
上面就是从
HWND
取得
IHTMLDocument2
接口的核心代码了,当然你需要加入
Oleacc.h
和
Oleacc.lib
文件,得到
IHTMLDocument2
接口后我们就用了同
ASP
同样强大的能力去造作
HTML
了,关于如何操作
HTML
这里就不谈了,有
ASP
知识的朋友一看到这里我想都明白了吧。
这里的关键函数就是
Oleacc.dll
导出的
AccessibleObjectFromWindow
,
这个函数的作用看一下名字就知道了,
MSDN
里给的说明如下:
Retrieves the address of the specified interface to the object associated with the given window.
所以这个函数不光可以得到
IHTMLDocument2
接口还可以得到
Office
等接口,有兴趣的可以试一试
.
4.
如何编写插件?
MySpy
支持插件,而且为
MySpy
开发插件很容易,当然这主要靠作者的合理设计和完整的开发文档(大家不要砸我:)),编写插件本来不应该算
MySpy
的特色功能,或者说绝对不是什么核心技术,不过既然
MySpy
写了,又有人问,我就顺便介绍一下如何开发插件吧。
作者在开始设计插件结构的时候,徘徊在使用
COM
插还是普通
DLL
插的交叉路口,使用
COM
会容易编写代码,对于开发人员容易理解,而且现在的大多数软件都是使用
COM
作为插件的,但使用
COM
的最大问题是,将大大增加
MySpy
的身体臃肿度和增加
MySpy
的开发时间,因为作者需要单独编写一个
DLL
来封装整个
MySpy
,然后表露接口,这样就额外带来了将近
1
倍额外脂肪,这是作者不能接受的,还有就是编写
COM
插件对于开发人员要求太高了;使用
DLL
来做插件又有很多方法,是导出若干函数来负责若干功能还是导出
1
-
2
个函数来泛化设计呢?还有就是要不要插件同
MySpy
有交互呢(存在双向数据访问吗?)
最后作者选择了现在的解决方法,就是仅导出一个函数的泛化设计,这个设计类似于
Windows
的消息机制,就是
MySpy
发送若干消息给插件来通知插件做什么事情,插件也可以发送消息给
MySpy
来控制
MySpy
,而开发人员仅需要处理相应消息并返回必要的值,剩下的事情由
MySpy
完成,这样的解决方法不需要额外的
DLL
,在
MySpy
代码内部的适当位置发送适当的消息给插件,然后处理返回值就可以了。我们来看一下导出函数的格式:
extern "C" __declspec(dllexport)
int MMPlugin(MMSG msg,MPARAM wParam,MPARAM lParam)
{
switch(msg)
{
case MM_INIT:
//place your init code here
break;
case MM_DESTROY:
//place your destroy code here
break;
…
}
}
可以看到这个导出函数,很像
WndProc
函数,作者这样设计的灵感完全来源于
Windows
消息机制的巧妙,一个整型的
MPARAM
参数可以传递任何类型,任何大小的数据,作者真的很佩服
Windows
的消息机制,不知各位朋友有什么好的方法,不妨大家一起讨论一下。
至此
MySpy
的关键技术已经全部介绍完了,大家可能也看到了,作者对所有的技术介绍都是点到为止,并没有讨论的很详细,这并不是作者不愿意给出源代码,而是没有必要,在作者看来解决问题的方法是思想,如果大家有兴趣,自己试一试,像作者一样花个
10
-
20
天,肯定大有收获。
作者非常欢迎大家来信讨论
siney@yeah.net
。
感谢Aweay提供的技术知识。
posted on 2006-10-23 10:30
风籁 阅读(187)
评论(0) 编辑 收藏