excel VBA使用Windows API解析同名句柄

uklbhaso  于 2023-03-20  发布在  Windows
关注(0)|答案(1)|浏览(145)

我试图使用一个简单的VBA宏自动化一个基于网络的应用程序。首先,它是为一家公司,我的工作,因此应用程序是在安全的citrix环境。我启动它使用“应用程序启动器”程序。
我尝试我的手使用windows API。一个重要的限制,citrix环境,是我不能安装spy++在它上面。因为公司不允许它。因此,我使用另一个VBA代码,我发现在互联网上实际列出所有的窗口,对象,处理我的机器。这个代码是由马克罗林森写的。
现在,我尝试使用这些有限的信息来自动化GUI访问。
步骤1:使用App Launcher程序启动应用程序。x1c 0d1x
第2步:启动swift登录页面后,我单击HSM框选项。

步骤3:点击HSM框后,我们需要在下面的屏幕上填写用户名,密码和会话PIN。

在这里,我自动执行了步骤2,在该步骤中启动swift登录(手动单击),然后单击HSM盒选项(自动使用VBA)。但在第3步之后,我无法继续前进,因为我无法找到正确的句柄。如前所述,我不能使用spy ++,因为它不允许安装任何第三方软件。因此,我使用另一个VBA代码只是为了列出给定页面上的所有句柄。那么在这种情况下,我如何确定要单击哪个元素呢?
下面是我正在使用的代码。
我的VBA代码自动化步骤2。这是工作正常。

Private Declare PtrSafe Function apiGetClassName Lib "User32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare PtrSafe Function apiGetDesktopWindow Lib "User32" Alias "GetDesktopWindow" () As Long
Private Declare PtrSafe Function apiGetWindow Lib "User32" Alias "GetWindow" (ByVal hWnd As Long, ByVal wCmd As Long) As Long
Private Declare PtrSafe Function apiGetWindowLong Lib "User32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare PtrSafe Function apiGetWindowText Lib "User32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal aint As Long) As Long
Private Declare PtrSafe Function FindWindow Lib "User32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function FindWindowEx Lib "User32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function SendMessage Lib "User32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare PtrSafe Function SendMessageByString Lib "User32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
Private Declare Function GetWindowText Lib "User32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long

Private Const mcGWCHILD = 5
Private Const mcGWHWNDNEXT = 2
Private Const mcGWLSTYLE = (-16)
Private Const mcWSVISIBLE = &H10000000
Private Const mconMAXLEN = 255
Private Const BM_CLICK As Integer = &HF5
Private Const WM_ACTIVATE As Integer = &H6
Private Const WA_ACTIVE As Integer = &H1

Sub ClickPrintButtonWindowsAPI()
    
    Dim hw As Long, mxtextbox As Long, tokenbutton As Long
    Dim pwd As String

    hw = FindWindow(vbNullString, "xxxxx xxx SWIFT Login")
    MsgBox hw
    tokenbutton = FindWindowEx(hw, 0&, "Button", "HSM Box")
    MsgBox tokenbutton
    Call SendMessage(tokenbutton, WM_ACTIVATE, 0, 0)
    Call SendMessage(tokenbutton, BM_CLICK, 0, 0)
    
    subwindow = FindWindowEx(hw, 0&, "ComboBox", vbNullString)
    MsgBox subwindow
    pwdTxtbox = FindWindowEx(subwindow, 0&, "Edit", vbNullString)
    MsgBox pwdTxtbox
    Call SendMessage(pwdTxtbox, WM_ACTIVATE, 0, 0)
    Call SendMessageByString(pwdTxtbox, WM_SETTEXT, 0, "xxxxxxxx")
    
End Sub

VBA代码,我正在使用从马克罗林森列出所有的窗口,句柄,对象等。

Option Explicit
 
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
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
(ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
 
Private x As Integer
 
 'Used a user defined type here rather than Enum so that it works on 97
Private Type winEnum
    winHandle As Integer
    winClass As Integer
    winTitle As Integer
    winHandleClass As Integer
    winHandleTitle As Integer
    winHandleClassTitle As Integer
End Type
Dim winOutputType As winEnum
 
Public Sub GetWindows()
    x = 0
    winOutputType.winHandle = 0
    winOutputType.winClass = 1
    winOutputType.winTitle = 2
    winOutputType.winHandleClass = 3
    winOutputType.winHandleTitle = 4
    winOutputType.winHandleClassTitle = 5
     
    GetWinInfo 0&, 0, winOutputType.winHandleClassTitle
End Sub
 
 
Private Sub GetWinInfo(hParent As Long, intOffset As Integer, OutputType As Integer)
     'Sub to recursively obtain window handles, classes and text
     'given a parent window to search
     'Written by Mark Rowlinson
     'www.markrowlinson.co.uk - The Programming Emporium
    Dim hWnd As Long, lngRet As Long, y As Integer
    Dim strText As String
    hWnd = FindWindowEx(hParent, 0&, vbNullString, vbNullString)
    While hWnd <> 0
        Select Case OutputType
        Case winOutputType.winClass
            strText = String$(100, Chr$(0))
            lngRet = GetClassName(hWnd, strText, 100)
            Range("a1").Offset(x, intOffset) = Left$(strText, lngRet)
        Case winOutputType.winHandle
            Range("a1").Offset(x, intOffset) = hWnd
        Case winOutputType.winTitle
            strText = String$(100, Chr$(0))
            lngRet = GetWindowText(hWnd, strText, 100)
            If lngRet > 0 Then
                Range("a1").Offset(x, intOffset) = Left$(strText, lngRet)
            Else
                Range("a1").Offset(x, intOffset) = "N/A"
            End If
        Case winOutputType.winHandleClass
            Range("a1").Offset(x, intOffset) = hWnd
            strText = String$(100, Chr$(0))
            lngRet = GetClassName(hWnd, strText, 100)
            Range("a1").Offset(x, intOffset + 1) = Left$(strText, lngRet)
        Case winOutputType.winHandleTitle
            Range("a1").Offset(x, intOffset) = hWnd
            strText = String$(100, Chr$(0))
            lngRet = GetWindowText(hWnd, strText, 100)
            If lngRet > 0 Then
                Range("a1").Offset(x, intOffset + 1) = Left$(strText, lngRet)
            Else
                Range("a1").Offset(x, intOffset + 1) = "N/A"
            End If
        Case winOutputType.winHandleClassTitle
            Range("a1").Offset(x, intOffset) = hWnd
            strText = String$(100, Chr$(0))
            lngRet = GetClassName(hWnd, strText, 100)
            Range("a1").Offset(x, intOffset + 1) = Left$(strText, lngRet)
            strText = String$(100, Chr$(0))
            lngRet = GetWindowText(hWnd, strText, 100)
            If lngRet > 0 Then
                Range("a1").Offset(x, intOffset + 2) = Left$(strText, lngRet)
            Else
                Range("a1").Offset(x, intOffset + 2) = "N/A"
            End If
        End Select
         'check for children
        y = x
        Select Case OutputType
        Case Is > 4
            GetWinInfo hWnd, intOffset + 3, OutputType
        Case Is > 2
            GetWinInfo hWnd, intOffset + 2, OutputType
        Case Else
            GetWinInfo hWnd, intOffset + 1, OutputType
        End Select
         'increment by 1 row if no children found
        If y = x Then
            x = x + 1
        End If
         'now get next window
        hWnd = FindWindowEx(hParent, hWnd, vbNullString, vbNullString)
    Wend
     
End Sub

下面是运行上述代码后在excel中的输出。

如果你能在这里看到,下面是用户名和密码的句柄名称和值。我怎样才能选择“密码”编辑框?它的值是N/A。

  • 1640324静态用户名
  • 722818编辑不适用
  • 722816静态密码
  • 722814编辑不适用

我需要出去的路。
此外,第一步解析通过应用程序启动程序的树结构也是不可能的,因为间谍++相同的限制。我该怎么办?

x4shl7ld

x4shl7ld1#

谢谢Gserg的提示。我自己也解决了这个问题,通过递归引用。例如,类似下面的内容

firstedit = FindWindowEx(hw, 0&, "Edit", vbNullString) 
secondedit = FindWindowEx(hw, firstedit, "Edit", vbNullString ....

这样我就可以解析同一级别的所有编辑句柄,直到找到正确的句柄。

相关问题