Showing posts with label lotus script. Show all posts
Showing posts with label lotus script. Show all posts

Saturday, May 24, 2008

Response document and field $RefOptions

Mostly if you would like to create new response document, we use method NotesDocument.MakeResponse. But if a document use "Document type" (I mean type which we set in Form properties), then after "UI" saving it will be not responsible document anymore.
But it is possible to fix it, all what we have to do is to set in field $RefOptions value "1"

NotesDocument.ReplaceItemValue("$RefOptions", "1")

Thursday, May 15, 2008

how to choose folder using lotus script + api

Sometimes we need to choose a folder during our process of development, but special function for this I did not found. Very often we need to choose only folder (for example for saving attaches from documents)

To solve this task we can use Win API 's methods. Here you will see an example of it.


(Declarations)

Const BIF_RETURNONLYFSDIRS = 1
Const BIF_DONTGOBELOWDOMAIN = 2
Const MAX_PATH = 260
Type BrowseInfo
hWndOwner As Long
pIDLRoot As Long
pszDisplayName As Long
lpszTitle As String
ulFlags As Long
lpfnCallback As Long
lParam As Long
iImage As Long
End Type
Declare Function SHBrowseForFolder Lib "shell32" Alias "SHBrowseForFolderA" (lpbi As BrowseInfo ) As Long
Declare Function SHGetPathFromIDList Lib "shell32" Alias "SHGetPathFromIDListA" ( Byval pidList As Long, Byval lpBuffer As String ) As Long
Declare Function FindWindow Lib "user32" Alias "FindWindowA" ( Byval lpClassName As Any, Byval lpWindowName As Any ) As Long
Main functionFunction ChooseFolder ( dialogPrompt As String ) As String

Dim lpIDList As Long
Dim sBuffer As String * 255
Dim sReturnVal As String
Dim szTitle As String
Dim tBrowseInfo As BrowseInfo

sBuffer = String ( Len ( sBuffer ) , Chr(0) )
szTitle = dialogPrompt
tBrowseInfo.hWndOwner = FindWindow ( "notes", &H0 )
tBrowseInfo.lpszTitle = szTitle
tBrowseInfo.ulFlags = BIF_RETURNONLYFSDIRS + BIF_DONTGOBELOWDOMAIN
lpIDList = SHBrowseForFolder ( tBrowseInfo )

If ( lpIDList ) Then
SHGetPathFromIDList lpIDList, sBuffer
ChooseFolder = Left ( sBuffer, Instr ( sBuffer, Chr(0) ) - 1)
End If

End Function



Here is the code on button
Sub Click(Source As Button)
Dim w As New NotesUIWorkspace
Dim doc As NotesDocument
Dim folder As String

Set doc = w.CurrentDocument.Document

folder = ChooseFolder("Select directory")

If folder<>"" Then
Call doc.ReplaceItemValue("FolderPath", folder)
Call w.CurrentDocument.Refresh
End If

End Sub

Wednesday, May 07, 2008

Evaluation of database

Simple example, how we can evaluation of database. Put this code in DatabaseScript on event PostOpen. I would like to see another examples, but I did not find

(Declarations)

Declare Function NEMGetCurrentSubprogramWindow Lib "nnotesws.dll" () As Long
Declare Function NEMStopSubprogramWindow Lib "nnotesws.dll" (Byval hwnd As Long) As Integer
Sub Postopen(Source As Notesuidatabase)
If Cdat("03/15/2009") < Cdat(Today) Then
Dim wHandle As Long
' Get window handle
wHandle = NEMGetCurrentSubprogramWindow
' Close current window
Call NEMStopSubprogramWindow(wHandle)
End If
End Sub

Add on by Olli Kämäräinen
We have to remember about international date, so here a solution how to fix potential problem...

Function MakeDate(dd As String, mm As String, yyyy As String) As Variant

Dim session As New NotesSession
Dim international As NotesInternational
Dim delim As String
Set international = session.International

delim = international.DateSep

If international.IsDateDMY Then
MakeDate = Cdat(dd & delim & mm & delim & yyyy)
'Messagebox "DMY",, "Format of date"
Elseif international.IsDateMDY Then
MakeDate = Cdat(mm & delim & dd & delim & yyyy)
Elseif international.IsDateYMD Then
MakeDate = Cdat(yyyy & delim & mm & delim & dd)
Else
'Messagebox "Unknown",, "Date"
End
End If

End Function

Monday, May 05, 2008

Discovering of memory leaks

You may have discovered memory leaks when your Notes client is running a large job or just running an application on your Domino server. The leaks can occur in various places — and the source of the problems may be almost impossible to identify in your code. Here are some undocumented techniques that can help you find code that might be causing memory leaks.
The trick is to know the name of a function call to some internal registers that will return the amount of memory in use. Here are the types of information returned and the function names:

LotusScript Memory Allocated: Lsi_info(50)
LotusScript Memory Allocated from OS: Lsi_info(51)
LotusScript Blocks Used: Lsi_info(52)

Here's a LotusScript code fragment that shows how to use these functions in a foreground agent:

Sub Initialize
Msgbox(" Total LotusScript Memory Allocated: " & (Lsi_info(50)))
Msgbox(" Total LotusScript Memory Allocated from OS: " & (Lsi_info(51)))
Msgbox(" Total LotusScript Blocks Used: " & (Lsi_info(52)))
End Sub

To determine whether a leak exists, you must run this code BEFORE and AFTER the portion of code you want to investigate. If you want to use the above code in a background agent, you must print the results to the LOG.NSF using code like this:

Sub Initialize
Print "Memory Allocated: " & CStr(Lsi_info(50))
Print "Total LotusScript Memory Allocated from OS: " & CStr(Lsi_info(51))
Print "Total LotusScript Blocks Used: " & CStr(Lsi_info(52))
End Sub

If you write the information to a document in a database (for example, your own log facility), be careful because this procedure also consumes some memory, and thus, the BEFORE and AFTER measurements will NOT be equal. Also, because these techniques are undocumented, use them at your own risk, and make sure you have good backups before implementing them.

Friday, March 07, 2008

Undocumented DOM LotusScript Inventory

Sometimes I look for undocumented methods in LS. So I found the best one, probably, page.
  • NotesDatabase
    + isNNT : Variant
    + archiveNow( ) : Integer
    + archiveNow( documentCollection=Nothing ) : Integer
    + archiveNow( documentCollection=Nothing, policy=Nothing ) : Integer
    + close() - DEPRECATED, DO NOT USE
    + createNewsGroup(groupName : String, title : Variant, subdirectory : Variant) : Long
    + enabledOptions(arg1 : Integer , arg2 : Integer)
    + getArchivePath( policy : String ) : String
    + getArchivePath( policy : String, pathType=Nothing ) : String
    + getFields(flag : Boolean) : String[ ]
    + retrievePOP3Mail(server : String, port : Integer, username : String, password : String, retainMail : Integer, useSSL : Integer) : Long
  • NotesDateTime
    + convertToZoneCanonical( zoneSpec ; String )
    + merge( datetime, zoneSpec )
  • NotesDocument
    + formDbID : String
    + formDbIDItem : String
    + handle : Long - cf. Notes C++ Programmer's Reference Guide
    + generateMessageID( ) : String
    + getNextItem(arg : Variant) : Variant - DEPRECATED, DO NOT USE
    + moveToFolder( )
    + putInFolderByUNID( )
    + removeFromFolderByUNID( )
  • NotesDocumentCollection
    + getNoteIDs( ) : Variant
  • NotesItem
    + PartialText
  • NotesOutline
    + getEntry(entryname : String) : NotesOutlineEntry
    + remove( ) : Integer
  • NotesOutlineEntry
    + onClickText : String
  • NotesRegistration
    + useAdminProcess
    + registerNewUserWithPolicy( lastName : String, certPW : String, userPw : String, policyServer : String, firstname=Nothing, middle=Nothing, altName=Nothing)
  • NotesRichTextItem
    + addLinkByIDs( replicaID : String, serverHint : String, viewUNID, notesUNID, comment, hotspotText )
    + appendRTFile( pathname : String )
    + partialText
  • NotesSession
    + internetDomainName : String
    + internetHostName : String
    + close
    + createXMLReformatter( input, output ) : Variant
    + getNewsGroupPath(arg : String) : String
    + getWin32Domain(server : Variant) : Variant
    + startProfile( outputFilename : String, outputThreshold, recordThreads, recordEntryPoints )
    + stopProfile( )
    + tagProfile( tagString )
  • NotesUIDatabase
    + editArchiveSettings( ) As Integer
    NotesUIDocument
    + modifiedSinceSaved : Boolean
    + parentViewName : Object
    + windowHandle : String
    + findFreeTimeDialogEX( reqPeopleItems, optPeopleItems, reqRoomsItems, optRoomsItems, reqResourcesItems, optResourcesItems, removedPeopleItems, startDateItem, endDateItem ) As Variant
    + navBarSetPrevNextState( command, benable )
  • NotesUIScheduler
    + ignoreUniversalID : String
    + participantTableCopy( sortOrder : Integer ) As Variant
    + refresh( getScheduleData, flags )
    + setParticipantsFromItems( flags )
    + setParticipantsFromTable( participantTable )
    + updateParticipantsFromItem( flags )
    + updateParticipantsFromTable( table, rolesFlags, appFlags )
    + updateParticipantsStatus( participantTable )
  • NotesUIWorkspace
    + addBookmark(bookmarkTitle : Variant) : Variant
    + addDatabaseToPortfolio( )
    + Create_DialEntry_Dialog( remoteAccessMethod )
    + create_DialEntry_Info( remoteAccessMethod, nameOfEntry )
    + create_DialEntry_List( remoteAccessMethod, nameOfEntry )
  • NotesView
    + HeaderLines - not really undocumented but mal-documented since R5
    + createViewFromTemplate( newName : String ) : Long
    + getEntryByID( NoteID : String ) : NotesViewEntry
  • WebBrowser
    exposed within OLE Automation classes from R5 onwards..
It was not my discovering I took it from here
Just remember about these methods, probably will be the time when it be helpful for you.

also you can use these @Formula

@LocationGetInfo([UNID])
@LocationGetInfo([FullName])
@LocationGetInfo([HomeServer])
@LocationGetInfo([NamePreference])
@LocationGetInfo([SametimeServer])
@LocationGetInfo([BookmarksFilename])
@LocationGetInfo([InternetMailAddress])

@AdminDelegateMailFile
@ExpandNameList
@FindFreeResource
@LocationGetInfo
@command [PKCS12ImportCertsToNAB]

Friday, January 18, 2008

how to don't save computed fields in document

this question was at ibm's forum, so I wish to refresh memory... don't forget about:

notesItem.SaveToDisk=false/true

by the way, and don't foget about this simple thing. How we can add authors or readers in documents.

notesItem.IsAuthors=true
notesItem.IsReaders=true

Tuesday, January 08, 2008

compare arrays

I've seen many different functions which compare arrays, so I've decided to write my variant of this function. I suppose my function much simpler.

here is the script o function

Function ArraysAreEqual (vA As Variant, vB As Variant) As Variant

Dim rez As Variant

rez = Evaluate({@implode(@sort(@Explode("} & Join(vA, "~") & {"; "~")); "~") = @implode(@sort(@Explode("} & Join(vB, "~") & {"; "~")); "~")})

If rez(0) = 0 Then ArraysAreEqual = False Else ArraysAreEqual = True

End Function


advantages of my approach:
- more simple, just 1 line;
- faster;
- we can compare any number of arrays

but any advices will be appreciate! especially disadvantages !

Wednesday, January 02, 2008

how to take all schedule agents from db

it takes all schedule agents from database. I suppose that somebody will find better solution, but for this moment I don't see the better solutions...

Dim s As New NotesSession
Dim db As NotesDatabase
Dim nc As NotesNoteCollection

Set db = s.CurrentDatabase

Set nc = db.CreateNoteCollection(False)
nc.SelectAgents = True
Call nc.BuildCollection

Dim note As NotesDocument
Dim nid As String
Dim flag As String

nid = nc.GetFirstNoteId
For i = 1 To nc.Count

Set note = db.GetDocumentByID(nid)
flag = note.GetItemValue("$Flags")(0)

If Instr(flag, "S") Then
Print note.GetItemValue("$Title")(0)
End If
nid = nc.GetNextNoteId(nid)
Next

Friday, December 21, 2007

Windows 95 or Windows NT

I was surprised when my friend shown me this in "help" ! I gave respect to Lotus after that.

This example compiles and runs in either Windows 3.1, Windows NT, or Windows 95. Depending on whether the application is compiled and run under 16-bit Windows (Windows 3.1) or 32-bit Windows (Windows 95 or Windows NT), you should declare and use an appropriate Windows handle variable and the appropriate version of two Windows API functions.

GetActiveWindow returns the handle (an Integer in 16-bit Windows, a Long in 32-bit Windows) of the currently active window. GetWindowText returns the text in the window title bar.

Dim winTitle As String * 80
%If WIN16 ' 16-bit Windows
Dim activeWin As Integer ' Window handles are Integer.
Declare Function GetActiveWindow% Lib "User" ()
Declare Function GetWindowText% Lib "User" _
(ByVal hWnd%, ByVal lpstr$, ByVal i%)
%ElseIf WIN32 ' 32-bit Windows
Dim activeWin As Long ' Window handles are Long.
Declare Function GetActiveWindow& Lib "User32" ()
Declare Function GetWindowText% Lib "User32" _
Alias "GetWindowTextA" _
(ByVal hWnd&, ByVal lpstr$, ByVal i&)
%End If
' Print the name of the currently active window.
activeWin = GetActiveWindow() ' Returns an Integer or a Long.
Call GetWindowText(ActiveWin, winTitle$, 80)
Print winTitle$

Monday, December 17, 2007

crooser on openntf

I downloaded my crosser, which I did one year ago, to openntf (the biggest freeware lotus notes' portal in the world). I did it because I want to know what people think about it :) . maybe they will give me a push to next step. I wanted to do it from Summer 2007, but always forgot about it. Now the problem is solved.

will wait for any responces.

ooops, here is a link to my project on openntf

Thursday, November 01, 2007

Use doc.getitemvalue("fldName") instead doc.fldName

I think many developers for receiving value from field usually wrote next code:
...
dim n as integer
n = doc.fldName(0)
...

but they have to know that this code has some weak sides:
- it slowly then doc.GetItemValue("fldName")(0) near 15-20%;
- if in new version of Lotus Notes will appear new method with name "fldName" the application will work wrong

Thursday, September 06, 2007

how will be right to hide fields

Usually, developers Lotus Notes, write the hidden formula directly in every paragraph... But I recommend to write all hidden formulas in one field. So, this special field will contain all fields which you need to hide. So in paragraph you will need only write something like this:
hiddenFld = "NameOfField".

Of course, you can use the same idea for validations all necessary fields.

Just try it and I think you will like it :)

Tuesday, August 28, 2007

Converting Host Name To IP Address

This code was found on a Visual Basic web site and converted to LotusScript. It is a LotusScript class that allows you to convert a host name to its IP address. To use, create a new HostName object. Then check the IPAddress property of the new object to get the IP address. The property is a string.

This code is best stored in a script library. Create a new script library, then go to the (Declarations) section. The first part of that section is some constants:

Public Const IP_SUCCESS = 0
Private Const WSADescription_Len = 255 ' 256, 0-based
Private Const WSASYS_Status_Len = 127 ' 128, 0-based
Public Const WS_VERSION_REQD = &H101
Public Const MIN_SOCKETS_REQD = 1
Public Const SOCKET_ERROR = -1

After that, a custom Type is needed, still in the (Declarations) section.

Public Type WSADATA
wVersion As Integer
wHighVersion As Integer
szDescription(0 To WSADescription_Len) As Integer
szSystemStatus(0 To WSASYS_Status_Len) As Integer
wMaxSockets As Long
wMaxUDPDG As Long
dwVendorInfo As Long
End Type


Note: If you are using R6, then you can define szDescription and szSystemStatus as Byte arrays instead of Integer arrays.
Next comes the Windows API calls we will need to convert the host name to the IP address:

Declare Function gethostbyname Lib "wsock32" (Byval hostname As String) As Long
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (xDest As Any, xSource As Any, Byval nbytes As Long)
Declare Function lstrlenA Lib "kernel32" (lpString As Any) As Long
Declare Function WSAStartup Lib "wsock32" (Byval wVersionRequired As Long, lpWSADATA As WSADATA) As Long
Declare Function WSACleanup Lib "wsock32" () As Long
Declare Function inet_ntoa Lib "wsock32.dll" (Byval addr As Long) As Long
Declare Function lstrcpyA Lib "kernel32" (Byval RetVal As String, Byval Ptr As Long) As Long


Finally, the actual class definition comes. This class definition is pretty simplified (there aren't a lot of properties/methods).

Class HostName
Private HostNameStr As String
Public IPAddress As String
Public ErrMsg As String
Public Error As Integer
Sub New(host As String)
If SocketsInitialize() Then
Me.IPAddress = GetIPFromHostName(host)
Me.Error = 0
Me.ErrMsg = ""
If Not SocketsCleanup Then
Me.Error = 200
Me.ErrMsg = "Windows Sockets error occurred in Cleanup."
End If
Else
Me.Error = 100
Me.ErrMsg = "Windows Sockets for 32 bit Windows is not successfully responding."
Me.IPAddress = ""
End If
End Sub
End Class


Some additional functions are needed. Those are defined below. They are still part of the script library.

Private Function SocketsInitialize() As Integer
Dim WSAD As WSADATA
Dim success As Long
SocketsInitialize = (WSAStartup(WS_VERSION_REQD, WSAD) = IP_SUCCESS)
End Function

Private Function SocketsCleanup() As Integer
If WSACleanup() <> 0 Then
SocketsCleanup = False
Else
SocketsCleanup = True
End If
End Function

Private Function GetIPFromHostName(Byval sHostName As String) As String
Dim ptrHosent As Long
Dim ptrName As Long
Dim ptrAddress As Long
Dim ptrIPAddress As Long
Dim dwAddress As Long
ptrHosent = gethostbyname(sHostName & Chr(0))
If ptrHosent <> 0 Then
ptrName = ptrHosent
ptrAddress = ptrHosent + 12
CopyMemory ptrAddress, Byval ptrAddress, 4
CopyMemory ptrIPAddress, Byval ptrAddress, 4
CopyMemory dwAddress, Byval ptrIPAddress, 4
GetIPFromHostName = GetIPFromAddress(dwAddress)
End If
End Function

Public Function GetIPFromAddress(Address As Long) As String
Dim ptrString As Long
ptrString = inet_ntoa(Address)
GetIPFromAddress = GetStrFromPtrA(ptrString)
End Function

Public Function GetStrFromPtrA(Byval lpszA As Long) As String
GetStrFromPtrA = String$(lstrlenA(Byval lpszA), 0)
Call lstrcpyA(Byval GetStrFromPtrA, Byval lpszA)
End Function


(author is here http://www.sbacode.com/pageTips.aspx?id=207&)

Wednesday, August 22, 2007

CGI variables (Remote_Addr)

here are some examples of getting the CGI variables from a web-agent.

LotusScript
Sub Initialize
Dim session As NotesSession
Set session = New NotesSession
Dim doc As NotesDocument
Set doc = session.DocumentContext
Print "IP address =" + doc.Remote_Addr(0)
End Sub

Java
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
Document doc = agentContext.getDocumentContext();
getAgentOutput().println("IP address = " + doc.getItemValueString("Remote_Addr"));
}
catch(Exception e) {
e.printStackTrace();
}
}
}

Monday, July 16, 2007

Microsoft Excel Worksheet (Embedded Object)

Today I did a simple task, but I never do it before. So, I had a simple form with Microsoft Excel Worksheet (Embedded Object). My task was to extract this embedded object from notes's documents to disk in folder. I had 2 problems:
- how I can choose a folder on my own PC from Lotus Notes client?
- how I can extract object as MS Excek file and save it in chosen folder?

the first task I solved by using undocumented method of NotesUIWorkspace: Let folderTo = w.prompt(14, "", "")

second task I solved by using next code:

If doc.HasEmbedded Then
Forall o In doc.EmbeddedObjects
Set handle = o.Activate(True)
If Not handle Is Nothing Then
Set exWb = handle.Application.ActiveWorkBook

'
Let VNumber = doc.GetItemValue("VNumber")(0)
Let Agreement_1 = doc.GetItemValue("Agreement_1")(0)
Let fileName = VNumber & SEP & Agreement_1 & ".xls"
'


On Error Resume Next
Call exWb.SaveAs(folderTo & fileName)
Print {Operate with file '} & folderTo & fileName & {'}
On Error Goto ERR_THIS
End If
End Forall
End If

Monday, June 18, 2007

Layer vs Dialog

Some days ago one my friend showed me nice approach for creating dialog, maybe it was nice only for me but I think many of Lotus Motes developers never thought about this approach before. As usual I used form/subform to create UI of my future dialog and then show it using @dialogbox or notesuiworkspace, but in this approach we lay layer onto our main form from which we will show a dialog. One of the main advantage of this approach is that we can change window in Lotus Notes during working in dialog.

Tuesday, March 06, 2007

Folder with shared actions to DXL

I try to explain my task and a problem.
I must export ($Inbox) folder from my mail database to DXL file, then do modification in this DXL file (add action) and then I must import it into another database. But as you know folder ($Inbox) has shared action. So when I export folder to DXL file I see that the content of file contains next text



and of course, when I try to import DXL file as folder it generate bad folder. You can try it and you will see what I mean.
I have only 1 good idea, how to export folder with no . I must copy it to another database and resave it. Then all shared actions will change their type to non shared actions and my task will be solved. Unfortunaly I cant do it :(.

Maybe anybody can help me ?

Friday, March 02, 2007

NotesNoteCollection + ExportDesignElement + NotesDXLImporter

Here, I try to explain you how we can change design document with Lotus Script.
For example you want to put a subformA from database1 to formA in database2.

1) So, firstly you must copy our subform from database1 to database2.
Dim nc As NotesNoteCollection
Dim doc As NotesDocument
Dim El As String
Dim nid As String, nextid As String
Dim i As Integer

Set nc = db.CreateNoteCollection(False)
Let nc.SelectSubforms = True
Call nc.BuildCollection

Set GetNoteElement = Nothing
Let nid = nc.GetFirstNoteId

For i = 1 To nc.Count
Let nextid = nc.GetNextNoteId(nid)
Set doc = db.GetDocumentByID(nid)
Let El = doc.GetItemValue("$TITLE")(0)
If El = “subformA” Then
Set GetNoteElement = doc
Let i = nc.Count
End If
Let nid = nextid
Next

...
And then copy to database2 as usual notesdocument.
...

2) This is main step. You must take a formA from database2 and export it, then take the content of export file and add to it

Dim s As New notessession
Dim stream As NotesStream
Dim content As String
Set stream = s.CreateStream
If Not stream.Open(filepath, "UTF-8") Then
Print "Not open"
Exit Sub
End If
If stream.Bytes = 0 Then
Print "Not content"
Exit Sub
End If

Let content = stream.ReadText()

If Instr(content, {wtInclude}) = 0 Then
Let content = Replace(content, {}, {})
End If

Call stream.Truncate
Call stream.WriteText(content)
Call stream.Close

3) Then you must import this file to database2.

I tested it on XP and 2000, and it worked.