您现在的位置是: 软件 > 开发者网络 > 技术跟踪 > 技术理论 > 正文


-Win xp中的多种网络
-试验试验试验试验
-用Freehand实现位图矢量化
-网络电话面面观

关于Plug-In实现的描述
2001-12-12· ·胡朝晖··yesky

上一页  1 2 3  


  四 实现插件的功能

void CMainFrame::OnPluginMenu(UINT nID)
{
int ntheID;
CString strTemp;
CMyStruct* pStru;
//HMODULE pluginModule;

ntheID=nID-IDM_PLUGIN_0;
pStru=m_MapDWordToMyStru[ntheID];
//pluginModule=LoadLibrary(pStru->m_FullDllName);
//if (pluginModule!=NULL)
(*pStru->OperationFunc)(m_hWnd,2,NULL); //在DLL中实现的函数,即EXPORT
//出来的那个函数。
//FreeLibrary(pluginModule);
}

  实际上应该注意到这里我们定义了一个变量为m_MapDWordToMyStru,它是一个映射对象,根据菜单的ID号能够得到相应的插件的信息,而插件相关的信息都包含在MyStru中,MyStru中有一个重要的信息就是插件相关主函数的入口地址,实际上就是一个函数指针,在这里就是OperationFunc,它的类型为如下:

 
typedef UINT (* TYPEOF_PluginFunction)(HWND hWnd,U INT msg, LONG lParam);

  然后就可以定义TYPEOF_PluginFunction OperationFunc;

  接着在插件初始化的时候,通过API函数LoadLibrary把相关的DLL文件载入当前的进程空间中,然后对该指针赋值,如下:

OperationFunc=(TypeOf_PlugFunction )::GetProcAddress(pluginModule,"PluginFunction");

  这里PluginFunction就是EXPORT出来的函数。

  当然在应用程序和DLL中,我们要定义好一个公共的EXPORT函数。DLL实现这个函数相关的功能,而应用程序就调用这个函数,不同的插件(DLL)实现不同的功能。

  好,这里我们不妨设定这个函数为:

UINT PlugInFunction(HWND hWnd, UINT msg, LONG lParam);

  所有的插件必须实现这个EXPORT函数,这里hWnd实际上是应用程序传给DLL的窗口句柄,msg表示消息的类型,用户可以自己定义:比如当应用程序传递1 表示要等到插件的名称,2 表示要得到插件相关的小图标,3表示要执行的相关程序等等。反正你自己看着定义。而最后一个参数lParam是应用程序和DLL之间的信息传送区。C语言癖好者一看都知道,这实际上是传送一个变量的地址,这个变量可以是结构,对象或者是一般的变量,严格的说,只要定义好统一的一个变量,就可以通过这个lParam传递。举个例子表示这个参数是如何传递的。

Typedef struct tagMyStruc
{
 int i;
 char str[100];
 Carray myArray;
}MYSTRUC,*LPMYSTRUC;
 然后是这样的:
LPMYSTRUC myStru;
myStruc =new MYSTRUC;
//对myStru进行实例化,比如对成员变量赋值
PlugInFunc(m_hWnd,TYPE_GETNAME,(LONG)myStruc);
整个结构就传到DLL中去了,DLL如何接受呢。请看:
UINT PlugInFunction(HWND hWnd, UINT msg, LONG lParam);
{
 LPMYSTRUC myStru;
 myStru=(LPMYSTRUC)lParam;
 //这样客户端就收到这个结构,也可以对里面的内容进行赋值
 …….
}

  正所谓条条大路通罗马,我们是否只有这么一个方法来实现插件技术呢,答案当然是否定的,下面介绍另外一种模式。我们可以先定义一个通用的结构,不妨设为PlugInModule,它的数据类型是struct型的,里面包括一些主要的插件相关的参数和可以调用的函数,比如如下面的类型:

typedef struct PlugInModule{
DWORD Ver ; //版本
char *Description; //模块说明
BYTE *InputPointer; //输入数据 [in/out]
DWORD dwSize ; //输入数据的大小[in]
HWND hParentWnd ; //父窗口[in]
HINSTANCE hDllInst ; //Dll句柄 [in]
……. //其他一些属性
void (*PlugIn_Fun1)( PlugInModule * pModule ) ; //函数1
void (*PlugIn_Fun2)( PlugInModule * pModule ) ; //函数2
…….. //其他一些函数
} PlugInModule ;

  这个结构在插件服务器和插件DLL设计中都必须被显式的定义和遵守。

  然后在DLL中代码编写中,需要显示的定义一个全局的PlugInModule的实例,不妨设为showModule,然后对showMoudle中的变量和函数指针赋值。然后我们需要象上面说明的一样,定义一个插件服务器和插件DLL进行交互的函数,不妨还是命名为PlugiInFunction,该函数的定义如下:

typedef PlugInModule* (*PlugInFunction)();
 

  然后该函数返回showModule变量的地址。

  同时需要注意的是,在DLL中要实现在结构PluginModule中定义的所有的函数。

  然后,我们来考虑插件服务器中相关的代码,实际上就是两个部分,装载插件相关的DLL文件,执行插件中的函数(这些函数在结构PlugInModule中已经定义)。

  还是通过全局API函数LoadLibrary来装载插件相关的DLL文件,如下代码:

m_myPlugInst = ::LoadLibrary( lpFilePathName ) ; //这里m_myPlugInst用来表示装载
//DLL对象的模块句柄,
然后通过下面的代码:
m_GetModuleFunction = (TYPEOF_PlugInFunction)::GetProcAddress( m_myPlugInst ,
"PlugInFunction" ) ;
象前面一样,需要定义函数指针TYPEOF_PlugInFunction为如下:
typeof *PlugInModule (*TYPEOF_PlugInFunction)();
然后做这样的定义:TYPEOF_PlugInFunction m_GetModuleFunction
注意该函数返回的是一个指向结构PlugInModule的实例指针,所以用如下的代码:
m_OperPlugInF=m_GetMoudleFunction();
注意这里m_OperPlugInF定义如下:
PlugInModule* m_OperPlugInF;
对结构中的成员赋值:
m_OperPlugInF ->hParentWnd = m_hWnd ; //当前的插件服务器的窗口句柄
m_OperPlugInF ->hDllInst = m_myPlugInst ; //当前的插件实例模块句柄
然后我们需要操作该插件中的函数的话,就可以采用如下的形式:
m_OperPlugInF-> PlugIn_Fun1 (m_OperPlugInF);

  以上就是实现插件的第二种方式。

  当然我只是举几个简单的例子,你完全可以根据自己的需要定义不同的输出函数。不过最好要制定一个规范,写个正式的文档,以后可以让别人按照这个标准为你的应用程序增加插件。

  五 小结

  利用插件技术,我们可以动态的增加应用程序的功能,应用程序不需要重新编译就可以实现新的功能。控制面板的实现和我说的差不多。不过它的后缀用了cpl,应该可以在windows/system目录下看得到。


上一页  1 2 3  

【责任编辑:方舟】
【发表评论】【关闭窗口】
■ 相关内容
 TP监控器:MTS、EJB谁主沉浮
 对象组件技术COM+慨述
 分布式组件对象模型DCOM揭秘
 基于请求代理的中间件模型
感谢 访问天极网,如果您觉得该文章涉及版权问题,请看这里!