problem with SendMessageA

I’m using this code to get pal room text

I’m using vs2013 and nerframework 4

the problem is it’s some times retrieve the text and other times not I tried to breakpoint so every thing go fine but still some times it retrieve text after I breakpoint and sometimes when I restart the application it just retrieve empty string “”

what could cause that issue and how to fix

 

Declare Function SendMessageA Lib "USER32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As StringBuilder) As Integer

Call SendMessageA(hwnd, EM_GETLINE, (iLastLine - 2), strBuffer)

 

29 thoughts on “problem with SendMessageA

  1. it happen in both

    some time I tried it in even a private room

    I start the application it just retrieve empty string. Then I close and restart it work fine

    so I don’t know what cause the problem to make it retrieve empty string

  2. i have the hwnd correctly

    the strange thing is today I tried it so it retrieve some lines and other lines it give me empty string, I didn’t even restart the program while it still working some times it retrieve the text and some times it just give empty

    I don’t know why

  3. ok I kind of fix it  I just had to dim the StringBuilder in right way I did that

    Dim strBuffer As New StringBuilder(" ", 1024)

    the new issue now is that it get part of the line not the whole line exactly 32 letter

     

  4. ok now I know what is the problem

    it’s the net framework version it have to be 3.5

    when it’s 3.5 every thing work just fine

    but when it’s 4 it doesn’t work and my app have to be net framework 4

    so is there any way to fix this?

  5. now it just get 49 letter

    Sorry

    strBuffer.Append(ChrW(1024))
    

    ok now I know what is the problem
    it’s the net framework version it have to be 3.5
    when it’s 3.5 every thing work just fine
    but when it’s 4 it doesn’t work and my app have to be net framework 4
    so is there any way to fix this?

    No this is not the problem

  6. Try declaring SendMessage

    Declare Auto Function SendMessage Lib "USER32" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As StringBuilder) As Integer

     

  7. The problem is with marshaling.

    for ansi the code should be

    strBuffer.Append(Chr(1024 And 255))
    strBuffer.Append(Chr(1024 / 256))

     

    Because the buffer is marshaled from unicode to anso on it’s way out Char by Char. 1024 fits in a Char which is 2 byte unicode but when marshaled the high byte is lost. or somehow converted

    I suggest to declare and use SendMessage as follows, since the edit control is unicode anyway

    Declare Unicode Function SendMessage Lib “USER32” Alias “SendMessageW” _
    (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer,
    ByVal lParam As StringBuilder) As Integer

    strBuffer.Append(ChrW(1024))

  8. Did you add a null termination char at the end of the “buffer”? also make variable for sendmessage which should give you the amount of chars copied and see if that matches correctly, if it does I would guess you need to add a null terminated char at the end of your “buffer”, I also suggest against making a static length buffer and create this dynamically.

    show us the whole function you wrote and we can maybe help a little more on what the problem could be.

  9. The problem is with marshaling. for ansi the code should be
    <div id=”wpshdo_6″ class=”wp-synhighlighter-outer”>
    <div id=”wpshdt_6″ class=”wp-synhighlighter-expanded”>
    <table border=”0″ width=”100%”>
    <tbody>
    <tr>
    <td align=”left” width=”80%”>Code</td>
    <td align=”right”> </td>
    </tr>
    </tbody>
    </table>
    </div>
    <div id=”wpshdi_6″ class=”wp-synhighlighter-inner” style=”display: block;”>
    <div class=”vbnet” style=”font-family: monospace;”>strBuffer.<span class=”me1″>Append</span><span class=”br0″>(</span><span class=”kw7″>Chr</span><span class=”br0″>(</span>1024 <span class=”kw5″>And</span> 255<span class=”br0″>)</span><span class=”br0″>)</span> strBuffer.<span class=”me1″>Append</span><span class=”br0″>(</span><span class=”kw7″>Chr</span><span class=”br0″>(</span><span class=”nu0″>1024</span> <span class=”sy0″>/</span> <span class=”nu0″>256</span><span class=”br0″>)</span><span class=”br0″>)</span></div>
    </div>
    </div>
    Because the buffer is marshaled from unicode to anso on it’s way out Char by Char. 1024 fits in a Char which is 2 byte unicode but when marshaled the high byte is lost. or somehow converted I suggest to declare and use SendMessage as follows, since the edit control is unicode anyway
    <div id=”wpshdo_7″ class=”wp-synhighlighter-outer”>
    <div id=”wpshdt_7″ class=”wp-synhighlighter-expanded”>
    <table border=”0″ width=”100%”>
    <tbody>
    <tr>
    <td align=”left” width=”80%”>Code</td>
    <td align=”right”> </td>
    </tr>
    </tbody>
    </table>
    </div>
    <div id=”wpshdi_7″ class=”wp-synhighlighter-inner” style=”display: block;”>
    <div class=”vbnet” style=”font-family: monospace;”><span class=”kw6″>Declare</span> <span class=”kw1″>Unicode</span> <span class=”kw6″>Function</span> SendMessage Lib <span class=”st0″>”USER32″</span> <span class=”kw1″>Alias</span> <span class=”st0″>”SendMessageW”</span> _ <span class=”br0″>(</span><span class=”kw2″>ByVal</span> hwnd <span class=”kw2″>As</span> IntPtr, <span class=”kw2″>ByVal</span> wMsg <span class=”kw2″>As</span> <span class=”kw4″>Integer</span>, <span class=”kw2″>ByVal</span> wParam <span class=”kw2″>As</span> <span class=”kw4″>Integer</span>, <span class=”kw2″>ByVal</span> lParam <span class=”kw2″>As</span> StringBuilder<span class=”br0″>)</span> <span class=”kw2″>As</span> <span class=”kw4″>Integer</span> strBuffer.<span class=”me1″>Append</span><span class=”br0″>(</span><span class=”kw7″>ChrW</span><span class=”br0″>(</span><span class=”nu0″>1024</span><span class=”br0″>)</span><span class=”br0″>)</span></div>
    </div>
    </div>

    it keep showing my symbols at the end of the text like his 머ࢆ洰Հ╈࢐ even after I tried what you said

  10.     Declare Auto Function SendMessage Lib "USER32" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As StringBuilder) As Integer
    
    Dim strBuffer As New StringBuilder(1024)
    strBuffer.Append(Chr(1024 And 255))
            strBuffer.Append(Chr(1024 / 256))

    return symbol

    Declare Auto Function SendMessage Lib "USER32" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As StringBuilder) As Integer
    
    Dim strBuffer As New StringBuilder(1024)
            strBuffer.Append(1024)

    return nothing

        Declare Unicode Function SendMessage Lib "USER32" Alias "SendMessageW" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As StringBuilder) As Integer
    
    
    Dim strBuffer As New StringBuilder(1024)
    strBuffer.Append(Chr(1024 And 255))
            strBuffer.Append(Chr(1024 / 256))
    

     

    return nothing

        Declare Unicode Function SendMessage Lib "USER32" Alias "SendMessageW" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As StringBuilder) As Integer
    
    Dim strBuffer As New StringBuilder(1024)
            strBuffer.Append(ChrW(1024))

     

     

    return symbol

     

     

  11. Declaring auto will default to unicode so no need to test.
    What do you get with this:

    Declare Ansi Function SendMessage Lib “USER32” Alias “SendMessageA” (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As StringBuilder) As Integer

    Dim strBuffer As New StringBuilder(1024)
    strBuffer.Append(Chr(1024 And 255))
    strBuffer.Append(Chr(1024 / 256))

  12. So shuld have the second and last code you posted. The only time you get garbage is when the biffer first word value is smaller than the line length and in unicode Append(ChrW(1024)) set the buffer first word to 1024

  13. i didn’t try this yet but right now when I type 123 in the room I get this 123꧐첼ಬ

    you are missing the null termination char, this is why you are getting weird characters, which bring me to this…

    Declare Ansi Function SendMessage Lib “USER32” Alias “SendMessageA” (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As StringBuilder) As Integer

    Dim strBuffer As New StringBuilder(1024)
    strBuffer.Append(Chr(1024 And 255))
    strBuffer.Append(Chr(1024 / 256))

    the part where you set the first char of the buffer is just stupid and so is the setting of the second char of the buffer, you need to set the buffer length the amount from  “EM_LINELENGTH” in which the first char in your buffer must be the amount of chars you are going to receive. setting the buffer to 1024 and then placing (1024 and 256) into the first char of the buffer is incorrect(equals 0 btw). all you are doing now is making a max amount of chars for the buffer which is why you are getting weird text and not terminating with a null char for the last buffer char.

    if you watch tutorial #5 I explain why and how this works…

    https://www.imfiles.com/topic/paltalk-programming-tutorial-seriesvideo/

     

    Example

    Function TForm1.GetPalText(const HwndIncommingText: Hwnd): String;
    var
      iLineCount, iLineLength, iLineIndex: Integer;
      szBuffer: array of WideChar;
    begin
     
      if isWindow(HwndIncommingText) = True then
      begin
        iLineCount := Sendmessage(HwndIncommingText, EM_GETLINECOUNT, 0, 0) - 2;
        iLineIndex := Sendmessage(HwndIncommingText, EM_LINEINDEX, iLineCount, 0);
        iLineLength := Sendmessage(HwndIncommingText, EM_LINELENGTH, iLineIndex, 0);
     
        if iLineLength = 0 then
        begin
          Result := 'Fail Line Length';
          Exit;
        end;
     
        SetLength(szBuffer, iLineLength);
        Word(szBuffer[0]) := iLineLength;
        Sendmessage(HwndIncommingText, EM_GETLINE, iLineCount, LParam(szBuffer));
        szBuffer[iLineLength] := #0;
        Result := PWidechar(szBuffer);
     
        szBuffer := Nil;
      end
      else
        Result := 'Fail Hwnd';
    end;

    in your case something similar to this should work if vb.net is zero based arrays(if not just +1)

    Dim strBuffer As New StringBuilder(iLineLength) // or maybe im strBuffer As New StringBuilder(iLineLength + 1)
    strBuffer.Append(Chr(iLineLength))

    then after you have gotten the text with EM_GETLINE you must add a null termination to the last char in your buffer.

    maybe something like strBuffer.Insert(iLineLength,Chr$(0))

  14. you are missing the null termination char, this is why you are getting weird characters, which bring me to this…

    the part where you set the first char of the buffer is just stupid and so is the setting of the second char of the buffer, you need to set the buffer length the amount from “EM_LINELENGTH” in which the first char in your buffer must be the amount of chars you are going to receive. setting the buffer to 1024 and then placing (1024 and 256) into the first char of the buffer is incorrect(equals 0 btw). all you are doing now is making a max amount of chars for the buffer which is why you are getting weird text and not terminating with a null char for the last buffer char.

    if you watch tutorial #5 I explain why and how this works…

    https://www.imfiles.com/topic/paltalk-programming-tutorial-seriesvideo/

    There is no need for no null character, StringBuilder is a .NET framework object and you can believe it was never sent to SendMessage. The framework wrap the SendMessage call to marshal the parameters. Theframework allocate an internal buffer to copy data from the StringBuffer before calling SendMessage and back to the StringBufferafter it return.
    The framework is not aware of the exact detail of the EM_GETLINE and just copy StringBuilder.length bytes before the call to the buffer, and after the call copy all charachters from it back to the StringBuilder until it finds a null charachter including garbage that is not relevant.

    To avoid this problem the first word need to be set to it’s capacity – 1.

    strBuffer.Append(Chr(1023 And 255))
    strBuffer.Append(Chr(1023 / 256))

    for SendMessageA, or

    strBuffer.Append(ChrW(1023))

    For SendMessageW

    While getting the length of the line will work most of the time, it isn’t fail proof

  15. After I looked into it a bit more it seems using Chr function is not a good idea, better use always ChrW instead

    strBuffer.Append(ChrW(1023 And 255))
    strBuffer.Append(ChrW(1023 / 256))
    
  16. I checked a bit more, and there is no elegant way to prevent the extra characters, but there is a way

    Dim iLineIndex As Integer = SendMessage(hwnd, EM_LINEINDEX, ilastLine, 0)
    Dim iLineLength As Integer = SendMessage(hwnd, EM_LINELENGTH, iLineIndex, 0)
    if iLineLength = 0 return Nothing ‘ or return “”
    Dim sb As StringBuilder = New StringBuilder(iLineLength)
    sb.Append(ChrW(iLineLength))
    sb.Length = iLineLength
    SendMessage(hwnd, EM_GETLINE, ilastLine, sb)

    sb.Length = iLineLength pads the buffer with null charachters, and setting the the first word of the buffer to the exact length ensures the end of the buffer is not being cluttered (which it is sometimes).
    It’s a bit overhead, but may be better than the overhad marshaling may have to do.
    Note: ilastLine = number of lines minus 2.
    Note 2: use unicode SendMessageW

    The declerations if you don’t have them

    Const EM_GETLINE As Integer = &HC4
    Const EM_LINEINDEX As Integer = &HBB
    Const EM_LINELENGTH As Integer = &HC1
    
    Declare Unicode Function SendMessage Lib "USER32" Alias "SendMessageW" _
    	(ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer,
    	ByVal lParam As StringBuilder) As Integer
    
    Declare Auto Function SendMessage Lib "USER32" _
    	(ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer,
    	ByVal lParam As Integer) As Integer
    
  17. chike what is the use of the two declaration???

    Declare Unicode Function SendMessage Lib "USER32" Alias "SendMessageW" _
         (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer,
         ByVal lParam As StringBuilder) As Integer
    
    Declare Auto Function SendMessage Lib "USER32" _
         (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer,
         ByVal lParam As Integer) As Integer
    

     

    will I use both or just one of them?

  18. You need both, one for EM_GETLINE and the other for EM_LINEINDEX and EM_LINELENGTH.

    Maybe you could use just the first one and and send Nothing as StringBuilder, but this works and maybe you will need a call that require integer lParam.

    EDIT: I’ve checked and you can use the first one only if you change the last parameter of the two other calls to Nothing.

Leave a Reply

You must Register or Login to comment on problem with SendMessageA