Follows 2 functions in C++ that attempt to accomplish this goal, and the way to use them.
- Code: Select all
// last_char_index
// parameters:
// in: richedit control HWND
// returns: index of last (empty) line
int last_char_index(HWND rich20)
{
int index, lines;
do {
if (!IsWindow(rich20)) {
// invalid window handle
return -1;
}
lines = (int) ::SendMessage(rich20, EM_GETLINECOUNT, 0, 0);
index = (int) ::SendMessage(rich20, EM_LINEINDEX, lines - 1, 0);
// loop till no change was changed between the 2 calls
} while (index == -1 || lines != (int) ::SendMessage(rich20, EM_GETLINECOUNT, 0, 0));
return index;
}
// get_next_line
// parameters:
// in: richedit control HWND
// in/out: bext index to get line from
// out: buffer for line text out
// in: buffer size
// returns: true if lines added and text retrived, false otherwise
bool get_next_line(HWND rich20, int& last_index, char *text_buff, int text_buf_size)
{
// last line char index
int index = last_char_index(rich20);
// check if text was cleared or haven't changed
if (index <= last_index) {
if (index < last_index) {
// text was cleared
last_index = index;
}
return false;
}
int line, next_index;
do {
// last index point to the bext line we need read
line = (int) ::SendMessage(rich20, EM_EXLINEFROMCHAR, 0, last_index);
// set the dirst word of the buffer to it's size - 1
// to reserve one byte for null char
*((WORD*) text_buff) = text_buf_size - 1;
int len = (int) ::SendMessage(rich20, EM_GETLINE, line, LPARAM(text_buff));
// the buffer returned is not null terminated unless there's no text
// sset the null terminator anyway
if (len > 0) {
text_buff[len] = '\0';
} else {
text_buff[0] = '\0';
}
// get character index for the begining of next line
next_index = (int) ::SendMessage(rich20, EM_LINEINDEX, line + 1, 0);
// check if text was cleared
// without this we may loop forever
if (last_char_index(rich20) < index) {
// part of the room text was cleared
// you may add code here to set last_index to point few lines back
return false;
}
// keep looping if last_index's line changed
} while (line != (int) ::SendMessage(rich20, EM_EXLINEFROMCHAR, 0, last_index));
last_index = next_index;
return true;
}
You start by calling last_char_index() when you 1st connect to the room saving the result for further use.
- Code: Select all
int my_last_index;
....
my_last_index = last_char_index(rich20);
Later on in the timer_tick function (or whenever you process room text) call get_next_line() in a loop untill tgere are no more lines left.
Note that my_last_index is passed by reference and updated with every successful call, or when the text is cleared.
- Code: Select all
char line_text[1024];
while (get_next_line(rich20, my_last_index, line_text, sizeof(line_text))) {
// process the line here
}
It appears that when the room text grow to near 250k characters, lines are deleted from the beggining of the room text. I cannot see any way around it other to clear the room text completely at that point. Something that will look like this (afrer the loop in the code above):
- Code: Select all
if (my_last_index > 240000) {
::SendMessage(rich20, WM_SETTEXT, 0, LPARAM(""));
}
I have only tested it briefly with version 9.2 build 236, but it seems to work well even if the text is manually freezed and scrolls fast when resumed.
Duplicates are possible, but only when resizing the room, and I havn't observed any.
I will add that with subclassing most of the cheks done in this code are not needed.





