سؤال

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.

هل كانت مفيدة؟

المحلول 3

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.

نصائح أخرى

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.

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);
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top