标题：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程序结构示例*/
/*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); }
工程实例
接下来，将介绍 Extension Manager 的一个工程实例，并希冀由这个工程实例对 Lotus C API 应用程序开发者在使用 Extension Manager 实现定制应用程序时给予一定的启发和指导。1）工程背景某客户为了加强内部办公环境的管理，需要强制用户加入 Windows 特定域。客户希望采取绑定邮件系统访问的方式：即限制用户只有登录 Windows 域后才可以访问邮件系统。2）工程设计为实现客户需求，我们可以设想在客户端部署一个 EM 程序。该客户端 EM 程序注册 EM_GETPASSWORD 事件，在Notes弹出密码输入对话框之前判断当前 Windows 用户是否在域中，如果不在域中就返回 ERR_BSAFE_USER_ABORT，这样可以阻止 Notes 客户端连接 Domino Server。程序片断请参考 Extension Manager 程序结构示例。
一切进行的很顺利，似乎工作到此已经万事大吉了。然而且慢，如果仔细考虑一下，这种方案是不可取的，如果客户端不安装这个EM程序怎么办？或者如果用户卸载这个 EM 程序的话怎么办？这样的话客户端完全可以绕开认证过程。
所以我们必须考虑在服务器端进行统一的控制，这就需要在服务器端也部署一个 EM 程序。该服务器 EM 程序注册 EM_SECAUTHENTICATION 事件，对每位向邮件服务器发送访问请求的用户进行实时授权鉴别，只有在客户端登录 Windows 域的情况下，服务器端 EM 进程才开启该用户访问邮件服务器的限制。
现在的问题是服务器端 EM 程序如何鉴别来访客户端是否在 Windows 域中？答案是 Socket 通信方法：客户端 EM 程序在经过相关判断之后，把 Notes 用户的信息写入到安装 Domino Server 的服务器的某个文件（如Info.DAT）中，服务器端 EM 程序在认证来访 Notes 用户的时候查询该文件，如果发现来访 Notes 用户信息在 Info.DAT 文件中存在，则授权该用户访问邮件服务器，否则则拒绝其访问。3）模块设计与实现系统分为三个组件，分别是：Notes 、客户端和EM 组件。
Notes 客户端 EM 组件  
功能说明：负责判断当前 Notes 用户的 Windows 域信息，并把相关信息发送给通信服务器，在接收到通信服务器的确认信息之后，更新登陆时间窗信息。（时间窗是一个时间段，某 Notes 客户端在域中登陆 Domino Server 之后，允许在时间窗内该 Notes 客户端不登陆域也能访问邮件服务器）
算法如下：
I. 捕获 EM_GETPASSWORD 消息
II. 读取注册表的内容，取得当前时间跟注册表中上一次登记的时间做比较，判断时间窗是否过期。
III. 如果时间窗未过期，即该 Notes 客户端已经在指定时间段内向 Server 注册过了，则直接返回 ERR_EM_CONTINUE. 把控制权交给 Notes，允许其连接邮件服务器。
IV. 如果时间窗过期，判断当前 Windows 用户否在域中，如果在域中，从注册表中读取通信服务器的 IP 和端口,把 Notes User 的信息发送过去，然后等待 Server 的响应。如果收到 Server 的响应，那么更新注册表中日期表项
V. 如果当前 Windows 用户不在域中，说明在时间窗之内没有人在域中登陆过 Domino Server，返回 ERR_BSAFE_USER_ABORT 阻止 Notes 连接邮件服务器。
Domino 服务器端 EM 组件
功能说明：捕获当前试图连接自己的 Notes 用户，读取用户信息文件，判断该当前用户是否为合法用户，从而决定是否授权该用户访问邮件服务器。
算法如下：
I. 注册 EM_SECAUTHENTION 事件
II. 在事件发生时获取当前申请连接的用户名字
III. 查询用户信息文件，若有跟当前用户匹配的信息，说明该用户是合法用户，返回 ERR_EM_CONTINUE 将控制权交给 Domino Server。否则，返回 ERR_SECURE_FAILED_AUTH，拒绝该用户的连接请求。
通信服务器程序
功能说明：负责读取所有客户端发送给自己的用户名信息，保存在用户信息文件中。以备 Domino Server 侧的 EM 程序访问。
该通信服务器是一个多线程并发程序，具备了四个模块，分别是：
a) 处理服务器模块
功能说明：负责整个通信服务器程序的启动和中止，并记录整个系统的 Log 信息
b) 消息件模块
功能说明：该模块由处理服务器模块启动，在启动的时候启动了三个线程，分别是：
接收消息线程：该线程启动通信模块，并等待通信模块的消息，如果通信模块通知该线程有消息到达，那么去获得该消息并写入接收消息队列里面
处理消息线程：该线程实时监测接收消息队列里面是否有数据，如果有数据，那么取出该数据，并写入用户信息文件里面，写入成功后，发送一个 UDP 消息到发送消息队列里面，UDP 消息包括某个客户端的 IP，端口以及确认消息。其定义为： struct UDPDATA{ unsigned longulIPAddr; unsigned short wPort; stringsData; }; 
发送消息线程：该线程实时监测发送消息队列里面是否有数据，如果有数据那么取出来进行分析，获得 IP 和端口，然后通过通信模块把数据发送出去。
c) 通信模块
功能说明：该模块封装了 Socket 通信的 API，完成网络通信功能。
d) 消息队列模块
功能说明：该模块实现了 Message Queue 的功能，是一个双向链表。目的是为了数据的缓存，防止用户数据丢失的可能性。系统有两个消息队列，一个是接收消息队列，负责保存接收的消息；另外一个是发送消息队列，负责保存发送的消息。
与Adobe Bridge ,Device Central区别
Adobe Bridge CS4是一款功能强大、易于使用的媒体管理器, 它可以让您轻松地管理、浏览、定位和查看创作资源。Adobe Creative Suite® 4 软件的所有六个版本以及大多数 Adobe 的专业创作应用程序中都包含 Bridge, 它提供了对项目文件和全局设置的集中访问以及 XMP 元数据的标记和搜索能力。我个人认为：简单的来讲他就是个图片查看器。
Adobe Device Central CS4 软件为手机和消费电子设备简化了创新、引人注目的内容的制作。通过测试自动化以及跨动态更新的设备配置文件库模拟移动内容的网络性能来节省时间。创建移动项目, 从一个中心位置管理资源、瞄准设备配置文件并导出选项。在播放内容时记录它, 并发送高品质的影片剪辑, 更轻松地向客户传达构思。与 Adobe Creative Suite® 4 组件智能集成, Adobe Device Central CS4 可以帮助创意专业人士和移动开发人员向无数移动订户交付引人入胜的体验。
Adobe Extension Manager CS4使您能够轻松地安装、管理和删除功能扩展。