Reputation: 97
Here is my dilemma. I have a program that uses SendMessage
to get text from a chat program. Now when I did this in Visual Basic I just put the SendMessage
in a loop and whenever the chat was updated so would my output.
This is not the case with C++
. When I put the SendMessage
in a loop it loops forever. Say the Chat is something like:
Apples
Bananas
Cheerios
Now lets say I run my program it finds the text and starts looping. Now in Visual Basic it would keep looping until it hit Cheerios
and it would stop and wait until someone in the chat typed something else.
With C++
it would output:
Apples
Bananas
Cheerios
Apples
Bananas
Cheerios
...
And go on forever. Is there a way to stop this? I was thinking along the terms of EOF
but that wouldn't help because as soon as it hit the last line it would go out of the loop and wouldn't pick up anything else that people typed in chat.
Here is the portion of the code that gets the text. Now not that I do have an loop that won't end until I set bLoop
to True
.
cout << " + found RichEdit20W window at: " << hwndRichEdit20W << endl << endl;
cout << "- get text " << endl;
bool bLoop = false;
int textLen = (int)SendMessage(hwndRichEdit20W, WM_GETTEXTLENGTH, 0, 0);
while (bLoop == false)
{
const int MAXSIZE = 32678;
wchar_t szBuf[MAXSIZE];
SendMessage(hwndRichEdit20W, WM_GETTEXT, (WPARAM)textLen, (LPARAM)szBuf);
wcout << szBuf;
}
Thanks for any help!
VB CODE UPDATE
This is how I did it in my VB program. This is for a game console and not a chat window but it should be the same concept right?
Note Do While PARENThwnd <> IntPtr.Zero
The handle is never 0 so it will be an infinite loop.
Private Sub bwConsole_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bwConsole.DoWork
Dim PARENThwnd As IntPtr
Dim CHILDhwnd As IntPtr
PARENThwnd = FindWindow(Nothing, "ET Console")
If PARENThwnd = IntPtr.Zero Then
txtConsole.Text = "ET Console is not availble."
Else
Do While PARENThwnd <> IntPtr.Zero
CHILDhwnd = GetDlgItem(PARENThwnd, 100)
Dim Handle As IntPtr = Marshal.AllocHGlobal(32767)
Dim NumText As Integer = CInt(SendMessage(CType(CHILDhwnd, IntPtr), WM_GETTEXT, CType(32767 \ Marshal.SystemDefaultCharSize, IntPtr), Handle))
Dim Text As String = Marshal.PtrToStringAuto(Handle)
txtConsole.Text = Text
Marshal.FreeHGlobal(Handle)
txtConsole.SelectionStart = txtConsole.TextLength
txtConsole.ScrollToCaret()
rtxtDefinition.Text = ""
Call GetDefinitions(txtConsole.Text)
Loop
End If
End Sub
Also will not be able to answer any questions until later tonight. Off to work.
Upvotes: 1
Views: 657
Reputation: 1642
In both VBA and C++ that structure will cause an infinite loop.
It sounds like you want an infinite loop, but don't want an infinite print out of the contents of the buffer.
As @IInspectable has pointed out (thanks!) sendmessage will copy the contents of the chat program into the buffer at every iteration of the loop.
So, either purge the chat window or let the program know what content is new and needs to be printed.
I'm on a linux box at the moment, so can't test this very easily. Please let me know if the following works...
#include <cwchar> // so we can use wcschr function
const int MAXSIZE = 32678; // moved outside of the loop
wchar_t szBuf[MAXSIZE]; // moved outside of the loop
szBuf[0] = L'\0'; // set sentinel (wide NULL!)
wchar_t* end_printed_message = szBuf;
//pointer to the end of the content that has been printed
while (bLoop == false)
{
SendMessage(hwndRichEdit20W, WM_GETTEXT, (WPARAM)textLen, (LPARAM)szBuf);
wchar_t* end_message_buffer = wcschr(szBuf, L'\0'); // find end of the string using wchar version of strchr()
if(end_printed_message != end_message_buffer){ // if the buffer contains something new
wcout << end_printed_message; // print out the new stuff (start at old end)
end_printed_message = end_message_buffer; // update the pointer to the end of the content
}
}
I don't know what headers you've already included, hence the use of 'ol faithful <cstring>
As an aside (yes, I will still bang on about this) mixed use of (w)cout is generally bad and may cause problems.
Upvotes: 0
Reputation: 20063
The first thing you need to understand is that the two versions of the code are doing very different things with the contents of the chat window. The VisualBasic version is taking that text and stuffing it into a text control. This has the effect of replacing the existing text with the new text from the chat window so you never see duplicates. The C++ version outputs the text to the output stream (console) each time it retrieves it. Unlike the text control used in the VB version the output stream appends the text rather than replaces it.
To get around this you need to keep tract of the previous text retrieved from the chat window and only output the difference. This may mean appending new text from the chat or outputting the entire string. The code below maintains a string buffer and manages appending or replacing the history of the chat. It also creates a new string containing only the differences from the last change allowing you to easily deal with updates.
class ChatHistory
{
std::wstring history;
public:
std::wstring update(const std::wstring& newText)
{
const std::wstring::size_type historySize = history.size();
if(newText.compare(0, historySize, history.c_str()) == 0)
{
history.append(newText.c_str() + historySize, newText.size() - historySize);
return history.c_str() + historySize;
}
else
{
history = newText;
}
return newText;
}
};
Below are the necessary changes to your code to use it. I haven't had a chance to test it with your exact set up but it should work.
ChatHistory history;
while (bLoop == false)
{
const int MAXSIZE = 32678;
wchar_t szBuf[MAXSIZE];
SendMessage(hwndRichEdit20W, WM_GETTEXT, (WPARAM)textLen, (LPARAM)szBuf);
std::wcout << history.update(szBuf);
}
Upvotes: 1
Reputation: 51413
You never update your bLoop
variable, causing the loop to run infinitely. If you want to break your loop, implement a loop termination condition that changes the value of bLoop
.
A condensed version of your code does the following:
bool bLoop = false;
while ( bLoop == false ) {
// This loop never terminates, unless bLoop is set to true
}
It is somewhat hard to understand, why you are looping to begin with. I suppose you hope the SendMessage
call would somehow guess that you don't want it to run, until some condition is met. There is no such magic built into functions.
To respond to text changes you should choose a different solution altogether: An event-based model. The supported way to implement this is through UI Automation.
Upvotes: 1