- This topic has 6 replies, 3 voices, and was last updated 14 years ago by chicagodavid52.
-
AuthorPosts
-
January 19, 2008 at 12:15 am #191158ChikeMember
Follows 2 functions in C++ that attempt to accomplish this goal, and the way to use them.
// 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] = '�'; } else { text_buff[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.
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.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):
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.
January 5, 2010 at 5:12 am #191164chicagodavid52MemberI’m glad I checked this forum and I need to do this exact same thing in vb so this will save me a lot of time. I’m worried about text loss when paltalk clears some text as the room text gets too large. What you have seems to allow for missing lines at that point. The alternative is for you to delete all the lines as you say but that means you have to make sure that no text gets into the room after you check it and before you delete all text. Have you had any experience with it in those cases and are any lines lost?
January 5, 2010 at 8:53 am #191163ChikeMember@usenet7 wrote:
Have you had any experience with it in those cases and are any lines lost?
I don’t use this method, nor VB. My dll subclasses the room text control and send the text to the application as it is inserted, track deleted lines, and never miss a line.
Of course I was aware of races therefore the minimize and not eliminate.January 6, 2010 at 2:48 am #191162StringMember@Chike wrote:
My dll subclasses the room text control and send the text to the application
Is this dll available for download and can it be used within a vb program?
January 6, 2010 at 6:59 am #191161ChikeMember@String wrote:
@Chike wrote:
My dll subclasses the room text control and send the text to the application
Is this dll available for download and can it be used within a vb program?
Attached the latest DLL I use.
It should be possible to be used in VB though it’s not trivial nor clean.
Only one window can be monitored, by one application only.
The application “connects” to a room window (haven’t tested IMs) and recives events that are sent over a pipe to a native thread that calls the callbacks supplied by the application.
I don’t use the handle_text callback but last time I tested it it workd fine.January 7, 2010 at 8:25 am #191160StringMemberThanks a lot Chike……
January 7, 2010 at 10:43 am #191159ChikeMember@String wrote:
Thanks a lot Chike……
Don’t thank me yet, it’s not just going to work.
Since the callbacks are called from a native thread, delegates are needed.
Type decleration:delegate void disconnect_delegate(void); delegate void text_delegate(const char *text); delegate void user_delegate(const char *name, int state);
The following example will only show the steps nesessary for the text callback.
You can have one delegate and use InvokeRequired or have 2, one that is called from the thread and the other invoked ny the 1st. I use the second method.Variables decleration:
text_delegate^ textHandler; text_delegate^ textCallback; GCHandle gchTextCallback;
Initialize delegates:
textHandler = gcnew text_delegate(this, &Form1::HandleText); textCallback = gcnew text_delegate(this, &Form1::TextCallback); gchTextCallback = GCHandle::Alloc(textCallback); // prevent garbage collection from moving in memory
Initialize library once, subsequent calls with NULL as parameter:
pal_lib_callbacks callbacks = {NULL, NULL, NULL}; callbacks.handle_text = (void (__stdcall *)(const char *)) Marshal::GetFunctionPointerForDelegate(textCallback).ToPointer(); PallibAppInit(&callbacks);
Note: only the callbacks that were set at first call will be called.
Attache the library with paltalk instance:if (PalllibConnectPal(hwnd) == 0) { // success }
Detache the library:
PallibAppDeinit(); PallibAppInit(NULL); // re-initialize, dirty I know
Connect to chat room, one room only:
char *str = static_cast( Marshal::StringToHGlobalAnsi(roomName).ToPointer()); PalllibConnectRoom(str); Marshal::FreeHGlobal(IntPtr(str));
Disconnect room:
PalllibDisconnectRoom(hwndPalRoom);
Note: having the room handle to the room that was connected is up to you.
Disconnect callback will be called if paltalk have been closed, call:
PallibAppDeinit(); PallibAppInit(NULL);
-
AuthorPosts
Related
- You must be logged in to reply to this topic.