Design Problem



  • Hallo, ich bin gerade dabei ein std ogl fenster oop gerecht umzusetezn.
    Dies hat soweit auch geklappt, bis ich in der WndProc Funktion auf Elemente der Fensterklasse zugreifen musste. Da die WndProc Funktion kein Element der Klasse ist, funktioniert dies allerdings nich, und auch eine Friend-Dekliration bringt nichts, da ich der WndProc Funktion keine Instanz der Klasse übergeben kann!? Die einzige Lösung wäre imho ein globales objekt, aber das will ich nich...



  • Ich blicke zwar kein stück durch dass, was du da planst durch, aber kannst du nicht einfach eine Zugriffsfunktion verwenden? 😕 😕



  • Leite halt von der WndProc alles an eine public Methode in deiner Fensterklasse weiter, das ist doch voll ok.



  • Aber die WndProc kennt die Klasse doch gar nicht! und übergeben kann ich sie ja auch nicht weil die wndproc fest definiert ist...
    ich habe es nun so versucht:

    OGLWindow *window = reinterpret_cast<OGLWindow *>(GetWindowLong(hWnd, GWL_USERDATA));
    

    und dann z.B. mit window->active auf die variablen / methoden zugegriffen, aber da gibt es immer einen absturz
    genauer gesagt hier

    case WM_ACTIVATE:
    		if(!HIWORD(wParam)) {
    			window->active = true;
    		}
    		else {
    			window->active = false;
    		}
    		return 0;
    	case WM_CLOSE:
    		PostQuitMessage(0);
    		return 0;
    	case WM_SIZE:
    		window->resize(LOWORD(lParam), HIWORD(lParam));
    		return 0;
    

    und das schon beim erstellen des Fensters, es gibt jedoch keine Fehlermeldung (man sieht wie das fenster entsteht, es verschwindet jedoch auch sofort wieder).
    wenn ich das window->active ausklammere klappt es (obwohl die resize methode aufgerufen wird) 😕



  • Dein Problem ist, nehme ich an, dass du in einer static-Methode (nämlich der Fensterprozedur) nicht auf den this Zeiger zugreifen kannst ?!?

    Oder eher nicht: "kein Element der Klasse ist".

    Mach die Fensterprozedur zu einer Methode der Klasse (setze static davor bei der Deklaration).

    Dann musst du folgendes machen, wenn du auf die Member der Klasse auch in dieser statischen methode zugreifen willst:

    // Deklaration
    
    class Class
    {
    
      static LPARAM CALLBACK WndProc(HWND hWindow, UINT nMessage ....);
    
    ...
    };
    
    // In irgendeiner Init-Methode deiner Klasse:
    
    SetWindowProp(this->mWindow, "this", (HANDLE) this);
    
    // In deiner Fenster-Prozedur (am besten am Anfang):
    
    LPARAM CALLBACK Class::WndProc(HWND hWindow, UINT nMessage ....)
    {
    
    Class *This = (Class*) GetWindowLong(hWindow, "this");
    
    switch (nMessage)
    {
     case WM_SIZE: This->Resize(....); break;
    }
    
    ....
    }
    

    EDIT: Wie wär es, wenn du von der Open-GL Klasse (was auch immer das ist) einfach ableitest und dann eben diese Methodik oben anwendest in der abgeleiteten Klasse?

    EDIT 2: Bzw. wenn OGLWindow eine von dir geschriebene Klasse ist, dann mach die Fensterprozedur eben einfach zur Memberfunktion dieser Klasse.



  • Ich glaube ich poste einfach mal den Code...

    OGLWindow.h

    #ifndef OGLWINDOW_H
    #define OGLWINDOW_H
    
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    #include <gl/gl.h>
    #include <gl/glu.h>
    #include <gl/glaux.h>
    #include "ErrorHandling.h"
    
    class OGLWindow
    {
    	friend LRESULT CALLBACK wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    
    	HINSTANCE hInstance;
    	HWND hWnd;
    
    	HGLRC hRC;
    	HDC hDC;
    
    	bool active;
    	bool fullscreen;
    
    public:
    	OGLWindow(HINSTANCE hInstance, LPSTR cmdLine, int cmdShow, char* title, int width, int height, int bpp, bool fullscreen);
    	~OGLWindow();
    
    	void resize(GLsizei width, GLsizei height);
    	void initGL();
    	void renderScene();
    
    	int start();
    };
    
    #endif
    

    und OGLWindow.cpp:

    #include "OGLWindow.h"
    
    LRESULT CALLBACK wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	OGLWindow *window = reinterpret_cast<OGLWindow *>(GetWindowLong(hWnd, GWL_USERDATA));
    	switch(message) {
    	case WM_ACTIVATE:
    		if(!HIWORD(wParam)) {
    			window->active = true;
    		}
    		else {
    			window->active = false;
    		}
    		return 0;
    	case WM_SYSCOMMAND:
    		switch(wParam) {
    		case SC_SCREENSAVE:
    		case SC_MONITORPOWER:
    			return 0;
    		}
    		break;
    	case WM_CLOSE:
    		PostQuitMessage(0);
    		return 0;
    	case WM_SIZE:
    		window->resize(LOWORD(lParam), HIWORD(lParam));
    		return 0;
    	}
    
    	return DefWindowProc(hWnd, message, wParam, lParam);
    }
    
    OGLWindow::OGLWindow(HINSTANCE hInstance, LPSTR cmdLine, int cmdShow, char* title, int width, int height, int bpp, bool fullscreen)
    {
    	this->fullscreen = fullscreen;
    
    	WNDCLASS wc;
    	wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    	wc.lpfnWndProc = wndProc;
    	wc.cbClsExtra = 0;
    	wc.cbWndExtra = 0;
    	wc.hInstance = hInstance;
    	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    	wc.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
    	wc.lpszClassName = "OGLWindow";
    	wc.lpszMenuName = NULL;
    
    	try {
    		if(!RegisterClass(&wc)) {
    			throw StartExcept("Klasse konnte nicht angemeldet werden.", __FILE__, __LINE__);
    		}
    		DWORD dwExStyle;
    		DWORD dwStyle;
    		if(fullscreen) {
    			DEVMODE dmScreenSettings;
    			memset(&dmScreenSettings, 0, sizeof(DEVMODE));
    			dmScreenSettings.dmSize = sizeof(DEVMODE);
    			dmScreenSettings.dmPelsWidth = width;
    			dmScreenSettings.dmPelsHeight = height;
    			dmScreenSettings.dmBitsPerPel = bpp;
    			dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
    			if(ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
    				throw StartExcept("Der Vollbildmodus wird von ihrer Grafikkarte nicht unterstützt.", __FILE__, __LINE__);
    			}
    			dwExStyle = WS_EX_APPWINDOW;
    			dwStyle = WS_POPUP;
    		}
    		else {
    			dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
    			dwStyle = WS_OVERLAPPEDWINDOW;
    		}
    		RECT windowRect;
    		windowRect.left = 0;
    		windowRect.top = 0;
    		windowRect.right = width;
    		windowRect.bottom = height;
    		AdjustWindowRectEx(&windowRect, dwStyle, false, dwExStyle);
    
    		if(!(hWnd = CreateWindowEx(	dwExStyle,
    									"OGLWindow", 
    									title,
    									WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle,
    									0,
    									0,
    									windowRect.right - windowRect.left,
    									windowRect.bottom - windowRect.top,
    									NULL,
    									NULL,
    									hInstance,
    									NULL))) {
    			throw StartExcept("Das Fenster konnte nicht erstellt werden.", __FILE__, __LINE__);
    		}
    		if(!(hDC = GetDC(hWnd))) {
    			throw StartExcept("GL Device Context konnte nicht erstellt werden.", __FILE__, __LINE__);
    		}
    		static	PIXELFORMATDESCRIPTOR pfd =					
    		{
    			sizeof(PIXELFORMATDESCRIPTOR),					
    			1,								
    			PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,				
    			PFD_TYPE_RGBA,
    			bpp,
    			0, 0, 0, 0, 0, 0,
    			0,
    			0,
    			0,
    			0, 0, 0, 0,
    			16,
    			0,
    			0,
    			PFD_MAIN_PLANE,
    			0,
    			0, 0, 0
    		};
    		GLuint pixelFormat;
    		if(!(pixelFormat = ChoosePixelFormat(hDC, &pfd))) {
    			throw StartExcept("Angemessenes Pixelformat konnte nicht gefunden werden.", __FILE__, __LINE__);
    		}
    		if(!(SetPixelFormat(hDC, pixelFormat, &pfd))) {
    			throw StartExcept("Pixelformat konnte nicht gesetzt werden.", __FILE__, __LINE__);
    		}
    		if(!(hRC = wglCreateContext(hDC))) {
    			throw StartExcept("GL Rendering Context konnte nicht erstellt werden.", __FILE__, __LINE__);
    		}
    		if(!wglMakeCurrent(hDC, hRC)) {
    			throw StartExcept("GL Rendering Context konnte nicht aktiviert werden.", __FILE__, __LINE__);
    		}
    	}
    	catch(StartExcept& eObj) {
    		ErrorHandling::getInstance()->handleError(eObj, true, true);
    	}
    
    	ShowWindow(hWnd, cmdShow);
    	SetForegroundWindow(hWnd);
    	SetFocus(hWnd);
    	resize(static_cast<GLsizei>(width), static_cast<GLsizei>(height));
    
    	initGL();
    }
    
    OGLWindow::~OGLWindow()
    {
    	if(fullscreen) {
    		ChangeDisplaySettings(NULL, 0);
    	}
    
    	try {
    		if(hRC) {
    			if(!wglMakeCurrent(NULL, NULL)) {
    				throw ShutdownExcept("DC und RC konnten nicht freigegeben werden.", __FILE__, __LINE__);
    			}
    			if(!wglDeleteContext(hRC)) {
    				throw ShutdownExcept("Rendering Context konnte nicht freigegeben werden.", __FILE__, __LINE__);
    			}
    			hRC = NULL;
    		}
    		if(hDC && !ReleaseDC(hWnd, hDC)) {
    			hDC = NULL;
    			throw ShutdownExcept("Device Context konnte nicht freigegeben werden.", __FILE__, __LINE__);
    		}
    		if(hWnd && !DestroyWindow(hWnd)) {
    			hWnd = NULL;
    			throw ShutdownExcept("hWnd konnte nicht freigegeben werden.", __FILE__, __LINE__);
    		}
    		if(!UnregisterClass("OGLWindow", hInstance)) {
    			hInstance = NULL;
    			throw ShutdownExcept("Konnte Klasse nicht abmelden.", __FILE__, __LINE__);
    		}
    	}
    	catch(StdExcept& eObj) {
    		ErrorHandling::getInstance()->handleError(eObj, false, false);
    	}
    }
    
    void OGLWindow::resize(GLsizei width, GLsizei height)
    {
    	if(height == 0) { 
    		height = 1;
    	}
    
    	glViewport(0, 0, width, height);
    
    	glMatrixMode(GL_PROJECTION);
    	glLoadIdentity();
    
    	gluPerspective(45.0f, static_cast<GLfloat>(width)/height, 0.1f, 100.0f);
    
    	glMatrixMode(GL_MODELVIEW);
    	glLoadIdentity();
    }
    
    void OGLWindow::initGL()
    {
    	glShadeModel(GL_SMOOTH);
    	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    	glClearDepth(1.0f);
    	glEnable(GL_DEPTH_TEST);
    	glDepthFunc(GL_LEQUAL);
    	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    }
    
    void OGLWindow::renderScene()
    {
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	glLoadIdentity();
    
    	glTranslatef(-1.5f,0.0f,-6.0f);				
    
    	glBegin(GL_TRIANGLES);					
    		glColor3f(1.0f,0.0f,0.0f);			
    		glVertex3f( 0.0f, 1.0f, 0.0f);			
    		glColor3f(0.0f,1.0f,0.0f);			
    		glVertex3f(-1.0f,-1.0f, 0.0f);		
    		glColor3f(0.0f,0.0f,1.0f);			
    		glVertex3f( 1.0f,-1.0f, 0.0f);		
    	glEnd();						
    }
    
    int OGLWindow::start()
    {
    	MSG msg;
    	bool done = false;
    	while(!done) {
    		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
    			if(msg.message == WM_QUIT) {
    				done = true;
    			}
    			else {
    				TranslateMessage(&msg);
    				DispatchMessage(&msg);
    			}
    		}
    		else {
    			if(active) {
    				renderScene();
    				SwapBuffers(hDC);
    			}
    		}
    	}
    
    	return msg.wParam;
    }
    

    vielleicht versteht ihr jetzt was ich meine? MfG



  • (1) Wo setzt du die User Data? In deiner Fenster-Prozedur holst du sie ja ab:

    OGLWindow *window = reinterpret_cast<OGLWindow *>(GetWindowLong(hWnd, GWL_USERDATA));
    

    Also schätze ich mal, du hast sie vorher mit SetWindowLong() auch gesetzt?

    Solltest du sie nicht setzen, dann ist das dein Problem. Prüfe window auf NULL, wenn's NULL ist, stimmt irgendwas nicht.

    (2)

    mache die Variable

    OGLWindow *window
    

    besser static, damit holst du sie nur einmal, vielleicht solltest du darüber nachdenken, das Abholen der User Data bei der WM_CREATE Behandlung zu machen.



  • aah, sehe ich das richtig, dass man mit den funktionen SetWindowLong und GetWindowLong eigene Werte für fenster setzen und lesen kann?! (hatte sie davor nur kopiert..)

    habe nun am ende des Konstruktors folgende eingefügt:

    SetWindowLong(hWnd, GWL_USERDATA, (LONG)this);
    

    und in der wndproc funktion lass frage ich den wert wie zuvor ab.
    jedoch ist er immer noch NULL (das erste mal, wo die WM_CREATE nachricht gesendet wird, nicht berücksichtigt)?!


Anmelden zum Antworten