When HCL introduced the 64 Bit Notes Client, the code to set and get data from the clipboard stopped working.
Here is some updated code. It works on HCL Notes 14 64 Bit. I have not tested on V12 64 bit, but it should work on this version too.
%REM
Library lib_clipboard32-64
Created Mar 4, 2024 by francesco@marzolo.com
Modified Mar 5, 2024 by Ulrich Krause
Description: Allows 64-32 bitness clipboard managing
%END REM
Option Public
Option Declare
Const CF_UNICODETEXT = 13
Const CF_TEXT = 1
Const OS_TRANSLATE_UNICODE_TO_LMBCS = 23
Const LSI_THREAD_PROC=1
Const LSI_THREAD_CALLPROC=10
Public Const GHND = &H42
'** 32-bit API calls
Declare Function OpenClipboard Lib "user32.dll" (ByVal hwnd As Long) As Long
Declare Function CloseClipboard Lib "user32.dll" () As Long
Declare Function GetClipboardData Lib "user32.dll" (ByVal wFormat 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 GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
Declare Function OSTranslateFromPtr Lib "nnotes.dll" Alias "OSTranslate" ( _
ByVal mode As Integer, _
ByVal strIn As Long, _
ByVal lenIn As Integer, _
ByVal strOut As LMBCS String, _
ByVal lenOut As Integer ) As Integer
'** 64-bit API calls
Declare Function OpenClipboard_64 Lib "user32.dll" Alias "OpenClipboard" (ByVal hwnd As double) As Long '** hwnd is a window handle
Declare Function GetClipboardData_64 Lib "user32.dll" Alias "GetClipboardData" (ByVal wFormat As Long) As Double '** returns a memory handle
Declare Function CloseClipboard_64 Lib "user32.dll" Alias "CloseClipboard" () As Long
Declare Function GlobalLock_64 Lib "kernel32.dll" Alias "GlobalLock" (ByVal hMem As Double) As Double '** hMem is a memory handle, returns a pointer
Declare Function GlobalUnlock_64 Lib "kernel32.dll" Alias "GlobalUnlock" (ByVal hMem As Double) As Long '** hMem is a memory handle, returns a BOOL
Declare Function GlobalSize_64 Lib "kernel32.dll" Alias "GlobalSize" (ByVal hMem As Double) As Long '** hMem is a memory handle, returns a size
Declare Function OSTranslateFromPtr_64 Lib "nnotes.dll" Alias "OSTranslate" ( _
ByVal mode As Integer, _
ByVal strIn As Double, _ '** strIn is a string pointer
ByVal lenIn As Integer, _
ByVal strOut As LMBCS String, _
ByVal lenOut As Integer ) As Integer
'to set clipboard
Private Const GMEM_MOVEABLE = &H40
Private Const GMEM_ZEROINIT = &H2
Declare Function EmptyClipboard Lib "user32" () As Long
Declare Function SetClipboardData Lib "user32" (ByVal wFormat As Long, ByVal hMem As Long) As Long
Declare Function IsClipboardFormatAvailable Lib "user32" (ByVal wFormat As Long) As Long
Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long '** returns a memory handle
Declare Function lstrcpy Lib "kernel32" Alias "lstrcpyA" (ByVal lpString1 As Long, ByVal lpString2 As String) As Long
Declare Function GlobalAlloc_64 Lib "kernel32" Alias "GlobalAlloc" (ByVal wFlags As Long, ByVal dwBytes As Long) As Double '** returns a memory handle
Declare Function NEMGetCurrentSubprogramWindow Lib "nnotesws.dll" () As Long
Declare Function SetClipboardData_64 Lib "user32" Alias "SetClipboardData" (ByVal wFormat As Long, ByVal hMem As Double) As Long
Sub Initialize
End Sub
Sub Terminate
End Sub
Public Function GetClipboard() As String
Dim session As New NotesSession
If (session.Platform = "Windows/64") Then
GetClipboard = GetClipboard64()
Exit Function
End If
Dim glbHandle As Long
Dim cbPointer As Long
Dim cbPointerLen As Long
Dim cbString As String
If OpenClipboard(0) Then
glbHandle = GetClipboardData(CF_UNICODETEXT)
cbPointer = GlobalLock(glbHandle)
cbPointerLen = GlobalSize(glbHandle)
cbString = Space(cbPointerLen)
Call OSTranslateFromPtr( OS_TRANSLATE_UNICODE_TO_LMBCS, _
cbPointer, cbPointerLen, cbString, cbPointerLen )
cbString = StrLeft(cbString, Chr(0))
Call GlobalUnlock(glbHandle)
Call CloseClipboard()
End If
GetClipboard = cbString
End Function
Public Sub SetClipboard(txt As String)
Dim session As New NotesSession
If (session.Platform = "Windows/64") Then
SetClipboard64(txt)
Exit Sub
End If
Dim hwnd As Long
Dim hGlobalMemory As Long
Dim lpGlobalMemory As Long
Dim ret As Long
On Error GoTo error_handler
' Get a handle to current window
hwnd = NEMGetCurrentSubProgramWindow()
If hwnd Then
' Allocate memory
hGlobalMemory = GlobalAlloc(CLng(GMEM_MOVEABLE Or GMEM_ZEROINIT),CLng(Len(txt)+1))
If hGlobalMemory Then
lpGlobalMemory = GlobalLock(hGlobalMemory)
If lpGlobalMemory Then
ret = lstrcpy(lpGlobalMemory, txt)
Call GlobalUnlock(hGlobalMemory)
If OpenClipboard(hwnd) Then
ret = EmptyClipboard()
ret = SetClipboardData(CF_TEXT, hGlobalMemory)
ret = CloseClipboard()
End If
Else
MsgBox "Can't allocated global memory pointer.", 32, "Error"
End If
Else
MsgBox "Can't allocated global memory handle.", 32, "Error"
End If
Else
MsgBox "Can't get window handle.", 32, "Error"
End If
Exit Sub
error_handler:
Print "Error: " + Error$(Err)
Resume Next
End Sub
Function describeError() As String
describeError=Error & " (at row " & Erl & " of " & GetThreadInfo(LSI_THREAD_CALLPROC) & ")"
End Function
Function GetClipboard64() As String
On Error GoTo sbreng
Dim session As New NotesSession
session.UseDoubleAsPointer = True
Dim glbHandle_64 As Double
Dim cbPointer_64 As Double
Dim cbPointerLen As Long
Dim cbString As String
If OpenClipboard_64(0) Then
glbHandle_64 = GetClipboardData_64(CF_UNICODETEXT)
cbPointer_64 = GlobalLock_64(glbHandle_64)
cbPointerLen = GlobalSize_64(glbHandle_64)
cbString = Space(cbPointerLen)
Call OSTranslateFromPtr_64( OS_TRANSLATE_UNICODE_TO_LMBCS, cbPointer_64, cbPointerLen, cbString, cbPointerLen )
cbString = StrLeft(cbString, Chr(0))
Call GlobalUnlock_64(glbHandle_64)
Call CloseClipboard_64()
End If
GetClipboard64=cbString
endop:
session.UseDoubleAsPointer = False
Exit Function
sbreng:
Dim errmsg$
errmsg$="Error: " & Err & ", call stack: " & describeerror()
Print errmsg
'ensure you execute anyway useDoubleAsPointer=False
Resume endop
End Function
Function SetClipboard64(txt As String)
Dim session As New NotesSession
session.UseDoubleAsPointer = True
Dim hGlobalMemory As Long
Dim lpGlobalMemory As Long
Dim hClipMemory As Long
Dim X As Long
hGlobalMemory = GlobalAlloc(GHND, Len(txt) + 1)
lpGlobalMemory = GlobalLock(hGlobalMemory)
lpGlobalMemory = lstrcpy(lpGlobalMemory, txt)
If GlobalUnlock(hGlobalMemory) <> 0 Then
MsgBox "Could not unlock memory location. Copy aborted."
GoTo OutOfHere2
End If
If OpenClipboard(0&) = 0 Then
MsgBox "Could not open the Clipboard. Copy aborted."
Exit Function
End If
X = EmptyClipboard()
hClipMemory = SetClipboardData(CF_TEXT, hGlobalMemory)
OutOfHere2:
If CloseClipboard() = 0 Then
MsgBox "Could not close Clipboard."
End If
session.UseDoubleAsPointer = False
End Function
Hi,
SetClipboard64() fails on 14 .0 FP1
here…
If GlobalUnlock(hGlobalMemory) 0 Then
MsgBox “Could not unlock memory location. Copy aborted.”
I tried switching GlobalUnlock for GlobalUnlock_64 but still failed.
Any suggestions would be gratefully received.
I have tested in my environment (Notes 12.0.2FP3 & 14.0.0FP1), and everything works as expected.
You do not have to make a call into SetClipBoard64() explicitly.
All you have to do is to call into setClipBoard and getClipBoard on 32 and 64 Bit. The code ‘knows’ where to go from there.
Thanks for trying Ulrich. I am calling SetClipBoard and it then calls SetClipBoard64() when using R14.
I’ve managed to get passed the “Could not unlock memory location” error by updating SetClipboard64 to use the _64 calls (see below).
Now I don’t get an error at all, but nothing is added to the Windows clipboard either!
Function SetClipboard64(txt As String)
Dim session As New NotesSession
session.UseDoubleAsPointer = True
Dim hGlobalMemory As Double
Dim lpGlobalMemory As Long
Dim hClipMemory As Long
Dim X As Long
hGlobalMemory = GlobalAlloc_64(GHND, Len(txt) + 1)
lpGlobalMemory = GlobalLock_64(hGlobalMemory)
lpGlobalMemory = lstrcpy(lpGlobalMemory, txt)
If GlobalUnlock_64(hGlobalMemory) 0 Then
MsgBox “Could not unlock memory location. Copy aborted.”
GoTo OutOfHere2
End If
If OpenClipboard_64(0&) = 0 Then
MsgBox “Could not open the Clipboard. Copy aborted.”
Exit Function
End If
X = EmptyClipboard()
hClipMemory = SetClipboardData_64(CF_TEXT, hGlobalMemory)
OutOfHere2:
If CloseClipboard_64() = 0 Then
MsgBox “Could not close Clipboard.”
End If
session.UseDoubleAsPointer = False
End Function
Sorted now. Couldn’t get the above to work so I’m using the code below which I’ve tested in 32 bit R9 and R12 and 64 bit R14.
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