2014-01-05 384 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