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).
@Chike wrote:
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.
And SendMessage is SendMessageA or SendMessageW?
@Chike wrote:
it is set to auto
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.
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.
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:
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).
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.
@Chike wrote:
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.
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.
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.
@Chike wrote:
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.
Well done, Autopilot.
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?
So it depends on the project settings, and probably is SendMessageW for your project.
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.
iRetval = SendMessage(hwnd, EM_GETLINE, iLine, baText)
Shouldn’t you check the value of IRetval to make sure it isn’t zero?
If it’s zero it will result in empty string.
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.
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:
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