【IT168技术文档】
Extension Manager基本概念:什么是 Extension Manager
Extension Manager 是 Lotus C API 提供的一个功能非常强大的设计机制,它允许应用程序设计者向 Notes/Domino 系统注册自己感兴趣的事件,例如:EM_NSFDBCLOSESESSION、EM_NSFDBCLOSE 等。从而在 Notes/Domino 进行内核操作之前(或者之后,取决于在事件注册中使用的是 EM_REG_BEFORE 还是 EM_REG_AFTER)来运行自己设计的特制插件程序。
Extension Manager程序设计规范
Extension Manager 插件程序的设计框架要符合一定的规则,这样才能被 Notes/Domino 系统在合适的时机调用。关于Extension Manager 的详细设计方法,请参考随 Lotus C API 一起发布的设计文档,基本上来讲,一个具备基本功能的 Extension Manager 插件程序应该具备以下几个要素:
1)DLL 入口函数:
Extension Manager 插件程序必须被编译为可执行的程序库(例如,Windows 系统的动态链接库 dll 或者是 UNIX 系统的 shared object)。程序库的结构和命名规则是跟平台相关的,详细信息请参考 Lotus C API 用户手册第十二章第二节:"Platform-Specific Naming Conventions" 。在 DLL 入口函数中,应当完成插件程序实例的创建和释放,并且负责在插件程序退出之前,注销向 Notes/Domino 系统注册的 EM_XX 事件。
2)插件程序入口函数:
该函数是定制插件程序的入口函数,EM事件的注册过程将会在此函数中加以实现。该函数声明格式如下所示
STATUS LNPUBLIC MainEntryPoint (void);
该入口函数的名字可任意给定,但是必须在模块定义文件(.def文件)中将其声明为导出函数(EXPORTS function),并且导出序号为1。
例子:
LIBRARY nextmngr INITINSTANCE EXPORTS MainEntryPoint@1
在注册回掉函数之前,推荐使用 EMCreateRecursionID() 函数,这样可以防止一个插件程序被多次调用。
插件程序回调函数 :该函数是 Extension Manager 插件程序的业务处理函数,负责在收到注册事件通知后进行定制处理。
Extension Manager 程序运行条件
要想运行一个定制的 Extension Manager 程序,需要做两件事情:
- 将编译成功的 DLL 文件放在 Notes/Domino 的主目录下
- 修改 notes.ini 文件,增加一个变量如下所示
EXTMGR_ADDINS=NEXTMNGR
如果有多个插件程序,在插件程序名之间用逗号格开。如果多个插件程序注册了同一个事件,则按照 notes.ini 文件中的插件程序的注册顺序来依次进行处理。
在了解了以上基础知识之后,我们将以 Windows 平台为例,给出一个简单而典型的 Extension Manager程序结构,本示例程序只是用来说明 Extension Manager 的程序架构和处理逻辑,不能编译运行,具体的 Extension Manager 示例程序,请参考随 Lotus C API 一起发布的 Sample。
Extension Manager程序结构示例
/* Extension Manager程序结构示例*/ /*system header file*/ #include <stdlib.h> …… /*Notes Domino Header File*/ #include <global.h> …… /*========================== GLOBAL VARIABLES ==============================*/ HEMREGISTRATION hHandler; //插件程序上下文句柄 EMHANDLER gHandlerProc; //插件程序回调函数句柄 WORD gRecursionID; //防止该程序被多次调用 CRITICAL_SECTION gCriticalSection; // 用于多线程同步 /*================== LOCAL FUNCTION PROTOTYES ===============================*/ STATUS LNPUBLIC MainEntryPoint( void ); //插件程序入口函数 STATUS LNPUBLIC EMHandlerProc( EMRECORD FAR * pExRecord); // 插件程序回调函数 BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD fdwReason, LPVOID lpReserved ); // DLL入口函数 /*===========================================================================*/ STATUS LNPUBLIC MainEntryPoint( void ) { STATUS error= NOERROR; error = EMCreateRecursionID( &gRecursionID ); error = EMRegister(EM_GETPASSWORD, EM_REG_BEFORE | EM_REG_AFTER,(EMHANDLER)gHandlerProc, gRecursionID, &hHandler); return( error ); } /*==========================================================================*/ STATUS LNPUBLIC EMHandlerProc( EMRECORD FAR * pExRecord ) { STATUS error = 0; switch(pExRecord->EId) { case EM_GETPASSWORD: { return(ERR_BSAFE_USER_ABORT ); } return error; } /*============================================================================*/ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD fdwReason, LPVOID lpReserved ) { STATUS error=NOERROR; switch(fdwReason) { case DLL_PROCESS_ATTACH: InitializeCriticalSection(&gCriticalSection); gHandlerProc = (EMHANDLER)MakeProcInstance((FARPROC)EMHandlerProc, hInstance); break; case DLL_PROCESS_DETACH: error = EMDeregister(hHandler); FreeProcInstance( gHandlerProc ); DeleteCriticalSection(&gCriticalSection); break; } return( TRUE ); UNREFERENCED_PARAMETER(lpReserved); }