WM_SETTEXT sendet nur ein Zeichen?
-
Hallo,
ich versuche gerade den Text eines externen Edit-Controls auszulesen und dann in ein zweites, ebenfalls externes, Edit-Control zu schreiben. Dazu benutze ich folgenden Code:
// Textlänge des ersten Edit-Controls bestimmen int length = SendMessage(hWnd1, WM_GETTEXTLENGTH, 0, 0); // Speicher für diesen Text reservieren wchar_t* buff = new wchar_t[length + 1]; // Text aus dem Edit-Control beziehen SendMessage(hWnd1, WM_GETTEXT, length + 1, reinterpret_cast<LPARAM>(buff)); // Text in das zweite Edit-Control schreiben (Hier ist das Problem) SendMessage(hWnd2, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(buff)); // Aufräumen delete[] buff;
Bis zur vorletzten Zeile (die mit WM_SETTEXT) funktioniert auch alles. Wenn ich das jetzt allerdings durchlaufen lasse sendet das WM_SETTEXT nur den allerersten Buchstaben des Buffer-Arrays!
Besonders seltsam ist dass das WM_SETTEXT funktioniert wenn ich anstatt einem wchar_t ein normales char-Array verwende, also so:
// Textlänge des ersten Edit-Controls bestimmen int length = SendMessage(hWnd1, WM_GETTEXTLENGTH, 0, 0); // Speicher für diesen Text reservieren char* buff = new char[length + 1]; // Text aus dem Edit-Control beziehen (Jetzt ist hier das Problem) SendMessage(hWnd1, WM_GETTEXT, length + 1, reinterpret_cast<LPARAM>(buff)); // Text in das zweite Edit-Control schreiben SendMessage(hWnd2, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(buff)); // Aufräumen delete[] buff;
Das Problem bei der Variante ist, dass jetzt das WM_GETTEXT nicht mehr funktioniert, also in das Buffer-Array werden keine Werte geschrieben, das Array bleibt uninitialisiert. Das WM_SETTEXT funktioniert damit aber (nur leider schreibt es jetzt halt uninitialisierte Werte in das zweite Edit-Control).
Wo liegt hier das Problem?
Viele Grüße,
hs
-
DOKU
Tipp: Bei den "Requirements" stehts
-
Hi schrieb:
DOKU
Tipp: Bei den "Requirements" stehtsHallo, die Doku kenn ich schon, versteh nicht ganz was mir die Liste bei den Requirements sagen soll.
Das Ganze funktioniert weder mit der dort angegebenen SendMessageW noch mit SendMessageA noch mit dem normalen SendMessage. Und mehr steht da unter Requirements nicht (Die Header etc. sind natürlich eingebunden sonst würds ja gar nicht erst kompilieren).Von daher hilft mir dieser Tipp nicht weiter.
-
Was sagen denn die Rückgabewerte?
-
Also, das erste Sendmessage (WM_GETTEXTLENGHT) gibt die Anzahl der Zeichen des Edit-Controls zurück. Dass der Rückgabewert stimmt hab ich schon überprüft.
Das zweite Sendmessage (WM_GETTEXT) gibt den selben Wert zurück (die Anzahl der bezogenen Zeichen), auch das ist korrekt.
Das dritte Sendmessage (WM_SETTEXT) gibt 1 zurück, also "Erfolg".
Von daher müsste ja alles passen, oder? Leider klappt es aus einem mir nicht ersichtlichen Grund trotzdem nicht.
-
Und du verwendest nun korrekterweise auch SendMessageW()?
-
Jawohl, hab alle SendMessages durch SendMessageW ersetzt, genau das Gleiche Verhalten, genau die gleichen Return-Werte.
In "buff" steht der Text auch korrekt, wenn ich mir den mittels:
for(int i = 0; i < length; i++) std::cout << static_cast<char>(buff[i]);
ausgeben lasse erhalte ich in der Konsole auch genau den richtigen Text des ersten Edit-Controls. Das funktioniert also.
Nur das WM_SETTEXT klappt irgendwie nicht, bzw. schickt es nur den ersten Buchstaben.
-
happystudent schrieb:
Jawohl, hab alle SendMessages durch SendMessageW ersetzt, genau das Gleiche Verhalten, genau die gleichen Return-Werte.
In "buff" steht der Text auch korrekt, wenn ich mir den mittels:
for(int i = 0; i < length; i++) std::cout << static_cast<char>(buff[i]);
ausgeben lasse erhalte ich in der Konsole auch genau den richtigen Text des ersten Edit-Controls. Das funktioniert also.
Funktioniert und zeigt, das die UNICODE Kenntnisse gegen NULL gehen
Wenn buff ein wchar_t ist, sollte man evtl. wcout verwenden und sich den
Umstand mit der for()-Schleife und dem Index sparen ...Es wäre zudem auch gesünder bei SendMessage() nicht length + 1 zu verwenden, sondern nur length.
-
merano schrieb:
Funktioniert und zeigt, das die UNICODE Kenntnisse gegen NULL gehen
Nun, das kann ich nicht abstreiten
merano schrieb:
Wenn buff ein wchar_t ist, sollte man evtl. wcout verwenden und sich den
Umstand mit der for()-Schleife und dem Index sparen ...Ja, also das Problem ist ja nicht das cout, das war nur als Beispiel mit dem ich sichergehen konnte dass kein Schrott in dem buff array steht. Worum es eigentlich geht ist ja das WM_SETTEXT. Wenn ich das Ganze so mache funktioniert es:
// Textlänge holen int length = SendMessageW(hWnd1, WM_GETTEXTLENGTH, 0, 0); // Zwei Buffer Arrays anlegen wchar_t* buff1 = new wchar_t[length + 1]; char* buff2 = new char[length + 1]; // Text in den ersten Buffer holen SendMessageW(hWnd1, WM_GETTEXT, textLength + 1, reinterpret_cast<LPARAM>(buff1)); // Dann in den zweiten Buffer umkonvertieren for(int i = 0; i <= length; i++) buff2[i] = static_cast<char>(buff1[i]); // Versenden (klappt so) SendMessageW(hWnd2, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(buff2)); // Aufräumen delete[] buff1; delete[] buff2;
Das find ich aber nicht besonders schön und performance technisch ist es bestimmt auch nicht optimal dass ich dann nochmal extra über das Ganze Array iterieren muss.
Wie löse ich das geschickter?
-
happystudent schrieb:
Ja, also das Problem ist ja nicht das cout, das war nur als Beispiel mit dem ich sichergehen konnte dass kein Schrott in dem buff array steht. Worum es eigentlich geht ist ja das WM_SETTEXT. Wenn ich das Ganze so mache funktioniert es:
// Textlänge holen int length = SendMessageW(hWnd1, WM_GETTEXTLENGTH, 0, 0); // Zwei Buffer Arrays anlegen wchar_t* buff1 = new wchar_t[length + 1]; char* buff2 = new char[length + 1]; // Text in den ersten Buffer holen SendMessageW(hWnd1, WM_GETTEXT, textLength + 1, reinterpret_cast<LPARAM>(buff1)); // Dann in den zweiten Buffer umkonvertieren for(int i = 0; i <= length; i++) buff2[i] = static_cast<char>(buff1[i]); // Versenden (klappt so) SendMessageW(hWnd2, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(buff2)); // Aufräumen delete[] buff1; delete[] buff2;
Das find ich aber nicht besonders schön und performance technisch ist es bestimmt auch nicht optimal dass ich dann nochmal extra über das Ganze Array iterieren muss.
Wie löse ich das geschickter?
Indem Du den ganzen Ramsch mit dem W und dem kopieren weglässt
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd, hWnd1, hWnd2; hInst = hInstance; // Instanzenhandle in der globalen Variablen speichern hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if(!hWnd) return FALSE; hWnd1 = CreateWindow(TEXT("EDIT"), TEXT("eins"), WS_CHILD | WS_VISIBLE, 20, 20, 200, 40, hWnd, (HMENU)1, hInstance, NULL); hWnd2 = CreateWindow(TEXT("EDIT"), TEXT("zwei"), WS_CHILD | WS_VISIBLE, 20, 60, 200, 40, hWnd, (HMENU)2, hInstance, NULL); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // Textlänge holen int length = SendMessage(hWnd1, WM_GETTEXTLENGTH, 0, 0); // Buffer anlegen wchar_t* buff1 = new wchar_t[length + 1]; // char* buff2 = new char[length + 1]; // Text in den ersten Buffer holen SendMessage(hWnd1, WM_GETTEXT, length+1, reinterpret_cast<LPARAM>(buff1)); // Versenden (klappt so) SendMessage(hWnd2, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(buff1)); // Aufräumen delete[] buff1; return TRUE; }
Bei mir steht dann zwei mal eins untereinander auf dem Bildschirm.
-
merano schrieb:
Indem Du den ganzen Ramsch mit dem W und dem kopieren weglässt
[...] // Buffer anlegen wchar_t* buff1 = new wchar_t[length + 1]; // char* buff2 = new char[length + 1]; [...]
Warum dann nicht:
TCHAR* buff1 = new TCHAR[length + 1];
wie in Zeile 13 auch:
hWnd1 = CreateWindow(TEXT("EDIT"), TEXT("eins") ...
?
-
Klar geht das und ist meines Erachtens auch besser.
-
merano schrieb:
Indem Du den ganzen Ramsch mit dem W und dem kopieren weglässt
Also jetzt doch ohne W?
merano schrieb:
Bei mir steht dann zwei mal eins untereinander auf dem Bildschirm.
Das ist ja das komische, bei mir klappt das mit diesem Code nicht (ist ja genau der gleiche wie aus meinem Anfangspost). Kann das vielleicht an dem Textfeld der externen Applikation liegen? Oder einfach an der Tatsache dass es eine externe Applikation ist?
Momentan klappt es halt leider nur mit dem Kopier-Schritt.
Belli schrieb:
Warum dann nicht:
Hab ich gleich ausprobiert, bringt leider auch nicht das gewünschte Ergebnis.
-
Belli schrieb:
Warum dann nicht:
TCHAR* buff1 = new TCHAR[length + 1];
Ist natürlich der saubere Weg, wollte hier aber keine neue Baustelle aufmachen.
Was ist genau eine "externen Applikation".
Du willst eine Fenster-Message an einen anderen Prozess senden ?
Die Doku sagt dazu:
Message sending is subject to UIPI. The thread of a process can send messages only to message queues of threads in processes of lesser or equal integrity level.
Wenn allerdings ein Zeichen ankommt sollte das ja erfüllt sein, oder ?
-
merano schrieb:
Was ist genau eine "externen Applikation".
Eine Anwendung die mir nicht zugänglich ist, wie zum Beispiel Notepad.
merano schrieb:
Wenn allerdings ein Zeichen ankommt sollte das ja erfüllt sein, oder ?
Ja schon. Das Senden an sich funktioniert ja auch einwandfrei wenn ich den zu sendenden Text davor per Schleife in normale chars umwandel.
-
GetWindowText function http://msdn.microsoft.com/en-us/library/windows/desktop/ms633520(v=vs.85).aspx
-
asbestos schrieb:
GetWindowText function http://msdn.microsoft.com/en-us/library/windows/desktop/ms633520(v=vs.85).aspx
Sicher? In der MS Doku steht: However, GetWindowText cannot retrieve the text of a control in another application.
Werds aber trotzdem mal ausprobieren, Danke.
-
habe das in MASM zb. mal so gemacht - mit erfolg:
include \masm32\include\masm32rt.inc .data? value dd ? buffer1 db 1024 dup (?) .data hbtn dd 123456 ; = handle of ctrl .code start: invoke GetWindowText,hbtn,addr buffer1,lengthof buffer1 ; hbtn = handle of ctrl mov value, eax invoke GetWindowText,hbtn,addr buffer1,value+1 print addr buffer1,13,10 inkey exit end start