Skip to content

[VB .NET] Read Line from Paltalk 10

Viewing 15 posts - 1 through 15 (of 20 total)
  • Author
    Posts
  • #187047
    autopilot
    Member

    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).

    #187066
    String
    Member

    Well done, Autopilot.

    #187065
    autopilot
    Member

    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.

    #187064
    Chike
    Member

    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?

    #187063
    autopilot
    Member

    @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.

    #187062
    autopilot
    Member

    @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.

    #187061
    Chike
    Member

    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.

    #187060
    autopilot
    Member

    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).

    #187059
    Chike
    Member

    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.

    #187058
    Chike
    Member

    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.

    #187057
    autopilot
    Member

    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

    #187056
    Chike
    Member

    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.

    #187055
    autopilot
    Member

    @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
    ...
    #187054
    Chike
    Member

    And SendMessage is SendMessageA or SendMessageW?

    #187053
    autopilot
    Member

    @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
Viewing 15 posts - 1 through 15 (of 20 total)
  • You must be logged in to reply to this topic.