Home » excel » vba – Sendkey twice based on success?

vba – Sendkey twice based on success?

Posted by: admin March 7, 2020 Leave a comment

Questions:

I was using sendkey to access Power Query and connect to SharePoint Folder. Everything was smooth until the Power Query Data Preview Dialog appears.

How do I allow sendkey to continue after the dialog appears? I’m using button to start macro and using Excel 2016.

Option Explicit
Sub Button1_Click()

    Dim spPath As String
    Dim strkeys As String

    spPath = "" 'SharePoint Link

    strkeys = "%APNFO" & spPath & "{Enter}{TAB 4}{Enter}" 
    'stops at first{Enter}, {TAB 4}{Enter} for EDIT
    Call SendKeys(strkeys)

End Sub

Update

Also tried to sendkey twice with True but same result, Stops at dialog.

Option Explicit
Sub Button1_Click()

    Dim spPath As String
    Dim strkeys As String
    Dim strkeys2 As String

    spPath = ""

    strkeys = "%APNFO" & spPath & "{Enter}"
    strkeys2 = "{TAB 4}{Enter}"
    Call SendKeys(Trim(strkeys), True)
    Call SendKeys(Trim(strkeys2), True)
    Debug.Print strkeys2

End Sub

Update2

I tried what @peh suggested, using sleep() and Application.wait(). I found out that once the macro is initialized, sendkey1 started and stopped by the Application.wait(). Only after the waiting time ends, then sendkey1 is being processed. And once sendkey1 started, sendkey2 also starts.

Also tried adding DoEvents, sendkey1 works perfect. However only after clicking the Cancel button, Application.wait() and sendkey2 will start.

Call SendKeys(Trim(strkeys))
Debug.Print Now & "Send Key 1"
'Do Events
Application.wait (Now + TimeValue("0:00:10"))
Call SendKeys(Trim(strkeys2), True)
Debug.Print Now & "Send Key 2"

Pannel

enter image description here

How to&Answers:

If the dialogue box is the same every time, or contains a consistent string of text in the caption, you may be able to use it’s caption to detect when it appears using this function in a loop with a timer that searches for a reasonable amount of time for the dialogue box:

Private Function GetHandleFromPartialCaption(ByRef lWnd As Long, ByVal sCaption As String) As Boolean

Dim lhWndP As Long
Dim sStr As String
GetHandleFromPartialCaption = False
lhWndP = FindWindow(vbNullString, vbNullString) 'PARENT WINDOW
Do While lhWndP <> 0
    sStr = String(GetWindowTextLength(lhWndP) + 1, Chr$(0))
    GetWindowText lhWndP, sStr, Len(sStr)
    sStr = Left$(sStr, Len(sStr) - 1)
    If InStr(1, sStr, sCaption) > 0 Then
        GetHandleFromPartialCaption = True
        lWnd = lhWndP
        Exit Do
    End If
    lhWndP = GetWindow(lhWndP, GW_HWNDNEXT)
Loop
End Function

Where sCaption is the name of your dialogue box. Then in your main body of code use:

If GetHandleFromPartialCaption(lhWndP, "Your Dialogue Box Caption") = True Then
SendKeys(....

Answer:

I am on my linux box right now so I can’t tinker with this to test, but you might attempt to read other properties of the window with a utility like:

https://autohotkey.com/boards/viewtopic.php?t=28220

Edit: if SendKeys absolutely won’t work, and you don’t want to go the UI automation route, and you don’t mind a dependency, you could install AutoHotkey and script that from VBA (e.g. using the Shell() command). AHK is more robust when it comes to keyboard macro automation.

If you had a unique classname, for example, you could use FindWindowEx to get the window handle:

Module-scoped ~

#If VBA7 Then
'32-bit declare
Private Declare Function FindWindowEx Lib "USER32" _
                              Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, _
                              ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
#Else
'64-bit declare
Private Declare PtrSafe Function FindWindowEx Lib "USER32" _
                              Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, _
                              ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr
#End If

Procedure ~

Dim appcaption as String
appcaption = "Excel"

#If VBA7 Then
Dim parenthandle as Long, childhandle as Long
#Else
Dim parenthandle as LongPtr, childhandle as LongPtr
#End If
parenthandle = FindWindow(vbNullString, appcaption)

If parenthandle Then

    childhandle = GetWindow(parenthandle, GW_CHILD)1   
    Do Until Not childhandle
        childhandle = GetWindow(childhandle, GW_HWNDNEXT)
    Loop

End If

If childhandle Then
    '
End If

This code is only proof of concept, as you could have muliple Excel Windows open, for example. It should give a good starting point, however.