It appears you have not yet registered with DEVPPL. To register please click here... (it's fast, easy and free!)

Forum

Log In Sponsors
Board index Programming Visual Basic Forum

Automate Winforms

Moderator: dafunkymunky

Automate Winforms

Postby oliverikawood on Tue Mar 10, 2009 10:09 am

Hi all,
I need to get handle of .NET controls. Here is my code.
Code: Select all
Sub Main()
   Dim hwndParent As Long
   hwndParent = Win32.user32.GetDesktopWindow
   Dim controlHandle As Long
   controlHandle = FindWindowsFormsControlRecursive(hwndParent, "listview_Report")
End Sub

Function FindWindowsFormsControlRecursive(startWnd As Long, controlName As String) As Long
    Dim childWnd As Long
    Dim tmpWnd As Long
    Dim retVal As Long

    ' Start with the first child.
    childWnd = GetWindow(startWnd, GW_CHILD)
    Do While childWnd <> 0 And retVal = 0
        ' Compare the WindowsFormsID and see if this is the control.
        If GetWindowsFormsID(childWnd) <> controlName Then
            tmpWnd = childWnd
            ' Do depth-first recursion on the children.
            retVal = FindWindowsFormsControlRecursive(tmpWnd, controlName)
            childWnd = GetWindow(childWnd, GW_HWNDNEXT)
        Else
            ' Found it.
            retVal = childWnd
            Exit Do
        End If

    Loop
   
    FindWindowsFormsControlRecursive = retVal
End Function

Function GetWindowsFormsID(ByVal wnd As Long) As String
    Dim PID As Long 'pid of the process that contains the control
    Dim msg As Long

    ' Define the buffer that will eventually contain the desired
    ' component's name.
    Dim bytearray As String * 65526

    ' Allocate space in the target process for the buffer as shared
    ' memory.
    Dim bufferMem As Long
    ' Base address of the allocated region for the buffer.
    Dim size As Long
    ' The amount of memory to be allocated.
    Dim written As Long
    ' Number of bytes written to memory.
    Dim retLength As Long
    Dim retVal As Long
    Dim errNum As Integer
    Dim errDescription As String
    Dim lp As Long

    size = 65527 '65536 'Len(bytearray)

    ' Creating and reading from a shared memory region is done
    ' differently in Win9x than in newer Oss.
    Dim processHandle As Long
    Dim fileHandle As Long

    msg = RegisterWindowMessage("WM_GETCONTROLNAME")

    If Not IsWin9x() Then
        On Local Error GoTo Error_Handler_NT
            'Dim dwResult As Long
            'dwResult = GetWindowThreadProcessId(wnd, VarPtr(PID))
            Call GetWindowThreadProcessId(wnd, PID)

            processHandle = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, 0, PID)
            If processHandle = 0 Then
                Error Err 'OpenProcess API Failed
            End If

            bufferMem = VirtualAllocEx(processHandle, 0, size, MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE)
            If bufferMem = 0 Then
                Error Err 'VirtualAllocEx API Failed
            End If

            ' Send message to the control's HWND for getting the
            ' Specified control name.
            retLength = SendMessage(wnd, msg, size, ByVal bufferMem)
           
            If retLength <> 0 Then
            ' Now read the component's name from the shared memory location.
                Call WriteProcessMemory(processHandle, bufferMem, bytearray, size, lp)
                retVal = ReadProcessMemory(processHandle, bufferMem, bytearray, size, lp)
                If retVal = 0 Then
                    Error Err 'ReadProcessMemory API Failed
                End If
            End If
           
Error_Handler_NT:
            errNum = Err
            errDescription = Error$
            ' Free the memory that was allocated.
            retVal = VirtualFreeEx(processHandle, bufferMem, 0, MEM_RELEASE)
            If retVal = 0 Then
                Error Err 'VirtualFreeEx API Failed
            End If
            CloseHandle (processHandle)
            If errNum <> 0 Then
                On Local Error GoTo 0
                Error errNum ', errDescription
            End If
        On Local Error GoTo 0

    Else
       On Local Error GoTo Error_Handler_9x
           
            Dim SA As SECURITY_ATTRIBUTES
           
            fileHandle = CreateFileMapping(INVALID_HANDLE_VALUE, SA, PAGE_READWRITE, 0, size, Null)
            If fileHandle = 0 Then
                Error Err 'CreateFileMapping API Failed
            End If
            bufferMem = MapViewOfFile(fileHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0)
            If bufferMem = 0 Then
                Error Err 'MapViewOfFile API Failed
            End If
           
            Call CopyMemory(bufferMem, bytearray, size)

            ' Send message to the treeview control's HWND for
            ' getting the specified control's name.
            retLength = SendMessage(wnd, msg, size, bufferMem)

            ' Read the control's name from the specific shared memory
            ' for the buffer.
            Call CopyMemoryA(bytearray, bufferMem, 1024)

Error_Handler_9x:
            errNum = Err
            errDescription = Error$

            ' Unmap and close the file.
            UnmapViewOfFile (bufferMem)
            CloseHandle (fileHandle)

            If errNum <> 0 Then
                On Local Error GoTo 0
                Error errNum 'errDescription
            End If
        On Local Error GoTo 0

    End If

    If retLength <> 0 Then
    ' Get the string value for the Control name.
    GetWindowsFormsID = ByteArrayToString(bytearray, retLength)
    End If

End Function

Function IsWin9x() As Boolean

    Dim osVerInfo As OSVERSIONINFO

    osVerInfo.dwOSVersionInfoSize = 128 + 4 * 5

    Dim l As Long
    l = GetVersionEx(osVerInfo)

    IsWin9x = osVerInfo.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS

End Function

Function ByteArrayToString(bytes As String, length As Long) As String
    Dim retValStr As String
    Dim l As Long
   
    If IsWin9x() Then
        retValStr = Left(bytes, InStr(1, bytes, Chr(0)) - 1)
    Else
        retValStr = String$(length + 1, Chr(0))
       
        l = WideCharToMultiByte(CP_ACP, 0, bytes, -1, retValStr, length + 1, Null, Null)

    End If

    ByteArrayToString = retValStr

End Function

And some declarations:
Code: Select all
Public Const MEM_COMMIT As Long = &H1000
Public Const MEM_RESERVE As Long = &H2000
Public Const MEM_RELEASE = &H8000&
Public Const PAGE_READWRITE = &H4

Public Const PROCESS_VM_OPERATION = &H8
Public Const PROCESS_VM_READ = &H10
Public Const PROCESS_VM_WRITE = &H20

Declare Function VirtualAllocEx Lib "kernel32" _
                              (ByVal hProcess As Long, _
                              ByVal lpAddress As Long, _
                              ByVal dwSize As Long, _
                              ByVal flAllocationType As Long, _
                              ByVal flProtect As Long) As Long

Declare Function ReadProcessMemory Lib "kernel32" _
                              (ByVal hProcess As Long, _
                              ByVal lpBaseAddress As Long, _
                              lpBuffer As Any, _
                              ByVal nSize As Long, _
                              lpNumberOfBytesRead As Long) As Long

Declare Function VirtualFreeEx Lib "kernel32" _
                              (ByVal hProcess As Long, _
                              ByVal lpAddress As Long, _
                              ByVal dwSize As Long, _
                              ByVal dwFreeType As Long) As Long

Declare Function WriteProcessMemory Lib "kernel32" _
                              (ByVal hProcess As Long, _
                              ByVal lpBaseAddress As Long, _
                              lpBuffer As Any, _
                              ByVal nSize As Long, _
                              lpNumberOfBytesWritten As Long) As Long

I got error in WideCharToMultiByte:
Code: Select all
Run-time error '94':

Invalid use of Null

It seems like bytes in ByteArrayToString is empty. What am I doing wrong?
oliverikawood
 
Posts: 2
Joined: Tue Mar 10, 2009 5:48 am

Re: Automate Winforms

Postby oliverikawood on Wed Mar 11, 2009 5:04 am

OK, this is solved. The issue is actually convert WideChar string into ANSI string. I use CopyMemory instead of WideCharToMultiByte.
Code: Select all
Public Declare Sub CopyMemoryA Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, cbCopy As Long)

Function ByteArrayToString(bytes As String, Length As Long) As String
   Dim retValStr As String
   If IsWin9x() Then
       retValStr = Left(bytes, InStr(1, bytes, Chr(0)) - 1)
   Else
       retValStr = String(Length - 1, Chr$(0))
       CopyMemory ByVal StrPtr(retValStr), ByVal bytes, Length * 2
   End If
   ByteArrayToString = retValStr
End Function
oliverikawood
 
Posts: 2
Joined: Tue Mar 10, 2009 5:48 am


Who is online

Users browsing this forum: No registered users and 4 guests