How to use RtlMoveMemory of kernel32 in Notes 64-bit?

In order to copy some information to the Windows clipboard in LotusScript, I use some Windows API calls for years now. Since it's Windows only and all Notes clients for Windows were 32-bit, I never had to consider 64-bit calls - until now with Notes 14 being 64-bit only.

The API call to set clipboard text is

Declare Function SetClipboardData        Lib "User32"    (Byval wFormat As Long, Byval hMem As Long) As Long

But in order to call this, I have to prepare the text in a "buffer" to handle it over to SetClipboardData. For this I use

Declare Sub CopyMemory                    Lib "kernel32" Alias "RtlMoveMemory"    (Destination As Any, Source As Any, Byval Length As Long)

And the call of this function crashes Notes 14 64-bit immediately.

What do I need to change for the 64-bit Notes client?

More of the code:

(Declarations)
' Clipboard formats
'
' see: http://msdn2.microsoft.com/en-us/library/ms649013.aspx
Public Const CF_BITMAP = 2 ' handle to a bitmap (HBITMAP, http://msdn2.microsoft.com/en-us/library/aa383751.aspx).
Public Const CF_DIB = 8 ' memory object containing a BITMAPINFO (http://msdn2.microsoft.com/en-us/library/ms532284.aspx) structure followed by the bitmap bits.
Public Const CF_DIBV5 = 17 ' Windows 2000/XP: memory object containing a BITMAPV5HEADER (http://msdn2.microsoft.com/en-us/library/ms532331.aspx) structure followed by the bitmap color space information and the bitmap bits.
Public Const CF_DIF = 5 ' Software Arts' Data Interchange Format.
Public Const CF_DSPBITMAP = &H82 ' Bitmap display format associated with a private format. The hMem parameter must be a handle to data that can be displayed in bitmap format in lieu of the privately formatted data.
Public Const CF_DSPENHMETAFILE = &H8E ' Enhanced metafile display format associated with a private format. The hMem parameter must be a handle to data that can be displayed in enhanced metafile format in lieu of the privately formatted data.
Public Const CF_DSPMETAFILEPICT = &H83 ' Metafile-picture display format associated with a private format. The hMem parameter must be a handle to data that can be displayed in metafile-picture format in lieu of the privately formatted data.
Public Const CF_DSPTEXT = &H81 ' Text display format associated with a private format. The hMem parameter must be a handle to data that can be displayed in text format in lieu of the privately formatted data.
Public Const CF_ENHMETAFILE = 14 ' handle to an enhanced metafile (HENHMETAFILE, http://msdn2.microsoft.com/en-us/library/aa383751.aspx).
Public Const CF_GDIOBJFIRST = &H300 ' through CF_GDIOBJLAST:
Public Const CF_GDIOBJLAST = &H3FF ' Range of integer values for application-defined Microsoft Windows Graphics Device Interface (GDI) object clipboard formats. Handles associated with clipboard formats in this range are not automatically deleted using the GlobalFree function when the clipboard is emptied. Also, when using values in this range, the hMem parameter is not a handle to a GDI object, but is a handle allocated by the GlobalAlloc function with the GMEM_MOVEABLE flag.
Public Const CF_HDROP = 15 ' handle to type HDROP (http://msdn2.microsoft.com/en-us/library/aa383751.aspx) that identifies a list of files. An application can retrieve information about the files by passing the handle to the DragQueryFile functions.
Public Const CF_LOCALE = 16 ' data is a handle to the locale identifier associated with text in the clipboard. When you close the clipboard, if it contains CF_TEXT data but no CF_LOCALE data, the system automatically sets the CF_LOCALE format to the current input language. You can use the CF_LOCALE format to associate a different locale with the clipboard text.
' An application that pastes text from the clipboard can retrieve this format to determine which character set was used to generate the text.
' Note that the clipboard does not support plain text in multiple character sets. To achieve this, use a formatted text data type such as Rich Text Format (RTF) instead.
' Windows NT/2000/XP: The system uses the code page associated with CF_LOCALE to implicitly convert from CF_TEXT to CF_UNICODETEXT. Therefore, the correct code page table is used for the conversion.
Public Const CF_METAFILEPICT = 3 ' handle to a metafile picture format as defined by the METAFILEPICT (http://msdn2.microsoft.com/en-us/library/ms649017.aspx) structure. When passing a CF_METAFILEPICT handle by means of Dynamic Data Exchange (DDE), the application responsible for deleting hMem should also free the metafile referred to by the CF_METAFILEPICT handle.
Public Const CF_OEMTEXT = 7 ' text format containing characters in the OEM character set. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals the end of the data.
Public Const CF_OWNERDISPLAY = &H80 ' Owner-display format. The clipboard owner must display and update the clipboard viewer window, and receive the WM_ASKCBFORMATNAME, WM_HSCROLLCLIPBOARD, WM_PAINTCLIPBOARD, WM_SIZECLIPBOARD, and WM_VSCROLLCLIPBOARD messages. The hMem parameter must be NULL.
Public Const CF_PALETTE = 9 ' handle to a color palette. Whenever an application places data in the clipboard that depends on or assumes a color palette, it should place the palette on the clipboard as well.
' If the clipboard contains data in the CF_PALETTE (logical color palette) format, the application should use the SelectPalette and RealizePalette functions to realize (compare) any other data in the clipboard against that logical palette.
' When displaying clipboard data, the clipboard always uses as its current palette any object on the clipboard that is in the CF_PALETTE format.
Public Const CF_PENDATA = 10 ' data for the pen extensions to the Microsoft Windows for Pen Computing.
Public Const CF_PRIVATEFIRST = &H200 ' through CF_PRIVATELAST:
Public Const CF_PRIVATELAST = &H2FF ' Range of integer values for private clipboard formats. Handles associated with private clipboard formats are not freed automatically; the clipboard owner must free such handles, typically in response to the WM_DESTROYCLIPBOARD message.
Public Const CF_RIFF = 11 ' represents audio data more complex than can be represented in a CF_WAVE standard wave format.
Public Const CF_SYLK = 4 ' Microsoft Symbolic Link (SYLK) format.
Public Const CF_TEXT = 1 ' text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals the end of the data. Use this format for ANSI text.
Public Const CF_WAVE = 12 ' represents audio data in one of the standard wave formats, such as 11 kHz or 22 kHz Pulse Code Modulation (PCM).
Public Const CF_TIFF = 6 ' tagged-image file format.
Public Const CF_UNICODETEXT = 13 ' Windows NT/2000/XP: unicode text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals the end of the data.

' Win-API functions used
Declare Function OpenClipboard Lib "User32" (Byval hWnd As Long) As Long
Declare Function CountClipboardFormats Lib "User32" () As Long
Declare Function EnumClipboardFormats Lib "User32" (Byval wFormat As Long) As Long
Declare Function GetClipboardData Lib "User32" (Byval wFormat As Long) As Long
Declare Function SetClipboardData Lib "User32" (Byval wFormat As Long, Byval hMem As Long) As Long
Declare Function EmptyClipboard Lib "User32" () As Long
Declare Function CloseClipboard Lib "User32" () As Long

Declare Function GlobalAlloc Lib "kernel32" (Byval wFlags&, Byval dwBytes As Long) As Long
Declare Function GlobalLock Lib "kernel32" (Byval hMem As Long) As Long
Declare Function GlobalUnlock Lib "kernel32" (Byval hMem As Long) As Long
Declare Function lstrcpy Lib "kernel32" (Byval lpString1 As String, Byval lpString2 As Long) As Long
Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (Byval lpString As Any) As Long
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, Byval Length As Long)

Public Sub SetClipboardText(Byval text As String)
'/**
' * puts text into clipboard.
' *
' * @param text to put into the clipboard.
' *
' * @author Thomas Bahn <tbahn@assono.de>, Bernd Hort <bhort@assono.de>
' * @version 2014-07-24
' */

Const GMEM_MOVEABLE = &H2
Const GMEM_ZEROINIT = &H40
Const GMEM_GHND = (GMEM_MOVEABLE Or GMEM_ZEROINIT)

Dim replaceList List As String
Dim handleForBuffer As Long
Dim pointerToBuffer As Long
Dim errorNr As Long

If Not IsDebugMode Then On Error Goto errorHandler

If session.Platform <> PLATFORM_W32 And session.Platform <> PLATFORM_W64 Then
replaceList("<%PLATFORM%>") = session.Platform
MessageBox ReplaceSubstringByList(GetProperty(COMMONS_LIBRARY & ".errmsg.unsupported.specific.platform"), replaceList), MB_OK + MB_ICONSTOP
Exit Sub
End If

' create buffer
handleForBuffer = GlobalAlloc(GMEM_GHND, Len(text) + 1)
If Isnull(handleForBuffer) Then ' NULL means error
errorNr = GetLastWinAPIError()
Error errorNr, GetLastWinAPIErrorText() & " (" & Cstr(errorNr) & ")"
End If

pointerToBuffer = GlobalLock(handleForBuffer)
If Isnull(pointerToBuffer) Then ' NULL means error
errorNr = GetLastWinAPIError()
Error errorNr, GetLastWinAPIErrorText() & " (" & Cstr(errorNr) & ")"
End If

' copy text to buffer
Call CopyMemory(Byval pointerToBuffer, Byval text, Len(text))

If GlobalUnlock(handleForBuffer) = 0 Then
errorNr = GetLastWinAPIError()
'If errorNr <> ERROR_SUCCESS Then
If errorNr <> NO_ERROR And errorNr <> 87 Then
Error errorNr, GetLastWinAPIErrorText() & " (" & Cstr(errorNr) & ")"
End If
End If

If OpenClipboard(0&) = 0 Then ' 0 means error
errorNr = GetLastWinAPIError()
Error errorNr, GetLastWinAPIErrorText() & " (" & Cstr(errorNr) & ")"
End If

If EmptyClipboard = 0 Then ' 0 means error
errorNr = GetLastWinAPIError()
Error errorNr, GetLastWinAPIErrorText() & " (" & Cstr(errorNr) & ")"
End If

If Isnull(SetClipboardData(CF_TEXT, handleForBuffer)) Then ' NULL means error
errorNr = GetLastWinAPIError()
Error errorNr, GetLastWinAPIErrorText() & " (" & Cstr(errorNr) & ")"
End If

If CloseClipboard = 0 Then ' 0 means error
errorNr = GetLastWinAPIError()
Error errorNr, GetLastWinAPIErrorText() & " (" & Cstr(errorNr) & ")"
End If
Exit Sub

errorHandler:
If HandleError() = RESUME_NEXT_LINE Then Resume Next
Call RethrowError()
End Sub

Hi Thomas,

We've seen couple of similar crashes in the past for Domino Server where agents are ported from 32-bit to 64-bit environment causing the server to crash. Specifically, agents that are using LotuScript C-call out due to the difference with how the platforms handle data types.

See this article:

Using LotusScript C-Callouts on non-32-bit Platforms

The notes.ini parameter LS64BITCCALLOUTPointerSupport=1 should be set to be able to return the pointer in type Double as mentioned in the above article. Further, there are cases were crashes are resolved by replacing the Long to Double type in the code.

Below suggestion have helped in past for such issues where agent crashes Domino Server.

1. Set the notes.ini parameter LS64BITCCALLOUTPointerSupport=1 and restart server.
2. Change the Long data types to Double in the code.

The same information is also available in below KB -->

HCL Domino crashes because of Agent using long data type

See if this information can help in your case.

Else, you might need to open a case for HCL Support team along with logs (NSD, console etc).

Regards,

Amit Sharma

Hello,

we are facing similar Problems. Years ago I copied some code from the Internet to read out the Notes Clients Hostname, IP-Address and OS Version. The Code uses 32-Bit dll calls, for example:

I'm currently trying to replace this with Java Code using LS2J. For the IP-Address, I got it running:

Maybe LS2J is also a way to go for you.

But what I'm missing is a Documentation of the Syntax. I find the Call for the Method quite strange, because of the "()L" in the second argument. What does this mean? The Domino 12.0.1 Designer Documentation doesn't show much to this topic.

@Ronald Hoppe Thank you for this idea, but as far as I know, I could not use Java to put something into the Windows clipboard or get it's content.

For the documentation: Do you mean LS2J documentation? When I start the Domino Designer and open the Help, I see quite some documentation under:
HCL Domino Designer Basic User Guide and Reference > HCL Domino Designer Basic User Guide and Reference > LotusScript Language > Beyond Core LotusScript > LS2J: Connecting with Java

LS2J is super confusing, even if you've used it before. The method signatures are explained (sort of) on this page: https://help.hcltechsw.com/dom_designer/14.0.0/basic/LSAZ_JAVACLASS_CREATEOBJECT_METHOD.html

For the GetMethod call in your example, the "()" part means it takes no parameters and the "Ljava/net/InetAddress" part means it returns a class ("L") of type java.net.InetAddress.

If, for example, the method took parameters of an int and a String, and it returned nothing ("void" in Java terminology), that part of GetMethod would be "(ILjava/lang/String;)V". The syntax actually comes from the Java JNI standard: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/types.html#type_signatures

Anyway, you can indeed use LS2J to read/write Clipboard data. We ended up doing that in the panagenda MarvelClient Config database as part of our 64-bit adjustments to the code. It's a little easier/cleaner if you put all the logic into a Java script library in a custom class, and then call that class using LS2J.

Here's what we do: there's a Java script library called ClipboardJava that contains this class:

package com.panagenda.util;

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;

public class ClipboardHelper {
private Exception lastException;

public String GetClipboard() {
	try {
		lastException = null;

		Toolkit toolkit = Toolkit.getDefaultToolkit();
		Clipboard clipboard = toolkit.getSystemClipboard();
		DataFlavor dataFlavor = DataFlavor.stringFlavor;

		if (clipboard.isDataFlavorAvailable(dataFlavor)) {
			Object text = clipboard.getData(dataFlavor);
			return (String)text;
		}
	} catch (Exception e) {
		lastException = e;
	}

	return "";
}


public boolean SetClipboard(String text) {
	try {
		lastException = null;

		Toolkit toolkit = Toolkit.getDefaultToolkit();
		Clipboard clipboard = toolkit.getSystemClipboard();
		clipboard.setContents(new StringSelection(text), null);

		return true;
	} catch (Exception e) {
		lastException = e;
	}

	return false;
}


public String getLastException() {
	if (lastException == null) {
		return "";
	} else {
		return lastException.getLocalizedMessage();
	}
}

}

And you can call it from LotusScript like this:

Option Public
Option Declare

UseLSX “*javacon”
Use “ClipboardJava”

Sub Initialize
Dim jSession As JavaSession
Dim jError As JavaError
Dim clipboardClass As JavaClass
Dim clipboardJava As JavaObject

Set jSession = New JavaSession
Set clipboardClass = jSession.GetClass("com.panagenda.util.ClipboardHelper")
Set clipboardJava = clipboardClass.CreateObject()

Dim clipText As String
clipText = clipboardJava.GetClipboard()
MessageBox "Clipboard text is: " &amp; clipText

Call clipboardJava.SetClipboard("New Clipboard Text from Agent!")
clipText = clipboardJava.GetClipboard()
MessageBox "Clipboard text is now: " &amp; clipText

End Sub

I hope that helps. :)

Hello Julian,

the Information what to to when the return Value is nothing, was exactly what I needed :-). Thanks for that.

Hi Thomas,

On a 64-bit client, you need to set NotesSession.UseDoubleAsPointer and change quite a few (but not all!) of the parameters and return values for the Clipboard and Global API calls from Long to Double. I have some example code for getting clipboard text on Win64 in my presentation at Collabsphere from 2023, I'm not sure if Richard made those slides available or not.

I'll also be talking about this very subject in a webinar about 64-bit clients for the Domino Developer at the end of January. I won't put a link here to avoid making this look like a blatant advertisement, but please check the panagenda.com website to sign up for the webinar if you're interested.

Anyway, it's doable but you might be better off using LS2J. See the sample code I posted below (or maybe above) as a response to Ronald on this thread.

- Julian

Hi @Julian Robichaux, nice to read you again after all those years. I saw, you'd give that session you mentioned and registered about two weeks ago. Ever waiting for it to come. ;-)

I assume, the Notes client would have to kick off a JVM for the LS2J alternative. Isn't this quite slow?

I was directed to have a notes.ini setting, but not to use this NotesSession property. I'll give it a try.

Thank you, Julian

@Julian Robichaux It worked!

I already had changed the "right" longs to doubles, but with the addition of NotesSession.UseDoubleAsPointer it works now. Even without the LS64BITCCALLOUTPointerSupport=1 notes.ini setting.

Thank you once more, Julian

For those interested in the solution. I have reduced my code to the minimum to send it to HCL for a case to be opened.

I'm not sure, if this is the most elegant solution, but it seems to work for me.

Now I have to integrate the solutions for Windows/32 and Windows/64 in one script library...

The code:

(Options)

Option Public
Option Declare

'%INCLUDE “AllWinAPIErrors.lss”

(Declarations)

Declare Public Function FormatMessage Lib "kernel32" Alias "FormatMessageA" (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments As Long) As Long 

Public Const PLATFORM_W32$ = “Windows/32”
Public Const PLATFORM_W64$ = “Windows/64”
Public Const NO_ERROR = 0
Public Const ERRNO_UNSUPPORTED_PLATFORM% = 15003

Public Const FORMAT_MESSAGE_IGNORE_INSERTS = &H200
Public Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
Public Const LANG_NEUTRAL = &H0
Public Const SUBLANG_DEFAULT = &H1

Declare Function GetLastError Lib “kernel32” () As Long

Public Const CF_TEXT = 1

’ Win-API functions used
Declare Function OpenClipboard Lib “User32” (ByVal hWnd As Double) As Long
Declare Function CountClipboardFormats Lib “User32” () As Long
Declare Function EnumClipboardFormats Lib “User32” (ByVal wFormat As Long) As Long
Declare Function GetClipboardData Lib “User32” (ByVal wFormat As Long) As Double
Declare Function SetClipboardData Lib “User32” (ByVal wFormat As Long, ByVal hMem As Double) As Long
Declare Function EmptyClipboard Lib “User32” () As Long
Declare Function CloseClipboard Lib “User32” () As Long

Declare Function GlobalAlloc Lib “kernel32” (ByVal wFlags&, ByVal dwBytes As Long) As Double
Declare Function GlobalLock Lib “kernel32” (ByVal hMem As Double) As Double
Declare Function GlobalUnlock Lib “kernel32” (ByVal hMem As Double) As Double
Declare Function lstrcpy Lib “kernel32” (ByVal lpString1 As String, ByVal lpString2 As Double) As Long
Declare Function lstrlen Lib “kernel32” Alias “lstrlenA” (ByVal lpString As Any) As Long
Declare Sub CopyMemory Lib “kernel32” Alias “RtlMoveMemory” (Destination As Any, Source As Any, ByVal Length As Long)

Dim session As NotesSession

Sub Initialize
	Dim result As String
	
	Set session = New NotesSession()
	session.UseDoubleAsPointer = True
	
	Call SetClipboardText("Test: " & CStr(Now))
	Print "SetClipboardText erfolgreich beendet"
	
	result = GetClipboardText(CF_TEXT)
	Print "GetClipboardText ergab: '" & result & "'"
End Sub
Public Function GetLastWinAPIError As Long
	'/**
	' * gets the number of error (if any) in the last Windows API call.
	' * 
	' * @return		number of error (if any) in the last Windows API call.
	' * 
	' * @author		Thomas Bahn <tbahn@assono.de>
	' * @version	2019-10-17
	' */
	
	If session.Platform <> PLATFORM_W32 And session.Platform <> PLATFORM_W64 Then Error ERRNO_UNSUPPORTED_PLATFORM, Replace(|The platform "<%PLATFORM%>" is not supported.|, "<%PLATFORM%>", session.Platform)
	
	GetLastWinAPIError = GetLastError()
End Function
Public Function GetLastWinAPIErrorText As String
	'/**
	' * gets the error message (if any) in the last Windows API call.
	' * 
	' * @return		error message (if any) in the last Windows API call.
	' * 
	' * @author		Thomas Bahn <tbahn@assono.de>
	' * @version	2019-10-17
	' */
		
	Dim buffer As String * 256
	Dim valueLength As Long
	
	If session.Platform <> PLATFORM_W32 And session.Platform <> PLATFORM_W64 Then Error ERRNO_UNSUPPORTED_PLATFORM, Replace(|The platform "<%PLATFORM%>" is not supported.|, "<%PLATFORM%>", session.Platform)
	
	valueLength = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS, 0&, GetLastError(), LANG_NEUTRAL Or (SUBLANG_DEFAULT * 1024) , buffer, 255, 0&)
	If valueLength = 0 Then
		GetLastWinAPIErrorText = "Error occured while determining the error text"
	Else
		GetLastWinAPIErrorText = Left$(buffer, valueLength)
	End If
End Function
Public Function GetClipboardText(ByVal clipboardFormat As Integer) As String
	'/**
	' * returns the current content of the clipboard in the given format (but always in a String)
	' *
	' * @param		clipboardFormat format to get.
	' * @return		current content of the clipboard in the given format (but as String)
	' *
	' * @author		Thomas Bahn <tbahn@assono.de>, Bernd Hort <bhort@assono.de>
	' * @version	2014-07-24
	' */
	
	Dim handleForBuffer As Double
	Dim pointerToBuffer As Double
	Dim clipboardData As String
	Dim positionNULLChar As Long
	Dim errorNr As Long
	
	If session.Platform <> PLATFORM_W32 And session.Platform <> PLATFORM_W64 Then
		MessageBox Replace(|The platform "<%PLATFORM%>" is not supported.|, "<%PLATFORM%>", session.Platform), 16
		GetClipboardText = ""
		Exit Function
	End If
	
	If OpenClipboard(0&) = 0 Then ' 0 means error
		errorNr = GetLastWinAPIError()
		Error errorNr, GetLastWinAPIErrorText() & " (" & CStr(errorNr) & ")"
	End If
	
	' get pointer to clipboard data
	handleForBuffer = GetClipboardData(clipboardFormat)
	If IsNull(handleForBuffer) Then ' NULL means error
		errorNr = GetLastWinAPIError()
		Error errorNr, GetLastWinAPIErrorText() & " (" & CStr(errorNr) & ")"
	End If
	
	pointerToBuffer = GlobalLock(handleForBuffer)
	If IsNull(pointerToBuffer) Then ' NULL means error
		errorNr = GetLastWinAPIError()
		Error errorNr, GetLastWinAPIErrorText() & " (" & CStr(errorNr) & ")"
	End If
	
	If pointerToBuffer <> 0 Then
		' copy clipboard data to string variable
		clipboardData = Space(lstrlen(ByVal pointerToBuffer)) ' grow string to neccessary size
		If IsNull(lstrcpy(clipboardData, pointerToBuffer)) Then ' copy contents, NULL means error
			errorNr = GetLastWinAPIError()
			Error errorNr, GetLastWinAPIErrorText() & " (" & CStr(errorNr) & ")"
		End If
		
		positionNULLChar = InStr(1, clipboardData, Chr$(0), 0)
		If positionNULLChar > 0 Then
			GetClipboardText = Mid(clipboardData, 1, positionNULLChar - 1) ' result is copied content until first NULL character
		Else
			GetClipboardText = clipboardData
		End If
		
		If GlobalUnlock(handleForBuffer) = 0 Then ' 0 means error
			errorNr = GetLastWinAPIError()
			If errorNr <> NO_ERROR Then				
				Error errorNr, GetLastWinAPIErrorText() & " (" & CStr(errorNr) & ")"
			End If
		End If
	End If
	
	If CloseClipboard = 0 Then ' 0 means error
		errorNr = GetLastWinAPIError()
		Error errorNr, GetLastWinAPIErrorText() & " (" & CStr(errorNr) & ")"
	End If
End Function
Public Sub SetClipboardText(ByVal Text As String)
	'/**
	' * puts text into clipboard.
	' *
	' * @param		text to put into the clipboard.
	' *
	' * @author		Thomas Bahn <tbahn@assono.de>, Bernd Hort <bhort@assono.de>
	' * @version	2014-07-24
	' */
	
	Const GMEM_MOVEABLE = &H2
	Const GMEM_ZEROINIT = &H40
	Const GMEM_GHND = (GMEM_MOVEABLE Or GMEM_ZEROINIT)
	
	Dim handleForBuffer As Double
	Dim pointerToBuffer As Double
	Dim errorNr As Long
	
	If session.Platform <> PLATFORM_W32 And session.Platform <> PLATFORM_W64 Then
		MessageBox Replace(|The platform "<%PLATFORM%>" is not supported.|, "<%PLATFORM%>", session.Platform), 16
		Exit Sub
	End If
	
	' create buffer
	handleForBuffer = GlobalAlloc(GMEM_GHND, Len(Text) + 1)
	If IsNull(handleForBuffer) Then ' NULL means error
		errorNr = GetLastWinAPIError()
		Error errorNr, GetLastWinAPIErrorText() & " (" & CStr(errorNr) & ")"
	End If
	
	pointerToBuffer = GlobalLock(handleForBuffer)
	If IsNull(pointerToBuffer) Then ' NULL means error
		errorNr = GetLastWinAPIError()
		Error errorNr, GetLastWinAPIErrorText() & " (" & CStr(errorNr) & ")"
	End If
	
	' copy text to buffer
	Call CopyMemory(ByVal pointerToBuffer, ByVal Text, CLng(Len(Text)))
	
	If GlobalUnlock(handleForBuffer) = 0 Then
		errorNr = GetLastWinAPIError()
		'If errorNr <> ERROR_SUCCESS Then
		If errorNr <> NO_ERROR And errorNr <> 87 Then 
			Error errorNr, GetLastWinAPIErrorText() & " (" & CStr(errorNr) & ")"
		End If
	End If
	
	If OpenClipboard(0&) = 0 Then ' 0 means error
		errorNr = GetLastWinAPIError()
		Error errorNr, GetLastWinAPIErrorText() & " (" & CStr(errorNr) & ")"
	End If
	
	If EmptyClipboard = 0 Then ' 0 means error
		errorNr = GetLastWinAPIError()
		Error errorNr, GetLastWinAPIErrorText() & " (" & CStr(errorNr) & ")"		
	End If
	
	If IsNull(SetClipboardData(CF_TEXT, handleForBuffer)) Then ' NULL means error
		errorNr = GetLastWinAPIError()
		Error errorNr, GetLastWinAPIErrorText() & " (" & CStr(errorNr) & ")"
	End If
	
	If CloseClipboard = 0 Then ' 0 means error
		errorNr = GetLastWinAPIError()
		Error errorNr, GetLastWinAPIErrorText() & " (" & CStr(errorNr) & ")"
	End If
End Sub

@Thomas Bahn Nice! Thanks for sharing the code.

Also a few finer points about UseDoubleAsPointer:

  • It's actually the same as LS64BITCCALLOUTPointerSupport=1, just that you can set it dynamically instead of "all or nothing". For details see https://help.hcltechsw.com/dom_designer/12.0.2/basic/H_USEDOUBLEASPOINTER_METHOD_SESSION.html
  • I'm not sure if there are side effects if you set it on a 32-bit client, I always recommend you keep it in an if/then block that only sets it if the client is 64-bit
  • Technically you're supposed to set it back to False when you're done, but in practice I haven't noticed any problems if you don't
  • The NotesSession.UseDoubleAsPointer property didn't exist before Notes 12.0.1, so if you try to run or compile the code on an older client you will get an error (another reason to make sure that line of code only runs on 64-bit clients)

@Julian Robichaux

The notes.ini setting LS64BITCCALLOUTPointerSupport=1 didn't work for me on my Notes client?!

"The NotesSession.UseDoubleAsPointer property didn't exist before Notes 12.0.1, so if you try to run or compile the code on an older client you will get an error"

Yikes!

Fast modification ("Execute" to the rescue!):

(Declarations)

[...]
If session.Platform = PLATFORM_W64 Then
	Execute |session.UseDoubleAsPointer = True|
End If
[...]

Hello Julian.

I have run into this exact problem.

I actually had a functioning code to SET content to the clipboard, but it stopped working as mentioned before. I am trying to follow all information I have found here and in other threads like the one from Thomas at assono. But I still struggle to put it all together completely. May I ask you for help?

You mentioned that you have some sample code lying around. If this includes a function, that sets data to the clipboard, it would be very much appreciated, if you would let me have it.

Possible?

Regards from Germany

Klaus

Hi @Klaus Charlier , there is actually some sample code by @Thomas Bahn in this thread, but it's kind of hard to find because the forum collapses the conversation threads by default. If you keep clicking the "Show Replies" link at the bottom right corner of all the replies you'll find it (there doesn't seem to be a way to link directly to it unfortunately).

this works for me in 32 bit and 64 bit:

Option Public
Option Declare
Sub SetClipboardText(ByVal Text As Variant)
Dim obj As Variant
Set obj = CreateObject("htmlfile")
Call obj.ParentWindow.ClipboardData.SetData("Text", Text)
End sub
Function GetClipBoardText() As String
On Error Resume Next
Dim obj As Variant
Set obj = CreateObject("htmlfile")
GetClipBoardText = obj.ParentWindow.ClipboardData.getData("Text")
End Function
Sub ClearClipBoardText()
Dim obj As Variant
Set obj = CreateObject("htmlfile")
Call obj.ParentWindow.ClipboardData.clearData("Text")
End sub

Excellent, thanks! :-D

Update: strangely, it work fine at one customer(12 & 14), but not at the other (12) - both installations on Microsoft Windows Server 2019 Datacenter

Any ideas?

Regards,

Seb

@Glen Urban Your code works great! Simple and compact. We tested the 32-bit client 12.0.1 and the 64-bit client 14.0.0.