【文章标题】miranda分析报告
【文章作者】曾健生
【作者邮箱】[email protected]
【作者QQ】190678908
【作者博客】http://blog.csdn.net/newjueqi
【作者声明】欢迎转载文章,但转载请保留文章的完整性以及注明文章的出处。
*******************************************************************************
前言:
Miranda IM是一款支持多协议的即时通讯客户端,非常简单和小巧,占用很少内存。Miranda IM是基于插件的,强大的插件系统使得Miranda IM非常的灵活。本人就针对Miranda的插件体系作一个简单的分析。
(1) 插件管理器
在Miranda中,插件是以service的形式存在的。插件可以在插件管理器内部注册服务,其中的几个关键函数说明如下:
1. HANDLE CreateServiceFunction(const char *name,MIRANDASERVICE serviceProc)
这个函数创建一个新的服务函数,返回值是指向这个服务函数的句柄。其中name参数指向服务名称的字符串,但必须注意了,由于name参数是自己指定的,所以必须保证服务名称的不重复性,不然创建服务会失败,serviceProc是被定义为int ServiceProc(WPARAM wParam,LPARAM lParam)。这个服务函数的句柄在退出时会自动销毁。
服务的保存是以以下结构体的形式保存的,
typedef struct
{
DWORD nameHash; //名称的Hash值
HINSTANCE hOwner; //模块句柄
MIRANDASERVICE pfnService; //回调函数指针
int isParam;
LPARAM lParam;
char name[1]; //服务名称
} TService;
另外管理器内部用结构体维护着一个服务链表
struct
{
TService** items;
int count, limit, increment;
FSortFunc sortFunc;
}static services;
保存着所有被登记的服务
2. int DestroyServiceFunction(HANDLE hService)
销毁由CreateServiceFunction创建的服务。
3. int CallService(const char *name,WPARAM wParam,LPARAM lParam)
调用已经注册的服务。
(2) 事件机制
1. HANDLE CreateHookableEvent(const char *name)
创建一个事件,但这个事件名称不一定只能是本插件使用,其它插件也可以用到,这个事件就可用于通讯。返回值是这个事件的句柄。但必须注意了,由于name参数是自己指定的,所以必须保证事件名称的不重复性,不然创建事件会失败。这个事件的句柄在退出时会自动销毁。
事件是保存是以以下结构体的形式保存的
typedef struct
{
char name[ MAXMODULELABELLENGTH ]; //事件名称
int id; //事件ID
int subscriberCount; //事件的回调函数的个数
THookSubscriber* subscriber; //事件的回调函数链表,指向所有相应这个事件的函数
MIRANDAHOOK pfnHook; //事件的默认回调函数
}THook;
事件的回调函数链的结构的如下
typedef struct
{
MIRANDAHOOK pfnHook;
HINSTANCE hOwner;
HWND hwnd;
UINT message;
}THookSubscriber;
另外管理器内部用结构体维护着一个事件链表,管理着所有事件
struct
{
THook** items;
int count, limit, increment;
FSortFunc sortFunc;
}static hooks;
2. HANDLE HookEvent(const char *name,MIRANDAHOOK hookProc)
将一个事件与一个回调函数指针绑定在一起
3. int DestroyHookableEvent(HANDLE hEvent)
销毁由CreateHookableEvent函数创建的事件。
4. int NotifyEventHooks(HANDLE hEvent,WPARAM wParam,LPARAM lParam)
产生特定的事件并调用函数来实现事件回调。其内部实现是进一步调用int CallHookSubscribers( HANDLE hEvent, WPARAM wParam, LPARAM lParam )函数的。
5. CallHookSubscribers( HANDLE hEvent, WPARAM wParam, LPARAM lParam )
调用THookSubscriber* subscriber里的函数。
(3)插件本身
插件里暴露了以下几个接口:
1. int __declspec(dllexport) Load(PLUGINLINK *link)
插件管理器装载插件时调用的接口。其中,PLUGINLINK *link指向的结构体如下:
typedef struct {
HANDLE (*CreateHookableEvent)(const char *);
int (*DestroyHookableEvent)(HANDLE);
int (*NotifyEventHooks)(HANDLE,WPARAM,LPARAM);
HANDLE (*HookEvent)(const char *,MIRANDAHOOK);
HANDLE (*HookEventMessage)(const char *,HWND,UINT);
int (*UnhookEvent)(HANDLE);
HANDLE (*CreateServiceFunction)(const char *,MIRANDASERVICE);
HANDLE (*CreateTransientServiceFunction)(const char *,MIRANDASERVICE);
int (*DestroyServiceFunction)(HANDLE);
int (*CallService)(const char *,WPARAM,LPARAM);
int (*ServiceExists)(const char *); //v0.1.0.1+
int (*CallServiceSync)(const char *,WPARAM,LPARAM); //v0.3.3+
int (*CallFunctionAsync) (void (__stdcall *)(void *), void *); //v0.3.4+
int (*SetHookDefaultForHookableEvent) (HANDLE, MIRANDAHOOK); // v0.3.4 (2004/09/15)
HANDLE (*CreateServiceFunctionParam)(const char *,MIRANDASERVICEPARAM,LPARAM); // v0.7+ (2007/04/24)
int (*NotifyEventHooksDirect)(HANDLE,WPARAM,LPARAM); // v0.7+
} PLUGINLINK;
由此可知,插件可以很方便的在插件管理器里注册服务和注册事件。
2. int __declspec(dllexport) Unload(void)
插件管理器卸载插件时调用的函数。
3. __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
获取插件的信息,指向的结构体如下:
typedef struct {
int cbSize; //
char *shortName; //插件名称
DWORD version; //版本
char *description; //描述
char *author; //作者
char *authorEmail; //EMAILL
char *copyright; // 版权声明
char *homepage; //主页
BYTE flags; // right now the only flag, UNICODE_AWARE, is recognized here
int replacesDefaultModule; //one of the DEFMOD_ constants in m_plugins.h or zero
/*********** WILL BE DEPRECATED in 0.8 * *************/
MUUID uuid; // 0.8.版本才用到
} PLUGININFOEX;
4. __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void)
插件的接口描述,其中Miranda内部已经自定义一系列的接口
结语
Miranda是通过插件管理器,事件机制,插件本身这三者构建出一个庞大的插件体系,通过这个开放式的框架,吸引了无数的开发人员投入了Miranda的阵营,开发出500多款插件,造就了Miranda的强大。从Miranda的例子可以说明开放式框架的魅力。