[VB .NET] Read Line from Paltalk 10

Since Paltalk 10 switched to the RichEdit20W control for room chat, a lot of people have struggled to retrieve incoming chat text. Here is a function I put together to return text from a given line:

Code Removed
See post below for new code.

Note:
I don’t know why, but just like before, the line index is still index – 2.
So to read the 5th line, the index would be (5 – 2).

19 thoughts on “[VB .NET] Read Line from Paltalk 10

  1. @Chike wrote:

    Now for the other question I had, is the returned array is really unicode or is it just ascii, you can see this quite clear with the debugger before converting.

    I am saying it is unicode as every other byte (alternating) in the array is = 0 and the “System.Text.Encoding.Unicode.GetString” does return the string.

    -		baText	{Length=1001}	Byte()
    (0) 65 Byte
    (1) 0 Byte
    (2) 108 Byte
    (3) 0 Byte
    (4) 101 Byte
    (5) 0 Byte
    (6) 114 Byte
    (7) 0 Byte
    (8) 116 Byte
    (9) 0 Byte
    ...
  2. @Chike wrote:

    And SendMessage is SendMessageA or SendMessageW?

    it is set to auto

    Declare Auto Function SendMessage Lib "USER32" (ByVal hwnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Byte()) As Integer
  3. Little endian means last significant byte first, that’s why the first byte is the lower part of the WORD, and the word is the lower part of DWORD etc.
    Big endian most significant byte first, and would be just the oposite.

    if iRetval was greater than the buffer it means memory outside the buffer was overriden.
    There is also no need to add a null termination byte to the buffer, EM_GETLINE won’t fill the NULL charachter i there is no space for it, and if you do want it than add 2(unicode char size)

    Now for the other question I had, is the returned array is really unicode or is it just ascii, you can see this quite clear with the debugger before converting.

  4. The result of EM_GETLINE is the number of TCHARs copied, no need for any checking,, it will never be greater than erquested.

    The word is the required TCHARs not the size of the buffer in bytes so no need to limit it to 32767, and it’s valu should be just MaxBuffer.

  5. After doing some investigation, my BitConverter.GetBytes was returning a 4 byte array = {1, 16, 0, 0}
    The integer passed to BitConverter.GetBytes was 4097.
    I am not sure why the BitConverter.GetBytes is returning a 4 bite array, but {1, 16} is correct for LittleEndian, so (if I understand it correctly) i need to reverse it to pass WORD {16, 1}. Therefore, I have removed the loop and changed it to:

    CODE REMOVED
    Updated code in post below

    Note:
    I have tested with many MaxBuffer values and passing the reversed first 2 bytes are always correct for the (MaxBuffer * 2) + 1 value as long as the value is less then 65535. Any time it gets a value greater then 65535, it will then cause problems, so I set a cap of 32767.

    I also added an If statement to handle a case if the MaxBuffer value was too low (smaller then line length).

  6. Yes, longest possible text is 65535 charachters.
    Use bSize whatever that is, basically you fill the array with zeros when using default.
    Send the function max buffer smaller than actual line length(10, 100) and see what you get.
    It is not about perfection it’s about writing code without bugs.
    I am not familiar with pointer casting in .NET, little endian should be good enough for paltalk.

  7. @Chike wrote:

    baText(0) = iCount
    baText(1) = iCount / 256
    This would be good for CPUs that use little endian byte order.

    First, baText(0) would fail to get set and throw an exception any time iCount is larger then 255, and second, I would rather see a method that is CPU independent.

    My function above may not be perfect, but has worked without fail in all of my testing situations so far.

  8. i could probably make the default much lower for the MaxBuffer, but I just set it ridiculously high to make sure it always picked up the whole line.

  9. It returns a 4 byte result because it is sent a 32bit value.
    You don’t need to reverse anything, and it’s still not going to be good for big endian machines which would need baText(0) = bSize(2) and baText(1) = bSize(3)
    Unlike the x86 which converting from word to byte or double word is trivial, big endian machines need special instructions to do so.
    I wouldn’t worry about endianness. Apart from mobile which this code wont work on anyway i am not aware of any other machines that run paltalk other then x86 or x64.

  10. @Chike wrote:

    EM_GETLINE needs the available length as a WORD(2 bytes) at the beginning and that definately not what there with the loop.

    So are you saying that the longest line EM_GETLINE can return is a length as WORD = FFFF?
    I have not tested with anything to see if and what the max is, but until I get problems with my function posted above, it is what I will be using.

  11. EM_GETLINE needs the available length as a WORD(2 bytes) at the beginning and that definately not what there with the loop.
    baText(0) = iCount
    baText(1) = iCount / 256
    This would be good for CPUs that use little endian byte order.

    It shouldn’t matter if the text is ANSI or Unicode as the SendMessageA/SendMessageW should convert. How do you see the array in debugger as byte or unicode charachters?

  12. Auto” keyword is set to let the target platform determines the suitable character width (ANSI or Unicode).

    So it depends on the project settings, and probably is SendMessageW for your project.

  13. After the room text get to about 250k pal start cutting line from the top. Since your application is outside paltalk you may have the text cut between 2 different calls.
    If the text cuts after you made the get number of lines call the line number is not valid anymore.
    It depends on how busy is the room.

  14. I’d like to thank you for posting this method of reading a line!!! I was using SendMessageA reading into a string type and occasionally em_getline wouldn’t read a line (iretval would return 0) and the errors got worse over time (like hours) so I had to restart the application a couple of times a day. This error was very frustrating as it wasn’t consistent. I don’t know how the Unicode got converted as I didn’t do anything else to the string.
    Using your SendMessage (W?) and reading into a byte array and converting the unicode seems to have fixed my reading problems. 🙂
    The reading issue has been nagging at me for many months.

  15. Thank you Chike for the clarifications. I still dont know why the first byte of the WORD value is the lower half of the WORD, but after removing the byte reversal, my iRetval is never more then my buffer.

    So here is the code after making the changes that Chike pointed out:

    Private Function ReadLine(ByVal hwnd As IntPtr, ByVal iLine As Integer, Optional ByVal MaxBuffer As Integer = 500) As String
    Dim iRetval As Integer
    Dim sAnswer As String = Nothing
    Dim baText() As Byte
    ' Cap MaxBuffer so it can never be too large
    If MaxBuffer > 65535 Then MaxBuffer = 65535
    ' Set byte array to max buffer size (times 2 for Wide) + 1
    ReDim baText((MaxBuffer * 2) + 1)
    ' Get bytes for max buffer size
    Dim bSize() As Byte
    bSize = BitConverter.GetBytes(MaxBuffer)
    ' Write max buffer size as WORD to begining of baText array
    baText(0) = bSize(0)
    baText(1) = bSize(1)
    ' Get Line data (iRetval = number of characters in line)
    iRetval = SendMessage(hwnd, EM_GETLINE, iLine, baText)
    ' Convert byte buffer to string trimmed to retval size
    sAnswer = System.Text.Encoding.Unicode.GetString(baText).Substring(0, iRetval)
    ' Return the retrieved string
    Return sAnswer
    End Function

    I still cap the buffer, but at the full 65535 size that EM_GETLINE can retrieve.

    Also due to the Pal limit on text, i lowered the default MaxBuffer size to 500

Leave a Reply

You must Register or Login to comment on [VB .NET] Read Line from Paltalk 10