C ++ SendMessage循环停止和行尾

时间:2014-01-05 15:44:17

标签: c++ winapi loops while-loop sendmessage

这是我的困境。我有一个使用SendMessage从聊天程序中获取文本的程序。现在,当我在Visual Basic中执行此操作时,我只是将SendMessage放在一个循环中,每当聊天更新时,我的输出也会如此。

C++不是这种情况。当我将SendMessage置于一个循环中时,它会永远循环。说聊天就像:

苹果
香蕉
麦片

现在让我说我运行我的程序它找到文本并开始循环。现在在Visual Basic中,它会一直循环直到它达到Cheerios并且它会停止并等到聊天中的某个人输入其他内容。

使用C++输出:

苹果
香蕉
麦片
苹果
香蕉
麦片
...

永远继续下去。有办法阻止这个吗?我正在考虑EOF的条款,但这无济于事,因为一旦它到达最后一行,它就会退出循环,并且不会接收人们在聊天中输入的任何其他内容。

以下是获取文本的代码部分。现在不是说我确实有一个循环,直到我将bLoop设置为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;

}

感谢您的帮助!

VB代码更新

这就是我在VB程序中的表现。这是一个游戏控制台而不是聊天窗口,但它应该是相同的概念吗?

注意Do While PARENThwnd <> IntPtr.Zero句柄永远不会为0,因此它将是一个无限循环。

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

直到今晚才能回答任何问题。下班。

3 个答案:

答案 0 :(得分:1)

您永远不会更新bLoop变量,导致循环无限运行。如果要中断循环,请实现更改bLoop的值的循环终止条件。

您的代码的精简版本执行以下操作:

bool bLoop = false;
while ( bLoop == false ) {
    // This loop never terminates, unless bLoop is set to true
}

有点难以理解,为什么要循环开始。我想你希望SendMessage调用会以某种方式猜测你不希望它运行,直到满足某些条件。功能中没有这样的魔力。

要响应文本更改,您应该完全选择其他解决方案:基于事件的模型。支持的实现方法是UI Automation

答案 1 :(得分:1)

您需要了解的第一件事是代码的两个版本与聊天窗口的内容做了非常不同的事情。 VisualBasic版本正在将该文本填充到文本控件中。这具有使用聊天窗口中的新文本替换现有文本的效果,因此您永远不会看到重复项。每次检索文本时,C ++版本都会将文本输出到输出流(控制台)。与VB版本中使用的文本控件不同,输出流会附加文本而不是替换它。

要解决此问题,您需要保留从聊天窗口中检索到的先前文本,并仅输出差异。这可能意味着从聊天中添加新文本或输出整个字符串。下面的代码维护一个字符串缓冲区,并管理追加或替换聊天的历史记录。它还会创建一个新字符串,其中仅包含与上次更改的差异,以便您轻松处理更新。

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;
    }
};

以下是对您的代码进行必要的更改以使用它。我没有机会用你的确切设置来测试它,但它应该可以工作。

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);
}

答案 2 :(得分:0)

在VBA C ++中,该结构将导致无限循环。

听起来你想要一个无限循环,但想要从缓冲区的内容中无限打印。

正如@IInspectable指出的那样(谢谢!)sendmessage会在循环的每次迭代中将聊天程序的内容复制到缓冲区中。

因此,要么清除聊天窗口,要让程序知道哪些内容是新的,需要打印。

我目前正在使用linux盒子,因此无法轻松测试。如果以下工作,请告诉我......

#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
    }
}

我不知道你已经包含哪些标题,因此使用'ol忠诚<cstring>

顺便说一句(是的,我仍然会对此有所了解)混合使用(w)cout是generally bad并且可能会导致问题。