使用DLL作为插件的设计框架

        在应用程序中,常常需要设计一种框架来适应需求的不断变化。经常地,在软件发布之后,用户需要增加新的功能,或者不同的用户需要根据各自特定的需求定制功能。为了达到这个目的而无需重写代码或者重做“开发——编译——测试——发布”等一系列任务,我们可以实现一种在不破坏现有代码的条件下可扩充模块的框架。使用插件(plug-in)的框架可以满足这一需要。

        那么什么是使用插件的框架呢?简单地说,这种框架能允许软件在启动时查找附加的功能模块并将其与软件整合。许多应用程序,例如Microsoft Office,就使用了类似的技术来允许第三方开发者来对已有的应用程序进行扩展。
        怎么样来开发使用插件的框架呢?一种非常简单的方法就是使用DLL(动态链接库)来实现插件扩展。当应用程序启动的时候,在预设的目录中查找符合一定规范的DLL文件。查找完成后,应用程序使用约定好的接口调用DLL模块。
        框架的生命周期如下所示:

1, 应用程序初始化。

2, On_Init()函数在指定的目录中查找DLL文件,例如,plug-in目录。

3, 应用程序对每个查找到的DLL调用load()函数。

4, load()调用之后,应用程序保存每个模块的名字,并对每个模块创建引用,这样,模块中的函数就可以在随后被调用。

5, 在应用程序运行的过程中,当用户选择菜单项时,相应的所定义的功能就会被执行。

6, 关闭应用程序时,调用unload()函数,用来释放load()函数中所申请的资源。

        下面给出一个C++中使用DLL作为插件的例子。
        为了将问题简化,这里使用Visual Studio DLL向导创建DLL文件。创建并导出一个名为 fnPlug1的函数,参数的空,返回类型为int,如下所示。
#define PLUG1_API __declspec(dllexport)
extern "C" PLUG1_API int fnPlug1(void);
        现在,我们来给DLL加入一个功能以便于观察到其正常工作。向你的DLL函数中加入如下代码。
PLUG1_API int fnPlug1(void)
{
   return 1234;
}

        当然,在实际应用中,你需要加入特定的的功能而不是简单地返回一个数字。

        为了使这个DLL文件作为插件整合进应用程序中,我们需要创建程序来进行驱动。我们的目的是找到所有的DLL文件,对其调用LoadLibrary()函数,存储HMODULE以供以后引用。
        下面给出一个例子。(注意我们使用.PLX扩展名代替了.DLL)
void CPluginDriverDlg::OnLoad()
{
   char filepath[MAX_PATH];

   //who are we really? Get the Exe Path
   GetModuleFileName(AfxGetApp()->m_hInstance,filepath,MAX_PATH-1);
   SetCurrentDirectory(ExtractFilePath(filepath));
   CFileFind finder;
   CString strWildCard = _T("*.plx"); //look for the plugin files

   //call this to set up the finder to iterate through all
   //the plugins
   BOOL bWorking = finder.FindFile(strWildCard);
   while (bWorking)
   {
     //have to call
     //FindNextFile() before GetFileName() or GetFilePath()
     //because FindFile just sets the object up and returns
     //true if _ANY_ files were found
     bWorking = finder.FindNextFile();

     HMODULE hm = LoadLibrary(finder.GetFilePath());
     if ( !hm )
     {
       MessageBox("couldn't load");
     }
     else
     {     
       //loaded OK, so add each library's HMODULE to an array.
       //m_dwa is an MFC CDWordArray
       m_dwa.Add((DWORD)hm);
     }
   }
}
        接下来,当你想要反复调用你的插件时,使用对每个插件存储的HMODULE来得到函数的地址,接着利用函数地址调用函数。
void CPluginDriverDlg::OnRunPlugins()
{
   for(int i=0; i<m_dwa.GetSize() ; i++)
   {
     //Find a function and use it
     PFUNC pFunc = (PFUNC)GetProcAddress(
     (HINSTANCE)m_dwa.GetAt(i), _T("fnPlug1"));
     if (pFunc != NULL)
     {
       int n = pFunc();
       CString answer ;
       answer.Format("The answer is %d", n);
       MessageBox(answer);
     }
   }
}
        说明一下,PFUNC的声明形式是:
typedef int (*PFUNC)(void);
        最后,一定要确保做好清理工作,从内存中释放所有的DLL文件,方法是使用FreeLibrary()函数。我在测试代码的DestroyWindow()中完成了这个功能。
BOOL CPluginDriverDlg::DestroyWindow()
{
   for (int i=0; i<m_dwa.GetSize() ; i++)
   {
     // Free all the libs we used
     FreeLibrary((HMODULE)m_dwa[i]);
   }

   return CDialog::DestroyWindow();
}

        实际上就是这么简单。你可以把任意多的插件放到预设的文件夹中;当你准备好后,执行插件中的函数。记住这是一个很简单的例子,它可以很简单地被扩充成健壮的模型,轻松载入你所需要的插件。


  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Qt中,要将一个库生成DLL(动态链接)作为插件,可以按照以下步骤进行操作: 1. 创建一个Qt项目,并将其类型设置为库(lib)项目。 2. 在项目文件(.pro文件)中添加以下内容: ``` TEMPLATE = lib CONFIG += plugin ``` 这样做可以确保项目被编译为插件库。 3. 在项目中实现插件的功能,包括类、函数等。 4. 在插件类的头文件使用`Q_INTERFACES`宏来声明该类实现了哪些Qt接口。例如: ```cpp class MyPlugin : public QObject, public MyInterface { Q_OBJECT Q_INTERFACES(MyInterface) // ... }; ``` 这样做可以告诉Qt框架该类实现了指定的接口。 5. 在插件类的实现文件使用`Q_PLUGIN_METADATA`宏来定义插件的元数据。例如: ```cpp Q_PLUGIN_METADATA(IID "com.example.MyInterface") ``` 这里的`"com.example.MyInterface"`是一个唯一的标识符,用于识别插件所实现的接口。 6. 构建项目,生成DLL文件。在构建过程中,Qt会自动处理插件相关的细节,生成可用于加载的DLL文件。 7. 将生成DLL文件放置在主应用程序可以访问到的位置。加载插件,主应用程序可以使用Qt提供的插件机制来加载并使用DLL。 需要注意的是,Qt框架提供了一些用于创建插件的基类和宏,如`QObject`、`Q_INTERFACES`、`Q_PLUGIN_METADATA`等。通过使用这些功能,Qt可以提供插件的自动发现、加载和使用机制,使插件开发更加方便。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值