标签存档: lotusscript

在 NSD 中查看 LotusScript 的调用堆栈

通过添加以下 Notes.ini 参数,可以抓取 LotusScript 的调用堆栈,帮助我们分析宕机等问题:

DEBUG_LS_DUMP=1

结果格式如下:

LotusScript Call Stack
<@@ ------ LotusScript Interpreter -> Call Stack for [ nlnotes:  0ef8:  1494]  (Time 10:38:14) ------ @@>

[3] COUNTVIEWS
[2] GETDBINFO @ line number 7
[1] COUNTDOCUMENTS @ line number 12
[0] INITIALIZE @ line number 2

请参考:Examining LotusScript call stack after a crash or hang with NSD

针对分类视图查询数据

在 Domino 应用开发中,有很多方法可以对数据进行查询。@dblookup 和 NotesView.getAllDocumentsByKey 利用了预先建好的视图索引,所以在各种查询数据的方法中,它们的性能是最出色的,也是我们最常用的。

最近在工作中遇到了一个于此相关的问题,请大家也注意:如果查询的视图具有多层分类,那么 @dblookup 和 getAllDocumentsByKey 只能返回第一个子分类下的结果。以如下数据为例:

分类1
  分类1.1
    文档1.1.1
  分类2.2
    文档1.1.2
分类2

如果以“分类1”作为查询条件,则只有“文档1.1.1”会返回,同样符合条件的“文档1.1.2”则丢失。

请参考:Troubleshooting @DbLookup, @DbColumn, GetAllDocumentsByKey

Domino 环境中的字符编码

大概在很早之前,我就知道在域中一个中文字符占三个字节,但是不知道其中的细节。最近在处理一个关于域内容超限的问题的时候,研究了一下字符编码,终于明白其中的原因。

在 Domino 环境下开发时,我们接触的字符编码主要有三种:

  • UTF-16:LotusScript 内部的字符编码,中文和英文都占两字节。
  • LMBCS(Lotus Multibyte Character Set):存到文档域中的值以及公式等使用,中文占三字节,英文占一字节。这是在 Unicode 标准推出之前,Lotus 为了解决多语言问题自己使用的编码方式。
  • 操作系统的编码方式:我们的 Domino 一般都跑在 GB2312 环境下,中文占两字节,英文占一字节。

UTF-16 和 GB2312 就不多说了,网上介绍的文章非常多。这里着重说明一下 LMBCS。

LMBCS 为了解决多语言问题,将字符分成了若干个组并将其分别编号,从 0×01 到 0x1F,其中 0×01 为 Latin-1(每个文字一字节),0×13 为简体中文(每个文字两字节)。然后每个字符都以自己的组编号开头,这样就实现了在一个字符串里面包含多种语言。例如“中文Test”以如下几个字节表示:

13 d6 d0 13 ce c4 01 74 01 65 01 73 01 74

其中加粗的部分为组编号。很明显这种访问有个很大的问题:每个字符都要标识其组编号,大大的浪费了空间。所以有了改良方案:每个程序(application file)有个默认的组编号,如果一个字符的组编号和默认的相同,则可以忽略不写(我没有找到设置这个组编号的方法,测试过程中它总是 0×01)。于是在默认组编号为 0×01 的情况下,上面的内容变成了这样:

13 d6 d0 13 ce c4 74 65 73 74

这样就有了中文占三字节,英文占一字节的结论。有了上面的背景知识,我们可以得到以下结果:

  • Len(“中文Test”) = 6,6 个字符
  • Lenb(“中文Test”) = 12,在 LotusScript 中占用 6×2 个字节
  • Lenbp(“中文Test”) = 8,按照操作系统的字符编码,占用 2×2+4 个字节
  • 值为”中文Test”的域大小为 10 (2×3+4)字节

顺便一提,由于 LotusScript 采用的编码与 Domino 环境中其他地方不同,所以每次读写域值、print 语句都会进行转换,所以减少这种转换可以提升性能。比如:

for i=1 to 100
    print i
next i

进行了 100 此编码转换,而

strTemp = ""
for i=1 to 100
    i = strTemp & i
next i
print strTemp

只进行了一次转换,所以性能上会有优势。

请参考:Computing Strings @Length

通过Lotusscript修改数据库主模板属性

上次我们提到有很多数据库属性,是存储在 Database Icon 文档 $Flags 域里面的。最近有同事问我能否修改数据库的主模板的属性,我们翻翻之前的 Flag 列表,好像没有哦。实际上 Database Icon 文档中还有一些其他的域,存储了数据库另外的属性。这次我们就来看看 $Title 域。

从名字上看,$Title 应该保存了数据库的标题。没错,标题确实是存在这个域里面的。不过呢,这里还放了一些其他的信息,包括数据库类别、主模板的属性、继承设计自哪个模板。所以我们通过修改这个域,就可以实现控制上述的四个属性了。数据具体的存储方式如下:

标题n类别n#1主模板名n#2继承的模板名

我们可以看到,系统是用“n”(也就是10号字符)来分隔各个部分的, 我们只要照着样子写回去就好了。但是在实验中我发现,如果用LS的 chr(10) 的话,保存后会变成另外的字符,而不是“n”。原因可能是由于 LS 的 Unicode 编码和 Notes 的 LMBCS 转化造成的。所以我们改用公式语言的 @Char(10) 就可以了。最后要说明的是,以上四部分信息没有的部分直接略过就可以了。下面部分代码仅供参考:

Set doc = db.GetDocumentByID(“FFFF0010″) ‘获得 DB Icon 文档
sTitle = |”title” +@char(10) + “#1| + strtemplatename + |” | ‘标题和模板信息
r = Evaluate(|@SetField( “$TITLE” ; | & sTitle & | )|,doc) ‘写入 $Title 域
Call doc.Save(True,True)

通过LotusScript编程修改数据库的属性

上一次我们提到,Database icon 文档里面包含很多数据库属性信息。实际上它们都保存在 $Flags 域中,而这个域中每个字符都代表一个属性,列表如下(来源于 Notes C API 中的 stdnames.h 文件):

Flag = Meaning / Action
4 = Allow Soft Deletes
Z = Enable LZ1 Compression
f = Do Not Allow Stored Forms
z = Do Not Maintain Unread Marks
h = Mark Parent Document on Reply or Forward
J = Use JavaScript when generating Web Pages
F = Launch Designated Frameset
n = Never Show Policy (ie. Never show About Database when first opened)
7 = Large UNK Table (ie. allow more fields in database)
6 = Allow Design Locking
K = Restore as lasted viewed by user
c = Show About Database if Modified
Q = Replicate Unread Marks to Clustered Servers Only
U = Replicate Unread Marks to All Servers (appears with Q set)
2 = Optimise Document Table Bitmap
3 = Maintain LastAccessed Property
1 = Don’t Support Specialised Response Hierarchy
M = Multilingual Database
X = Web Access Requires SSL Connection
8 = Web Access Don’t Allow URL Open
i = Display Images After Loading
5 = Allow Document Locking
g = Database Type = Library
j = Database Type = Personal Journal
b = Database Type = Domino Directory
B = Database Type = Directory Catalog
m = Database Type = Multi DB Search
u = Database Type = Portfolio
A = Database Type = Mailbox
r = Database Type = Mailfile
p = Always Show About Database Document (ie. When Opened in the Client Property)
l = Launch Designated Navigator
s = Launch Designated Navigator in Own Window (used in conjuction with l above)
a = Launch First Attachment in About Database Document
d = Launch First DocLink in About Database Document
P = Web Launch = Show About Database Document
S = Web Launch = Open Designated Frameset
E = Web Launch = Open Designated Page
L = Web Launch = Open Designated Navigator in its Own Window
D = Web Launch = Open First DocLink in About Database Document
T = Web Launch = Open Designated DocLink
V = Web Launch = Open First Document in Designated View

通过向这个域中增加(或除去)字符标记,即可设置(或取消)相应的属性。下面是一段具体的代码:

Set doc = db.GetDocumentByID(“FFFF0010″) ‘获得 Icon 文档
doc.~$Flags = doc.~$Flags(0) & “x” ‘x代表需要增加的属性
doc.Save (True, False)

获得数据库中的特殊设计元素

数据库中的一些特殊元素,他们有着固定的 Note ID。如下表:

Note ID Database Element
FFFF0002 “About This Database” document
FFFF0004 Default form
FFFF0008 Default view
FFFF0010 Database icon
FFFF0020 Database Design Collection (view)
FFFF0040 Database ACL
FFFF0100 “Using This Database” document
FFFF0800 Replication Formul

比如通过 db.GetDocumentByID(“FFFF0010″) 即可获得 Database icon 文档。而这个文档中保存了很多数据库属性信息,也就是说我们可以通过编程来修改这些数据库属性。是不是有点意思了呢?

请参考 Getting Default Elements in the Database

创建显示特殊文档的视图:$FormulaClass的奥秘

一般情况下,视图都是用来显示文档的。实际上通过更改视图 $FormulaClass 的值,我们可以让它显示其他的内容。参照下表:

Note Class Type Hex Value Decimal Value Comments
NOTE_CLASS_DOCUMENT 0×0001 1 document note
NOTE_CLASS_INFO 0×0002 2 notefile info (help-about) note
NOTE_CLASS_FORM 0×0004 4 form note
NOTE_CLASS_VIEW 0×0008 8 view note
NOTE_CLASS_ICON 0×0010 16 icon note
NOTE_CLASS_DESIGN 0×0020 32 design note collection
NOTE_CLASS_ACL 0×0040 64 acl note
NOTE_CLASS_HELP_INDEX 0×0080 128 Notes product help index note
NOTE_CLASS_HELP 0×0100 256 designer’s help note
NOTE_CLASS_FILTER 0×0200 512 filter note
NOTE_CLASS_FIELD 0×0400 1024 field note
NOTE_CLASS_REPLFORMULA 0×0800 2048 replication formula
NOTE_CLASS_PRIVATE 0×1000 4096 Private design note, use $PrivateDesign view to locate/classify
NOTE_CLASS_DEFAULT 0×8000 32,768 MODIFIER – default version of each
NOTE_CLASS_ALL 0x7fff 32,767 all note types
NOTE_CLASS_ALLNONDATA 0x7ffe 32,766 all non-data notes
NOTE_CLASS_NONE 0×0000 0 no notes

比如我们一般的视图,$FormulaClass 的值为1,所以显示一般文档 ;如果是4,则显示所有表单设计元素(实际上,每个设计元素都可以说是一种特殊的文档)。另外还可以这样用:如果将 $FormulaClass 的值指定为 1548(4 + 8 + 512 + 1024),则可以同时显示表单、视图等几种设计元素。

修改 $FormulaClass 域的方法,可以通过类似如下的代码实现:

Set view= db.GetView(“FormView”)
Set doc = db.GetDocumentByUNID(view.UniversalID)
Call doc.ReplaceItemValue(“$FormulaClass”, “4″)

至于这样的视图有什么用,就要看自己的想像力了。比如创建一个包含所有设计元素的视图,就可以通过名字来查找设计元素文档了。

请参考 Modifying $FormulaClass in ViewsFun with $FormulaClass

使用LotusScript远程调试器的几个问题

除了按照帮助文档的步骤做好各种配置之外,还有以下几个要注意的地方:

  • 全限定的Internet 主机名这个域填写的域名在服务器端必须能解析为IP,否则无法连接
  • 想要调试的代理必须在根目录下,否则找不到需要调试的代理(这个应该是一个Bug,不过目前可以采用在根目录下建一个相同设计的库的方法,来解决这个问题)
  • 远程调试仅对定时代理有效,想要调试Web代理,可以将其设定为定时代理,日程选择从不执行即可

ColumnValues属性一个需要注意的问题

notesViewEntry.ColumnValues属性有这样一个特性:当某一列的列公式是一个常量时,他的列值是不会包含在ColumnValues数组里面的。所以如果想要让他能包含在ColumnValues数组里面,就需要在公式中和某个域扯上关系,如:@If(@Text(fldCbsj)="";114;114) 就可以了。

关于ls函数调用的两个问题

先看看下面的一点代码:

问题是三次msgbox打出来的都应该是什么?我们先来分析以下这段代码,答案在最后揭晓。

继续阅读 »