OpenDOM

Sunday, December 09, 2007

Undocumented LotusScript R8loaded


Here’s a short list of undocumented LotusScript properties and methods I built out the Notes R8 notes32.tlb type library.

Usual caution applies to such unsupported materiel. Use this at your personal convenience with no guarantee.

  • NotesDatabase
    archiveDestinations : Variant
  • NotesDocument
    SequenceTime : Variant
Plot Undocumented DOM LotusScript Using Visual Basic 2005 Express free Edition and Use Rational Rose to Identify Undocumented DOM Properties and Methods detail steps to follow in order to dive into Domino/Notes R8 LotusScript hidden features. Undocumented DOM LotusScript Inventory details LotusScript undocumented properties and methods in Notes Release 7.

Labels: , ,

Wednesday, July 25, 2007

OpenDOM fun!



Friday, April 06, 2007

Interfaces & Abstract Classes with LotusScript


Interface and abstract classes define objects properties and methods, just as ordinary classes do. One generally creates as many objects as necessary from standard classes, while interface classes are solely intended to describe contracts that future objects will guarantee. Interfaces classes usually contain no code and can't be used to instantiate objects. In turn abstract classes prototype properties and methods. Abstract classes can't be instantiated either and require to be derived so that its subclasses benefit from their code. Compilers closely control interface compliant classes and usually prevent from interface or abstract classes instantiations.

Designers usually resort to interface or abstract classes to build loosely coupled application code that's more adaptable, more maintainable and ends up being more robust. Although such class constructs are missing from native LotusScript, those object oriented design concepts can be implemented in your LotusScript code with little effort.

As an exemple, consider designing a LotusScript.io.File class that holds the following subset of attributes and operations: canWrite( ), getAbsolutePath( ), length( ), list( ), renameTo( ). You may either develop a full LotusScript solution, either build an LS2J based solution, either resort to Windows Script Host COM object library or even call Windows/32 native functions. Defining iFile interface class sounds a valuable approach that exhibits properties and methods regardless of the implemented inner workings. While your calling code relies on a stable interface, your concrete implementations can vary at will or be changed without notice. Doing so you're building a loosely coupled Notes or Domino application.

Figure 1: StopWatches UML Class Diagram

OpenDOM open source project you can download from www.openntf.org contains numerous code samples benefitting from interfaces and abstract classes design constructs. Its LotusScript.lang.StopWatches library uses iTicker public interface in four different implementations accommodating LotusScript release 3 and 4+, Windows/16 and Windows/32 contexts. LotusScript.lang.Rn or LotusScript.windows.winnn packages, or namespaces, contain iTicker interface compliant concrete classes. StopWatches public class internal iTicker engine gets loaded dynamically according to the most appropriate situation.

You can prevent from objects instantiation, and make sure properties and methods get derived or overridden. But creating private LotusScript class constructors as in ..
Public Class iVehicle
Private Sub New
End Sub
End Class ' iVehicle
.. throws the following compiler exception :
<noteName>: <eventName>: <lineNumber>: Illegal PRIVATE declaration of: NEW

As LotusScript does not natively support interface classes or private constructors as above I adopted another approach. I prevent from interface or abstracts classes instantiation at runtime only throwing exception in class constructors, I force properties and methods to be derived throwing equivalent runtime exceptions as in :
%INCLUDE "LsErr.lss"
Public Class iVehicle '
Public Sub New ' This forbids interface instantiation, please derive me !
If Typename( Me ) = "IVEHICLE" Then Error ErrNotAnObject
End Sub ' New
Public Property Get Color As NotesColor
Error errPropGetNotDefined
End Property ' Color
Public Property Set Price As Currency
Error errPropSetNotDefined
End Property ' Price
Public Sub starts( )
Error ErrNotAMethod
End Sub ' starts( )
End Class ' iVehicle

Public Class aShuttle
Public Property Get isFree As Boolean '
Error errPropSetNotDefined
End Property ' isFree
End Class ' aShuttle

Once I established my interface, I can devise to write as many concrete classes implementing it and provide a factory class or routine serving context dependent objects :
Private Class Car As iVehicle
' Your code goes here ..
End Class ' Car As iVehicle

Private Class Truck As iVehicle
' Your code goes here ..
End Class ' Truck As iVehicle

Public Function createVehicle As iVehicle
If ( so And so ) Then
Set Me.createVehicle = New Car
Else
Set Me.createVehicle = New Truck
End If
End Function

OpenDOM LotusScript.lang.Factory class creates objects this way. It is inspired from « Performance Considerations for Domino Applications » IBM redbook whose « B-2 Dynamic Script Library Loading » worth reading appendix explains how to dynamically load LotusScript libraries in your object oriented programs. While IBM code performs objects dynamic instantiation, attentive reading reveals such is accomplished using variants that defeat compiler time type checks. Adding interface classes your code overcomes this obstacle and offers multiple advantages :
  • You're designing loosely coupled LotusScript while building application classes regardless of their internal technical alternatives you will freely accommodate,
  • Early bound objects allow type safety controls to occur at compile time which is considered a best practice,
  • LotusScript interpreter memory footprint increases progressively as library objects are gradually loaded. Although libraries are compiled prior to be loaded, this gets mostly unnoticed and is largely compensated by memory minimised consumption.
In order to achieve early binding of dynamic objects, Factory class makes intensive use of interface or abstract classes. As opposed to IBM NewObj original routine Factory class dynamically instantiates strongly typed objects, thus provides compile-time checks which enforces applications robustness and reliability.

Places of interest:

Labels: , , , , , , ,

Wednesday, March 21, 2007

Static Properties & Methods in LotusScript Classes


In Java and JavaScript languages, static properties and static methods are shared by all instances of a given class. Non static members relate to objects instantiated from a class and are relevant to a single instance of that class thus File objects share pathSeparator operating system dependent static property, while getAbsolutePath( ), canWrite( ) properties differ from a File object to another as the delete( ) method yields separate results for every object. Utilizing static members does not require to instantiate objects e.g. java.io.File class pathSeparator property can be referenced typing File.pathSeparator or java.io.File.pathSeparator.

Creating class level properties or methods in LotusScript may be useful. Consider a Platform class with properties such as Newline and supportsCOM. Although this class exhibits different information depending on the operating system, Newline and supportsCOM results are identical across all instances of the Platform class for a given Notes client or Domino server. Imagine a LotusScript.math package holding a Trigo utility class with sin(), cos() methods and a PI static property whose precisions are greater than that of native LotusScript Pi constant and functions.

Although static members are not available in LotusScript to the extent Java and Javascript languages provide them, you can implement similar constructs with identical coding syntax. As an exemple I shall use LotusScript.lang.Interpreter class and its Release property, available from OpenDOM open source project at www.openntf.org site to illustrate my point.

Private Release As String
Release = lsi_info( 6 )

While these two lines are the simplest way to compute a given LotusScript interpreter release, I like to protect my code from any sins including my own and I tend to adopt the following defensive coding technique :

Static Private Property Get INTERPRETER_RELEASE As String
Static this As String
If this = "" Then this = Lsi_info( 6 )
INTERPRETER_RELEASE = this
End Property ' LotusScript.lang.Interpreter.RELEASE property

LotusScript simplified Interpreter public class spells as follows :

Public Class Interpreter '
Property Get RELEASE As String '
Me.RELEASE = INTERPRETER_RELEASE
End Property ' LotusScript.lang.Interpreter.RELEASE
End Class ' LotusScript.lang.Interpreter Class

Note every objects instantiated from the Interpreter class share a common RELEASE property that can be qualified static as in Java and JavaScript. The Interpreter.RELEASE syntax can be implemented in "LotusScript.lang" script library as :

Static Public Property Get Interpreter As Interpreter
Static this As Interpreter
If this Is Nothing Then Set this = New Interpreter
Set Interpreter = this
End Property ' LotusScript.lang.Interpreter class

Such ability can be extended to LotusScript.lang.Interpreter.RELEASE fully qualified class name coding two extra classes and two properties as in :

Public Class lang '
Public Property Get Interpreter '
Set Me.Interpreter = LANG_INTERPRETER
End Property ' LotusScript.lang.Interpreter
End Class ' LotusScript.lang.* Package
Public Class LotusScript '
Public Property Get lang As lang '
Set Me.lang = LOTUSSCRIPT_LANG
End Property ' LotusScript.lang.* Package
Public io As Variant ' As io__ '
Public net As Variant ' As net__ '
End Class ' LotusScript.* Package

Static Private Property Get LOTUSSCRIPT_LANG As lang
Static this As lang
If this Is Nothing Then Set this = New lang
Set LOTUSSCRIPT_LANG = this
End Property ' LotusScript.lang.* package
Static Public Property Get LotusScript As LotusScript
Static this As LotusScript
If this Is Nothing Then
Set this = New LotusScript
End If
Set LotusScript = this
End Property ' LotusScript.* package

Any agents, forms or views now require few lines of code to fully reuse "LotusScript.lang" package library :

Use "LotusScript.lang"
Msgbox LotusScript.lang.Interpreter.RELEASE,, _
"LotusScript.lang.Interpreter.RELEASE"
' OR
With LotusScript.lang
Msgbox Interpreter.RELEASE,, _
"Interpreter.RELEASE"
End With

Labels: , , , , ,

Tuesday, February 06, 2007

Rehabilitate Document Preview !

Since framesets have been available to Domino designers, that is from release 5 onwards, Notes applications attempted to escape from the traditional 3-panes user interface that long-time proposed a left navigation pane, a right-top view pane and a right-bottom document preview. As developers discovered the flexibility offered by framesets, few Notes applications have exhibited original interfaces, many applications have retained a traditional 3-frames arrangement while others even presented a somewhat limited 2-frames disposition.

As framesets have become prevalent while building Notes applications user interfaces or entry points, this post proposes to rehabilitate document preview in applications that rely on framesets.

3 different dispositions keep accompanying Notes classical 3-panes default presentation. You obtain them selecting View - Document Preview - Arrange Preview... context menu as illustrated in figure 1 below. Notice the so-called "Bottom Right" usual layout you're familiar with. While choosing a location end-users are provided three different interfaces. Unfortunately, nowadays frameset built applications rarely offer such a flexible and powerful user-oriented design.

Figure 1: View - Document Preview - Arrange Preview... dialog window.

While I do not mean developers should systematically propose multiple variations in pane arrangements, bringing particular attention and care while building user interfaces is common wisdom in designers community. Observe end-users are offered another option, past document preview activation. Using View - Document Preview - Zoom Preview context menu, documents can be maximised or set back to preview mode. If you feel like emulating document preview and zoom in framesets, please read on!

Despite this long introduction, enabling document preview in framesets is easy, although not really documented. Suffice to name a frame "NotesPreview" and you're done! Truth is framesets secretly resort to "NotesPreview" hardcoded name to implement document preview. Say your application uses a 2-frame arrangement, as shown in figure 2, and you intend to zoom documents using a 3-frame arrangement as in figure 3. Split the right frame in 2 rows, name its bottom empty frame "NotesPreview", set its height to 0 and make sure the upper frame links target "NotesPreview" lower frame. Save your frameset and observe View - Document Preview context menu now contains two new options: Show Preview and Zoom Preview.

I have systematically implemented document preview whenever I could and I've retained my addiction to document preview/zoom combined with the usage of framesets. Don't frustrate your experienced Notes users and start "NotesPreview"ing to their benefit !

Figure 2: 2-Frame arrangement i.e. Right-Left


Figure 3: 3-Frame arrangement so-called "Bottom Right"


Figure 4: Naming a frame "NotesPreview" suffices to implement show preview or zoom preview for documents.

Labels: , ,

Saturday, December 30, 2006

Opening Control Panel applets in modal dialog boxes - Windows/32 only

Executing Windows/32 Control Panel applets from LotusScript is easy. Suffice to code a Shell statement appending the applet name to the control program and the job is done. The following code sample opens up "Display Properties" and "Tweak UI" control panel dialogs.


Dim TaskID As Integer
taskID% = Shell( "control desk.cpl" ) ' Let's open up "Display Properties" window ..
taskID% = Shell( "tweakui.cpl" ) ' .. then "Tweak UI" dialog box afterwards.

Applets shelled this way run independently from Notes applications whereas the ability to execute applets in Notes threads is tied to your client operating system. Nir Sofer's site [1] details how Visual Basic programmers can display Control Panel applets within modal dialog boxes. Nir achieves this performing Windows API calls and using VarPtr() Visual Basic only statement. While VarPtr() is not supported in LotusScript, designers with appropriate Windows/32 C API experience, can implement equivalent functionality. Thus Nir's Visual Basic code ..



Private Declare Function CPlApplet_Main Lib "main.cpl" Alias "CPlApplet" _
( ByVal hwndCPl As Long, ByVal uMsg As Long, ByVal lParam1 As Long, _
ByVal
lParam2 As Long ) As Long
Private Sub MainCplApplet( lParam1 As Long )
If CPlApplet_Main( hWnd, CPL_INIT, 0, 0 ) <> 0 Then
CPlApplet_Main hWnd, CPL_INQUIRE, lParam1, VarPtr( ci )
CPlApplet_Main hWnd, CPL_DBLCLK, lParam1, ci.lData
CPlApplet_Main hWnd, CPL_STOP, 0, ci.lData
CPlApplet_Main hWnd, CPL_EXIT, 0, 0
End If

.. can be translated into LotusScript as:


Declare Private Function Applet Lib "main.cpl" Alias "CPlApplet" _
( Byval hwndCPl As Long, Byval uMsg As Long, Byval lParam1 As Long, _
Byval
lParam2 As Long ) As Long
Declare Private Function AppletVarPtr Lib "main.cpl" Alias "CPlApplet" _
( Byval hwndCPl As Long, Byval uMsg As Long, Byval lParam1 As Long, _
lParam2 As CPLINFO ) As Long ' NOTE the last argument modification HERE !
If Applet( hwnd, CPL_INIT, 0, 0 ) <> 0 Then
' Visual Basic VarPtr() statement does not exist in LotusScript ...
AppletVarPtr hwnd, CPL_INQUIRE, lParam1, ci
' ... AppletVarPtr declare is emulating VarPtr(ci) statement
CPlApplet_Main hWnd, CPL_DBLCLK, lParam1, ci.lData
CPlApplet_Main hWnd, CPL_STOP, 0, ci.lData
CPlApplet_Main hWnd, CPL_EXIT, 0, 0
End If

Note AppletVarPtr() above function in Windows C API second declare statement, its last argument is defined as a CPLINFO structure. It is sent by reference instead of being sent by value which emulates VarPtr() Visual Basic statement. All control panel applets can be called this way. I decided not to code numerous declares, but used an APPLET_CODE_TEMPLATE string where AppletName and lParam1 arguments are dynamically substituted. This way applets are loaded and executed at runtime as in:


Private Sub AppletLoader( Byval appletName As String, Byval parm1 As String )
toList( 0 ) = appletName
toList( 1 ) = parm1
' Domino Release 6 ONLY
Execute Replace( APPLET_TEMPLATE_CODE, fromList, toList )
End Sub

I wrapped up a few applets' calls in a ControlPanel class bundled in OpenDOM open source project that you can download from OpenNTF.org site. You can use it as shown below:



Use "LotusScript.windows.win32"
Dim ui As New ControlPanel
ui.AccessibilityOptions
ui.DisplayProperties
ui.MultimediaProperties
ui.AppletLoader "tweakui", "0"

I hope you'll find ControlPanel class useful and shall be glad to hear about any interesting usage you experiment with it or about any extensions you make to it.


Credit: [1] Executing Control Panel applets

Labels: , , , ,

Thursday, December 14, 2006

Plot Undocumented DOM LotusScript Using Visual Basic 2005 Express free Edition

Today's post is a three steps introspection guide to «Lotus Notes Automation Classes» best kept secrets.

1. Suffice to add a new reference to your .NET project using Project - Add reference... menu.

As an alternative you can equally right-click Solution explorer window and select Add reference...
2. You then select «Lotus Notes Automation classes» from the COM tab component list. Activate the class browser either keying F2 either selecting View - Object browser command menu.

3. You can now explore the lotus package classes and view their attributes and operations.

Note that depending on your PC's color palette undocumented properties and methods will be denoted in light grey.

Using Microsoft C# 2005 Express free Edition functions equally. I guess any other professional .NET toolkit would work just as well. Note that latest #Develop open source IDE does not provide COM libraries equivalent expansion.

Labels: , ,