Skip to main content
GameDev.net gamedev.net
🔒 Locked

[SOLVED]WndProc

Started by Aidamina Sep 10, 2005 at 4:13 AM 21 replies 6.1k views
Original Post
Aidamina
Aidamina
I'm writing a program that uses opengl but i got a problem: I got a class which initialises the opengl window and i got the WndProc in another class. I use this:

wc.lpfnWndProc = (WNDPROC )p_trendering->p_tengine->WndProc;
To point to:

 LRESULT CALLBACK  engine::WndProc(HWND hwnd, UINT msg, WPARAM  wParam, LPARAM lParam)
which is declared static in the class. But in the WndProc function i can't call any member of the engine class. Like:

tengine->myfunction();
where tengine is an instance of the class and myfunction a function. Any suggestions? [Edited by - Aidamina on September 12, 2005 6:03:27 AM]
-->My Site<--
tompp
tompp
right here on gamedev

http://www.gamedev.net/reference/articles/article1810.asp
Beware of the Mighty Hamster!
Aidamina
Aidamina
Thx for the link but that doesnt solve my issue, because i don't know a good way to implement this whole new class in my engine.

I tried google but i don't really know where to look for....

Anyone else got some suggestions?
-->My Site<--
dave
dave
If i understand you correctly, you cant access the parts of the class from the static member.

Well if this is the case this is a solution which is a little messy but good enough. Firstly make another static member call m_pThis or something and in the constructors initialisation list give it the value 'this'. So now u have a static pointer to this. Don't forget to give this value some substance by putting myclass::m_pThis in the CPP file.

Now in the static file you can do:

m_pThis->Member();

or whatever.

Hope you understand, if not reply and i will try again [smile].

ace

Aidamina
Aidamina
I understand and i thought it would work but it throws this:

Unhandled exception at 0x00421f68 in engine.exe: 0xC0000005: Access violation reading location 0xcdcdcdd1.

when i do:

m_pThis->AnotherClass->myfunction();

and yes i did this:

engine * engine::m_pThis=NULL;

and this:

engine::engine(void)
{
m_pThis=this;



}
-->My Site<--
dave
dave
What is the value of the pointer when u try and dereference it?
iliak
iliak
Here maybe ?
- Iliak -
[ ArcEngine: An open source .Net gaming framework ]
[ Dungeon Eye: An open source remake of Eye of the Beholder II ]
JohnBolton
JohnBolton
Quote:
Original post by Aidamina
Unhandled exception at 0x00421f68 in engine.exe: 0xC0000005: Access violation reading location 0xcdcdcdd1.

0xcdcdcdcd is a special value that Visual Studio uses to indicate uninitialized data. 0xcdcdcdd1 is 0xcdcdcdcd + 4 -- you are using an uninitialized pointer.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Aidamina
Aidamina
Ok this might be help full and i got it working partially

I can now acces private members of the class, but i can't acces public pointer members:

Unhandled exception at 0x0042200b in engine.exe: 0xC0000005: Access violation reading location 0xcdcdcdd1.

CAN DO:

engine* p_engine=NULL;
p_engine = (engine*)GetWindowLong(hwnd, GWL_USERDATA);
p_engine->keys[0]=true; //privat member

CAN NOT DO:

engine* p_engine=NULL;
p_engine = (engine*)GetWindowLong(hwnd, GWL_USERDATA);
p_engine->trendering->topengl->setstate(true); //trendering is pointer to class

ALSO TRIED:

engine* p_engine=NULL;
p_engine = (engine*)GetWindowLong(hwnd, GWL_USERDATA);
if (p_engine)
p_engine->trendering->topengl->setstate(true); //trendering is pointer to class

Any suggestions?
-->My Site<--
barrysee
barrysee
If you're so bent on using your class in your static callback function, why not just use a global variable that points to your class:

my_class* cptr;

my_class::my_class()
{
cptr = this;
}

LRESULT CALLBACK my_class::WndProc(HWND wnd, int Msg, WPARAM wParam, LPARAM lParam)
{
cptr->whatever_function();
// ...
}
Aidamina
Aidamina
Nope i wanna avoid globals, i know im a bitch, you dont have to tell me :P
-->My Site<--
JohnBolton
JohnBolton
Quote:
Original post by Aidamina
CAN NOT DO:
p_engine->trendering->topengl->setstate(true); //trendering is pointer to class

The problem has nothing to do with private and public members.

p_engine (or p_engine->trendering) points to uninitialized data. Thus, p_engine->trendering (or p_engine->trendering->topengl) has the value 0xcdcdcdcd.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
sathenzar
sathenzar
So I take it you don't want to take a single point of reference method? B/c that might make your engine work a little easier.
Aidamina
Aidamina
JohnBolton:

I'm sure i initialised the data before i create the window.
Actually the window is created in the topengl class

sathenzar:

I'm not sure what you mean, is it a global pointer to the engine class, ifso i dont want globals periode

to all:

When does the wndproc get called for the first time?
After the window creation?
-->My Site<--
bjogio
bjogio
try this:
LRESULT CALLBACK MessProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){   Engine* creator;   //.....   case WM_CREATE:   {		      if(((LPCREATESTRUCT)lParam)->dwExStyle & WS_EX_MDICHILD)      {         creator = (Engine*)((LPMDICREATESTRUCT)((LPCREATESTRUCT)lParam)->lpCreateParams)->lParam;      } else      {         creator = (Engine*)((LPCREATESTRUCT)lParam)->lpCreateParams;      }   //...}

and create the window like this:
Engine::CreateWindow(){   CreateWindowEx(blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, blah, this);}

in this way you will pass a pointer to your engine as the LPARAM of WM_CREATE message and you will be able to access to every member without the needing of a global object. If you want more explanation on the code ask.
[ILTUOMONDOFUTURO]
RDragon1
RDragon1
struct Engine{	LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { ... }}LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	if( engine.get() ) return engine->WndProc( hwnd, message, wParam, lParam );	else return DefWindowProc( hwnd, message, wParam, lParam );}std::auto_ptr<Engine> engine;int main(){	engine = new Engine;	...	engine.reset();}
Evil Steve
Evil Steve
bjogio's method will only work for the WM_CREATE message. What I think is happening, is Aidamina is using a similar message, but only initialising the pointer in WM_CREATE. So any other messages that come along (E.g. WM_NCCREATE which comes before WM_CREATE) will have an invalid pointer, which will have the value 0xcdcdcdcd.
You need to save off the pointer somnehow. Either using a static varible inside the static message proc, or by using the 32-bit extra data value that Windows gives every window. Here's what I do:
LRESULT CALLBACK CRenderWindow::StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){CRenderWindow* pParent;   // Get pointer to app //   if(uMsg == WM_CREATE)   {      // Save the pointer in the windows user data //      pParent = (CRenderWindow*)((LPCREATESTRUCT)lParam)->lpCreateParams;      SetWindowLongPtr(hWnd,GWL_USERDATA,(LONG_PTR)pParent);   }   else   {      // Get the pointer if it exists. If it doesn't, call default //      pParent = (CRenderWindow*)GetWindowLongPtr(hWnd,GWL_USERDATA);      if(!pParent) return DefWindowProc(hWnd,uMsg,wParam,lParam);   }   pParent->m_hWnd = hWnd;   return pParent->WindowProc(uMsg,wParam,lParam);}LRESULT CRenderWindow::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam){   // Usual message processing here}

That code will work fine, but you miss a WM_NCCREATE message (because the pointer isn't valid yet). That shouldn't really matter unless you're doing window skinning though.

Hope this helps.
bjogio
bjogio
sorry guys, a stupid mistake. The WndProc internal pointer must be declared static.

static Engine* creator = NULL;

in this way the pointer remain valid until all the life-time of the engine itself cause we can assume the WM_CREATE is the first message sent to the WndProc.
Here's the corrected code:
LRESULT CALLBACK MessProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){   static Engine* creator = NULL;   //.....   case WM_CREATE:   {		      if(((LPCREATESTRUCT)lParam)->dwExStyle & WS_EX_MDICHILD)         creator = (Engine*)((LPMDICREATESTRUCT)((LPCREATESTRUCT)lParam)->lpCreateParams)->lParam;      else creator = (Engine*)((LPCREATESTRUCT)lParam)->lpCreateParams;   }   //...}

too few hours of sleep = very stupid mistake
[ILTUOMONDOFUTURO]
Evil Steve
Evil Steve
Quote:
Original post by bjogio
in this way the pointer remain valid until all the life-time of the engine itself cause we can assume the WM_CREATE is the first message sent to the WndProc.
Actually, you get several messages before WM_CREATE:
WM_GETMINMAXINFO, WM_NCCREATE, WM_NCCALCSIZE, WM_CREATE in that order (Which also makes my post wrong - I said you only miss WM_NCCREATE...)

The point is though, you shouldn't assume that WM_CREATE is the first message you recieve. If you do that, you'll end up with an uninitialized pointer.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.