Accessing the clipboard in Windows becomes quite tricky in VBA, particularly if you have to stay 32 and 64 bits compatible.
Here’s my compilation of portable routines, inspired by MSDN, Internet scraping and good sense.
First the Declares section (I know, it pours out of the frame on the right, just select and copy the text):
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | 'Update 20.05.2017, those 3 declarations were missing: Const GMEM_ZEROINIT = &H40 Const GMEM_MOVEABLE = &H2 Const GHND = (GMEM_MOVEABLE Or GMEM_ZEROINIT) #If Win64 Then     'To copy text on the clipboard     Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)     Private Declare PtrSafe Function GlobalUnlock Lib "kernel32" (ByVal hMem As LongLong) As Long     Private Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As LongLong) As LongPtr     Private Declare PtrSafe Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As LongLong) As LongPtr     Private Declare PtrSafe Function GlobalSize Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr     Private Declare PtrSafe Function CloseClipboard Lib "user32" () As Long     Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hwnd As LongLong) As Long     Private Declare PtrSafe Function EmptyClipboard Lib "user32" () As Long     Private Declare PtrSafe Function lstrcpy Lib "kernel32" Alias "lstrcpyA" (ByVal lpString1 As Any, ByVal lpString2 As String) As LongPtr     Private Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As LongPtr     Private Declare PtrSafe Function SetClipboardData Lib "user32" (ByVal wFormat As Long, ByVal hMem As LongLong) As LongLong     Private Declare PtrSafe Function EnumClipboardFormats Lib "user32" (ByVal wFormat As Long) As Long     Private Declare PtrSafe Function IsClipboardFormatAvailable Lib "user32" (ByVal wFormat As Long) As Long   #Else     Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)     Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long     Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long     Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long     Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long     Private Declare Function CloseClipboard Lib "user32" () As Long     Private Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long     Private Declare Function EmptyClipboard Lib "user32" () As Long     Private Declare Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, ByVal lpString2 As Any) As Long     Private Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long     Private Declare Function SetClipboardData Lib "user32" (ByVal wFormat As Long, ByVal hMem As Long) As Long     Private Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long     Private Declare Function EnumClipboardFormats Lib "user32" (ByVal wFormat As Long) As Long     Private Declare Function IsClipboardFormatAvailable Lib "user32" (ByVal wFormat As Long) As Long #End If   Public Enum eCBFormat     CF_TEXT = 1     CF_BITMAP = 2     CF_METAFILEPICT = 3     CF_SYLK = 4     CF_DIF = 5     CF_TIFF = 6     CF_OEMTEXT = 7     CF_DIB = 8     CF_PALETTE = 9     CF_PENDATA = 10     CF_RIFF = 11     CF_WAVE = 12     CF_UNICODETEXT = 13     CF_ENHMETAFILE = 14     CF_HDROP = 15     CF_LOCALE = 16     CF_MAX = 17     CF_OWNERDISPLAY = &H80     CF_DSPTEXT = &H81     CF_DSPBITMAP = &H82     CF_DSPMETAFILEPICT = &H83     CF_DSPENHMETAFILE = &H8E     CF_PRIVATEFIRST = &H200     CF_PRIVATELAST = &H2FF     CF_GDIOBJFIRST = &H300     CF_GDIOBJLAST = &H3FF   End Enum | 
Then the VBA code:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | #If Win64 Then Public Function ClipBoard_HasFormat(ByVal phWnd As LongLong, _                    ByVal peCBFormat As eCBFormat) As Boolean #Else Public Function ClipBoard_HasFormat(ByVal phWnd As Long, _                    ByVal peCBFormat As eCBFormat) As Boolean #End If   Dim lRet    As Long   If OpenClipboard(phWnd) > 0 Then     lRet = EnumClipboardFormats(0)     If lRet <> 0 Then       Do         If lRet = peCBFormat Then           ClipBoard_HasFormat = True           Exit Do         End If         lRet = EnumClipboardFormats(lRet)       Loop While lRet <> 0     End If     CloseClipboard   Else     'Problem: Cannot open clipboard   End If End Function #If Win64 Then Public Function ClipBoard_GetTextData(ByVal phWnd As LongLong) As String   Dim hData       As LongPtr   Dim lByteLen    As LongPtr   Dim lPointer    As LongPtr   Dim lSize       As LongLong #Else Public Function ClipBoard_GetTextData(ByVal phWnd As Long) As String   Dim hData       As Long   Dim lByteLen    As Long   Dim lPointer    As Long   Dim lSize       As Long #End If   Dim lRet        As Long   Dim abData()    As Byte   Dim sText       As String   lRet = OpenClipboard(phWnd)   If lRet > 0 Then     hData = GetClipboardData(eCBFormat.CF_TEXT)     If hData <> 0 Then       lByteLen = GlobalSize(hData)       lSize = GlobalSize(hData)       lPointer = GlobalLock(hData)       If lSize > 0 Then         ReDim abData(0 To CLng(lSize) - CLng(1)) As Byte         CopyMemory abData(0), ByVal lPointer, lSize         GlobalUnlock hData         sText = StrConv(abData, vbUnicode)       End If     Else       'Problem: Cannot open clipboard     End If     CloseClipboard   End If   ClipBoard_GetTextData = sText End Function Public Function ClipBoard_SetData(psData As String) As Boolean   #If Win64 Then     Dim hGlobalMemory   As LongLong     Dim lpGlobalMemory  As LongPtr     Dim hClipMemory     As LongLong   #Else     Dim hGlobalMemory   As Long     Dim lpGlobalMemory  As Long     Dim hClipMemory     As Long   #End If   Dim fOK             As Boolean   fOK = True   ' Allocate moveable global memory.   #If Win64 Then     hGlobalMemory = GlobalAlloc(GHND, LenB(psData) + 1)   #Else     hGlobalMemory = GlobalAlloc(GHND, Len(psData) + 1)   #End If   If hGlobalMemory = 0 Then     Exit Function   End If   ' Lock the block to get a far pointer   ' to this memory.   lpGlobalMemory = GlobalLock(hGlobalMemory)   ' Copy the string to this global memory.   lpGlobalMemory = lstrcpy(lpGlobalMemory, psData)   ' Unlock the memory.   If GlobalUnlock(hGlobalMemory) <> 0 Then     fOK = False     GoTo OutOfHere2   End If   ' Open the Clipboard to copy data to.   If OpenClipboard(0&) = 0 Then     fOK = False     Exit Function   End If   ' Clear the Clipboard.   Call EmptyClipboard   ' Copy the data to the Clipboard.   hClipMemory = SetClipboardData(eCBFormat.CF_TEXT, hGlobalMemory) OutOfHere2:    Call CloseClipboard    ClipBoard_SetData = fOK End Function | 
Update: just a quick sample (Access VBA):
| 1 2 3 4 5 | If ClipBoard_HasFormat(Application.hWndAccessApp, eCBFormat.CF_TEXT) Then   Dim sText       As String   sText = ClipBoard_GetTextData(Application.hWndAccessApp)   '... End If | 
There’s an Access 2016 demo database (on devinfo.net), open it, go to the VBA editor (ALT+F11), go to the debug Windows (CTRL+G), type “Test” (without the quotes of course) and hit ENTER; any text in the clipboard will be displayed in the debug window.
Enjoy.
Recent Comments