2014-01-05 168 views
1

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

这不是C++的情况。当我把SendMessage放在一个循环中时,它会永远循环。说,聊天是一样的东西:

苹果
香蕉
麦片

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

随着C++它会输出:

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

而且永远持续下去。有没有办法阻止它?我一直在考虑EOF的条款,但这并没有什么帮助,因为只要它到达最后一行,它就会退出循环,并且不会接收任何人在聊天中输入的内容。

以下是获取文本的部分代码。现在不是我有一个循环不会结束,直到我设置bLoopTrue

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 

也不能回答任何问题,直到今晚晚些时候。去上班。

+0

请显示有效的VB代码。 –

+0

你的VB代码显然必须有一些循环终止条件,它是什么? – paulm

+0

增加了VB代码。这与我从C++代码中获得的部分是一样的;只是循环。除了关闭程序时,并没有终止。 – Unreliaable

回答

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

我不知道你已经包含的内容标题,因此使用的“老忠实间歇泉<cstring>

顺便说一句(是的,我仍然会对此产生影响)(w)cout的混合使用是generally bad,可能会导致问题。

+0

如果我只使用'cout'而不是'wcout',那么我得到一串随机数,因为它是'UNICODE',它们是宽字符 – Unreliaable

+0

作为@IInspectable指出,UI自动化可能是正确的路要走。但是......如果你想要一个'肮脏'的解决方案(并且在一个无限循环内部运行可能会属于该类别),那么你可以使用你的方法,但是改变在循环的每次迭代中打印出来的东西...... – GnomeDePlume

+0

呃... ...这应该怎么做?你只是写你的内容给cout。将缓冲区的第一个字符设置为'NUL'不会执行任何操作。另外,'WM_GETTEXT'将会覆盖缓冲区... – IInspectable

1

您从不更新您的bLoop变量,导致循环无限运行。如果你想打破你的循环,实现一个循环终止条件,改变bLoop的值。

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

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

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

要响应文本更改,您应该完全选择不同的解决方案:基于事件的模型。支持的方式是通过UI Automation

+0

从“现在不是我有一个循环,直到我设置bLoop为真,才会结束。”好像OP知道他的环路状况...... – GnomeDePlume

+1

@Gnome这可能是也可能不是这种情况。问题*“有没有办法阻止这个[循环]?”*由“实现循环终止条件”*来回答。我还提供了一个解决方案,如何正确实现这一点。 – IInspectable

+0

@IInspectable我知道循环没有结束。我用它编程,因为那是我在VB程序中做的。它会不断更新,以便在输入任何内容时自动更新。我只是想知道是否有一种方法用'SendMessage'来知道一条线是否被添加到了我所迷恋的聊天窗口中。如果是的话,我该如何添加1行,而不是再次加载整个事情。 – Unreliaable

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

+1不错!我无法与此争辩:D @ Unreliaable如果没有解决/你感觉复古,那么给我的版本一个镜头。 – GnomeDePlume

+0

@Captain Obvlious它的作品非常好。它削减了最后一项工作的最后一个角色,但我会努力解决这个问题。也出于某种原因,它不想在输入新文本时进行更新,但我也会对其进行处理。感谢代码! – Unreliaable