goo blog サービス終了のお知らせ 

Lunatic Sol

IT Tips

CreateFTIndex メソッドのオプション

2004-06-09 22:22:29 | LotusScript
LotusScript で全文索引のオプションをチェックできないかな、とデザイナーヘルプを見ていたら Notes 6 からいくつか FT 関連で追加されているメソッドがあることを発見。そのうちのひとつ CreateFTIndex メソッド (NotesDatabase クラス) では全文索引のオプションをセットすることができる。これは便利ということでいろいろ試してみた。しかし一点不明なことがある。FTINDEX_ATTACHED_BIN_FILES の動きがよくわからない。

Sub Initialize
    Dim s As New NotesSession
    Dim db As NotesDatabase
    Set db = s.CurrentDatabase
    options& = FTINDEX_ATTACHED_BIN_FILES
    Call db.CreateFTIndex(Clng(options&), True)
End Sub

上記のように FTINDEX_ATTACHED_BIN_FILES 単体で処理すると全文索引のオプションが全部外れてしまう。でも、5つのオプションを全部組み合わせてみたら添付ファイルの詳細検索も設定される。うーん、といろいろやってみたらわかった。どうやら FTINDEX_ATTACHED_FILES (1) と組み合わせないと使えないらしい。

でも良く考えたら当然の動作なのかも。だって「簡易検索 (フィルターなし)」と「詳細検索 (添付ファイルフィルターあり)」はどちらかしか選択できないオプションであり、仮に FTINDEX_ATTACHED_BIN_FILES だけで有効になるのだとすると、FTINDEX_ATTACHED_FILES と組み合わせた時にはどっちが有効になるのかわからないもんね。

ただそうであったとしても、ヘルプにはちゃんと書いておいて欲しいなぁと思ったり。ちゅうことで、上記サンプルの options& のところを FTINDEX_ATTACHED_BIN_FILES + FTINDEX_ATTACHED_FILES にしてあげれば添付ファイルフィルターを有効にした FT オプションがセットされます。

2004/06/25 Updated
テストでは options& という Long 型変数は使わずに FTINDEX_ATTACHED_BIN_FILES + FTINDEX_ATTACHED_FILES と定数を合算した 17 を直接明示していました。その環境では何ら問題ない。で、あとで options& という変数を使うと失敗しました。あれれ?と思って CreateFTIndex の引数にて Clng() で強制的に LONG 型に変換してあげたら問題なくオプションが効きました。ということで、Clng() をセットするのを忘れないように。サンプルの赤字部分です。

GetLastUpdatedBy

2004-04-24 22:51:11 | LotusScript
文書の $UpdatedBy フィールド見れば更新者のリストはピックアップできます。でも、それを LotusScript でやりたい場合、GetItemValue で $UpdatedBy を Variant でとって、配列の最後を取得しないといけません。数行ですが、毎回書くのが面倒って時に使えるかな?っていう程度のシンプルなファンクションです。

NotesDocument オブジェクトを引数に渡して、NotesName クラスオブジェクトを戻り値として受け取ります。NotesName クラスなので Common プロパティ、Abbreviated プロパティなど任意のものを使えるので、取り扱いやすいと思います。

Function GetLastUpdatedBy(doc As NotesDocument) As NotesName
    Dim updatedBy As Variant
    updatedBy = doc.GetItemValue("$UpdatedBy")
    Set GetLastUpdatedBy = New NotesName(updatedBy(Ubound(updatedBy)))
End Function

GetAgentUNID

2004-04-06 20:15:48 | LotusScript
NotesAgent の UNID が必要になるケースはまぁそうそうないと思いますが、諸事情により LotusScript 内で取得する必要がありました。NotesAgent クラスには UNID を表示するプロパティがありません。よって、別の方法で取得しないといけません。

そこで目をつけたのは NotesURL プロパティです。NotesURL は notes:// ではじまる URL 形式で NotesAgent の UNID をその戻り値に含んでいます。そこを加工して取得することにしました。先に書いた IsValidUNID を使っているので、忘れずに同じオブジェクト内に Function を入れておいてください。

引数は NotesAgent オブジェクトで、戻り値は String 型の UNID です。何らかの理由で正しい UNID が取得できない場合は空白文字を返すようにしています。

Function GetAgentUNID(agent As NotesAgent) As String
    Dim splitURL As Variant
    splitURL = Split(agent.NotesURL, "/")
    GetAgentUNID = splitURL(Ubound(splitURL))
    If Instr(GetAgentUNID, "?OpenAgent") Then
        GetAgentUNID = Strleft(GetAgentUNID, "?OpenAgent")
    End If
    If Not IsValidUNID(GetAgentUNID) Then
        GetAgentUNID = ""
    End If
End Function

IsValidUNID

2004-04-06 20:01:41 | LotusScript
LotusScript で UNID を扱う場合、プロパティで見るコロン (:) やハイフン (-) の入った形式ではなくて、32文字のつながった文字列である必要があります。

クラスプロパティからとる場合は問題ないでしょうが、文字列を整形して作った UNID の場合チェックしておいた方が無難です。ということで、そのためのファンクションを書いてみました。

引数として strUnid (String 型) を受け取り、その文字列の Validity をチェックします。True が返れば Valid、False が返れば Invalid ということになります。

Function IsValidUNID(strUnid As String) As Boolean
    If Len(strUnid) <> 32 Then
        IsValidUNID = False
    Elseif strUnid Like "*[!0-9a-fA-F]*" Then
        IsValidUNID = False
    Else
        IsValidUNID = True
    End If
End Function

Boolean 型は Notes 6 からの型なのでノーツ R5 では上のが使えません。なので、下の IsValidUNIDR5 を使います。Integer 型の戻り値なので 1 が Valid で 0 が Invalid です。

Function IsValidUNIDR5(strUnid As String) As Integer
    If Len(strUnid) <> 32 Then
        IsValidUNIDR5 = 0
    Elseif strUnid Like "*[!0-9a-fA-F]*" Then
        IsValidUNIDR5 = 0
    Else
        IsValidUNIDR5 = 1
    End If
End Function

濁点・半濁点を含む半角カナを StrRight / StrLeft で処理する

2004-03-22 22:16:21 | LotusScript
あんまし半角カナを取り扱うことって個人的にはないのですが、世の中そういう処理をしたいケースってのはあるようです。今日はこの半角カナを取り扱った際の LotusScript での問題を解決する方法の話。

StrRight や StrLeft っていう便利なファンクションが LotusScript にはあるんですが、半角カナに濁点・半濁点が含まれている場合、このファンクションがちゃんと動作しないようです。

濁点・半濁点を含む半角カナを StrLeft 関数および StrRight 関数の引数に使用すると空白文字が返される

StrLeft2 と StrRight2 ってのがサポート技術情報に載っているので、この方法を使って解決できるみたいです。半角カナを取り扱う場合は回避ファンクションを使って対応しておけばいいですね。

Val 関数で16進数を10進数変換する際の注意点

2004-03-01 11:45:13 | LotusScript
久々に LotusScript ネタです。今日は16進数を10進数に変換したり、8進数を10進数に変換したり、結構便利に使える Val 関数の注意点。</p><p>Designer 6 Help などの Val 関数の例を読むと Val("&HFF") というような記述になっています。実際にこれの戻り値を見てみましょう。

Sub Initialize
    Msgbox Val("&HFF")
End Sub
256 という値が返って来ます。問題ないですね。では今度は同じような方法で 8000 という値を Val("&H8000") として結果を調べてください。また FFFF という値を Val("&HFFFF") として結果を調べてみてください。どういう結果が出てきましたか?

前者は -32768、後者は -1 という結果だったと思います。どうやら、符号付16ビット (Signed Short) 整数で変換した結果を返してしまうようです。これは恐らく、LotusScript の Integer データ型が -32768 から 32767 の符号付16ビット整数の範囲であるからかと思います。でも32ビット整数として扱いたい場合、これでは困ります。どうすればいいでしょうか?

Val 関数のヘルプをよく読むと、接尾辞に関する説明があります。これを使うのです。LotusScript の中で Long データ型にしてあげれば 8000 や FFFF も32ビット整数 (符号付) の範囲に入りますよね。Val 関数で 0x8000 を10進数に変換する際以下のような構文に直してみてください。

Sub Initialize
    Msgbox Val("&H8000&")
End Sub
32768 が返って来ましたよね?同様に FFFF でも試してみると 65535 が返されますよ。

ClearNetworkCache

2004-02-09 12:05:00 | LotusScript
Notes はロケーション文書に $Saved* というフィールド名で過去に接続したサーバーのネットワーク情報を保持しています。そして、その値をキャッシュとして使っています。

機能しているときは良いのですが、たとえばサーバーのネットワークアドレスが変わってしまった、などで接続ができなくなった場合、これらを全てクリアすることで解決できることがあります。ということで、今日はそのフィールドを全部 Remove してしまうスクリプトのサブルーチンです。

Where are Server Addresses Cached in Notes and Domino? に詳細が載っていますが、Notes クライアントの場合はロケーション文書に、Domino の場合はサーバー文書にこれらのデータは保持されています。

それぞれに対応できるように、NotesDocument オブジェクトを引数として受け取るサブルーチンにしてみました。Notes の場合はロケーション文書の NotesDocument オブジェクトを、Domino の場合はサーバー文書の NotesDocument オブジェクトを引数として渡してあげればいいわけです。

Sub ClearNetworkCache(doc As NotesDocument)
    '#### Network Cache Fields
    Dim nwCache(4) As String
    nwCache(0) = "$SavedAddresses"
    nwCache(1) = "$SavedDate"
    nwCache(2) = "$SavedPorts"
    nwCache(3) = "$SavedServers"
    nwCache(4) = "$SavedTriedDate"

    Dim isCleard As Integer
    isCleard = 0

    Dim i As Integer
    For i = 0 To Ubound(nwCache)
        If doc.HasItem(nwCache(i)) Then
            Call doc.RemoveItem(nwCache(i))
            isCleard = 1
        End If
    Next

    If isCleard = 1 Then
        Call doc.Save(True,True)
    End If
End Sub

たとえばこれを個人アドレス帳のエージェントとして登録する場合は、以下のようなコードをアクションメニューエージェント (トリガーはなし) として作成してあげれば、現在のロケーションのキャッシュをクリアできますね。

Sub Initialize
    Dim s As New NotesSession
    Dim aBook As NotesDatabase
    Dim locID As String
    Dim locDoc As NotesDocument

    Set aBook = GetLocalAddressBook(s)
    If Not aBook.IsOpen Then
        Call aBook.Open(aBook.Server,aBook.FilePath)
    End If

    locID = GetLocationID(s)
    Set locDoc = aBook.GetDocumentByID(locID)

    Call ClearNetworkCache(locDoc)
End Sub

尚、上記のコードでは GetLocalAddressBookGetLocationID を使っていますが、引数に NotesSession オブジェクトを渡す形にしています。なので、Function スコープ内の Dim s As New NotesSession はアポストロフィーでコメントアウトして、Function を GetLocalAddressBook(s As NotesSession) のようにして引数を受け取る形に改良してください。過去のサンプルではわかりやすくするため Function の中で NotesSession オブジェクトを Initialize していましたが、ここでは引数にしています。理由はまた別の機会で触れたいと思います。

SxGetDbClassID & SxGetDbClassName

2004-01-27 18:18:52 | LotusScript
久々に LotusScript ネタです。このネタは前からあったのですが、整理していたら時間が経過しすぎてしまいました。

NSFDbClassGet というファンクションが Notes C API Toolkit で公開されているのですが、このファンクション Notes データベースのクラスを返してくれる便利なファンクションです。

NotesPeek を使えば確認できるのですが、LotusScript アプリケーション上でチェックしたい場合には NSFDbClassGet を直接 Call してしまうのが良いです。

実際に返してくれる値は Integer 型のデータなのですが、Toolkit の中の nsfdb.h を見ると以下のように定義されていることがわかります。
#define  DBCLASS_NOTEFILE  0xff01

なので、nsfdb.h のマクロを参考にして LotusScript でも NSFDbClassGet の戻り値から DBCLASS_xxx を返すようにしてみました。hDB は NSFDbOpen を直接 Call してあらかじめ取得して....ん?あー、そういえば NSFDbOpen() を Call するサンプルってまだやってなかったですね。最後にサンプル書いておくので、それを参考にしてくださいです。後日あらためて NSFDbOpen と NSFDbClose だけについても記事書きます。
Function SxGetDbClassID(hDB As Integer) As Integer
    Dim retClass As Integer
    Call NSFDbClassGet(hDB, retClass)
    SxGetDbClassID = retClass
End Function

Function SxGetDbClassName(dbClassId As Integer) As String
    Const DBCLASS_VALID_MASK = &HFF00
    Select Case dbClassId Xor DBCLASS_VALID_MASK
    Case 0:    SxGetDbClassName = "DBCLASS_NSFTESTFILE"
    Case 1:    SxGetDbClassName = "DBCLASS_NOTEFILE"
    Case 2:    SxGetDbClassName = "DBCLASS_DESKTOP"
    Case 3:    SxGetDbClassName = "DBCLASS_NOTECLIPBOARD"
    Case 4:    SxGetDbClassName = "DBCLASS_TEMPLATEFILE"
    Case 5:    SxGetDbClassName = "DBCLASS_GIANTNOTEFILE"
    Case 6:    SxGetDbClassName = "DBCLASS_HUGENOTEFILE"
    Case 7:    SxGetDbClassName = "DBCLASS_ONEDOCFILE"
    Case 8:    SxGetDbClassName = "DBCLASS_V2NOTEFILE"
    Case 9:    SxGetDbClassName = "DBCLASS_ENCAPSMAILFILE"
    Case 10:   SxGetDbClassName = "DBCLASS_LRGENCAPSMAILFILE"
    Case 11:   SxGetDbClassName = "DBCLASS_V3NOTEFILE"
    Case 12:   SxGetDbClassName = "DBCLASS_OBJSTORE"
    Case 13:   SxGetDbClassName = "DBCLASS_V3ONEDOCFILE"
    Case 14:   SxGetDbClassName = "DBCLASS_V4NOTEFILE"
    Case 15:   SxGetDbClassName = "DBCLASS_V5NOTEFILE"
    Case 16:   SxGetDbClassName = "DBCLASS_V6NOTEFILE"
    Case Else:  SxGetDbClassName = "DBCLASS_UNKNOWN"
    End Select
End Function

実際に使う場合は (Declarations) に以下の3行を追加して、Initialize イベントなどで以下のように Call してみてください。ちなみにこのサンプルは Notes 6 (W32) を前提にしているので、R5 の場合などは path を desktop5.dsk のように変更してください。尚、このサンプルを実行してなんらかの障害が出たとしても当方、一切責任は負えませんのでその点もあらかじめご了承ください。
Declare Function NSFDbOpen Lib "nnotes" (Byval PathName As String, rethDB As Integer) As Integer
Declare Function NSFDbClose Lib "nnotes" (Byval hDB As Integer) As Integer
Declare Function NSFDbClassGet Lib "nnotes" (Byval hDB As Integer, retClass As Integer) As Integer

Sub Initialize
    Dim path As String
    path = "desktop6.ndk"
    Dim ret As Long
    Dim hDB As Integer
    Dim dbClassID As Integer
    Dim dbClassName As String
    ret = NSFDbOpen(path, hDB)
    If ret = 0 Then
        dbClassID = SxGetDbClassID(hDB)
        dbClassName = SxGetDbClassName(dbClassID)
        ret = NSFDbClose(hDB)
        Msgbox "DBCLASS NAME:" & Chr(9) & dbClassName,,"Lotus Notes"
    End If
End Sub

NotesMIMEEntity::Headers プロパティを各ヘッダフィールドごとに分割する

2004-01-04 06:03:36 | LotusScript
今回のネタは全然たいしたものではありません。ただ、個人的に毎回書くのが面倒なのと 13 10 という組み合わせを時々忘れてネットを検索してしまうので、そういうのを防止するために SxSplitMIMEHeaders() というファンクションにしただけのものです。

このファンクションでは Split 関数が必要なのですが、ノーツ R5 の場合はそれがありません。なのでノーツ R5 で Split で紹介した方法を使います。Notes 6 の場合は Split 関数を使えば OK です。SxSplitMIMEHeaders() の引数に NotesMIMEEntity クラスの Headers プロパティの値を入れてください。

ノーツ R5 の場合
Function SxSplitMIMEHeaders(expression As String) As Variant
    SxSplitMIMEHeaders = SxSplit(expression, Chr(13) + Chr(10))
End Function

Notes 6 の場合
Function SxSplitMIMEHeaders(expression As String) As Variant
    SxSplitMIMEHeaders = Split(expression, Chr(13) + Chr(10))
End Function

GetLocalAddressBook

2003-12-30 15:41:16 | LotusScript
個人アドレス帳のファイル名を names.nsf 以外にしている人はほぼいないでしょう。ですので、個人アドレス帳の NotesDatabase オブジェクトを取得したい場合は Dim db As New NotesDatabase("","names.nsf") でほとんど問題ありません。でも、Notes 上確実に個人アドレス帳を取得させたい場合はこの方法は適当ではありません。

方法としては NotesSession クラスの GetEnvironmentString メソッドで NAMES= をとる方法もあるのですが、NotesSession クラスの AddressBooks プロパティと IsPrivateAddressBook プロパティを使って取得する方法でファンクション化してみました。

Function GetLocalAddressBook As NotesDatabase
    Dim s As New NotesSession
    Dim books As Variant
    books = s.AddressBooks
    Forall b In books
        If b.IsPrivateAddressBook Then
            Set GetLocalAddressBook = b
            Exit Forall
        End If
    End Forall
End Function

これを実際に使ってみたい場合は以下のようなコーディングを Initialilze イベントなどに入れると OK です。

Sub Initialize
    Dim db As NotesDatabase
    Set db = GetLocalAddressBook
    Call db.Open(db.Server,db.FilePath)
End Sub