SendKeys Alternative using API

Ohad1997

New Member
Joined
Aug 13, 2017
Messages
21
for my understanding using sendmessage is a more reliable way to simulate key press then using sendKeys

How can i replace this line of code:

SendKeys "^a"

With a sendMessage alternative?
 

Excel Facts

What is the fastest way to copy a formula?
If A2:A50000 contain data. Enter a formula in B2. Select B2. Double-click the Fill Handle and Excel will shoot the formula down to B50000.
Hello Ohad1997,

What does "^a" do and which application do want to send it to?
 
Upvote 0
It selects all, its pressing ctr and A via code but its unreliable, im trying to send it to a an adobe reader pdf file to copy its data after opening, before you suggest it, using another external program is not optional sadly
 
Upvote 0
Sendmessage takes the hwnd (window handle) of the target window in its first argument so you will first need to retrieve this handle.

You could use the FindWindow API to get the hwnd but you will need to know the adobe reader class name (different according to version) or the pdf window title.

The GetClassName API returns class name and the GetWindowText API returns the window title.

If there are more than one instance of adobe reader loaded at the same time, finding the right one may become a bit more difficult.
 
Last edited:
Upvote 0
Hello Jaafar & Ohad1997,

It looks like Acrobat Reader can be controlled from VBA using late binding to activate the "Select All" and "Copy" menu items. My attempts at trying to find the correct window to use with SendMessage has not been particularly successful. Perhaps if I had Spy++ it would be easier. I will test this new approach more tomorrow.
 
Upvote 0
got so far, but it doesnt work, any ideas?

important note: the program does get focus from this code(set focus works)


Code:
Private Declare Function SendMessage Lib "user32.dll" Alias _
"SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long _
, ByVal wParam As Long, ByVal lParam As Long) As Long


Private Declare Function FindWindow Lib "user32.dll" Alias _
"FindWindowA" (ByVal lpClassName As String, ByVal _
lpWindowName As String) As Long


Private Declare Function SetForegroundWindow _
Lib "user32" (ByVal hwnd As Long) As Long


Public Const WM_SETTEXT As Integer = &HC
Public Const WM_GETTEXT As Integer = &HD
Public Const WM_GETTEXTLENGTH As Integer = &HE
Public Const LB_SETSEL = &H185&
Public Const WM_COPY = &H301




Sub GetAllText()
Dim res As Long
Program = FindWindow(vbNullString, "pdf.pdf - Adobe Acrobat Reader DC")
Dim setFocus As Long
setFocus = SetForegroundWindow(Program)
res = SendMessage(Program, LB_SETSEL, 0, -1)
res = SendMessage(Program, WM_COPY, 0, 0&)
End Sub
 
Last edited:
Upvote 0
Hello Ohad1997,

After a lot of reading and testing, I was able to create some code that will copy all of the text from a PDF using Ctrl+A and Ctrl+C. There were a couple of issues with copying and pasting from the PDF window.

With the free version of Acrobat Reader, the keys will only work when the PDF window is active. The other issue was synchronizing the VBA code with PDF operations. I was finally able to achieve this by checking if the clipboard was empty. Once the clipboard had data, it would then be pasted to the next available column on the ActiveSheet.

The workbook at the link below has all the working code in it. There is a button on the sheet to run the main macro. It requires you have a PDF file open.

Copy All Text in PDF.xlsm
 
Upvote 0
Hi Leith Ross,

I couldn't get your code working. The clipboard is not loaded with the pdf text and the While Wend line in the CopyPDFText sub gets stuck and never exits.

I haven't studied your code properly yet but when I run it that's what I get... BTW, I tested your code on Excel 2010 64bit/Win 2010 64bit if that matters.

The SendInput API doesn't take a hwnd and so doesn't care which window it sends the input to hence it is not very reliable and could send the keystrokes to the wrong window.

I took a different approach via the use of the PostMessage API which does take a hwnd in its first parameter.

Code in a Standard Module:
Code:
Option Explicit

[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If"]#If[/URL]  VBA7 Then
    [URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If"]#If[/URL]  Win64 Then
        Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As LongPtr
        Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
    [URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else"]#Else[/URL] 
        Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As LongPtr
        Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As Long) As LongPtr
    [URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End"]#End[/URL]  If

    Declare PtrSafe Function SetKeyboardState Lib "user32" (lppbKeyState As Byte) As Long
    Declare PtrSafe Function AttachThreadInput Lib "user32" (ByVal idAttach As Long, ByVal idAttachTo As Long, ByVal fAttach As Long) As Long
    Declare PtrSafe Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As LongPtr, lpdwProcessId As Long) As Long
    Declare PtrSafe Function GetCurrentThreadId Lib "kernel32" () As Long
    Declare PtrSafe Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As Long
    Declare PtrSafe Function SetForegroundWindow Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
    Declare PtrSafe Function GetKeyboardState Lib "user32" (kbArray As Byte) As Long
    Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
    Declare PtrSafe Function ShowWindow Lib "user32" (ByVal hwnd As LongPtr, ByVal nCmdShow As Long) As Long
    Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
    Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
    Declare PtrSafe Function SetLayeredWindowAttributes Lib "user32" (ByVal hwnd As LongPtr, ByVal crey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As LongPtr
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else"]#Else[/URL] 
    Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
    Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
    Declare Function SetKeyboardState Lib "user32" (lppbKeyState As Byte) As Long
    Declare Function AttachThreadInput Lib "user32" (ByVal idAttach As Long, ByVal idAttachTo As Long, ByVal fAttach As Long) As Long
    Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
    Declare Function GetCurrentThreadId Lib "kernel32" () As Long
    Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long
    Declare Function GetKeyboardState Lib "user32" (kbArray As Byte) As Long
    Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
    Declare Function GetActiveWindow Lib "user32" () As Long
    Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
    Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongPtrA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
    Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongPtrA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    Declare Function SetLayeredWindowAttributes Lib "user32" (ByVal hwnd As Long, ByVal crey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End"]#End[/URL]  If

Const WM_KEYDOWN = &H100
Const VK_CONTROL = &H11
Const GWL_EXSTYLE = (-20)
Const WS_EX_LAYERED = &H80000
Const LWA_ALPHA = &H2&
Const SW_NORMAL = 1


Sub CopyPDFText()

    [URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If"]#If[/URL]  VBA7 Then
        Dim hwnd As LongPtr, lActiveHwnd As LongPtr
    [URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else"]#Else[/URL] 
        Dim hwnd As Long, lActiveHwnd As Long
    [URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End"]#End[/URL]  If
        Dim tCurKB(255) As Byte, tInitKB(255)  As Byte
        Dim lThreadID As Long
     
        On Error GoTo errHandler
    
        lActiveHwnd = GetActiveWindow
        hwnd = FindWindow("AcrobatSDIWindow", vbNullString)
        If hwnd Then
            Call SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) Or WS_EX_LAYERED)
            SetLayeredWindowAttributes hwnd, 0, 0, LWA_ALPHA
            lThreadID = GetWindowThreadProcessId(hwnd, ByVal 0)
            AttachThreadInput GetCurrentThreadId, lThreadID, True
            SetForegroundWindow hwnd
            ShowWindow hwnd, SW_NORMAL
            GetKeyboardState tInitKB(0)
            tCurKB(VK_CONTROL) = &H80
            SetKeyboardState tCurKB(0)
            Call PostMessage(hwnd, WM_KEYDOWN, VK_CONTROL, 0)
            Call PostMessage(hwnd, WM_KEYDOWN, VBA.vbKeyA, 0)
            DoEvents
            Call PostMessage(hwnd, WM_KEYDOWN, VK_CONTROL, 0)
            Call PostMessage(hwnd, WM_KEYDOWN, VBA.vbKeyC, 0)
            Sleep 100
errHandler:
            SetKeyboardState tInitKB(0)
            AttachThreadInput GetCurrentThreadId, lThreadID, False
            SetForegroundWindow lActiveHwnd
            Call SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) Or WS_EX_LAYERED)
            SetLayeredWindowAttributes hwnd, 0, 255, LWA_ALPHA
        Else
            MsgBox "No PDF application found!"
        End If
End Sub

BTW, I wonder if this can be achieved via automating the PDF application instead of via the windows API ? It should be more elegant and accurate.
 
Last edited:
Upvote 0

Forum statistics

Threads
1,223,885
Messages
6,175,187
Members
452,616
Latest member
intern444

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top