[c++] WM_CHAR / EN_CLICKED-Messages??

hey leute!
hab folgendes problem: hab mich jetz in die gui-programmierung mit der winapi eigearbeitet und will jetzt so ne art toolbox programmieren, die links oben im eck wartet bis man darauf clickt, um dann eingaben shell-like zu verarbeiten oder evtl an die cmd.exe zu pipen. das layout steht, allerdings hab ich probleme zu erkennen, wann der benutzer [ENTER] auf der tastatur drueckt. die WM_CHAR-message wird nur geschickt, wenn ich kein control auf meiner form aktiviert ist. hab in der beschreibung zum edit-control gelesen, dass ein enter-druck in einem solchen control die gleiche auswirkung hat, wie wenn der default-pushbutton geclickt wird. funktioniert aber auch nicht ?( schön langsam gehen mir wirklich die ideen aus, das einzige was mir noch bleibt is die EN_CHANGE-message vom edit-control, aber wie soll ich da ein enter rauslesen?

hier mein code:
Code:
#include <windows.h>
#include <stdio.h>

//Fenster-abmessungen
#define TB_HEIGHT 150
#define TB_WIDTH 600
#define CTL_INPUT_HEIGHT 20
#define WINDOW_CAPT 21

//Prototypen fuer funktionen
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void FontUpdate(int fHeight, LPCTSTR fName);
void AddLine(HWND hWin, LPCTSTR sLine, DWORD sLen);

//////////////////////////////////////////////
//		Global Vars
static char gszClassName[]  = "TB_MAIN";
static HINSTANCE ghInstance = NULL;
HWND hwnd;
HWND ctl_stat=NULL,ctl_input=NULL, ctl_defbtn;

//////////////////////////////////////////////
//		Error-Displaying..
void die(LPSTR eText,DWORD dwErr) 
{
  char szMsg[256];
  char retMsg[512];
  DWORD dwFlags = FORMAT_MESSAGE_IGNORE_INSERTS |
                  FORMAT_MESSAGE_MAX_WIDTH_MASK |
                  FORMAT_MESSAGE_FROM_SYSTEM;

  if (!FormatMessage(dwFlags, NULL, dwErr, 0, szMsg, sizeof(szMsg), NULL)) strcpy(szMsg, "Unknown error.");
  sprintf (retMsg,"%s\n%s (%i)", eText,szMsg, dwErr);
  MessageBox(NULL, retMsg, "Error", MB_OK);
  ExitProcess(1);
}
//Overload fuer die() mit einem Parameter
void die(LPSTR eText) {die(eText, GetLastError());};

//////////////////////////////////////////////
//		Window-Procedure
LRESULT CALLBACK WindowProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
//Lokale Variablen
	RECT wndRect;
	TCHAR Buf[512];
	switch(uMsg) {
		case WM_CREATE:
			//Controls erstellen
			ctl_defbtn = CreateWindowEx(
						NULL,
						"Button",
						"df",
						WS_BORDER | WS_CHILD |// WS_VISIBLE |
						BS_DEFPUSHBUTTON,
						TB_WIDTH-20, TB_HEIGHT - CTL_INPUT_HEIGHT - WINDOW_CAPT,
						20, 20,
						hwndDlg, NULL,
						ghInstance,
						NULL);
			if(!ctl_defbtn) die("Window-Init failed:\nCould not create Default Pushbutton control:");
			ctl_stat = CreateWindowEx(
						NULL,
						"Edit",
						" ",
						WS_BORDER | WS_CHILD | WS_VISIBLE | WS_VSCROLL | 
						ES_READONLY | ES_MULTILINE,
						0, 0,
						TB_WIDTH, TB_HEIGHT - CTL_INPUT_HEIGHT - WINDOW_CAPT,
						hwndDlg, NULL,
						ghInstance,
						NULL);
            if (!ctl_stat) die("Window-Init failed:\nCould not create Status control:");
			ctl_input = CreateWindowEx(
						NULL,
						"Edit",
						" ",
						WS_BORDER | WS_CHILD | WS_VISIBLE | ES_MULTILINE,
						0, TB_HEIGHT - CTL_INPUT_HEIGHT - WINDOW_CAPT,
						TB_WIDTH-20, CTL_INPUT_HEIGHT,
						hwndDlg, NULL,
						ghInstance,
						NULL);
            FontUpdate(13, "Courier New");
			break;
		case WM_CLOSE:
			DestroyWindow(hwndDlg);
			break;
		case WM_CHAR:
			//if (wParam==L'\n') {
				//if (GetFocus()==ctl_input) {
					die("wM_CHAR catched!");
					TCHAR iBuf[512];
					SendMessage(ctl_input, WM_GETTEXT, 512,(LPARAM)iBuf);
					SendMessage(ctl_stat, WM_SETTEXT, NULL, (LPARAM)iBuf);
					ZeroMemory(iBuf, 512*sizeof(TCHAR));
					SendMessage(ctl_input, WM_SETTEXT, NULL, (LPARAM)iBuf);					
				//}
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		case WM_COMMAND:
				if(HIWORD(wParam)==BN_CLICKED){
					die("BN_CLICKED catched!");
					/*int len=GetWindowTextLength(ctl_input);
					LPSTR buf = (LPSTR)malloc(len+1);
					if(!GetWindowText(ctl_input, buf, len)) die("Err get text");
					AddLine(ctl_stat, buf, len);*/
				}
			break;
		case WM_LBUTTONDOWN:
				if(!GetWindowRect(hwndDlg, &wndRect)) 
					die ("Error retrieving Window coords:");
				while(wndRect.top < -5 || wndRect.left < -15) {
					if(wndRect.top < -5) wndRect.top+=5;
					if(wndRect.left < -15) wndRect.left+=15;
					if(!MoveWindow(hwndDlg, wndRect.left, wndRect.top, TB_WIDTH, TB_HEIGHT, TRUE))
						die("Error Moving window:");
					Sleep(8);
				}
				if(!MoveWindow(hwndDlg, 0, 0, TB_WIDTH, TB_HEIGHT, TRUE))
					die("Error Moving window:");
				SetFocus(ctl_input);
				UpdateWindow(hwndDlg);
			break;
		case WM_ACTIVATE:
			if(wParam==WA_INACTIVE) {
		//Fenster aus dem sichtfeld bewegen
			if(!GetWindowRect(hwndDlg, &wndRect)) die ("Error retrieving Window coords:");
			while(wndRect.top > -TB_HEIGHT+10 || wndRect.left > -TB_WIDTH+16) {
				if(wndRect.top > -TB_HEIGHT+10) wndRect.top-=5;
				if(wndRect.left > -TB_WIDTH+16) wndRect.left-=15;
				if(!MoveWindow(hwndDlg, wndRect.left, wndRect.top, TB_WIDTH, TB_HEIGHT, TRUE))
					die("Error Moving window:");
				Sleep(5);
			}
			}
			break;
		default:
			return DefWindowProc(hwndDlg, uMsg, wParam, lParam);
	}
	return 0;
}

//////////////////////////////////////////////
//		AddLine
void AddLine(HWND hWin, LPCTSTR sLine, DWORD sLen) {
	LPSTR buf, buf2;
	int len = GetWindowTextLength(hWin)+2;
	buf = (LPSTR)malloc(len);
	buf2 = (LPSTR)malloc(len+sLen);

	if(!GetWindowText(hWin, buf, len)) die("Error retrieving win Text:");
	sprintf(buf2, "%s\r\n%s", buf, sLine);
	if(!SendMessage(hWin, WM_SETTEXT,(WPARAM)NULL, (LPARAM)buf2)) die("Error setting new text:");
	SendMessage(hWin, EM_SETSEL, len+sLen, len+sLen);
	SendMessage(hWin, EM_SCROLLCARET, NULL, NULL);
	free(buf);
	free(buf2);
}


//////////////////////////////////////////////
//		FontUpdate
void FontUpdate(int fHeight, LPCTSTR fName) {
			HFONT hFont = CreateFont(
					  fHeight,				// height of font
					  0,					// average character width
					  0,					// angle of escapement
					  0,					// base-line orientation angle
					  FW_LIGHT,				// font weight
					  FALSE,				// italic attribute option
					  FALSE,				// underline attribute option
					  FALSE,				// strikeout attribute option
					  DEFAULT_CHARSET,		// character set identifier
					  OUT_DEFAULT_PRECIS,	// output precision
					  CLIP_DEFAULT_PRECIS,	// clipping precision
					  DEFAULT_QUALITY,		// output quality
					  DEFAULT_PITCH,		// pitch and family
					  fName					// typeface name
					);
			SendMessage(ctl_input, WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE);
			SendMessage(ctl_stat, WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE); 
}

//////////////////////////////////////////////
//		Main Procedure

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
      WNDCLASSEX WndClass;
       MSG Msg;

       ghInstance = hInstance;

       WndClass.cbSize        = sizeof(WNDCLASSEX);
       WndClass.style         = NULL;
       WndClass.lpfnWndProc   = WindowProc;
       WndClass.cbClsExtra    = 0;
       WndClass.cbWndExtra    = 0;
       WndClass.hInstance     = ghInstance;
       WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
       WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
       WndClass.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1);
       WndClass.lpszMenuName  = NULL;
       WndClass.lpszClassName = gszClassName;
       WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

       if(!RegisterClassEx(&WndClass)) {
               MessageBox(0, "Window Registration Failed!", "Error!", MB_ICONSTOP | MB_OK);
               return 0;
       }

       hwnd = CreateWindowEx(
               NULL,
               gszClassName,
               "Me Toolbox",
               WS_BORDER,
               0, -WINDOW_CAPT,
               TB_WIDTH, TB_HEIGHT,
               NULL, NULL,
               ghInstance,
               NULL);

	    if(!hwnd) die("Error Creating Dialog:");
		ShowWindow(hwnd, SW_SHOW);
       UpdateWindow(hwnd);

       while(GetMessage(&Msg, NULL, 0, 0)) {
               TranslateMessage(&Msg);
               DispatchMessage(&Msg);
       }
       return Msg.wParam;
}
achja, ich kompilier das ganze mit Digital Mars. habs aber auch schon mit dem VCToolkit probiert...

thx i.a. & mfg jacky
 
Was mir spontan einfällt: ES_WANTRETURN zu den Eigenschaften des Edits hinzuzufügen.

ES_WANTRETURN Specifies that a carriage return be inserted when the user presses the enter key while entering text into a multiline edit control in a dialog box. If you do not specify this style, pressing the enter key has the same effect as pressing the dialog box's default push button. This style has no effect on a single-line edit control.
 
nö das isses nich, mein input-feld is ja garnicht multiline (sollte es zumindest, habs grad rausgemacht..) ES_WANTRETURN bewirkt ja eher da gegenteil: wenn im (multiline-)input-feld enter gedrueckt wird, wird ein absatz eingefuegt und eben NICHT der default-button aktiviert. aber ohne diese option ändert sich sowieso nix. kann ich irgendwie die message-handler von meinem control selbst schreiben und so evtl an die messages kommen? wollte ein gui-programm ohne mfc schreiben, aber dass das garnicht geht, war mir net klar X(

--jacky
 
Ok, dann versuchte doch einfach per WM_KEYUP
selber die Tasten einzulesen /filtern usw.
Es gibt auch noch mehr Methoden, betätigte Tasten abzufragen wie z.B GetKeyState/GetAsyncKeyState oder gleich GetKeyboardState, ist aber eher schwereres Geschütz.
 
...dann versuchte doch einfach per WM_KEYUP selber die Tasten einzulesen /filtern usw.
Das geht nur wenn das Edit-Feld ge"subclassed" wurde.

...wollte ein gui-programm ohne mfc schreiben, aber dass das garnicht geht, war mir net klar
Na,na, mal nicht so pessimistisch :

In der MainMessageLoop der Anwendung lässt sich ein Filter einbauen (ist aber unsauber):

Code:
(Zeile 228)
while(GetMessage(&Msg, NULL, 0, 0)) {


  if ( Msg.hwnd    == ctl_input ) {
  if ( Msg.message == WM_CHAR )   {
  if ( Msg.wParam  == 0x0D )      {
       MessageBox(0, "ENTER pressed", "WM_CHAR", MB_ICONSTOP |   MB_OK);
  }}}

               TranslateMessage(&Msg);
               DispatchMessage(&Msg);
       }
 
juppi danke danke funzt wunderbar =)
unsauber is immerhin besser als garnet funktionierend.

Das geht nur wenn das Edit-Feld ge"subclassed" wurde.
was meinst du damit? die das subclassing mittels mfc/visual c++? oder gäbs doch noch ne andere möglichkeit?

thnx'n'greez jacky
 
Original von heinzelJacKy
juppi danke danke funzt wunderbar =)
unsauber is immerhin besser als garnet funktionierend.

Das geht nur wenn das Edit-Feld ge"subclassed" wurde.
was meinst du damit? die das subclassing mittels mfc/visual c++? oder gäbs doch noch ne andere möglichkeit?

thnx'n'greez jacky

Er meint wahrscheinlich Subclassing mittels SetWindowLongPtr:
http://windowssdk.msdn.microsoft.com/en-us/library/ms644898.aspx
http://windowssdk.msdn.microsoft.com/en-us/library/ms649784.aspx
(Mehr Informationen gibts bei google)
 
@Lesco
SetWindowLongPtr ?? Das ist ja WinAPI-64 oder ?

@heinzelJacKy
Mit "subclassing" ist immer gemeint, dass man dem EDIT-Feld eine eigene "WinProc" zuweisen kann.
Dann sendet das Betriebssystem sämtliche Botschaften (WM_KEYDOW, WM_KEYUP, WM_MOUSEMOVE...) nicht mehr an das EDIT-Feld sondern an die neue "WinProc".
Dadurch hat man mehr Kontrolle über das Verhalten des EDIT-Feldes.
Realisieren lässt sich sowas am einfachsten im sog. "mfc/visual c++"-Style.
Dann sind die Beispiele immer "CAP-kompatibel (CopyAndPaste-kompatibel)"(aber laufen wenigstens).
Allerdings geht es auch komplizierter. WinAPI from scratch sozusagen.
Als Anhang dabei eine Vorlage für eine GUI mit "gesubclass"tem EDIT-Feld, das sogar ohne "WINDOWS.H" auskommt.
 
Original von merker
@Lesco
SetWindowLongPtr ?? Das ist ja WinAPI-64 oder ?

Soweit ich weiß nicht, jedoch ist es 64-Bit kompatibel und das alte SetWindowLong scheint obsolet zu sein:
Aus der SetWindowLong-Erklärung
This function has been superseded by the SetWindowLongPtr function. To write code that is compatible with both 32-bit and 64-bit versions of Microsoft Windows, use the SetWindowLongPtr function.
 
ok werd mir das mit dem subclassing nochmal durch den kopf gehen lassen, aber momentan bin ich mit der version ganz gluecklick =) hier mal eine vorläufige version von dem programm inklusive source, falls es jemanden interessiert. kann noch net viel ausser alles nach cmd.exe zu schicken, zum beenden des dings "!exit" oder alt-f4 druecken. verzieht sich nach links oben ins eck, draufklicken zum wiederherstellen.

edit/nexxte frage :D:
nachdem jetz die vorhandenen probleme gelöst wurden, hab ich schon wieder n neues: die anwendungen, die ueber meine "shell" gestartet werden, werden nich angezeigt! also wenn ich z.b. "mspaint" eingebe, wird zwar der prozess erstellt (laut procexp) aber ein fenster wird nicht erstellt, bzw erst erstellt, wenn ich ein paar neue befehle eingebe oder das prog beende. weiß aber nicht, wieso sich das so komisch verhält, aber wenn ich die pipes nicht setze (als nur cmd.exe ganz normal mithilfe meines progs starte) funktioniert es ausgezeichnet. irgendwer ne idee? ?(


mfg jacky
 
Zurück
Oben