| | | 关于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 | | | 感谢
访问天极网,如果您觉得该文章涉及版权问题,请看这里!
|
|