首页 | 资讯动态 | linux基础 | 系统管理 | 网络管理 | 编程开发 | linux数据库 | 服务器技术 | linux相关 | linux认证 | 嵌入式 | 下载中心 | 专题 | linux招聘 | 镜像站
OKLinux中文技术站
·设为首页
·加入收藏
·联系我们
系统管理: 中文环境 系统管理 桌面应用 内核技术 | Linux基础: 基础入门 安装配置 常用命令 经验技巧 软件应用 | Linux数据库: Mysql Postgre Oracle DB2 Sybase other
网络管理: 网络安全 网络应用 Linux服务器 环境配置 黑客安全 | 编程开发: PHP CC++ Python Perl Shell 嵌入式开发 java jsp | PHP技术: PHP基础 PHP技巧 PHP应用 PHP文摘
Linux资讯 Linux招聘 Linux专题 Apache | Linux相关: 硬件相关 Linux解决方案 Linux认证 企业应用 其它Unix | 相关下载: 资料下载 参考手册 开发工具 服务器类 软路由 其它
 技术搜索:
会员中心 注册会员 高级搜索  
  → 当前位置:首页>系统管理>内核技术>正文

Linux下插件开发应用案例

http://www.oklinux.cn  2006-02-22  来源: oklinux收集整理  何哥      会员收藏  游客收藏  【 】 
   在Linux 上愈来愈多的应用程序利用Plugin编程技术来实现扩展功能,目前应用比较广泛的有Gimp、Netscape/Mozilla、XMMS和Nessus等,本文将简单介绍这些软件的Plugin的架构和编程。


   给软件以生命力的Plugin


   众所周知,要让一个软件具有生命力,最重要的一点是要让它提供并支持越来越多的功能,而这一点单凭开发者自身是很难独立做到的,需要让第三方的软件开发者可以通过作者提供的一种途径来为该软件添加功能。

   最初,人们是使用关联模式,也就是像Windows下的文件扩展名一样,根据不同的文件关联,使用不同的软件打开相应的文件。这种方式编写扩展最为容易和自由,但是存在一定的缺陷,首先是不能利用宿主软件的资源,其次是软件的界面风格不易统一、灵活性不好。后来出现了Plugin结构,也就是利用动态连接库的方式制作Plugin(在Windows平台下是DLL、在Linux/Unix环境下是share object library),Plugin程序只能依附于宿主程序运行,不能独立运行,使用Plugin的优点是系统开销小、速度快,同宿主程序结合紧密、灵活性好。
   在Linux上,最著名的Plugin架构就是Netscape提出的Plugin架构,比较出名的还有WinAmp(www.winamp.com)(在Linux 上改名叫XMMS,网址为www.xmms.org),这个MP3 播放软件中多彩多姿的插件(Plugin)系统和皮肤(skin)系统为其一统天下做出了不可磨灭的贡献。现在WinAmp已开始提供一个NSDN(Null Soft Develop Network)来让大家开发Plugin,由此可见Plugin对于一个软件来说是多么重要。


   Linux下插件安装


   在Linux上,使用某种软件的Plugin的方法很简单,一般该宿主软件都会提供一些缺省的Plugin,而且会搜寻相应的Plugin目录,用户可以把Plugin安装到系统的Plugin目录下也可以安装到自己的目录下。比如,要安装Netscape的Plugin,可以设定$NPX_PLUGIN_PATH这个环境变量到你的新Plugin目录,或者把Plugin安装到下列路径上:

  

QUOTE:

/usr/local/lib/netscape/Plugins

   $MOZILLA_HOME/Plugins

   $HOME/.netscape/Plugins
   Netscape会自动搜寻这些Plugin目录来自动加载相应的Plugin,其他的软件如Gimp、 XMMS和Nessus等的使用方法与此大同小异。


   最简单Plugin架构的实现


   首先,我们要编写一个宿主程序,该宿主程序必须为Plugin提供相应的接口,例如在本例子中的Action,然后宿主程序可以通过dlopen来打开相应的Plugin,调用dlsym 和createproc来创建Plugin的进程,最后还要调用Plugin执行相应的动作,一切完成后要用dlclose 来关闭Plugin。宿主程序的源代码如下:

  

QUOTE:

Plugin_main.h

   #ifndef _PLUG_MAIN_H_

   #define _PLUG_MAIN_H_

   // 定义强制C类型以回避C++命名规范,这样我们就可以定义dlsym()

   #ifdef __cplusplus

   extern "C" {

   #endif

   class CPlugMain

   {

   public:

   virtual int Action() = 0;

   };

   // 下面是Plugin的通用函数,每个Plugin都会重载这个函数,主程序将创建惟一的子进程

   extern CPlugMain CreatePlug();

   typedef CPlugMain  (CREATEPLUG_PROC)();
   #ifdef __cplusplus

   }

   #endif //#define cplusplus

   #endif //#define _PLUG_MAIN_H_

   

   Plugin_main.cpp

   #include "Plugin_main.h"

   #include <stdio.h>

   #include <dlfcn.h> //动态链接库相关函数

   //下面将定义固定的Plugin名称,读者可以自行定义如同Windows注册表那样的Plugin注册系统

   #define NUM_PLUGINS 2

   char  szPlugins[] =
   {

   "./Plugin1.so",

   "./Plugin2.so"

   };

   int main( int argc, char  argv )

   {

   CREATEPLUG_PROC createproc[NUM_PLUGINS];

   CPlugMain  pPlugins[NUM_PLUGINS];

   void  handle[NUM_PLUGINS];

   char  error;

   int i;

   // 加载所有Plugin

   for ( i=0; i<NUM_PLUGINS; i++ )

   {

   printf( "加载Plugin %s.\n", szPlugins );

   // 加载Plugin动态链接库

   if (NULL == (handle = dlopen( szPlugins, RTLD_LAZY )))

   {

   handle = NULL;

   printf( "dlopen error (%s)\n", szPlugins );

   }

   else

   {

   // 取得CreatePlug的地址

   createproc = (CREATEPLUG_PROC)dlsym( handle, "CreatePlug" );

   if ((error = dlerror()) != NULL)

   {

   dlclose( handle );

   handle = NULL;

   printf( "dlsym error (%s)\n", szPlugins );

   }

   else

   {

   // 创建Plugin进程

   pPlugins = createproc();

   }

   }

   }

   // 执行Plugin的动作

   printf( "正在运行Plugin ..\n" );

   for ( i=0; i<NUM_PLUGINS; i++ )

   {

   if (handle != NULL)

   {

   pPlugins->Action();
   }

   }

   // 关闭Plugin

   for ( i=0; i<NUM_PLUGINS; i++ )

   {

   if (handle != NULL)

   {

   dlclose( handle );

   handle = NULL;

   }

   }

   return 0;

   }
   

   下面是一个最简单的Plugin,只包含了Plugin_main.h 这个头文件,并且实现Action和CreatePlug这两个函数。源程序如下:

  

QUOTE:

Plugin_1.h

   #ifndef _PLUGIN_1_H_

   #define _PLUGIN_1_H_

   #include ″Plugin_main.h″

   class CPlugin1  public CPlugMain

   

   public

   virtual int Action 

   

   #endif //#define _PLUGIN_1_H_



   Plugin_1.cpp



   #include ″Plugin_main.h″

   #include ″Plugin1.h″

   #include <stdio.h>

   int CPlugin1Action 

   

   printf( "这是Plugin 1,运行正常\n" );

   return 0;

   }



   CPlugMain  CreatePlug()

   {

   return new CPlugin1;

   }

   }
   

   值得注意的是,编译这个Plugin的时候要使用 -shared参数来产生动态链接库.so文件,例如:gcc -o Plugin1.so Plugin1.o -shared。


   Plugin开发实战


   我们来看看如何为现有的一些软件编写Plugin,其中最复杂的是Netscape 4.x 和Mozilla (Netscape 6.x)的Plugin编写工作,而Xmms/Gimp/Nessus的Plugin相对来说要容易编写得多。

   1. Netscape 4.x / Mozilla 的Plugin结构

   Netscape的Plugin结构相对比较古老,Netscape提供的接口包括NPP 系列和NPN 系列,其中NPP 系列中Plugin必须自行实现,包括:NPP_Destroy、NPP_DestroyStream、

   NPP_GetJavaClass、NPP_HandleEvent、NPP_Initialize、NPP_New、NPP_NewStream、NPP_Print、NPP_SetWindow、NPP_Shutdown、NPP_StreamAsFile、NPP_URLNotify、NPP_Write和NPP_WriteReady。

   NPN 系列是Plugin要求Netscape提供的一些函数,包括:NPN_DestroyStream、
   NPN_GetJavaEnv、NPN_GetJavaPeer、NPN_GetURL、

   NPN_MemAlloc、NPN_MemFlush、NPN_MemFree、

   NPN_NewStream、NPN_PostURL、NPN_RequestRead、

   NPN_Status、NPN_UserAgent、NPN_Version和NPN_Write。

   每种Plugin都有两种工作模式,即嵌入式和全页面方式,Plugin需要实现的工作包括以下内容:

   (1)登记一种或几种Plugin要操作的MIME格式;

   (2)在浏览器的窗口中间绘图;

   (3)接收鼠标/键盘输入;

   (4)从相应的URL中下载/发送数据。

   用户如果要开发Netscape的Plugin,首先要在ftp://ftp.netscape.com/pub/sdk/Plugin/unix

   下载相应的SDK 文件,里面有简单的例子,用户可以自行修改成自己的Plugin。

   Mozilla/Netscape 6.x的Plugin架构是目前最先进的一种,它主要有下列优点:

   (1)提供基于C++的API函数;

   (2)提供了XPCOM,它是COM (the Component Object Model)的一个子集,XP的意思是cross-platform(跨平台),这使得新的Plugin的跨平台性和不同版本的兼容性得到了极大的提高;

   (3)完全向后兼容,所有老的4.x 系列的Netscape Plugin 都可以继续使用。

   Mozilla 的Plugin架构将原来的NPP 系列接口改变为:NPIPlugin、 NPIPluginInstance和NPIPluginStream 三个类;NPN 系列接口被扩充为NPIPluginManager、NPIPluginManagerStream、NPIPluginInstancePeer和NPIPluginStreamPeer

   四个类,其中NP的意思是Netscape Plugin, I的意思是Interface。

linux插件开发参考文献 xmms插件开发指南: http://www.xmms.org

gimp插件开发指南: http://www.gimp.org/plugin_devel.html

nessus插件开发指南: http://www.nessus.org/doc/plugins_api.txt

http://www.nessus.org/doc/nasl.html

netscape 4.x 系列插件开发指南:

http://developer.netscape.com/docs/manuals/
communicator/plugin/index.htm

ftp://ftp.netscape.com/pub/sdk/plugin/unix

mozilla netscape 6.x 系列插件开发指南:  
http://www.doczilla.com/development/extmoz.html

http://www.mozilla.org/docs/plugin.html

http://www.mozilla.org/docs/extendmoz.html


   要开发Mozilla 的Plugin,用户需要下载Mozilla 的源代码,而Plugin的例子程序可以在http://lxr.mozilla.org/mozilla/source/

   Plugin/ 上查阅,具体文档请参阅附录。

   2. Xmms的Plugin架构

   Xmms的Plugin分为输入(Input )、输出(Output)、可视化(Visualization)、通用(General)、效果(Effect)和其他(Misc)五种,要开发Xmms的Plugin需要安装xmms-devel这个软件包,下面是一个最简单的Xmms可视化的Plugin:
  

QUOTE:

xmms-Plugin.c

   #include <gtk/gtk.h>

   #include "xmms/Plugin.h"

   static GtkWidget window = NULL,button;

   static void Plugin_init(void);

   static void Plugin_cleanup(void);

   VisPlugin Plugin_vp =

   {

   NULL,

   NULL,

   0,

   NULL, / 描述函数 /

   0,

   1,

   Plugin_init, / 初始化函数 /

   Plugin_cleanup, / 结束函数 /

   NULL, / 关于函数 /

   NULL, / 配置函数 /

   NULL, / disable_Plugin /

   NULL, / playback_start /

   NULL, / playback_stop /

   NULL, / render_pcm /

   NULL / render_freq /

   };

   VisPlugin get_vPlugin_info(void)

   {

   Plugin_vp.description =

   g_strdup_printf("Hello World!");

   return &&Plugin_vp;

   }

   #define WIDTH 250

   #define HEIGHT 100

   static void Plugin_destroy_cb(GtkWidget w,gpointer data)

   {

   Plugin_vp.disable_Plugin(&&Plugin_vp);

   }

   static void Plugin_init(void)

   {

   if(window)

   return;

   window = gtk_window_new(GTK_WINDOW_DIALOG);

   gtk_window_set_title(GTK_WINDOW(window),"Hello World");

   gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);

   gtk_widget_realize(window);

   gtk_widget_set_usize(window, WIDTH, HEIGHT);

   button = gtk_button_new_with_label ("Hello World");

   gtk_container_add (GTK_CONTAINER (window), button);

   gtk_widget_show(button);

   gtk_widget_show(window);

   }

   static void Plugin_cleanup(void)

   

   if (window)
   {

   gtk_widget_destroywindow 

   }

   }
   3. Gimp的Plugin架构

   Gimp的Plugin结构比较特殊,使用了宏定义来实现Plugin接口。

   MAIN()宏调用gimp_main、使得Plugin可以被Gimp调用, Gimp 的Plugin接口比较简单,在gimp启动时将查询所有的Plugin并注册到一个PDB (procedural database)中,每个Plugin只需要实现下面的结构:

  

QUOTE:

typedef void ( GimpInitProc) (void);

   typedef void ( GimpQuitProc) (void);

   typedef void ( GimpQueryProc) (void);

   typedef void ( GimpRunProc) (gchar name,

   gint nparams,

   GimpParam param,

   gint nreturn_vals,

   GimpParam return_vals);

   struct _GimpPluginInfo

   {

   / Plugin初始化函数 /

   GimpInitProc init_proc;

   / Plugin推出函数 /

   GimpQuitProc quit_proc;

   / 告知宿主程序本Plugin的功能,执行注册到PDB的功能 /

   GimpQueryProc query_proc;

   / 实现Plugin的功能 /

   GimpRunProc run_proc;

   };


   Gimp的Plugin就是通过上面的四个函数来实现的。

   关于Linux 下面的Plugin的使用和编程就介绍到这里,其中Netscape/Mozilla的Plugin编程最为复杂,不过对有一定编程经验的用户来说,好好研究一下 Mozilla的Plugin编程是会很有好处的。

   本文的所有例子程序都在Linux-Plugin-Example.zip中,用户可以到http://opencjk.org/Linux-Plugin- Example.zip网址自行下载。 所有程序均在RedHat 7.0、gcc-2.96、 glibc-2.1.92 下编译通过。

上一篇:为Linux 应用程序编写 DLL   下一篇:Linux内核研究系列之可执行文件格式


收藏于收藏夹】 【评论】 【推荐】 【打印】 【关闭
相关文档
·Linux内核研究系列之可执行文件格式
·为Linux 应用程序编写 DLL
·LINUX动态链接库高级应用
·在Linux中建立一个XML的开发环境
·Linux 编程之MD5算法研究
·Linux 编程之JAVA上加密算法的实现用例
·基于Linux系统的语音卡开发平台
·Pthread 与 Linux
·Bochs 调试技术
·Linux发行版制作指南
·Linux常用C函数—接口处理篇
·Linux 编程之GPU计算
·Linux常用C函数—字符测试篇
·Linux下的软件开发
·Linux内核编程全集1
·Linux常用C函数—内存及字符串操作篇
发表评论
密码: 匿名评论
评论内容:

(不超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规)
 
  最新文档
·Linux系统下内核定时器的用法
·学习园地:Linux系统内核中判断大小的
·系统编译:如何给Make命令来传递参数
·Linux 2.6内核中sysfs文件系统简单概述
·Fedora 8 Linux系统的内核配置注意事项
·升级Linux内核的一般步骤方法
·Linux发行版知识普及:三个版本的CPUID
·编译安装Virtualbox驱动模块
· Linux系统的内核解读入门
·新手学堂 Linux系统的内核解读入门
·Linux系统内核中网络参数的意义及其应
·走向Linux系统高手之路 内核编译过程解
  阅读排行
· 深入理解LINUX内核中文版下载地址
·基于S3C44B0微处理器的uClinux内核引导
·Kernel command using Linux system ca
·Linux 2.6内核如何武装Fedora Core 2
·Process priority and control on AIX
·Linux操作系统的内核编译内幕详解
·推荐:Linux用户态与内核态的交互
·通过振动向Linux ThinkPad传输信息
·Linux操作系统源代码详细分析(二)
·Linux系统内核接收以太帧的处理程序
·Linux and symmetric multiprocessing
·主流嵌入式Linux系统下GUI解决方案
·揭秘Linux内核调试器之内幕
·用命令行加挂Linux的文件系统简介
·Linux内核和核心OS组件的测试与分析
网摘收藏: