' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ' * ' * Retrieving and modifying doclinks ' * ' * sample code from ' * LotusScript to Lotus C API Programmer Guide by Normunds Kalnberzins, (c) 2000-2003 ' * ' * http://www.ls2capi.com ' * ' * Author: Normunds Kalnberzins ' * ' * This code has been written as a sample to illustrate aspects of handling of Lotus C API from LotusScript ' * and may be reused, modified on full responsibility of the developer and provided this notice is preserved ' * ' * The author does not guaranty it to fit any particular purpose and it is up to the developer ' * to modify, test it and determine the limits of its applicability ' * ' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ' * * * * * * * * START (Function library) [$LINKS] ' * * * * * * * * ' * ' * manipulates $LINKS item ' * %INCLUDE "c:\lss\capis\samples\memoryManagerExt" ' include memory manager class ' * * * * * * * * START (Const) [ODS_TYPE] ' * * * * * * * * ' * Const ODS_WORD = 0 Const ODS_DWORD = 1 Const ODS_BYTE = 3 ' * * * * * * * * END (Const) [ODS_TYPE] ' * * * * * * * * ' * * * * * * * * START (Const) [MISC] ' * * * * * * * * ' * Const ITEM_LINKS = {$Links} Const s_zero_8 = "00000000" Const TYPE_COMPOSITE = 1 ' * * * * * * * * END (Const) [MISC] ' * * * * * * * * ' * * * * * * * * START (Type) [BLOCKID] ' * * * * * * * * ' * Public Type BLOCKID pool As Long block As Long ' Integer may not be enough End Type ' * * * * * * * * END (Type) [BLOCKID] ' * * * * * * * * ' * * * * * * * * START (Type) [TIMEDATE] ' * * * * * * * * ' * ' * 2 long elements ' * Public Type TIMEDATE innards (1) as Long End Type ' * * * * * * * * END (Type) [TIMEDATE] ' * * * * * * * * ' * * * * * * * * START (Type) [UNIVERSALNOTEID] ' * * * * * * * * ' * Public Type UNIVERSALNOTEID File As TIMEDATE Note As TIMEDATE End Type ' * * * * * * * * END (Type) [UNIVERSALNOTEID] ' * * * * * * * * ' * * * * * * * * START (Type) [NOTELINK] ' * * * * * * * * ' * Public Type NOTELINK File as TIMEDATE ' /* File's replica ID */ View as UNIVERSALNOTEID Note as UNIVERSALNOTEID ' /* Note's Creation TIMEDATE */ End Type ' * * * * * * * * END (Type) [NOTELINK] ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_OSUNLOCKOBJEC ' * * * * * * * * ' * ' * unlock handle ' * Declare Sub W32_OSUnlockObject Lib "nnotes" Alias "OSUnlockObject" ( Byval handle As Long) ' * * * * * * * * END (Declaration) [W32_OSUNLOCKOBJECT] ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_OSLOCKOBJECT] ' * * * * * * * * ' * Declare Function W32_OSLockObject Lib "nnotes.dll" Alias "OSLockObject" ( Byval handle As Long) As Long ' * * * * * * * * END (Declaration) [W32_OSLOCKOBJECT] ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_NSFITEMINFO] ' * * * * * * * * ' * Declare Function W32_NSFItemInfo Lib "nnotes.dll" Alias "NSFItemInfo" (Byval note_handle As Long, Byval item_name As Lmbcs String, Byval name_len As Integer, item_blockid As blockid, value_datatype As Integer, value_blockid As blockid, value_len As Long) As Integer ' * * * * * * * * END (Declaration) [W32_NSFITEMINFO] ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_ODSREADMEMORY ' * * * * * * * * ' * Declare Sub W32_ODSReadMemory Lib "nnotes.dll" Alias "ODSReadMemory" (pSource As Long, Byval typeODS As Integer, pDest As Any, Byval Iterations As Integer ) ' * * * * * * * * END (Declaration) [W32_ODSREADMEMORY] ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_ODSLENGTH] ' * * * * * * * * ' * Declare Function W32_ODSLength Lib "nnotes" Alias "ODSLength" (Byval odstype As Integer) As Integer ' * * * * * * * * END (Declaration) [W32_ODSLENGTH] ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_NSFITEMDELETE ' * * * * * * * * ' * Declare Function W32_NSFItemDeleteByBLOCKID Lib "nnotes" Alias "NSFItemDeleteByBLOCKID" (Byval note_handle As Long, Byval blck_pool As Long, Byval blck_blck As Long) As Integer ' * * * * * * * * END (Declaration) [W32_NSFITEMDELETEBY ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_NSFITEMAPPEND ' * * * * * * * * ' * Declare Function W32_NSFItemAppend Lib "nnotes" Alias "NSFItemAppend" (Byval hNote As Long, Byval flags As Integer, Byval ItemName As String, Byval ItemNameLength As Integer, Byval itemType As Integer, Byval Buff As Long, Byval BuffLength As Long) As Integer ' * * * * * * * * END (Declaration) [W32_NSFITEMAPPEND] ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_NSFNOTEUPDATE ' * * * * * * * * ' * Declare Function W32_NSFNoteUpdate Lib "nnotes" Alias "NSFNoteUpdate" (Byval note_handle As Long, Byval update_flags As Integer) As Integer ' * * * * * * * * END (Declaration) [W32_NSFNOTEUPDATE] ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_OSLOADSTRING] ' * * * * * * * * ' * Declare Sub W32_OSLoadString Lib "nnotes" Alias "OSLoadString" (Byval null1 As Long, Byval sError As Integer, Byval errstr As String, Byval lenstr As Integer) ' * * * * * * * * END (Declaration) [W32_OSLOADSTRING] ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_OSMEMORYALLOC ' * * * * * * * * ' * Declare Function W32_OSMemoryAllocate Lib "nnotes" Alias "OSMemoryAllocate" (Byval dwtype As Long, Byval size As Long, rethandle As Long) As Integer ' * * * * * * * * END (Declaration) [W32_OSMEMORYALLOCAT ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_OSMEMORYLOCK] ' * * * * * * * * ' * Declare Function W32_OSMemoryLock Lib "nnotes" Alias "OSMemoryLock" (Byval handle As Long) As Long ' * * * * * * * * END (Declaration) [W32_OSMEMORYLOCK] ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_OSMEMORYUNLOC ' * * * * * * * * ' * Declare Sub W32_OSMemoryUnLock Lib "nnotes" Alias "OSMemoryUnlock" (Byval handle As Long) ' * * * * * * * * END (Declaration) [W32_OSMEMORYUNLOCK] ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_OSMEMORYFREE] ' * * * * * * * * ' * Declare Sub W32_OSMemoryFree Lib "nnotes" Alias "OSMemoryFree"( Byval handle As Long) ' * * * * * * * * END (Declaration) [W32_OSMEMORYFREE] ' * * * * * * * * ' * * * * * * * * START (Declaration) [W32_ODSWRITEMEMOR ' * * * * * * * * ' * Declare Sub W32_ODSWriteMemory Lib "nnotes" Alias "ODSWriteMemory" (pSource As Long, Byval typeODS As Integer, pDest As Any, Byval Iterations As Integer ) ' * * * * * * * * END (Declaration) [W32_ODSWRITEMEMORY] ' * * * * * * * * ' * * * * * * * * START (Method) [REPLACEDOC] ' * * * * * * * * ' * Public Sub replaceDoc (idx As Integer, docTarget As Notesdocument, docLinks List As Notelink) Dim head_blckid_last As BlockID, head_blckid As BlockID, val_blckid As BlockID ' content and value block id Dim iType As Integer ' item type Dim iRc As Integer ' return code Dim length As Long Dim pBuff As Long Dim link As NOTELINK On Error Goto err_this Call getNoteLink(docTarget, link) ' the new link print "Replace #", idx, getDocUNID(docLinks (idx)), "with", docTarget.subject(0), docTarget.universalid docLinks (idx) = link ' replace EXIT_THIS: Exit Sub ERR_THIS: Print Error$ Resume Exit_THIS End Sub ' * * * * * * * * END (Method) [REPLACEDOC] ' * * * * * * * * ' * * * * * * * * START (Method) [INITIALIZE] ' * * * * * * * * ' * Sub Initialize Dim ses As New notessession ' one and only session Dim ndb As notesdatabase ' current DB Dim doc As notesdocument ' current document being processed: Dim docNew As notesdocument ' current document being processed: Const DUMMY="~someincredibleitem" Dim docLinkList List As NOTELINK ' array of NoteLink structures dim idx as Integer Set ndb=ses.CurrentDatabase Set doc = ndb.unprocesseddocuments.getFirstDocument Set docNew = ndb.alldocuments.getnthdocument(Cint(Rnd*1000 mod ndb.alldocuments.count)) If doc.hasItem (ITEM_LINKS) Then If readLinks(doc, docLinkList ) Then ' some movement to force save (otherwise use NSFNoteUpdate) Call doc.replaceItemValue(DUMMY,1) Call doc.removeItem(DUMMY) idx = Cint(rnd *1000 mod 4) ' generate pseudo-random number 0-3 If Iselement(docLinkList(idx)) Then Call replaceDoc(idx, docNew, docLinkList) ' point 1st link to docNew Call doc.removeItem (ITEM_LINKS) if writeLinkList (doc, docLinkList) then ' if $Links written OK Call doc.save(True, True) print "ok..." End if End If End If End If End Sub ' * * * * * * * * END (Method) [INITIALIZE] ' * * * * * * * * ' * * * * * * * * START (Method) [OSUNLOCKOBJECT] ' * * * * * * * * ' * ' * unlock handle ' * Public Sub OSUnlockObject (handle) Call W32_OSUnlockObject (handle) ' just on OS for this sample End Sub ' * * * * * * * * END (Method) [OSUNLOCKOBJECT] ' * * * * * * * * ' * * * * * * * * START (Method) [READLINKS] ' * * * * * * * * ' * ' * here we assume that there is only one $LINKS item ' * Public Function readLinks (doc As Notesdocument, docLinkList List As Notelink) Dim head_blckid_last As BlockID, head_blckid As BlockID, val_blckid As BlockID ' content and value block id Dim iType As Integer ' item type Dim iRc As Integer ' return code Dim length As Long Dim pBuff As Long Dim count as Integer, i as Integer Dim link as NOTELINK On Error Goto err_this ' process the first and hopefully only item If W32_NSFItemInfo (doc.handle, ITEM_LINKS, Len(ITEM_LINKS), head_blckid, iType, val_blckid, length)<> 0 Then Exit Function pBuff = LockBlock(val_blckID) Call W32_ODSReadMemory (pbuff, ODS_WORD, iType, 1) ' skip type If iType = NOTELINKS Then Call W32_ODSReadMemory (pbuff, ODS_WORD, count, 1) for i = 0 to count-1 Call W32_ODSReadMemory (pbuff, ODS_DWORD, link.File.innards(0), 10) docLinkList (i) = link print time, "read...", getDocUNID(link) next i readLinks = True Else readLinks = False End If Call W32_OSUnlockObject(val_blckID.pool&) EXIT_THIS: Exit Function ERR_THIS: Print Error$ Resume Exit_THIS End Function ' * * * * * * * * END (Method) [READLINKS] ' * * * * * * * * ' * * * * * * * * START (Method) [LOCKBLOCK] ' * * * * * * * * ' * Public Function LockBlock (BlockID As Blockid) As Long LockBlock = W32_OSLockObject (BlockID.pool&) + BlockID.block End Function ' * * * * * * * * END (Method) [LOCKBLOCK] ' * * * * * * * * ' * * * * * * * * START (Method) [GETNOTELINK] ' * * * * * * * * ' * ' * convert document to NOTELINK structure ' * Public Function Getnotelink (docSource As Notesdocument, link As Notelink) Dim vw as String, note as String Dim UNID as String, td as TIMEDATE, nl as NOTELINK link = nl ' init link if docSource is Nothing then exit function ' DB Replica id if Not docSource.parentDatabase is nothing then UNID = docSource.parentDatabase.ReplicaID link.File.Innards(1) =Val("&h" & Left(UNID,8)) link.File.Innards(0) =Val("&h" & Right(UNID,8)) End if ' View UNID (0) if Not docSource.ParentView is Nothing then ' add view information UNID = docSource.ParentView.UniversalID vw = Left(UNID,16) note =Right(UNID,16) link.View.File.Innards(1) =Val("&h" & Left(vw,8)) link.View.File.Innards(0) =Val("&h" & Right(vw,8)) link.View.Note.Innards(1) =Val("&h" & Left(note,8)) link.View.Note.Innards(0) = Val("&h" & Right(note,8)) End if ' Document UNID UNID = docSource.UniversalID vw = Left(UNID,16) note =Right(UNID,16) link.Note.File.Innards(1) =Val("&h" & Left(vw,8)) link.Note.File.Innards(0) =Val("&h" & Right(vw,8)) link.Note.Note.Innards(1) =Val("&h" & Left(note,8)) link.Note.Note.Innards(0) = Val("&h" & Right(note,8)) End Function ' * * * * * * * * END (Method) [GETNOTELINK] ' * * * * * * * * ' * * * * * * * * START (Method) [GETDBREPLICAID] ' * * * * * * * * ' * ' * retrieve replica id from the link ' * Public Function getDbReplicaID (nl As Notelink) As String getDbReplicaID = Right$ (s_zero_8 & Hex(nl.file.innards(1)),8) & Right$ (s_zero_8 & Hex(nl.file.innards(0)),8) End Function ' * * * * * * * * END (Method) [GETDBREPLICAID] ' * * * * * * * * ' * * * * * * * * START (Method) [GETDOCUNID] ' * * * * * * * * ' * ' * retrieve document universal id ' * Public Function getDocUNID (nl As Notelink) As String getDocUNID = Right$ (s_zero_8 & Hex(nl.Note.File.innards(1)), 8) & Right$(s_zero_8 & Hex(nl.Note.File.innards(0)),8) & Right$(s_zero_8 & Hex(nl.Note.Note.Innards(1)),8) & Right$(s_zero_8 & Hex(nl.Note.Note.Innards(0)), 8) End Function ' * * * * * * * * END (Method) [GETDOCUNID] ' * * * * * * * * ' * * * * * * * * START (Method) [WRITELINKLIST] ' * * * * * * * * ' * Public Function writeLinkList (doc As Notesdocument, docLinkList List As Notelink) Dim lenlist As Integer, itemtype As Integer Dim pbuff0 As Long, p as Long Dim lenbuff as long Dim rc as Integer ' return (error) code Dim memman as new MemoryManagerExt Dim j As Integer Dim countLinks as Integer ' count of links ' count the links forall L in docLinkList j = j + 1 End forall countLinks = j lenbuff = countLinks * 40 + 2 ' 40 - length of one NOTELINK + one word counter p = memman.newbuffer (lenbuff) pbuff0 = p Call W32_ODSWriteMemory (p, ODS_WORD, countLinks,1) Print "writing", countLinks, "links" For j = 0 To countLinks-1 ' we used 0-based indexes print time, "write...", getDocUNID(docLinkList(j)) Call W32_ODSWriteMemory (p, ODS_DWORD, docLinkList(j).File.Innards(0), 10) Next j rc% = W32_NSFItemAppend (doc.handle, 0, ITEM_LINKS, Len(ITEM_LINKS), NOTELINKS, pBuff0, lenBuff) ' the item type is NOTELINKS if rc%=0 then writeLinkList = True Else print getError(rc%) writeLinkList = False End if End Function ' * * * * * * * * END (Method) [WRITELINKLIST] ' * * * * * * * * ' * * * * * * * * START (Method) [GETERROR] ' * * * * * * * * ' * ' * Get Notes error ' * Public Function getError (enum As Integer) As String Dim s As String*256 W32_OSLoadString 0, enum And &h03FFFFFFF, s, 256 getError = Strleft(s, Chr(0)) End Function ' * * * * * * * * END (Method) [GETERROR] ' * * * * * * * * ' * * * * * * * * START (Method) [OSLOCKOBJECT] ' * * * * * * * * ' * Public Function OSLockObject (handle) As Long OSLockObject = W32_OSLockObject (handle) ' use only one OS in this sample End Function ' * * * * * * * * END (Method) [OSLOCKOBJECT] ' * * * * * * * * ' * * * * * * * * END (Function library) [$LINKS] ' * * * * * * * *