扩展管理器允许可执行的程序库的应用程序注册一个回调例程将被调用之前,之后,进行选择或之前和 Domino或Notes后,内部操作。
这允许C API应用程序执行数据库镜像或添加其他访问控制。
头文件extmgr.h定义了标识受支持的通知事件的名称。
扩展管理器应用程序构建为可执行程序库(例如,用于Windows的动态链接库或用于UNIX环境的共享对象库)。 程序库的结构和命名约定是平台相关的; 有关详细信息,请参阅“平台特定命名约定”一章。
您必须通过添加EXTMGR_ADDINS条目来识别notes.ini文件中扩展的可执行程序库。 在notes.ini中应该只有一个这样的条目; 列出同一条目中的所有扩展程序管理器库,以逗号分隔。 例如,要在Win32系统上运行extmngr和extpwd示例程序,notes.ini中的条目应为:
注册回调函数
注册回调函数以接收通知事件的第一步是调用EMCreateRecursionID以获取递归标识。 虽然此步骤是可选的,但通常需要这样做,因为如果当前线程已经调用了扩展,则阻止Domino或Notes调用该扩展。 例如,如果应用程序期望在NSFDbOpen上获得通知,并且在处理该通知时调用NSFDbOpen,这可以防止无休止的循环。
每个扩展管理器DLL或共享对象只需要一个递归ID。 相同的递归ID适用于进程中的所有线程。 您可以在注册的每个扩展上单独设置,以允许在某些扩展上递归,而不在其他扩展上递归。 您可以在多个扩展程序中使用相同的ID。 你不必记住递归ID,因为所有的检查在Domino或Notes完成,它被释放在关机。
一旦应用程序获得递归ID,则使用所需通知的ID调用EMRegister,标志指示何时调用函数,回调函数的地址和递归ID。 标志值可以是:
在调用EMRegister的入口点例程中,不要对Domino和Notes执行任何C API函数调用(扩展管理器EMxxx函数调用除外)。 扩展管理器DLL或共享对象作为Domino或Notes初始化的一部分加载,并且作为该启动的一部分调用扩展管理器入口点例程。 当调用扩展管理器入口点例程时,Domino或Notes的其他组件的初始化尚未完成。
当应用程序使用Extension Manager完成时,使用EMDeregister删除注册的所有回调函数。 未能注销回调函数可能会导致Domino或Notes崩溃。 不要在EM_TERMINATENSF通知的回调例程中取消注册回调函数。
扩展以每个进程为基础进行注册。 注册扩展后,进程中的所有线程都调用该扩展。 如果使用递归ID,它将应用于该进程中的所有线程。
回调函数
回调函数具有以下声明:
Domino或Notes提供的单个参数是指向EMRECORD结构的指针。 该结构的字段是:
EId是在注册函数时提供的值(或者如果为多个通知注册了相同的函数,则为其中一个值)。 NotificationType通知函数此通知是在尝试操作之前还是在完成操作之后。 如果NotificationType为EM_BEFORE,则状态字段未定义; 如果EM_AFTER,此字段包含操作的返回值。 Ap指向提供给核心函数的参数; 因为从一个函数到另一个函数不同,必须使用通知ID来确定通知的相应函数,以便可以使用global.h中的VARARG_xxx宏正确解释参数。
重要提示:如果通知类型是EM_BEFORE(已执行操作前),输入参数的功能将是有效的。 例如,如果其中一个输入参数是音符句柄,则使用VARARG_xxx解释时,该值将是活动的并有效。 但是,如果通知类型为EM_AFTER(在执行操作之后),则输入参数(例如注释句柄)将不再有效,因为内部Notes处理在操作完成后释放或释放句柄。 处理EMxxx函数调用时请记住这一点。
注释可以以“规范”格式打开。 发生这种情况时,通常转换为主机格式的数据类型字段和数据值保留未转换。 检查注释中数据的扩展管理器回调函数必须通过在尝试解释注释内容之前调用具有头成员_NOTE_FLAGS的NSFNoteGetInfo()来检查标志NOTE_FLAG_CANONICAL。
注意:扩展管理器通知EM_AGENTISENABLED有一个非常不同的标注签名,因为函数返回的不是STATUS。 签名如下:STATUS LNPUBLIC AgentIsEnabled(HAGENT hAgent,BOOL * return_value)
要检索此函数的Core错误代码,请检查* return_value参数,而不是EMRECORD结构的Status变量。
回调返回码
回调函数的返回代码控制Domino或Notes在返回后执行的处理。 了解Domino或Notes用于支持通知的内部操作的步骤很有帮助:
在大多数情况下,使用EM_REG_BEFORE注册的回调函数应返回ERR_EM_CONTINUE,以确保Domino或Notes执行请求的操作。 例外情况指出本章中,并在参考 ,具体回调函数条目下。
编写将非Domino数据库转换为Domino数据库的扩展管理器。
在扩展管理器Sample \ misc \ extmngr中,当对样本数据库“animals.nsf”捕获EM_NSFCREATEDB和EM_NSFCLOSEDB通知时,非Domino数据库将转换为Domino数据库。 此示例演示了在捕获特定通知时使用Extension Manager执行复杂数据库操作。
当用户创建一个名为“animals”的新数据库时,扩展管理器会捕获EM_NSFCREATEDB和EM_NSFCLOSEDB通知。 在关闭数据库并捕获EM_NSFCLOSEDB通知之前,程序会创建Domino数据库“animals.nsf”所需的表单,视图和文档,以反映非Domino数据库“animals.db”中包含的数据。
其他数据库操作可以由扩展管理器通过在完成之前或之后以及之前和之后捕获特定通知来处理。 有关支持的Extension Manager通知的列表,请参阅头文件“extmgr.h”。
捕获Domino或Notes密码提示请求
使用Extension Manager可以捕获的操作之一是Domino或Notes密码提示请求。 扩展ID代码为EM_GETPASSWORD。 此操作没有相应的API函数。 头文件extmgr.h记录了get password操作的参数。
示例程序misc \ extpwd使用扩展管理器捕获密码提示请求。 为了简单起见,程序显示一个对话框以获取密码。 然而,这不是必要的; 所有Domino或Notes需要的是将密码的字符写入请求中提供的地址。
仅在尝试操作之前调用EM_GETPASSWORD请求的扩展管理器挂接。 使用EM_REG_AFTER标志注册回调函数不起作用。
EM_GETPASSWORD请求使用以下特殊状态代码来指示Domino或Notes操作的状态:
更可能的攻击是提供一个扩展,提示用户输入密码,然后将密码提供给Domino或Notes,并将密码存储在不安全的位置。 用户应该注意,除Domino或Notes密码对话框提示以外的用户界面可能不安全; 系统管理员和应用程序开发人员必须实现流程,以确保用户密码不会以这种方式受到损害。
另一个风险来自为合法目的存储密码的应用程序。 例如,如果密码存储在磁盘文件中,则知道该事实的不道德的个人可以从该文件获得密码。 如果可能,应用程序不应该将密码存储在未经授权的人可以获取密码的任何地方。
捕获Domino或Notes复制冲突通知
通过捕获复制冲突通知,您可以让扩展管理器自动处理复制冲突。 扩展ID代码为EM_NSFCONFLICTHANDLER。 此操作没有相应的API函数。 头文件extmgr.h将参数记录到复制冲突处理程序。
Notes C API 4.5版引入了几个新功能,扩展管理器可以使用这些功能来确定如何处理复制冲突。 这些功能包括:
如果希望Domino或Notes处理复制冲突,请传回ERR_EM_CONTINUE。 例如,如果复制冲突处理程序中发生错误,您可能希望自己中止处理该冲突,并将ERR_EM_CONTINUE传回Domino或Notes。
复制冲突处理程序需要安装在可能涉及复制和后续冲突解决的每个Domino或Notes安装上。 Domino或Notes调用失去复制冲突的安装上的扩展管理器复制冲突处理程序(如果有)。
示例程序misc \ extconf演示了处理复制冲突的扩展管理器。
编写扩展管理器以处理发出的邮件
扩展程序管理器通知(EM_MAILSENDNOTE)可用于处理发出的邮件。 示例程序\ mail \ extmail演示了如何拦截某些传出的邮件。 如果通知类型为EM_BEFORE,并且邮件消息的主题文本为“Extension Manager”,则Extension Manager会修改邮件正文文本,通知用户邮件已被拦截。 如果通知类型为EM_AFTER,则扩展管理器创建包含用户邮件信息的新邮件消息,附加扩展管理器日志文件,并将消息发送到发出邮件消息的发起者。
扩展管理器限制
扩展管理器应用程序构建为可执行程序库(例如,用于Windows的动态链接库或用于UNIX环境的共享对象库)。 程序库的结构和命名约定是平台相关的; 有关详细信息,请参阅“平台特定命名约定”一章。
您必须通过添加EXTMGR_ADDINS条目来识别notes.ini文件中扩展的可执行程序库。 在notes.ini中应该只有一个这样的条目; 列出同一条目中的所有扩展程序管理器库,以逗号分隔。 例如,要在Win32系统上运行extmngr和extpwd示例程序,notes.ini中的条目应为:
- EXTMGR_ADDINS = nextmngr.dll,nextpwd.dll
注册回调函数
注册回调函数以接收通知事件的第一步是调用EMCreateRecursionID以获取递归标识。 虽然此步骤是可选的,但通常需要这样做,因为如果当前线程已经调用了扩展,则阻止Domino或Notes调用该扩展。 例如,如果应用程序期望在NSFDbOpen上获得通知,并且在处理该通知时调用NSFDbOpen,这可以防止无休止的循环。
每个扩展管理器DLL或共享对象只需要一个递归ID。 相同的递归ID适用于进程中的所有线程。 您可以在注册的每个扩展上单独设置,以允许在某些扩展上递归,而不在其他扩展上递归。 您可以在多个扩展程序中使用相同的ID。 你不必记住递归ID,因为所有的检查在Domino或Notes完成,它被释放在关机。
一旦应用程序获得递归ID,则使用所需通知的ID调用EMRegister,标志指示何时调用函数,回调函数的地址和递归ID。 标志值可以是:
- EM_REG_BEFORE - 在尝试操作之前调用例程
EM_REG_AFTER - 操作完成后调用例程
Both - 在尝试操作之前调用例程,在操作完成后再次调用
在调用EMRegister的入口点例程中,不要对Domino和Notes执行任何C API函数调用(扩展管理器EMxxx函数调用除外)。 扩展管理器DLL或共享对象作为Domino或Notes初始化的一部分加载,并且作为该启动的一部分调用扩展管理器入口点例程。 当调用扩展管理器入口点例程时,Domino或Notes的其他组件的初始化尚未完成。
当应用程序使用Extension Manager完成时,使用EMDeregister删除注册的所有回调函数。 未能注销回调函数可能会导致Domino或Notes崩溃。 不要在EM_TERMINATENSF通知的回调例程中取消注册回调函数。
扩展以每个进程为基础进行注册。 注册扩展后,进程中的所有线程都调用该扩展。 如果使用递归ID,它将应用于该进程中的所有线程。
回调函数
回调函数具有以下声明:
- STATUS LNCALLBACK ExtMgrCallback(EMRECORD far * pExtRec);
Domino或Notes提供的单个参数是指向EMRECORD结构的指针。 该结构的字段是:
- EId通知ID
NotificationType EM_BEFORE或EM_AFTER
状态核心错误代码
Ap指向提供给Domino或Notes核心函数的参数的指针
EId是在注册函数时提供的值(或者如果为多个通知注册了相同的函数,则为其中一个值)。 NotificationType通知函数此通知是在尝试操作之前还是在完成操作之后。 如果NotificationType为EM_BEFORE,则状态字段未定义; 如果EM_AFTER,此字段包含操作的返回值。 Ap指向提供给核心函数的参数; 因为从一个函数到另一个函数不同,必须使用通知ID来确定通知的相应函数,以便可以使用global.h中的VARARG_xxx宏正确解释参数。
重要提示:如果通知类型是EM_BEFORE(已执行操作前),输入参数的功能将是有效的。 例如,如果其中一个输入参数是音符句柄,则使用VARARG_xxx解释时,该值将是活动的并有效。 但是,如果通知类型为EM_AFTER(在执行操作之后),则输入参数(例如注释句柄)将不再有效,因为内部Notes处理在操作完成后释放或释放句柄。 处理EMxxx函数调用时请记住这一点。
注释可以以“规范”格式打开。 发生这种情况时,通常转换为主机格式的数据类型字段和数据值保留未转换。 检查注释中数据的扩展管理器回调函数必须通过在尝试解释注释内容之前调用具有头成员_NOTE_FLAGS的NSFNoteGetInfo()来检查标志NOTE_FLAG_CANONICAL。
注意:扩展管理器通知EM_AGENTISENABLED有一个非常不同的标注签名,因为函数返回的不是STATUS。 签名如下:STATUS LNPUBLIC AgentIsEnabled(HAGENT hAgent,BOOL * return_value)
要检索此函数的Core错误代码,请检查* return_value参数,而不是EMRECORD结构的Status变量。
回调返回码
回调函数的返回代码控制Domino或Notes在返回后执行的处理。 了解Domino或Notes用于支持通知的内部操作的步骤很有帮助:
- Domino或Notes调用使用EM_REG_BEFORE注册的任何函数。 如果任何函数返回非ERR_EM_CONTINUE以外的值,Domino或Notes不会调用任何后续函数,也不会执行该操作。
- Domino或Notes执行操作。
- Domino或Notes调用使用EM_REG_AFTER注册的任何函数。 如果任何函数返回非ERR_EM_CONTINUE以外的值,Domino或Notes不会调用任何后续函数,并返回该值作为操作的结果(内部或调用操作的API应用程序)。
在大多数情况下,使用EM_REG_BEFORE注册的回调函数应返回ERR_EM_CONTINUE,以确保Domino或Notes执行请求的操作。 例外情况指出本章中,并在参考 ,具体回调函数条目下。
编写将非Domino数据库转换为Domino数据库的扩展管理器。
在扩展管理器Sample \ misc \ extmngr中,当对样本数据库“animals.nsf”捕获EM_NSFCREATEDB和EM_NSFCLOSEDB通知时,非Domino数据库将转换为Domino数据库。 此示例演示了在捕获特定通知时使用Extension Manager执行复杂数据库操作。
当用户创建一个名为“animals”的新数据库时,扩展管理器会捕获EM_NSFCREATEDB和EM_NSFCLOSEDB通知。 在关闭数据库并捕获EM_NSFCLOSEDB通知之前,程序会创建Domino数据库“animals.nsf”所需的表单,视图和文档,以反映非Domino数据库“animals.db”中包含的数据。
其他数据库操作可以由扩展管理器通过在完成之前或之后以及之前和之后捕获特定通知来处理。 有关支持的Extension Manager通知的列表,请参阅头文件“extmgr.h”。
捕获Domino或Notes密码提示请求
使用Extension Manager可以捕获的操作之一是Domino或Notes密码提示请求。 扩展ID代码为EM_GETPASSWORD。 此操作没有相应的API函数。 头文件extmgr.h记录了get password操作的参数。
示例程序misc \ extpwd使用扩展管理器捕获密码提示请求。 为了简单起见,程序显示一个对话框以获取密码。 然而,这不是必要的; 所有Domino或Notes需要的是将密码的字符写入请求中提供的地址。
仅在尝试操作之前调用EM_GETPASSWORD请求的扩展管理器挂接。 使用EM_REG_AFTER标志注册回调函数不起作用。
EM_GETPASSWORD请求使用以下特殊状态代码来指示Domino或Notes操作的状态:
- ERR_BSAFE_EXTERNAL_PASSWORD
密码由外部源提供。 (扩展管理器挂钩被视为外部源。)此状态代码必须通过提供密码的扩展管理器挂钩返回到Domino或Notes。
- ERR_BSAFE_USER_ABORT
密码请求已取消。 这对应于用户在Notes密码对话框中单击取消。
- ERR_EM_CONTINUE
Domino或Notes执行常规处理(即,显示密码对话框提示)。
- ERR_BSAFE_EXTERNAL_PASSWORD
更可能的攻击是提供一个扩展,提示用户输入密码,然后将密码提供给Domino或Notes,并将密码存储在不安全的位置。 用户应该注意,除Domino或Notes密码对话框提示以外的用户界面可能不安全; 系统管理员和应用程序开发人员必须实现流程,以确保用户密码不会以这种方式受到损害。
另一个风险来自为合法目的存储密码的应用程序。 例如,如果密码存储在磁盘文件中,则知道该事实的不道德的个人可以从该文件获得密码。 如果可能,应用程序不应该将密码存储在未经授权的人可以获取密码的任何地方。
捕获Domino或Notes复制冲突通知
通过捕获复制冲突通知,您可以让扩展管理器自动处理复制冲突。 扩展ID代码为EM_NSFCONFLICTHANDLER。 此操作没有相应的API函数。 头文件extmgr.h将参数记录到复制冲突处理程序。
Notes C API 4.5版引入了几个新功能,扩展管理器可以使用这些功能来确定如何处理复制冲突。 这些功能包括:
- NSFNoteFindMatchingItem在一个笔记中查找与另一个笔记中的相同项匹配的项。
NSFNoteFindDivergenceTime当两个音符最后同步时查找。
NSFItemGetModifiedTime获取项目的最后修改时间。
NSFItemGetModifiedTimeByBLOCKID获取项目的最后修改时间,给定项目的BLOCKID。
- NSFNoteFindMatchingItem在一个笔记中查找与另一个笔记中的相同项匹配的项。
如果希望Domino或Notes处理复制冲突,请传回ERR_EM_CONTINUE。 例如,如果复制冲突处理程序中发生错误,您可能希望自己中止处理该冲突,并将ERR_EM_CONTINUE传回Domino或Notes。
复制冲突处理程序需要安装在可能涉及复制和后续冲突解决的每个Domino或Notes安装上。 Domino或Notes调用失去复制冲突的安装上的扩展管理器复制冲突处理程序(如果有)。
示例程序misc \ extconf演示了处理复制冲突的扩展管理器。
编写扩展管理器以处理发出的邮件
扩展程序管理器通知(EM_MAILSENDNOTE)可用于处理发出的邮件。 示例程序\ mail \ extmail演示了如何拦截某些传出的邮件。 如果通知类型为EM_BEFORE,并且邮件消息的主题文本为“Extension Manager”,则Extension Manager会修改邮件正文文本,通知用户邮件已被拦截。 如果通知类型为EM_AFTER,则扩展管理器创建包含用户邮件信息的新邮件消息,附加扩展管理器日志文件,并将消息发送到发出邮件消息的发起者。
扩展管理器限制
- 在调用EMRegister的入口点例程中,不要对Domino和Notes执行任何C API函数调用(扩展管理器EMxxx函数调用除外)。 Domino或Notes的其他组件的初始化目前尚未完成。
- 所有Domino和Notes应用程序激活notes.ini文件中指定的扩展管理器。 在扩展管理器的入口点,您只能通过在调用EMRegister之前检查调用应用程序的名称来注册Notes客户端的扩展管理器。 例如,对于Windows 32位应用程序,如果调用的应用程序的名称不是nnotes.dll,则不要调用EMRegister。
- 不要在EM_TERMINATENSF通知的回调例程中取消注册回调函数。
- 不要调用在扩展管理器中需要回调函数的C API函数(例如NSFItemScan)。
- 请小心处理mail.box文件中的邮件。 如果您拦截EM_NSFNOTEOPEN通知以更改影响邮件路由的文档(例如,更改发送到字段以重定向邮件),则可能无法获得所需的结果。 在这一点上,路由器可能已经包含关于消息的状态信息,并且可以将消息递送到原始接收者。
- 有一个报告异常,当捕获EM_NSFNOTECLOSE,然后使用关联的对象句柄时,Notes返回了一个“超出范围的句柄”错误。 这是一个罕见的情况,并且由于Notes在实际释放它之前内部丢弃对象。 为了防止发生此错误,建议您通过调用OSLockObject()来测试句柄的有效性。 如果调用返回NULLHANDLE,不要在任何进一步处理中使用句柄。
- 从R5.0开始,Extension Manager例程中的printf的输出被缓冲。 要查看输出,你可以使用fflush函数刷新缓冲区,或者使用AddInLogErrorText函数。
- 请注意,当相应的数据库信号量被锁定时,可以调用Extension Manager回调例程。 在这种情况下,您不能调用需要获取数据库信号量的C API例程,否则将发生死锁。 例如,您不能在捕获EM_NSFMARKREAD的例程中调用NSFDbGetUnreadNoteTable。 类似地,您不能在捕获具有相同文件夹ID的EM_NSFADDTOFOLDER的例程中调用NSFFolderGetIDTable。
-------------------------------------------------- -------------------------------------------------- ------