PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [C++/MFC] Member Funktion aus CALLBACK Funktion aufrufen


BavariaBlade
2006-08-10, 20:27:03
Hi,

der Windows MultimediaTimer führt immer diese Funktion aus:

void CALLBACK MMTimerProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
{
.....
}


Da es eine Callback Funktion ist, steht sie außerhalb meiner Klasse.
wie kann ich diese Funktion dazu überreden eine nicht static member Fuktion auszuführen, z.B. so:

void CALLBACK MMTimerProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
{
D3DAPP::Render();
}


HIIILLFEEE *g*

Matrix316
2006-08-10, 21:34:46
Kommt so ne Fehlermeldung, dass er keine non-static member function aufrufen kann? Ich glaube, dann gehts nicht. Sowas ähnliches hatte ich auch mal vor einiger Zeit.

tokugawa
2006-08-10, 21:48:28
Bei MS APIs sind Callback-Funktionen immer so designt dass du einen "User-pointer" mitliefern kannst. Über diesen kannst du einen Pointer auf die Instanzvariable des Objekts das du brauchst übergeben, und dann darüber die Methode aufrufen.

BavariaBlade
2006-08-11, 12:07:29
Juhu,
danke es geht!! Für Leute die ähnliche Probleme haben hier mal mein pseudo Code:

3DApp.h:



//Header für den MultimediaTimer einbinden
#include "mmsystem.h"
#include "windows.h"

class 3DApp
{
public:
bool m_timerActive;
void Render();
}
// außerhalb der Klasse die CALLBACK Funktion deklarieren
void CALLBACK MMTimerProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2);



3DApp.cpp:

//Konstruktor
3DApp::3DApp()
{
//Pointer der Klasse 3DApp in DWORD_PTR casten und in usr speichern
DWORD_PTR usr =(DWORD_PTR)this;

// Multimedia Timer starten
// (Intervall: 20 Millisekunden, Auflösung: 1 Millisekunde, Pointer:usr mit übergeben, Timereinstellungen:mit Callback und periodisch):
timeSetEvent(20, 1, (LPTIMECALLBACK)&MMTimerProc ,usr, TIME_CALLBACK_FUNCTION | TIME_PERIODIC);
}

void 3DApp::Render()
{
.....
}

void CALLBACK MMTimerProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
{

if (((3DApp*)dwUser)->m_timerActive == false)
{
// Timer killen
timeKillEvent(uTimerID);

}
else{
//so greife ich dann auf die MemberFunktion von 3DApp zu
((3DApp*)dwUser)->Render();
}


}



Anders als den wm_timer müsst ihr diesen timer unbedingt killen, sonst gibt es Probleme.
Der Multimediatimer (bis zu 1ms) ist sehr viel genauer als der wm_timer(ca. 55ms). Der Multimediatimer läuft zudem in einem extra thread. Wenn ihr noch mehr dazu wissen wollt:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_multimedia_timers.asp

Danke nochmal,
servus BB

tokugawa
2006-08-11, 19:17:39
Schön, dass es geklappt hat :)

Ein paar Anmerkungen noch:
1) man könnte die Callback-Funktion als syntaktischen Teil der Klasse deklarieren, als statische Funktion, also


class 3DApp
{
public:
bool m_timerActive;
void Render();

static void CALLBACK MMTimerProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2);
};


Und dann halt bei der Implementation:


void CALLBACK D3DApp::MMTimerProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
{
usw.
}


(Änderungen in Fettschrift)

2) Ist das wirklich so beabsichtigt das Rendern mit fixem periodischem Time-Step mittels Timer zu machen? Wenn ja, ist das so ok.

Wenn das aber so sein soll wie bei den meisten Spielen/3D-Anwendungen, dann wird das normalerweise so gemacht dass Render() in der Messageloop so oft wie möglich aufgerufen wird, und nur dann wenn Events in der Messagequeue sind, diese verarbeitet werden.

Allerdings weiß ich nicht, wie man das in MFC machen würde.

Crazy_Chris
2008-05-15, 17:42:50
*push* :eek:

Was mache ich wenn in der CALLBACK Routine nicht bekannt ist was für ein Objekt übergeben wurde und dementsprechend der Compiler nicht weiß welche Funktion da aufgerufen wird?

So funktioniert es leider nicht: :frown:

extern "C"
void CALLBACK timerServiceRoutine( UINT id, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2 )
{
DWORD_PTR* unbekanntesObjekt = (DWORD_PTR*) dwUser;
unbekanntesObjekt->DoSomething();
}

unbekanntesObjekt ist ja nur ein anonymer DWORD Pointer.

Danke :|

del_4901
2008-05-15, 21:59:42
dynamic_cast<> prüft zur Laufzeit ob der Objekttyp stimmt.

Crazy_Chris
2008-05-15, 22:48:37
dynamic_cast<> prüft zur Laufzeit ob der Objekttyp stimmt.


Funktioniert das nicht nur in einer Vererbungshierarchie? :confused:

Ectoplasma
2008-05-16, 00:17:42
extern "C"
void CALLBACK timerServiceRoutine( UINT id, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2 )
{
DWORD_PTR* unbekanntesObjekt = (DWORD_PTR*) dwUser;
unbekanntesObjekt->DoSomething();
}

Das kann nicht gehen, weil du eine Vererbungshierarchie brauchst. Das obige Konstrukt funktioniert übrigens mit keiner Sprache der Welt. Du brauchst zumindest so etwas wie ein Object Typ, von dem sich alle anderen Klassen abgeleitet haben. Crazy_Chris hat das schon richtig bemerkt.

del_4901
2008-05-16, 00:25:37
Das kann nicht gehen, weil du eine Vererbungshierarchie brauchst. Das obige Konstrukt funktioniert übrigens mit keiner Sprache der Welt. Du brauchst zumindest so etwas wie ein Object Typ, von dem sich alle anderen Klassen abgeleitet haben. Crazy_Chris hat das schon richtig bemerkt.
naja den kann man sich ja schnell selber bauen und static casten.