0

I use VBA and Windows API to navigate through an read only text box control of a program. I can retrieve each value in the textbox by copying it using Ctrl + C and read the clipboard. Here is my code:

Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hWnd As LongPtr) As LongPtr
Private Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal uFormat As LongPtr) As LongPtr
Private Declare PtrSafe Function CloseClipboard Lib "user32" () As LongPtr
Private Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr
Private Declare PtrSafe Function GlobalUnlock Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr
Private Declare PtrSafe Function GlobalSize Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Private Declare PtrSafe Function lstrcpy Lib "kernel32" Alias "lstrcpyW" (ByVal lpString1 As Any, ByVal lpString2 As Any) As LongPtr
Private Const CF_UNICODETEXT As LongPtr = 13&
Private Const GMEM_MOVEABLE As LongPtr = &H2&
Private Const GMEM_ZEROINIT As LongPtr = &H40&

 
Public Const GHND = &H42
Public Const CF_TEXT = 1
Public Const MAXSIZE = 4096
Sub main()
    Call Ctrl_C
    Call ClipBoard_GetData
End Sub

Sub Ctrl_C()
    
    Dim inputArray(1 To 2) As tagINPUT_keybd
        
    ' Set up the first input structure for "Alt" key press
    inputArray(1).INPUTTYPE = 1 ' INPUT_KEYBOARD
    inputArray(1).ki.wVk = VK_CONTROL
    inputArray(1).ki.dwFlags = 0 ' Key press
        
    ' Set up the second input structure for "M" key press
    inputArray(2).INPUTTYPE = 1 ' INPUT_KEYBOARD
    inputArray(2).ki.wVk = VK_C
    inputArray(2).ki.dwFlags = 0 ' Key press
    
    ' Send the keydown events
    Call SendKeybdInput(2, inputArray(1), LenB(inputArray(1)))
    
    ' Set up the first input structure for "Atl" key release
    inputArray(1).ki.dwFlags = KEYEVENTF_KEYUP ' Key release
    
    ' Set up the second input structure for "O" key release
    inputArray(2).ki.dwFlags = KEYEVENTF_KEYUP ' Key release
    
    ' Send the keyup events
    Call SendKeybdInput(2, inputArray(1), LenB(inputArray(1)))
    Sleep (100)
End Sub
    


Function ClipBoard_GetData()
    Dim hClipMemory As LongPtr
    Dim lpClipMemory As LongPtr
    Dim MyString As String
    Dim RetVal As LongPtr

    If OpenClipboard(0&) = 0 Then
      Debug.Print "Cannot open Clipboard. Another app. may have it open"
     
    End If
         
  ' Obtain the handle to the global memory
  ' block that is referencing the text.
    hClipMemory = GetClipboardData(CF_TEXT)
    If IsNull(hClipMemory) Then
        MsgBox "Could not allocate memory"
        GoTo OutOfHere
    End If

  ' Lock Clipboard memory so we can reference
  ' the actual data string.
    lpClipMemory = GlobalLock(hClipMemory)

    If Not IsNull(lpClipMemory) Then
        MyString = Space$(MAXSIZE)
        RetVal = lstrcpy(MyString, lpClipMemory)
        RetVal = GlobalUnlock(hClipMemory)
      
     ' Peel off the null terminating character.
        MyString = Mid(MyString, 1, InStr(1, MyString, Chr$(0), 0) - 1)
    Else
        MsgBox "Could not lock memory to copy string from."
    End If

OutOfHere:

    RetVal = CloseClipboard()
    ClipBoard_GetData = MyString

End Function

This code works but sometimes it could not get the value of the clipboard which I copied from the program. Sometimes the message:

"Cannot open Clipboard. Another app. may have it open"

appear and I understand that the value of OpenClipboard(0&) is equal 0. So I wonder if there is anyway to let the GetClipboardData always get the copied data, or should I loop the copy function again to let the copied strings appears?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Lv Linh
  • 31
  • 3
  • Maybe put `OpenClipboard` in a loop with a call to `Sleep` and see if that fixes it. You might be calling `ClipBoard_GetData` too soon after performing the copy. – Tim Williams Jul 11 '23 at 16:59

0 Answers0