miranda插件开发思想

http://www.sayme.cn/blog/article.asp?id=1

 

最近接触了一些插件式开发的软件,很是感兴趣。觉得插件式开发首先从软件结构上来说是清晰且完美的,而从开源思想来看,能够让众多的用户来在你的软件上叠加新的功能,这个力量将是惊人的。firefox等优秀软件的成功我认为可以算是插件式开始的成功。

Miranda IM (1) 事件处理机制

  Miranda 是一个支持多协议的,运行于windows平台下的IM软件。其使用pure c语言编写,其架构体系支持插件方式加载,如多协议的支持msn,yahoo,gtalk等都以插件的方式加载,用户可以根据需要加载,同时皮肤界面相关组件如clist等也以插件的方式加载。
  如上所述平台的实现以一些技术实现为基础,先要说的是miranda中的事件定义,通知机制。因为使用纯C编写的,所以不可能采用如com中的连接点等方式来作为事件通知,但miranda采用的事件通知方式,跟COM的连接点方式原理类似。所不同的是COM的实现如MFC,ATL有一套机制来实现,这样用户可以定义不同的事件接口函数。而在纯C的实现中,我们要保证程序的简洁实用,最简单的办法当然是所有事件函数的原型是一样的,这样有助于事件的管理和程序实现。其事件原型是 typedef int (*MIRANDAHOOK)(WPARAM,LPARAM) 有点类似于win32的消息处理函数。
  1  事件定义:
       HANDLE CreateHookableEvent(const char *name) 创建一个事件,即其他模块可以和这个事件绑定,到此事件发生时,通知相应模块。
       static THookList *hook 。此链表记录通过上面函数创建的事件。创建的时候以一个hash算法将字符串转化为一个整数,这个整数为这个事件的唯一标识。
  2 HookEvent:
      即相当于COM 连接点的Advise的过程。
      HANDLE HookEvent(const char *name,MIRANDAHOOK hookProc)
      THookList结构中THookSubscriber* 记录通过HookEvent传递的事件函数指针,其也为一个链表。
  3 卸载Hook
     int UnhookEvent(HANDLE hHook)
     调用此函数卸载通过HookEvent放上去的事件。
   4 事件通知
      当特定事件产生需要通知时,调用函数来实现事件回调并通知
      int (*NotifyEventHooks)(HANDLE,WPARAM,LPARAM)
      
    由THookSubscriber定义
    typedef struct {
    MIRANDAHOOK pfnHook;
    HINSTANCE hOwner;
    HWND hwnd;
    UINT message;
} THookSubscriber;
   可知其还可以实现一个win32消息的回调,即通过Windows消息的方式来通知那些通过HookEventMessage添加的窗口句柄。

    综上所述,miranda在事件实现这块代码并不复杂,虽然不像COM的连接点那样灵活,但也基本上满足需要。
      
 在分析Miranda插件体系之前,先看看一个简单的COM为基础的插件加载方式。
  
    在这种以接口为基础的结构中,每个插件需要实现接口IPlugin接口,IPlugin接口有两个接口函数:
    OnLoad
    OnUnLoad
    这两个函数很好理解,即主程序加载插件时调用OnLoad,卸载插件时调用OnUnLoad。
    1 程序加载插件时,可以看到OnLoad的参数IPluginManager,这个参数是指向插件管理器的指针,插件实现方可以通过这个接口来获取其他接口(通过QueryObject接口函数),可以向这个管理器中加入新的接口(通过AddObject接口函数)
    2 当此插件被卸载时,即OnUnLoad被调用时,插件实现方需要调用RemoveObject将自己加入到插件管理器中的接口删除。
    3 添加和删除接口的通知。在插件式体系中,可能一些插件接口某些任务的完成或者开始依赖于其他插件的接口,即A插件需要得知我是什么时候可以得到B插件,一个简单的实现方式就是在B插件的接口加入到插件管理器中后,则显示的通知A接口。同时如果A插件向管理器中加入的接口,那么他在卸载的时候会将此接口删除,而删除前也需要做一个通知,通知所有使用此接口的插件停止使用此接口。这个可以使用连接点的方式来通知。
    综上所述,一个简单的插件平台就搭建起来了,之所以先讲这个基于COM的插件平台,是发现Miranda实现的插件平台跟这种以COM为基础的插件平台类似。
    下面说说Miranda的插件体系及具体实现:
     Miranda类似上面所述的插件管理器称之为“service”,所有“service”函数存放在TServiceList 这个List中,其由以下函数完成:
     1 HANDLE CreateServiceFunction(const char *name,MIRANDASERVICE serviceProc)
创建一个service函数,将其加入到全局的TServiceList列表中,其他接口也通过此name来调用这个加入的函数。
     2  int DestroyServiceFunction(HANDLE hService)
     删除一个service函数
     3  int CallService(const char *name,WPARAM wParam,LPARAM lParam)
      即通过name来调用全局service List中的函数。
      由上面的分析可以得知,Miranda这种基于C的简单实现有以下弊端:
      > 函数的唯一标识name,由自己定义,并自己保证其不重复,而COM中,使用GUID来定义从某种程度上程序来保证了其不重复。
      > 其加入的函数原型MIRANDASERVICE 是统一的,即加入的函数函数原型是一致的。而在COM实现中,可以有更加灵活的接口函数加入。
      > 没有通知机制,即这些函数的调用可能因为某插件被卸载而失败。也使得如果插件之间有相互的调用,则其加载有其先后顺序,不能做到无序加载。
     在插件的加载时,由于插件一般都位于独立的dll中,所以在miranda的实现中使用了PLUGINLINK *link
来将主程序的主要函数传给插件方,PLUGINLINK实际上是一组函数指针组成的结构:
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)
} PLUGINLINK;
     这样给插件方提供了一种方式来调用service list中的函数,这个跟我们之前COM的简单插件模型中的OnLoad(IPluginManager*) 的想法不谋而合。
     总的来说,前面讲的这两种插件方式总体思想是略有不同,COM的实现可扩展性更强,而miranda中的这个实现更加优雅简单。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值