Willkommen ~Gast!
Registrieren || Einloggen || Hilfe/FAQ || Staff
Probleme mit der Registrierung im Forum? Melde dich unter registerEin Bild.
Autor Beitrag
000
27.05.2001, 22:25
Gandalf



Hi

Erstmal sorry das ich diese Frage in diesem Forum stelle, aber ich weiß ned wo ich sonst fragen könnte... eigentlich wollt ich ja auf www.gamedev.net fragen aber meine englisch Kenntnisse sind dann doch zu gering gewesen die Frage auf englisch zu formulieren.. :)
Also das hat nichts mit HalfLife-Coding zu tun sorry... soll nicht wieder vorkommen..

Folgendes ist mein Problem:
Ich habe angefangen eine Klasse zu schreiben mit der man ein OpenGL fenster aufsetzen kann. Klar ich könnte auch wgl verwenden und mir das selberbasteln sparen...
Aber das ganze wird im Grunde eh eher eine Übung als ein Projekt mit großem praktischen Nutzen.. :)

However.. ich steh da jetzt vor einem kleinen Problemchen...
In der Klasse soll eine Fenster-Nachrichtenbehandlungsroutine integriert sein, aber wenn man möchte soll man über eine methode eine eigene Nachrichtenbehandlungsroutine angeben können, die dann statt der integrierten verwendet wird. Also mach ich einen Funktionszeiger:

Quellcode:typedef LRESULT (CALLBACK *tpWndProc)(HWND,UINT,WPARAM,LPARAM);
tpWndProc pWndProc;

Der Konstruktor der Klasse setzt den Zeiger anfangs auf die Adresse der integrierten Nachrichtenbehandlungsroutine, welche ich so deklariert habe:

Quellcode:[b]static[/b] LRESULT CALLBACK GLProc(HWND,UINT,WPARAM,LPARAM);

und Über die Methode

Quellcode:UseOwnWndProc(tpWndProc _pWndProc){pWndProc=_pWndProc;};

kann man eine dein Zeiger auf eine eigene Nachrichtenbehandlungsroutine setzen.

Jetzt habe ich aber das Problem das der Zeiger den ich definiert habe nur dann auf die Interne Routine Zeigen kann wenn diese als static deklariert ist.. dadurch kann die Routine jetzt scheinbar selbst nur mehr auf static deklarierte Variablen in der Klasse zugreifen.
Und zwar hab ich da das array "bool keys[255];" auf das zugegriffen werden muss. wenn ich nicht static davor schreibe gehts überhaupt ned. und wenn dann meldet der Linker folgenden Fehler:
GLWindowClass.obj : error LNK2001: Nichtaufgeloestes externes Symbol "private: static bool * GLWindow::keys" (?keys@GLWindow@@0PA_NA)

Und jetzt hab ich echt keine Idee mehr warum der fehler kommt :((

Ich habe dann noch probiert den Zeiger auf die Interne Routine anders zu definieren, dass ich mir das static sparen kann:

Quellcode:typedef LRESULT (CALLBACK GLWindow::*tpIntWndProc)(HWND,UINT,WPARAM,LPARAM);

Allerdings nimmt den Die WNDCLASS struktur nicht an :(

Hmm... Wenn Jemand da eine Idee hat wie ich dieses merkwürdige Nichtaufgelöste externe Symbol wegkrige wäre das echt cool :)
Vielleicht is es ja eh nur ein gaanz dummer Fehler von mir den Ich da irgendwo gemacht hab.. :)

Und sorry nochmal weil das im relativ OT ist..

--

Gandalf
Mein Rekord: 57 :)
Gekillte Gelsen Zähler (2001):9

zum Seitenanfang zum Seitenende Profil || Suche
001
28.05.2001, 00:19
Another1



das gleiche problem hatte valve im HalfLife code, da man im HalfLife code zeiger auf eine Think und Touch functionen etc. setzen kann. Da C++ das aber auf nichtstatische memberfunctionen verbietet, empfehl Ich dir mal das Standard SDK Code Only irgendwo runterzuladen und zu schauen wie valve das gemacht hat (war irgendwas die adress extra speichern, dann wieder konvertieren, naja schaus dir einfach an)

die function zum zeiger setzen heißt SetThink und die setzt m_pfnThink = pfnNewThinkFunction o.ä ...

// edit: ich habs mir selbst nochmal angeschaut, hier ist es für die Think function mal für dich aufbereitet:

in class CBaseEntity der pointer auf die Thiunk function (m_pfnThink) ist so deklariert:

void (CBaseEntity ::*m_pfnThink)(void);

aufgerufem wird die function dann so:

(this->*m_pfnThink)();

und letztendlich wird noch ein Macro benutzt um die function von der klasse aus zu setzen:

#define SetThink( a ) m_pfnThink = static_cast <void (CBaseEntity::*)(void)> (a)

wenn du jetzt also ne function hast
void CBaseEntity::BlaBla(void);

und willst sie sozusagen in CBaseEntity::Init() m_pfnThink zuweisen, dann musst du von CBaseEntity::Init() nur noch

SetThink(BlaBla);

aufrufen,

das wars, keine compiler errors oder warnings =()

--

Another1

...relaxing..atm =)
... und Schweiz suckt!

zum Seitenanfang zum Seitenende Profil || Suche
002
28.05.2001, 17:46
Gandalf



Danke erstmal für deine Antwort, und dafür das du mir das aus dem HalfLife SDK rausgesucht hast.

Das Problem ist nur das mein Problem dadurch nicht gelöst wird, sondern nur verschoben... Das mit dem MemberFunktionszeiger definieren hab ich eh schon probiert. Nur muss ich den Zeiger an die WNDCLASS Struktur übergeben, damit ich das Fenster anmelden kann...
Das Problem besteht darin das WNDCLASS.lpfnWndProc keinen Zeiger akzeptiert, der so deklariert ist das er ein "Klassenfunktionszeiger" ist...

Also prinzipiell wäre das genial, allerdings müsste ich jetzt den Zeiger
Quellcode:LRESULT (CALLBACK GLWindow::*pWndProc)(HWND,UINT,WPARAM,LPARAM)
in
Quellcode:LRESULT (CALLBACK *pWndProc)(HWND,UINT,WPARAM,LPARAM)
umwandeln müsste damit er übergeben werden kann... aber das kann c++ nicht selbst umwandeln, und mit <static_cast>, ned mal mit <reinterpret_cast> geht das :((

Hm. aber es muss eine Lösung geben... Es gibt für alles eine Lösung :)
Najo.. wenns überhaupt ned anders geht mach ich die WndProc halt als Funktion ausserhalb der Klasse, und geb die einfach in der .h mit dazu.. erscheint mir zwar nicht unbedingt professionel. aber wenns echt ned anders geht bleibt mir wohl nichts anderes übrig.. :/

Njo. Dennoch nochmal danke für die Antwort, und das du dir die Mühe gemacht hast mir das rauszusuchen und zu beschreiben.

--

Gandalf
Mein Rekord: 57 :)
Gekillte Gelsen Zähler (2001):9

zum Seitenanfang zum Seitenende Profil || Suche
003
28.05.2001, 18:49
static_caster



ein forum mit richtig dick so c++ befindet sich unter

http://www.programmersheaven.com/wwwboard/board3/wwwboard.asp

.
die haben garantiert antwort auf deine fragen. (besonders NullAndVoid!!).
ist allerdings englisch, aber, du wirst dich schon durchfitzen :)

--

zum Seitenanfang zum Seitenende Profil || Suche
004
28.05.2001, 19:16
Killing Me Softly



Zwei Möglichkeiten:
a) du vergißt das mit dem Zeiger und deklarierst deine Nachrichtenbehandlungsroutine als virtuel. Derjenige, der die Routine überschreiben will muß dann halt ne neue Klasse von deiner Klasse ableiten und die Routine neu definieren. Hat den Vorteil, das der Benutzer deiner Klasse weiterhin auf deine Behandlungsroutine zurückgreifen kann und es ist C++-sauber.
b) du übergibst bei deiner Callback-Funktion einfach 'this' und greifts über den Zeiger auf das Objekt deiner Klasse zu.

--

Der Horizont vieler Menschen ist ein Kreis mit Radius Null - und das nennen sie ihren Standpunkt.

zum Seitenanfang zum Seitenende Profil || Suche
005
28.05.2001, 20:34
Another1



gehts nit einfach die reine adresse der function irgendwie in nem void* zu speichern (letztendlich is es ja auch nur ne adresse =)

so wie

Quellcode:
GLWindow* pYourWin = new GLWindow(...) ....
[...]
void *pfnFunc = (void*)(pYourWin->pWndProc);
tpWndProc pWndProcFunc;
pWndProcFunc = (tpWndProc*)pfnFunc;
[...]
WNDCLASS.lpfnWndProc = pWndProcFunc;

... eigentlich müsste das doch hinhauen .. oder? gib mal deine ICQ please, ich glaub da kommen wir weiter *G*

--

Another1

...relaxing..atm =)
... und Schweiz suckt!

zum Seitenanfang zum Seitenende Profil || Suche
006
28.05.2001, 20:51
Gandalf



Also mal danke an alle die mir geantwortet haben: )

@static_caster:
Hehe ich kann die Frage ja nicht mal auf deutsch so stellen das man sie beim ersten mal durchlesen versteht :) und auf englisch gleich gar ned :)
Null And Void kenn ich übrigens.. der is auch im gamedev forum :)

@Killing Me Softly:
Das geht leider nicht so einfach, weil WNDCLASS ist eine Struktur der Win32 API, und die will eben leider keine Funktionszeiger die über eine Klasse deklariert sind... :(

@Another1:
Ich hab die ICQ nummer im Profil eingetragen...
Wär echt lässig wenn wir das schaffen :) mit Void Zeigern hab ich mir auch schon gedacht das das unter Umständen gehen könnte, aber dann im Endeffekt hab ich keine Idee gehabt wie ich das am besten löse :)

--

Gandalf
Mein Rekord: 57 :)
Gekillte Gelsen Zähler (2001):9

zum Seitenanfang zum Seitenende Profil || Suche