Updating a pointer outside function

Started by
4 comments, last by Erzengeldeslichtes 17 years, 9 months ago
Hello. For a little D3D 'wrapper' project I'm doing (just putting learned stuff into a class) I need to create a 'gameloop' function. Basically this function would just enter the standard program loop, and it is customisable because the user can pass a function pointer as first argument. That function will the be used as 'content' of the loop. However, to allow for a bit more flexibility, I also want the user to be able to access the MSG struct so that he/she can deal with windows messages him/her self. I actually have two questions in regards to this: 1. Is it possible at all, to have a MSG pointer point to a MSG struct that is initialized in a function (not in same scope)? 2. If so, how would I do that? I imagine the function call would be a bit like the D3D matrix functions where you pass the address of the matrix to be changed, but I have no idea how those functions look 'from the inside' :P 3. If not, how could I then give control over the MSG struct to the user? I was thinking of perhaps giving the class a MSG member, but if it is avoidable I would rather not do that because I want the user to be able to specify his own MSG struct name that he wants to be able to monitor... Edit: to test things I used the MSG struct as a class member. This does not work quite fine yet. I'll show the situation:

// Create an instance of my class
u3D::IUniverse3DInterface u;

// The function that will be used in the game loop
bool SampleFunction ( void )
{
    if ( u.msg.message == WM_KEYDOWN && u.msg.wParam == VK_ESCAPE ) {
        DestroyWindow ( u.WindowHandle );
        return false;
    }
    
    return true;
}

int WINAPI WinMain ( (left parameters out) )
{
    u.CreateScreen ( leaving parameters out );

    u.InitGameLoop ( SampleFunction );

    return 0;
}

The InitGameLoop takes the 'loop function' as an argument but somehow the 'msg' member of the class doesn't become available to that function ( My compiler VC++ 6.0 doesn't make a problem out of it though ). In any case, if I press escape, the window doesn't close. [Edited by - rogierpennink on July 19, 2006 9:27:47 AM]
Advertisement
You don't use the MSG structure yourself, you pass it into PeekMessage, GetMessage, TranslateMessage, and DispatchMessage. To handle windows messages you define a Window Procedure in your window class:
LRESULT CALLBACK WindowProc(HWND hw, UINT msg, WPARAM w, LPARAM l){/*Etc*///This is necessary. Always send any messages you don't handle into //DefWindowProc or Microsoft programmers will get very annoyed with you.return DefWindowProc(hw, msg, w, l); }WNDCLASS wc = {0};//This is necessary, windows won't register the class if the size isn't right.wc.cbSize = sizeof(wc);//Now you set the actual window procedure.//This will be called during DispatchMessage.wc.lpfnWndProc = WindowProc;//This is necessary to indentify your class.wc.lpszClassName = "MyClass";//Now you register it so that you can use it.RegisterClass(&wc);//Now use it by creating a window.CreateWindow("MyClass", /*etc*/);//pragma region and pragma endregion are useful in MSVC to group peices of code#pragma region "Message Loop"//Now for the MSG structure.MSG msg;do{	//Yield some processor to fellow processes.	Sleep(0);	//Get any messages without suspending the process	while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))	{		//Now translate and dispatch the messages to their proper		//window procedures		TranslateMessage(&msg);		DispatchMessage(&msg);		//And just in case, if we've been asked to quit we will.		//This is one of the few messages to handle outside a window proc.		if(msg.message == WM_QUIT) goto Break;	}//Use (bool PerFrameRender()) to render each frame and return true to continue.} while(PerFrameRender());//Yes, yes, "gotos are 3v1l"//But more readable than trying to put in a while(DontQuit && PerFrameRender());Break://Other Stuff#pragma endregion


So if you want your user to have access to window messages, you'll have to give them access to your window procedure. If you don't know this, you should probably concentrate on making a complete functional program for yourself before you start one that is intended for other people.

Of course, there are ways to do what you ask, and it's quite simple to do what you ask (friends, globals), but you should not be doing what you're asking to do. You should look for some tutorials on the 'net, or you can use the Platform SDK's help documentation's development guides (Win32&Com Development->Development Guides->Windows API->Windows API->A Generic Sample Application is where it's found in MSVC2k5 Pro's help files).

[Edited by - Erzengeldeslichtes on July 19, 2006 11:59:58 AM]
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
Yes, I understand the message loop. Basically, my class has a 'standard' message function that only checks for the WM_DESTROY event. The user can set a self-made message function as default if he/she wants to.

However, what I do fairly often when I can't be bothered to customise the message loop just for making my program close on an ESC keypress is to just add a check before TranslateMessage and DispatchMessage and act upon that.

I wanted my class to offer this same flexibility by allowing the user to use the public MSG struct in his/her own game loop. What I don't understand is, I have no problem using the msg struct for that purpose in the InitGameLoop, but somehow an 'outside' function can't use the public MSG member of the class...
Reacting to the MSG struct is a bad thing. Imagine, if you will, calling CreateWindow("BUTTON", /*etc*/);. You now have a button in your application, and it has its own window procedure. But some hypothetical function which checks someMsg.message == WM_KEYDOWN && someMsg.wparam == VK_ENTER doesn't care, and reacts to the enter key even though the button wants to react to it too, causing side effects the user didn't intend.

You can't tell me this won't happen--you said this was for a user to use. You can't guarentee how the user will use it.

Stick with window procedures. If you want a flexible window procedure, use std::map<HWND, std::map<UINT, bool(*)(LRESULT&, WPARAM, LPARAM)> >--you can insert your windows and message function pointers as you want. I use an HWND of 0 to indicate "global", except in my case it's "If the window didn't specify a message or returned false", which prevents side-effects.

For more flexibility you can use boost::function instead of bare function pointers.
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
Well, I'm not such an advanced C++ user that I know much about std::map nor about the boost library.

But I always had this idea that windows sends messages to the WindowProc function via TranslateMessage and DispatchMessage. If I react on say, the escape key by checking the contents of msg.message and msg.wparam, then the actions in the WindowProcedure can still be done on that event, can't they?

I assume the user is indeed unpredictable and that handling a message twice this way could cause conflicts, but by user I meant me and maybe one or two friends, so it isn't really what you'd call 'public'.

For your information however, I think I found the problem. The 'user' function was called after TranslateMessage and DispatchMessage, which rules out any of this 'pre-processing' I imagined to have in my class.

Thanks for your information though, I will surely read up on std::map and possibly on the boost library as well...
Yes, the window procedure can be called afterward. Heck, you could probably fill the MSG struct yourself and feed it to TranslateMessage. It's just not a good idea. Both can have side-effects that make the program behave oddly.


The point is, Microsoft tells you how you're supposed to interact with Windows through the API. If you don't do it the way they recommend, then they don't guarentee that you will get expected results.

For example, Microsoft says that if you do not handle a message, you should return DefWindowProc (Otherwise they get a bit annoyed). They also state what you should return if you DO handle the message. Right now, you're handling the message without actually returning the code for having handled it. Even if you yourself never use a message twice, if Microsoft makes a change to DefWindowProc, your program may behave eratically, with unintended side-effects.

As for std::map, I recommend learning the standard template library. It makes programming easier. Boost is nice to have, but everyone has STL so it's the most useful.

If you don't know the STL, you're probably not advanced enough to deal with the complexities of making an application with exposed functionality. Why not just make a program which is self contained and functional? It's easier and causes fewer headaches.

[Edited by - Erzengeldeslichtes on July 19, 2006 2:29:18 PM]
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?

This topic is closed to new replies.

Advertisement