`
isiqi
  • 浏览: 16538394 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论
阅读更多

插件模式已经在软件开发中得到了广泛的应用,这种设计扩展性强,便于插件和主程 序独立升级,本文描述了基于普通 DLL 的插件模式的实现方法,并介绍了本人的一些经验。

1. 原理和特点

基于普通 DLL 实现插件模式的原理:利用 LoadLibrary 打开指定的动态链接库,然后用 GetProcAddress 取得库中指定函数的地址并调用其功能。设计插件时应把功能分类并制定接口,插件 管理器针对接口编程。

举个例子,某类插件负责对数据的读和写,现制定接口:

BOOL read(void *pIn);

BOOL write(void *pOut);

我们在主程序中要调用指定插件的读功能,可使用下面代码(略去对返回值的检 验):

typedef BOOL (*FN_Read)(void *pIn);

FN_Read fnRead = NULL;

HMODULE hDll = LoadLibrary(“plugin\test.dll”);

fnRead = (FN_Read) GetProcAddress(hDll, “read”);

BOOL bRet = fnRead(xxxxx);

使用这种方法实现插件模式,不需要注册表的参与,便于达到软件“绿色”的要求, 但管理器调用具体插件的时候,要指定路径(一般是固定的)。

2. 实现方法

一般实际应用中不会直接采用上面例子中的方法,因为不易扩展,而且复用性也差。 不同的人有自己不同的实现方法,下面我来讲一下我的方法。

l 首先,定义一个“插件成员”基类,用来传递插件 DLL 中特定功能函数(接口)的指针。

//--------------------------------

// 描述 : 插件成员类

//--------------------------------

class CPluginMember

{

public:

void (*fnOnOpenPlugin)(void *pParam);

void (*fnOnClosePlugin)(void *pParam);

CPluginMember()

{

fnOnOpenPlugin = NULL;

fnOnClosePlugin = NULL;

};

};

这个类包括两个函数指针,分别是打开插件和关闭插件时要调用的,默认值为空。

l 然后,自己实现一个插件管理器,负责从 DLL 中获得特定的“插件成员”对象,如果这个过程成功,那么就可以通过该“插件成 员”对象调用插件的功能了。

//-------------------------------------------------------------

//DESC : 打开插件

//

//lpszPluginDLL : 插件文件名

//pParam : 参数指针

//

//RETURN : 成功 TRUE 失败 FALSE

//-------------------------------------------------------------

BOOL CPluginManager::Open(LPCTSTR lpszPluginDLL, void *pParam)

{

// 加载 DLL

m_hDll = LoadLibrary(lpszPluginDLL);

if (!m_hDll)

{

// 加载 DLL 失败

_RPT0(_CRT_WARN, "Cannot Load plugin file.\n");

return FALSE;

}

else

{

FN_GetPlugin fnGetPlugin;

// 取得 GetPlugin 地址

fnGetPlugin =(FN_GetPlugin)GetProcAddress(m_hDll, PLUGIN_INTERFACE);

if (NULL == fnGetPlugin)

{

// 取得 GetPlugin 地址失败

_RPT0(_CRT_WARN, "Cannot retrieve GetPlugin()'s handle.\n");

return FALSE;

}

else

{

try

{

// 取得插件的 ( 函数 ) 成员

m_pPlugin = fnGetPlugin();

if(!m_pPlugin)

{

_RPT0(_CRT_WARN, "Cannot get plugin members.\n");

return FALSE;

}

// 执行初始化操作

if(m_pPlugin->fnOnOpenPlugin)

{

m_pPlugin->fnOnOpenPlugin(pParam);

}

}

catch(...)

{

// 取得插件成员发生错误,如类型不匹配

_RPT0(_CRT_WARN, "Error occured when handle plugin members.\n");

return FALSE;

}

return TRUE;

}

}

};

//-------------------------------------------------------------

//DESC : 关闭插件

//

//pParam : 参数指针

//

//RETURN : 成功 TRUE 失败 FALSE

//-------------------------------------------------------------

BOOL CPluginManager::Close(void *pParam)

{

// 执行关闭前的清除操作

if(!m_pPlugin)

{

_RPT0(_CRT_WARN, "No plugin is open, Ignore closing operation\n");

return FALSE;

}

if(m_pPlugin->fnOnClosePlugin)

{

m_pPlugin->fnOnClosePlugin(pParam);

}

m_pPlugin = NULL;

BOOL bRet = FreeLibrary(m_hDll);

m_hDll = NULL; // 说明插件关闭

return bRet;

};

//-------------------------------------------------------------

//DESC : 判断插件是否处于打开状态

//

//RETURN : 处于打开返回 TRUE ,否则 FALSE

//-------------------------------------------------------------

BOOL CPluginManager::IsOpen()

{

return (m_hDll != NULL);

};

有了这两个类,就可以实现基本的插件模型了,其它的功能(比如插件的搜索、类型 判断)都可以在这个基础上衍生出来。这种方法已经成功应用到一个图像处理组件中,为开发提供了不少便利。

3. 使用方法

在插件 DLL 工程中:

l 继承 CPluginMember 并加入所需接口

class CPluginMemberTest : public CPluginMember

{

public:

void (*fnTest)();

};

l 定义一个“插件成员”的全局变量 g_plgTest ,和一个名为 GetPlugin 的函数(可导出), GetPlugin 任务是把 g_plgTest 返回给主程序中的调用者

CPluginMemberTest g_plgTest;

__declspec(dllexport) CPluginMember* GetPlugin();

CPluginMember* GetPlugin()

{

return (CPluginMember*)&g_plgTest;

};

l 将实现指定功能函数的地址,在 DLL 初始化的时候,保存到 g_plgTest

BOOL CTestDllApp::InitInstance()

{

CWinApp::InitInstance();

g_plgTest.fnOnClosePlugin = NULL;

g_plgTest.fnOnOpenPlugin = NULL;

g_plgTest.fnTest = TestFunc;

return TRUE;

}

在主程序工程中使用下述代码即可调用插件的功能了:

CPluginMember member;

CPluginManager manager;

BOOL bRlt = manager.Open(_T(“PluginFullPath”), NULL);

CPluginMemberTest *plgTest = (CPluginMemberTest*)manager.m_pPlugin;

plgTest->fnTest();

manager.Close();

分享到:
评论

相关推荐

    IDA_plug-in_writing_in_C_or_C++.rar

    IDA_plug-in_writing_in_C_or_C++, 中文和英文两个。IDA_plug-in_writing_in_C_or_C++

    编写、加载和存取插件程序(Plug-Ins)

    在IT领域,插件(Plug-Ins)是一种增强软件功能的可扩展机制。它们是独立的代码模块,能够被主应用程序动态地加载和卸载,从而实现特定的附加功能。在C++编程语言中,创建和管理插件是一个常见的需求,特别是在需要...

    Designing Software Synthesizer Plug-Ins in C++

    Bridging the gap from theory to programming, Designing Software Synthesizer Plug-Ins in C++ For RackAFX, VST3 and Audio Units contains complete code for designing and implementing software ...

    Professional C++, 4th Edition

    Each feature is explained by example, each including actual code snippets that you can plug into your own applications. Case studies include extensive, working code that has been tested on Windows ...

    win下使用gvim编译C/C++安装包

    在Windows环境下,使用GVim编辑器进行C/C++编程并编译安装包是一个高效且灵活的方法。GVim是Vim编辑器的一个图形界面版本,它提供了丰富的代码编辑功能,尤其适合程序员进行源代码编辑。本教程将详细介绍如何在...

    vim plug taglist cscope

    TagList 支持多种编程语言,包括 C、C++、Java、Python 等。安装 Vim Plug(一个 Vim 插件管理器)后,可以通过以下命令来安装 TagList: ``` Plug 'tomtom/tlib_vim' Plug 'taglist/vim-taglist' ``` 之后,在 ...

    dlna C++ source code

    3. **控制协议(Control Protocol)**:基于UPnP(Universal Plug and Play)的协议,允许设备互相发现、控制和通信。 4. **内容格式(Content Format)**:定义了媒体内容的编码和传输方式,如MPEG、MP3、JPEG等。 ...

    汽车运动模拟(C++)

    在这个C++程序中,我们正在构建一个汽车运动的模拟,其中包含了汽车的多个关键组件,如火花塞、引擎、轮胎和方向盘。以下是对程序中各个类及其功能的详细解释: 1. **Spark Plug(火花塞)**:火花塞是内燃机的一个...

    c++实现的端口映射

    对于更复杂的端口映射场景,例如动态端口映射(DMZ)或UPnP(Universal Plug and Play)自动端口映射,可能还需要额外的库或协议支持。 总之,通过C++实现的端口映射程序,开发者可以深入了解网络编程和Winsock API...

    C++usb 驱动类型

    在Windows操作系统中,USB驱动主要分为三大类:用户模式驱动(User-Mode Driver, UMD)、内核模式驱动(Kernel-Mode Driver, KMD)和通用即插即用(Universal Plug and Play, UPnP)驱动。C++通常用于编写内核模式...

    IDA Pugin Writing in C++.pdf

    用 C++ 编写 IDA Pugin (英文)

    API Design for C++

    depth discussions of interface design, documentation, testing, and the advanced topics of scripting and plug-in extensibility. Throughout, he focuses on various API styles and patterns that will allow...

    Professional C++ 4th.zip

    Professional C++ is the advanced manual for C++ programming. Designed to help ... Each feature is explained by example, each including actual code snippets that you can plug into your own applications

    c++类的一个练习

    * `MainBoard` 是一个类,定义了三个成员变量 `i`、`j` 和 `k`,三个成员函数 `Plug`、`SelfCheck` 和 `show2`。`MainBoard` 负责处理主板的信息,包括插件 CPU 和 Memory 的检查。 * `Computer` 是一个类,定义了五...

    Visual C++.NET 开发驱动程序详解

    开发者需要理解PnP(Plug and Play)和WMI(Windows Management Instrumentation)的概念,以确保驱动程序能适应系统的动态变化。 10. **驱动程序测试**:最后但同样重要的是,全面的测试是确保驱动程序质量和可靠...

    upnp C++代码

    UPnP(通用即插即用,Universal Plug and Play)是一种网络协议,旨在简化设备在网络上的自动发现和控制。在C++环境中实现UPnP,通常涉及对相关标准协议的理解和编程,如SOAP(简单对象访问协议)、HTTP(超文本传输...

    UPNP映射C++源码

    UPNP映射C++源码是用于实现P2P内网穿透的一种技术,它基于通用即插即用(Universal Plug and Play,UPnP)协议。UPnP是一种允许网络设备自动发现并配置网络服务的技术,主要设计目的是简化家庭和小型办公网络的设置...

    GNU ARM Eclipse Plug-in

    Eclipse是一款开源的、跨平台的集成开发环境,广泛应用于Java、C++、Python等多种编程语言的开发。其强大的插件机制使其可以扩展到各种特定领域,如移动应用开发、嵌入式系统开发等。 2. **ARM架构**: ARM...

    plug110(OllyDBG的插件源码)

    6. **编译设置**:`Bc55`和`Vc50`可能是针对 Borland C++ 和 Visual C++ 的编译配置,开发者需要根据实际的开发环境进行调整。 通过学习和分析Plug110源码,开发者不仅可以了解OllyDBG插件的基本框架,还可以借鉴其...

Global site tag (gtag.js) - Google Analytics