WM_SETTEXT langsam - Teil-Senden möglich?



  • Hallo,

    ich hab eine Frage beüglich WM_SETTEXT. Und zwar benutze ich das um Text in das Edit-Control einer anderen Anwendung zu schicken was auch funktioniert.

    Allerdings ist dies ziemlich langsam, je länger der zu versendende Text wird. Ich hab jetzt eine Anwendung in der ich synchron zwei Eidit-Controls verbinden möchte: Einmal das Edit-Control meiner Anwendung und dann das einer Fremd-Anwendung.

    Wenn ich jetzt in mein Edit-Control schreibe soll das direkt in das andere Edit-Control geschickt werden. Problem ist jetzt halt wenn ich nur einen Buchstaben hinzufüge wird per WM_SETTEXT trotzdem der gesamte Inhalt versendet, was bei einem sehr langem Text nicht mehr wirklich skaliert.

    Daher meine Frage: Gibt es performantere Mittel/Wege als WM_SETTEXT für sowas? Oder kann es daran liegen dass die Anwendungen in verschiedenen Prozessen laufen?

    Denn ein normales Edit-Control macht das ja vermutlich auch mit WM_SETTEXT und ist dabei überhaupt nicht langsam...

    Viele Grüße,
    hs



  • EM_SETSEL + EM_REPLACESEL



  • s.a. Wie Text programmgesteuert an ein Edit-Steuerelement angefügt (auch wenn die Übersetzung zum Totlachen ist 😉



  • happystudent schrieb:

    Denn ein normales Edit-Control macht das ja vermutlich auch mit WM_SETTEXT und ist dabei überhaupt nicht langsam...

    Ein normales Edit-Control bearbeitet seinen eigenen Text natürlich nicht mit WM_SETTEXT . Das "besitzt" den Text ja selbst, hat also keine Not diesen über irgendwelche Window-Messages zu bearbeiten.
    Und falls es das doch tun sollte, dann wird es vermutlich EM_REPLACESEL o.Ä. verwenden, nicht WM_SETTEXT .



  • Hallo,

    danke schonmal für die Antworten. Komischerweise ist trotz EM_SETSEL + EM_REPLACESEL kein wirklicher Performance-Gewinn zu erkennen... Kann es sein dass EM_REPLACESEL trotudem über den gesamten Text des Edit-Controls iteriert?

    hustbaer schrieb:

    Ein normales Edit-Control bearbeitet seinen eigenen Text natürlich nicht mit WM_SETTEXT . Das "besitzt" den Text ja selbst, hat also keine Not diesen über irgendwelche Window-Messages zu bearbeiten.
    Und falls es das doch tun sollte, dann wird es vermutlich EM_REPLACESEL o.Ä. verwenden, nicht WM_SETTEXT .

    Hm, aber irgendwie muss es ja auch den string welchen es besitzt "physikalisch" in die Textbox bringen... und alle Funktionen die sowas tun die ich gefunden hab wie SetWindowText oder SetDlgItemText sind letztendlich nur Wrapper für WM_SETTEXT.

    Was könnte EM_REPLACESEL so ausbremsen? Auf jeden Fall scheint es nicht mit der Länge des Textes zu skalieren, was mich ziemlich irritiert...



  • happystudent schrieb:

    Hm, aber irgendwie muss es ja auch den string welchen es besitzt "physikalisch" in die Textbox bringen... und alle Funktionen die sowas tun die ich gefunden hab wie SetWindowText oder SetDlgItemText sind letztendlich nur Wrapper für WM_SETTEXT.

    Text bringt man "physikalisch" mit einer der Text-Zeichen-Funktionen auf den Bildschirm. TextOut, DrawText etc.
    Dazu behandelt man in seiner Window-Procedure WM_PAINT, und malt in Reaktion auf WM_PAINT dann eben den Text.

    happystudent schrieb:

    Was könnte EM_REPLACESEL so ausbremsen? Auf jeden Fall scheint es nicht mit der Länge des Textes zu skalieren, was mich ziemlich irritiert...

    Kannst du das zu nem minimalen Beispiel zusammenkürzen?

    Ansonsten: dass die Windows Edit Controls langsam sind, ist bekannt. Merkt man auch schön wenn man ein 100 MB File in Notepad aufmacht.
    Als Ersatz gäbe es z.B. Scintilla. Das ist sehr sehr flott. Hab aber keine Ahnung wie einfach bzw. fummelig das einzubinden ist.



  • hustbaer schrieb:

    Text bringt man "physikalisch" mit einer der Text-Zeichen-Funktionen auf den Bildschirm. TextOut, DrawText etc.
    Dazu behandelt man in seiner Window-Procedure WM_PAINT, und malt in Reaktion auf WM_PAINT dann eben den Text.

    Achso ok, das war mir nicht klar. Dachte das erledigt WM_SETTEXT intern gleich mit^^

    hustbaer schrieb:

    Kannst du das zu nem minimalen Beispiel zusammenkürzen?

    Ja, werd mich mal dran setzen. Danke auf jeden Fall schonmal 👍



  • Hallo nochmal,

    hustbaer schrieb:

    Kannst du das zu nem minimalen Beispiel zusammenkürzen?

    das hab ich jetzt mal gemacht. Anbei der Code.

    Zur Erklärung: Das Programm sucht nach dem Fenster "test.txt - Editor", also einer Textdatei test.txt die in Notepad geöffnet ist und erstellt ein Edit-Control das mit dessen Edit-Controls "verknüpft" ist.

    Wenn man in die eigene Textbox Text eingibt wird dieser in Echtzeit in das Notepad Fenster übertragen. Dieser Übertragungsprozess allerdings frisst bei sehr langen Texten sehr viel Performance.

    Die Anwendung hat zwei verschiedene Funktionen um den Text zu versenden, einmal onTextChanged, welches WM_SETTEXT verwendet und einmal onTextChanged2 welches EM_REPLACESEL verwendet. Defaultmäßig wird erstere verwendet.

    Der Einfachheit halber versendet onTextChanged2 immer nur ein einziges Zeichen, welches vorne an den Text des Notepad Edit-Controls angehängt wird.

    Leider sind sowohl WM_SETTEXT als auch EM_REPLACESEL ziemlich lahm. Wenn ich bei gleicher Textmenge direkt in Notepad schreibe, gibt es allerdings überhaupt keine Performance Probleme.

    Wie kann ich hier noch eine bessere Performance erreichen?

    // Required includes
    #include <iostream>
    #include <string>
    #include <sstream>
    #include <Windows.h>
    
    // Global variables for our window handles
    HWND editor = NULL;
    HWND editorEditControl = NULL;
    HWND myWindow = NULL;
    HWND myEditControl = NULL;
    
    // Function to retrieve the text of an edit control
    int GetWindowString(HWND hwnd, std::wstring &s) {
    
    	int textLength = GetWindowTextLength(hwnd);
    	wchar_t *buffer = new wchar_t[textLength + 1];
    	GetWindowText(hwnd, buffer, textLength + 1);
    	s = buffer;
    	return textLength;
    }
    
    // Our onTextChanged event with WM_SETTEXT
    void onTextChanged()
    {
    	std::wstring text;
    
    	// Get the text-length of our edit control
    	int textLength = GetWindowTextLength(myEditControl);
    
    	// Get the text of our edit control
    	GetWindowString(myEditControl, text);
    
    	// Send this text to the notepad edit control
    	SendMessage(editorEditControl, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(text.c_str()));
    }
    
    // Our onTextChanged event with EM_REPLACESEL (simplified, just sends an "a")
    void onTextChanged2()
    {
    	SendMessage(editorEditControl, EM_SETSEL, 0, 0);
    
    	// Replace the selection with the entered string
    	SendMessage(editorEditControl, EM_REPLACESEL, false, (LPARAM)"a");
    }
    
    // WindowProc of our custom window
    long __stdcall WindowProcedure(HWND window, unsigned int msg, WPARAM wp, LPARAM lp)
    {
    	switch (msg) {
    		case WM_COMMAND:
    			if (HIWORD(wp) == EN_CHANGE)
    				onTextChanged(); // Fire an onTextChanged event here
    			break;
    		case WM_DESTROY:
    			PostQuitMessage(0);
    			return 0L;	
    	}
    	return DefWindowProc(window, msg, wp, lp);
    }
    
    // EnumChildWindows callback function
    BOOL CALLBACK EnumChilds(HWND hwnd, LPARAM lParam)
    {
    	wchar_t buffer[256];
    	GetClassName(hwnd, buffer, MAX_PATH);
    	std::wstring className(buffer);
    
    	if (className == L"Edit")
    		editorEditControl = hwnd;
    	return true;
    }
    
    // Main function
    int _tmain(int argc, _TCHAR* argv[])
    {
    	// Find the main window of the editor of the file test.txt
    	editor = FindWindow(NULL, L"test.txt - Editor");
    
    	// Get the handle to its edit control
    	EnumChildWindows(editor, EnumChilds, 0);
    
    	// Create a new window class
    	const wchar_t* const myclass = L"myclass";
    	WNDCLASSEX wndclass = { sizeof(WNDCLASSEX), CS_DBLCLKS, WindowProcedure, 0, 0, GetModuleHandle(0), LoadIcon(0, IDI_APPLICATION), LoadCursor(0, IDC_ARROW), HBRUSH(COLOR_WINDOW + 1), 0, myclass, LoadIcon(0, IDI_APPLICATION) };
    
    	// Register that window class
    	if (RegisterClassEx(&wndclass)) {
    
    		// Create our window and its edit control
    		myWindow = CreateWindowEx(0, myclass, L"title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 600, 400, 0, 0, GetModuleHandle(0), 0);
    		myEditControl = CreateWindowEx(WS_EX_CLIENTEDGE, L"Edit", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, 0, 0, 600, 400, myWindow, 0, GetModuleHandle(0), 0);
    
    		// If that was successfull
    		if (myWindow) {
    
    			// Show our windows
    			ShowWindow(myWindow, SW_SHOWDEFAULT);
    			ShowWindow(myEditControl, SW_SHOWDEFAULT);
    
    			// Unlimited editing size
    			SendMessage(myEditControl, EM_SETLIMITTEXT, 0, 0);
    
    			// Message loop of our window
    			MSG msg;
    			while (GetMessage(&msg, 0, 0, 0)) {
    				TranslateMessage(&msg);
    				DispatchMessage(&msg);
    			}
    		}
    	}
    
    	return 0;
    }
    

  • Mod

    Nicht die Nachrichten sind lahm, sondern Dein SendMessage in den anderen Prozess. Der Kontextswitch und alles was damit zusammenhängt.

    PostMessage kannst Du auch nicht verwenden, da es sich um Zeigeerhandelt und der Speicher ja auch nicht in den anderen Prozess kopiert werden muss. All das macht SendMessage. Es wundert mich nicht, das das "lahm" ist.

    Welchen Sinn soll das haben?
    Man kann doch selbst die Datei Speichern. Warum zwei Edit-Controls die synchron gehalten werden müssen. Wobei das nicht mal mit Sicherheit klappen muss, wenn EM_REPLACESEL verwendet wird.



  • Martin Richter schrieb:

    Nicht die Nachrichten sind lahm, sondern Dein SendMessage in den anderen Prozess. Der Kontextswitch und alles was damit zusammenhängt.

    PostMessage kannst Du auch nicht verwenden, da es sich um Zeigeerhandelt und der Speicher ja auch nicht in den anderen Prozess kopiert werden muss. All das macht SendMessage. Es wundert mich nicht, das das "lahm" ist.

    Ok, und wie könnte man es dann lösen um diesen Kontextswitch zu verhindern?

    Martin Richter schrieb:

    Welchen Sinn soll das haben?
    Man kann doch selbst die Datei Speichern. Warum zwei Edit-Controls die synchron gehalten werden müssen

    Es geht nicht darum den Text in einer Datei zu speichern, sondern wirklich darum zwei Edit-Controls synchron zu halten. Es geht darum eine alte Anwendung zu erweitern, dafür brauche ich das.


Log in to reply