Eigentlich wollte ich diesen Blog-Eintrag anders nennen: "Von einem, der auszog, Notes 14 zu testen". Sicherlich poetischer, aber weniger informativ (als Titel) und weniger "suchmaschinengeeignet".
Hintergrund dieses Artikel ist aber tatsächlich, dass ich das Experiment wagen wollte, meinen Domino Administrator, Designer und Notes-Client auf Version 14 zu bringen, obwohl wir viele komplexe Anwendungen entwickelt haben und nutzen. Gegenüber früheren Hauptversionen gab es zwei große Änderungen, die aus meiner Sicht das Potential haben könnten, dass ich zumindest mit einigen Anwendungen Probleme haben könnte: Es gibt den Notes-Client in der Version 14 nur noch als 64-bit Anwendung und das ziemlich in die Jahre gekommene Java 8 wurde durch ein "bewährtes" Java 17 ersetzt.
Die ersten Tests - Excel-Export über die COM-Schnittstelle und Java, sogar über die LS2J-Schnittstelle - liefen sofort anstandslos. Ehrlich gesagt, hätte ich mit etwas anderem gerechnet. Ich habe erst während des Tests nachgeschaut, dass bei mir schon Microsoft Office in der 64-bit-Version installiert war, sonst hätte ich es sicherlich neu installieren müssen.
Ärger gab es dann an anderer Stelle, an die ich zunächst gar nicht gedacht hatte: Wir nutzen in unseren Anwendungen an verschiedenen Stellen C-API-Aufrufe aus LotusScript heraus. Die Notes-C-API-Aufrufe liefen auch alle glatt durch, aber eine in unserem assono Passwort-Safe Pro häufig genutzte Funktion, die Windows-C-API-Aufrufe nutzt, sorgte für einen reproduzierbaren, sofortigen Absturz des Notes-Clients. Es geht dabei um das Kopieren von Text in die Windows-Zwischenablage.
Quell des Ungemachs: Pointer
Im Kern ging es bei dem Problem um die Verwendung von Pointern (Zeigern auf bestimmte Speicherbereiche). Die "Größe" der Pointer, also wie viele Bits diese lang sind, unterscheidet sich zwischen einer 32-bit-Anwendung und einer 64-bit-Anwendung unter Windows: Sie sind dann nämlich 32-bit bzw. 64-bit lang.
Generell ist bei C-API-Aufrufen aus LotusScript heraus, die Abbildung von LotusScript- und C-Datentypen für mich schon immer eines der eher schwierigeren Themen gewesen.
Im 32-bit Notes-Client war es aber noch relativ einfach: Ein Pointer in C ist 32-bit lang, genauso wie der LotusScript-Datentyp Long. Grundsätzlich ließen sich also Long-Variablen und -Ausdrücke verwenden, wenn es um Pointer in der Aufrufsignatur von C-Funktionen ging.
Im 64-bit Notes-Client sind - wie in allen 64-bit Anwendungen unter
Windows - die Pointer 64-bit lang, Long ist aber weiterhin nur 32-bit.
Nun ist zwar der Notes-Client in der 64-bit-Variante neu, aber den Domino-Server gibt es schon länger in 64-bit. Dort sind viele Probleme schon aufgetreten und gelöst worden. Und das kam mir jetzt auch zu Gute.
Workarounds
Es gibt in LotusScript einen Datentyp, der 64-bit lang ist: Double.
Weil sich Double aber nicht einfach so als Pointer verwenden lässt, hat
HCL einen Workaround eingebaut: Ist die notes.ini-Einstellung
LS64BITCCALLOUTPointerSupport=1 auf dem Domino-Server gesetzt, lassen
sich Double-Variablen und -Ausdrücke wie 64-bit-Pointer verwenden. Siehe "HCL Domino crashes because of Agent using long data type" und "Using LotusScript C-Callouts on non-32-bit Platforms".
Großer Pferdefuß dabei: Das gilt dann natürlich für alle Double in allen LotusScript-Agenten und -Bibliotheken in allen Anwendungen auf dem Server...
In Notes und Domino 12.0.1 kam der "bessere Workaround" in Gestalt der NotesSession.UseDoubleAsPointer-Property.
Wenn man die Property innerhalb von LotusScript-Code auf True setzt,
lassen sich Double-Werte als Pointer verwenden. Und man kann es nach
Bedarf ein- und ausschalten, so dass man an anderen Stellen im Code
Doubles noch normal als Gleitkommazahlen einsetzen kann.
Was bedeutet das Ganze jetzt konkret?
Ich zeige das an einem kleinen, isolierten Beispiel. Hier die ursprüngliche Version für den 32-bit Notes-Client:
Declare Function SetClipboardData Lib "User32" (Byval wFormat As Long, Byval hMem As Long) As Long
Declare Function GlobalLock Lib "kernel32" (Byval hMem As Long) As Long
Das sind zwei der C-Funktionen, die wir brauchen, um einen Text in die Windows-Zwischenablage zu kopieren.
Einige der Longs sind Pointer, andere "nur" Zahlenwerte. Nur an den Stellen, wo Pointer erwartet werden, darf/muss man Long durch Double ersetzen:
Declare Function SetClipboardData Lib "User32" (ByVal wFormat As Long, ByVal hMem As Double) As Long
Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Double) As Double
Bevor man diesen C-Funktionen dann aufruft, muss man daran denken, die Property auf True zu setzen:
' irgendwo vorher: Dim session as New NotesSession
session.UseDoubleAsPointer = True
Jetzt gibt es nur ein kleines, ganz, ganz unwichtiges Problem: Sobald diese Zeile im Code steht, lässt sich das Gestaltungselement (Agent, Script-Bibliothek, ...) nicht mehr mit einem Domino Designer vor 12.0.1 kompilieren. Autsch!
Zum Glück kann man den Execute-Befehl nutzen, um diese Code-Zeile vor dem Compiler zu "verstecken". Also stattdessen:
Execute |session.UseDoubleAsPointer = True|
Wichtig: Alle Variablen, auf die Execute zugreifen soll, müssen global und Public deklariert sein, also im (Declarations)-Abschnitt. Das ist bei session sicherlich einfach umsetzbar (machen wir sogar immer so über eine Basis-Script-Bibliothek).
Danke!
Auf meinem Weg habe ich im HCL Community-Forum Hilfe gesucht und gefunden in dem Eintrag: "How to use RtlMoveMemory of kernel32 in Notes 64-bit?" Dort findet man auch ein deutlich größeres Code-Beispiel.
Besonders bedanken möchte ich mich bei einem Bekannten aus den USA, den ich wohl schon vor bald zwei Jahrzehnten auf einer Konferenz kennengelernt habe: Julian Robichaux. Herzlichen Dank für deine wertvolle Hilfe!
Und wie der Zufall so spielt: Julian wird am 30. Januar ein Webinar zu dem Thema halten: "Developer Special: How to Prepare Applications for Notes 64-bit Clients". Ich habe mich schon Mitte Dezember angemeldet. Ich habe die sichere Ahnung, dass es wieder großartig wird!