Results 1 to 4 of 4

Thread: Strange SendMessage API Lag/Delay Issue

  1. #1

    Thread Starter
    New Member
    Join Date
    Apr 2011
    Posts
    4

    Question Strange SendMessage API Lag/Delay Issue

    Hello

    I am trying to automate a few non standard systems by using common API's such as SendMessage & PostMessage. I can use these API's as I intended, however there are issues where the code seems to go too fast. It's simple enough to have some sort of wait code for automating things such as Internet explorer by doing a Do Until ReadyState..., but when trying something similar on external windows, I seem to hit a problem.

    Take for instance this example; I need to send text to a textbox with WM_SETTEXT, I can get the handles no problem, I can also run this no successfully if I press F11 and step into each line, if however I let it run at normal speed, the code doesn't end up entering the text into the textbox, my solution was to have the code do another SendMessage to do WM_GETTEXTLENGTH & WM_GETTEXT so that the code can check if the text has been entered to the textbox and loop until it is there, to my surprise however, the WM_GETTEXTLENGTH & WM_GETTEXT actually think that the text has been entered even though there is no text in the textbox, it even knows what text is supposed to be in there. Even more perculier is that when I do WM_GETTEXTLENGTH & WM_GETTEXT again on that control, it goes back to saying that there is no text within the textbox.

    Code:
    Private Enum WindowMessages
        WM_SETTEXT = &HC
        WM_GETTEXT = &HD
        WM_GETTEXTLENGTH = &HE
    End Enum
    
    Private Declare Function SendMessage Lib "user32" Alias _
    "SendMessageA" (ByVal hWnd As Int32, ByVal wMsg As Int32, ByVal _
    wParam As Int32, lParam As String) As Int32
    
    Private Sub TestExample(ByVal hWndTextBox As Int32, ByVal TextString As String)
    '####Using the hWnd of a Combo box control and a string to enter in the combo box.####
    
        Dim TextLength As Int32
        Dim ItemText As String
    
        Do Until ItemText = TextString
            SendMessage(hWndTextBox, WM_SETTEXT, 0, TextString) > 0
            TextLength = SendMessage(hWndTextBox, WM_GETTEXTLENGTH, 0, 0)
            ItemText = Space(TextLength)
            SendMessage(hWndTextBox, WM_GETTEXT, TextLen + 1, ItemText)
        Loop
    
    End Sub
    It sounds a bit confusing, I'm puzzled myself, if you have any solutions I would really like to know, the Sleep API would make it partially work as it makes the system physically wait, but I know that theres the possibility that would fail sometimes too, is there some sort of screen paint/refresh that would work or something?

    I look forward to any solutions.

    Many Thanks

    Xenac

  2. #2
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Strange SendMessage API Lag/Delay Issue

    Are you using VB6? If so, the following lines have a syntax error:

    Code:
    SendMessage(hWndTextBox, WM_SETTEXT, 0, TextString) > 0
    SendMessage(hWndTextBox, WM_GETTEXT, TextLen + 1, ItemText)
    It looks like you are checking the return value of the WM_SETTEXT message to see if it succeeded. However, it seems your code above just ignores the result anyway and proceeds to retrieve the text regardless of whether it was successfully set in the first place.

    I've done some tests in Win 7 and I've been able to set and retrieve the text of other processes' Edit windows (and some other window classes too) very rapidly using both A & W versions of the SendMessage API. I'm not certain what the problem might be in your case. Can you reveal more clues?
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  3. #3

    Thread Starter
    New Member
    Join Date
    Apr 2011
    Posts
    4

    Re: Strange SendMessage API Lag/Delay Issue

    Thanks for your reply Bonnie West

    In answer to your questions:

    I am using Visual Studio 2010 or (VB 10.0). I've created a better example below which removes the syntax error and is easier to test.

    The part where the WM_SETTEXT is was supposed to set the text to something e.g. "F:\TestDocument.txt", then do a WM_GETTEXTLEN & WM_GETTEXT to see if the WM_SETTEXT has been entered; if the WM_GETTEXT brought back information saying that the text didn't match what the WM_SETTEXT entered then it would loop until there was a physical sign of the text being entered. The problem that occurs is that the WM_GETTEXT brings back information that there is text in the box even though it's not actually there.

    The new example of the code tests the same issues with Notepad (as it's a good example system to test), in this scenario the code opens Notepad and initiates the Open dialog, which works fine, but the actual WM_SETTEXT does the same thing again. When you run it you will see that the message box brings back the text that should be in the file name combobox edit control even though the combobox has nothing in it.

    Should I be using something like ReplyMessage to confirm if somethings gone through maybe?

    Code:
    Public Class TestClass
    
        Private Enum APIMessages
            WM_COMMAND = &H111
            WM_SETTEXT = &HC
            WM_GETTEXT = &HD
            WM_GETTEXTLENGTH = &HE
    	 GW_HWNDNEXT = &H2
    	 BM_CLICK = &HF5
        End Enum
    
        '####Declarations.####
    
        Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
            ByVal hWnd As Int32, _
            ByVal wMsg As Int32, _
            ByVal wParam As Int32, _
            ByVal lParam As String _
        ) As Int32
    
        Public Declare Function SendMessageCallback Lib "user32" Alias "SendMessageCallbackA" ( _
            ByVal hwnd As Int32, _
            ByVal Msg As Int32, _
            ByVal wParam As Int32, _
            ByVal lParam As String, _
            ByVal lpResultCallBack As Int32, _
            ByVal dwData As Int32 _
        ) As Int32
    
        Public Declare Function GetParent Lib "user32" (ByVal hWnd As Int32) As Int32
    
        Private Declare Function GetTopWindow Lib "user32.dll" (ByVal hwnd As Int32) As Int32
    
        Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" ( _
            ByVal lpClassName As String, _
            ByVal lpWindowName As String _
        ) As Int32
    
        Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" ( _
            ByVal hWndParent As Int32, _
            ByVal hWndChildAfter As Int32, _
            ByVal lpszClassName As String, _
            ByVal lpszWindowName As String _
        ) As Int32
    
        Public Sub OpenNotepad()
    
            '####Open Notepad and then initiate the open dialog.####
    
            On Error GoTo ErrHandler
    
            Dim TestFileOpen As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) & "\test.txt"
            Dim MSNotepad As Int32
            Dim OpenDialog As Int32 = 0
            Dim Wnd_ComboBoxEx32 As Int32
            Dim Wnd_ComboBox As Int32
            Dim Wnd_Edit As Int32
            Dim Wnd_OpenBtn As Int32
            Dim StartProcess As Process = Process.Start("notepad.exe")
    
            If FindWindow("Notepad", vbNullString) > 0 Then Err.Raise(440, , "Must close other versions of the window.")
    
            '\\Get the handle of the application that has been opened.
            Do Until MSNotepad > 0
                MSNotepad = (StartProcess.MainWindowHandle)
            Loop
    
            '\\Initiate the Open file command.
            SendMessageCallback(MSNotepad, APIMessages.WM_COMMAND, &H2, &H0, &H0, &H0)
            Do Until OpenDialog > 0
                OpenDialog = FindWindow(vbNullString, "Open")
            Loop
    
            '\\Determine if the window is the correct one by getting it's parent.
            'If GetParent(OpenDialog) = MSNotepad Then MsgBox("Found the open window successfully!")
            'If OpenDialog = 0 Then Err.Raise(440, , "Unable to find the open dialog.")
    
            '\\Find the filename combobox.
            Wnd_ComboBoxEx32 = WaitForFindWindow(OpenDialog, "ComboBoxEx32")
            '\\Find the comboboxes inner control.
            Wnd_ComboBox = WaitForFindWindow(Wnd_ComboBoxEx32, "ComboBox")
            '\\Find the comboboxes edit control.
            Wnd_Edit = WaitForFindWindow(Wnd_ComboBox, "Edit")
            '\\Type the filename within the filename combobox.
            SendMessage(Wnd_Edit, APIMessages.WM_SETTEXT, &H0, TestFileOpen)
            MsgBox(GetText(Wnd_Edit))
            '\\Find the Open button control.
            Wnd_OpenBtn = WaitForFindWindow(OpenDialog, "Button", "&Open")
            '\\Type the filename within the filename combobox.
            SendMessage(Wnd_OpenBtn, BM_CLICK, &H0, &H0)
    
            Exit Sub
    
    ErrHandler:
    
            MsgBox("The following error occured:" & vbCr & vbCr & Err.Description, vbCritical)
    
        End Sub
    
        Private Function GetText(ByVal hWnd As Int32) As String
    
            '####Gets the textlength and text contained.####
    
            Dim TextLen As Integer = SendMessage(hWnd, APIMessages.WM_GETTEXTLENGTH, vbNullString, vbNullString) + 1
            Dim Buffer As String = New String(" "c, TextLen)
    
            SendMessage(hWnd, APIMessages.WM_GETTEXT, TextLen, Buffer)
            GetText = Buffer
    
        End Function
    
        Private Function WaitForFindWindow( _
            ByVal hWnd As Int32,
            Optional ByVal lpszClassName As String = vbNullString,
            Optional ByVal lpszWindowName As String = vbNullString) As Int32
    
            '####Runs FindWindowEx and waits for the control to get a hWnd value.####
    
            Dim cWnd As Int32
    
            Do Until cWnd > 0
                cWnd = FindWindowEx(hWnd, vbNullString, lpszClassName, lpszWindowName)
            Loop
    
            WaitForFindWindow = cWnd
    
        End Function
    
    End Class

  4. #4
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Strange SendMessage API Lag/Delay Issue

    Unfortunately, I don't code in VB.Net so I may not be able to help you much. However, I did try reproducing the core part of your problem using VB6. I was able to successfully send some text (via SendMessageW WM_SETTEXT) to the File name ComboBox of the Open dialog box. In your latest code above, you're still ignoring the return value of the WM_SETTEXT message. Assuming the call failed, your code continues with the next SendMessage calls regardless. You should be checking the return value and should proceed only if successful. You should also check the description of the last API error, if any. Sorry, but I still have no idea why your code doesn't work correctly.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

Tags for this Thread

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