Results 1 to 12 of 12

Thread: windows API Help - IPC (clicking toolbar button)

  1. #1

    Thread Starter
    Member Mythrandil's Avatar
    Join Date
    Mar 2006
    Posts
    55

    windows API Help - IPC (clicking toolbar button)

    Hoping there are one or two windows developer gurus around that can help me with some IPC.

    Currently developing an automation tool to test new desktop OS builds at work. Need to be able to open menu items on toolbarwindow32 windows (main menu of explorer windows). Now this requires retrieving information of all the buttons on the toolbar, obtaining the button ID of desired menu and sending a WM_COMMAND message with the ID. I'm having trouble retrieving button information.

    Now im using openprocess, virtualallocex to allocate virtual memory in the target process, and then sending the TB_GETBUTTON message with a pointer to the allocated memory then reading out the result. Allocation and the send message works fine but reading the processmemory back out is failing but not returning an error code, getlastwin32error returns nothing either.

    Sorry for vb code, not my choice

    Declarations
    Code:
    <StructLayout(LayoutKind.Sequential)> _
            Public Structure TBBUTTON
                Public iBitmap As Integer
                Public idCommand As Integer
                Public fsState As Byte
                Public fsStyle As Byte
                Public bReserved1 As Byte
                Public bReserved2 As Byte
                'Public bReserved2() As Byte
                Public dwData As Integer
                Public iString As Integer
            End Structure
    
     <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
            Private Shared Function VirtualAllocEx(ByVal hProcess As IntPtr, ByVal lpAddress As IntPtr, _
            ByVal dwSize As IntPtr, ByVal flAllocationType As VMemAllocType, ByVal flProtect As MemProtection) As IntPtr
            End Function
    
            <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
            Private Shared Function VirtualFreeEx(ByVal hProcess As IntPtr, ByVal lpAddress As IntPtr, _
            ByVal dwSize As IntPtr, ByVal dwFreeType As UInteger) As <MarshalAs(UnmanagedType.Bool)> Boolean
            End Function
    
            <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
            Public Shared Function WriteProcessMemory(ByVal hProcess As IntPtr, ByVal lpBaseAddress As IntPtr, ByVal lpBuffer As IntPtr, ByVal nSize As IntPtr, ByVal lpNumberOfBytesWritten As IntPtr) As Integer
            End Function
    
            <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
            Public Shared Function ReadProcessMemory(ByVal hProcess As IntPtr, ByVal lpBaseAddress As Integer, ByVal lpBuffer As Integer, _
            ByVal iSize As IntPtr, ByVal lpNumberOfBytesRead As IntPtr) As Boolean
            End Function
    
            <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
            Public Shared Function ReadProcessMemory(ByVal hProcess As IntPtr, ByVal lpBaseAddress As IntPtr, ByVal lpBuffer As Byte(), _
            ByVal iSize As IntPtr, ByVal lpNumberOfBytesRead As IntPtr) As Boolean
            End Function
    
            <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
            Public Shared Function OpenProcess(ByVal dwDesiredAccess As ProcessFlags, ByVal bInheritHandle As Boolean, ByVal dwProcessId As UInteger) As IntPtr
            End Function
    
            <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
            Private Shared Function GetWindowThreadProcessId(ByVal hwnd As IntPtr, ByRef lpdwProcessId As UInteger) As UInteger
            End Function
    Function
    Code:
    Dim bInfo As TBBUTTON
    
                Dim localPtr As Integer
                Dim remotePtr As Integer
                Dim bInfoSize As Integer
                Dim res As Integer
                Dim hwndProcess As IntPtr
                Dim pid As UInteger
                Dim bText As String
                Dim tbCount As Integer
                Dim lret As Integer
                'ReDim bInfo.bReserved2(1)
                tbCount = SendMessageSync(hwnd, Methods.TB_BUTTONCOUNT, IntPtr.Zero, IntPtr.Zero)
                bInfoSize = Marshal.SizeOf(bInfo)
                If tbCount > 0 Then
                    GetWindowThreadProcessId(hwnd, pid)
                    hwndProcess = OpenProcess(ProcessFlags.PROC_VM_OPREADWRITE, False, pid)
                    remotePtr = VirtualAllocEx(hwndProcess, Nothing, bInfoSize, VMemAllocType.MEM_RESERVECOMMIT, MemProtection.PAGE_READWRITE)
                    For tbIndex As Integer = 0 To tbCount - 1         
                        Dim hret As Integer = SendMessageSync(hwnd, Methods.TB_GETBUTTON, tbIndex, remotePtr)
                        gcInfo = GCHandle.Alloc(bInfo, GCHandleType.Pinned)
                        localPtr = gcInfo.AddrOfPinnedObject().ToInt32()
                        gcInfo.Free()
    
                        res = ReadProcessMemory(hwndProcess, remotePtr, localPtr, Len(bInfo), IntPtr.Zero)
    
                        Dim str As String = Marshal.GetLastWin32Error()
    
                    VirtualFreeEx(hwnd, remotePtr, Marshal.SizeOf(remotePtr), &H8000UI)
                    CloseHandle(hwndProcess)
                End If
    As mentioned above, the read process memoery call fails, the return value is -1 The documentation states it returns 0 for fail, non zero for pass.

    Wondering if the problem lies in incorrect use of types in pinvoke calls or the struct tbbutton is incorrect, or my use of a pinned pointer is wrong, or whether I need to use adjusttokenpriviledges to ensure I have rights. Though I'm running under admin and examples similar to this don't use it.

    Relevant documentation
    Virtualallocex
    Read Process Memory
    TBBUTTON Struct
    Last edited by Mythrandil; Aug 5th, 2008 at 02:57 PM.

  2. #2
    Addicted Member
    Join Date
    Mar 2008
    Posts
    143

    Re: windows API Help - IPC (clicking toolbar button)

    Quote Originally Posted by Mythrandil
    As mentioned above, the read process memoery call fails, the return value is -1 The documentation states it returns 0 for fail, non zero for pass.
    Why do you think the read process memory call failed? A -1 would indicate success.
    Shut up and eat your banana!

  3. #3

    Thread Starter
    Member Mythrandil's Avatar
    Join Date
    Mar 2006
    Posts
    55

    Re: windows API Help - IPC (clicking toolbar button)

    Because after the readprocessmemory call all bInfo's members are still default values (0's)

    I assumed read memory was failing as send message returns 1 indicating success.

    Maybe my memory allocation is therefore at fault? - The call does return a memory address though.

  4. #4
    Addicted Member
    Join Date
    Mar 2008
    Posts
    143

    Re: windows API Help - IPC (clicking toolbar button)

    gcInfo = GCHandle.Alloc(bInfo, GCHandleType.Pinned)
    localPtr = gcInfo.AddrOfPinnedObject().ToInt32()
    gcInfo.Free()

    res = ReadProcessMemory(hwndProcess, remotePtr, localPtr, Len(bInfo), IntPtr.Zero)
    Try moving gcInfo.Free() to after your call to ReadProcessMemory. Also, why use Len(bInfo) instead of bInfoSize in your ReadProcessMemory call?
    Shut up and eat your banana!

  5. #5

    Thread Starter
    Member Mythrandil's Avatar
    Join Date
    Mar 2006
    Posts
    55

    Re: windows API Help - IPC (clicking toolbar button)

    Quote Originally Posted by michaelerice
    Try moving gcInfo.Free() to after your call to ReadProcessMemory. Also, why use Len(bInfo) instead of bInfoSize in your ReadProcessMemory call?
    Tried moving free afterwards and same behaviour. Returns -1 and bInfo is still all zero's.

    I tried len(bInfo) just to compare whether it returned same size as marshal.sizeof, it does and I just forgot to change it back.

  6. #6
    Addicted Member
    Join Date
    Mar 2008
    Posts
    143

    Re: windows API Help - IPC (clicking toolbar button)

    A couple of items in your signature for ReadProcessMemory may be incorrect. Consider the following...

    Code:
    <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError=true)> 
    Public Shared Function ReadProcessMemory( _
        ByVal hProcess As IntPtr, _
        ByVal lpBaseAddress As IntPtr, _
        <Out()>ByVal lpBuffer() As Byte, _
        ByVal dwSize as Integer, _
        ByRef lpNumberOfBytesRead as Integer
      ) As Boolean
      End Function
    Shut up and eat your banana!

  7. #7

    Thread Starter
    Member Mythrandil's Avatar
    Join Date
    Mar 2006
    Posts
    55

    Re: windows API Help - IPC (clicking toolbar button)

    Quote Originally Posted by michaelerice
    A couple of items in your signature for ReadProcessMemory may be incorrect. Consider the following...

    Code:
    <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError=true)> 
    Public Shared Function ReadProcessMemory( _
        ByVal hProcess As IntPtr, _
        ByVal lpBaseAddress As IntPtr, _
        <Out()>ByVal lpBuffer() As Byte, _
        ByVal dwSize as Integer, _
        ByRef lpNumberOfBytesRead as Integer
      ) As Boolean
      End Function
    Thanks will give that a shot, how would I modify the use of local pointer to accomodate a byte array?

  8. #8

    Thread Starter
    Member Mythrandil's Avatar
    Join Date
    Mar 2006
    Posts
    55

    Re: windows API Help - IPC (clicking toolbar button)

    I have fixed the problem now but still having trouble reaching my original target of clicking a toolbarwindow32 menu (File, edit etc)

    TB_Buttonpressed just causes the buttons gfx to change and not trigger the context menu to appear, wm_command does nothing!

    Any ideas?

  9. #9
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: windows API Help - IPC (clicking toolbar button)

    Are you sure that you absolutely have to 'test' the new desktop builds this way? I mean, are you sure there is no managed .NET code that can do what you want instead of having to use all these APIs just to click one button..
    Also, from what I can see, this is pretty much all API stuff so you probably should of posted it in the API part of the forum
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  10. #10
    Addicted Member
    Join Date
    Jan 2008
    Location
    Essex, UK
    Posts
    149

    Re: windows API Help - IPC (clicking toolbar button)

    Quote Originally Posted by chris128 View Post
    Are you sure that you absolutely have to 'test' the new desktop builds this way? I mean, are you sure there is no managed .NET code that can do what you want instead of having to use all these APIs just to click one button..
    Also, from what I can see, this is pretty much all API stuff so you probably should of posted it in the API part of the forum
    Lol . In other words 'I dont know how to answer your question'.

    Here is a technique i am using to click on 'File' menus and items found in 3rd party programs i am trying to control. This method however may not work with 'Toolbar' controls. The code is for a test program i developed so its not been made specifically for your question im afraid.

    Code:
    Public Class Form1
    
        Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
        Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Integer
        Public Declare Function GetMenu Lib "user32" Alias "GetMenu" (ByVal hwnd As Integer) As Integer
        Public Declare Function GetSubMenu Lib "user32" Alias "GetSubMenu" (ByVal hMenu As Integer, ByVal nPos As Integer) As Integer
        Public Declare Function GetMenuItemID Lib "user32" Alias "GetMenuItemID" (ByVal hMenu As Integer, ByVal nPos As Integer) As Integer
        ' The GetMenuItemID function retrieves the menu item identifier of a menu item located at the specified position in a menu.
        Public Declare Function GetMenuItemCount Lib "User32.Dll" (ByVal hMenu As IntPtr) As Integer
        ' The GetMenuItemCount function determines the number of items in the specified menu. 
    
        Private Declare Auto Function PostMessage Lib "user32.dll" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
        ' The PostMessage function places (posts) a message in the message queue associated with the thread that created the 
        ' specified window and returns without waiting for the thread to process the message. 
    
        Private Const WM_COMMAND = &H111
        Private Const WM_MENUSELECT = &H11F
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    
            Dim lhWnd As IntPtr, lMenu As IntPtr, submenu As IntPtr, lID As Integer
            Dim total As Integer
            Dim windowname As String
    
            windowname = TextBox1.Text
    
            lhWnd = FindWindow(vbNullString, windowname)
            lMenu = GetMenu(lhWnd)
            submenu = GetSubMenu(lMenu, 0)
            lID = GetMenuItemID(submenu, 0)
            total = GetMenuItemCount(submenu)
    
            Label1.Text = "Parent Handle :" & lhWnd.ToString
            Label2.Text = "Menu Handle :" & lMenu.ToString
            Label3.Text = "SubMenu Handle :" & submenu.ToString
            Label4.Text = "MenuItem ID :" & lID.ToString
            Label5.Text = "Amount Of Menu Items : " & total
    
            'SendMessage(lhWnd, WM_COMMAND, lID, 0&)
            PostMessage(lhWnd, WM_COMMAND, lID, 0&)
    
        End Sub
    
    End Class
    Development Enviroment: Visual Studio 2008, VB.NET

    Recommend Winspector, far better then SPY++
    http://www.windows-spy.com/

  11. #11
    I'm about to be a PowerPoster! kleinma's Avatar
    Join Date
    Nov 2001
    Location
    NJ - USA (Near NYC)
    Posts
    23,373

    Re: windows API Help - IPC (clicking toolbar button)

    Just to throw another option your way, are these new OS builds Vista, or are you still using an older operating system like XP?

    Vista and up has a complete UI automation API that would likely make this much easier
    http://msdn.microsoft.com/en-us/library/ms747327.aspx

  12. #12
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: windows API Help - IPC (clicking toolbar button)

    Quote Originally Posted by appolospb View Post
    Lol . In other words 'I dont know how to answer your question'.
    No I dont know how to do it via API, I rarely use APIs. How terrible of me.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width