Jump to content
  • Advertisement
Sign in to follow this  
EnlightenedOne

Wrapping DXUT into a class

This topic is 2803 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello forum,

I will try to be very brief as I am rewriting this due to the new forum redirecting my page.

I wanted to wrap DXUT into a class so I could manage it in a convenient and logical way. I created this class and made it a header file:

[font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"]class[/font][/font][/font][font="Consolas"][font="Consolas"] DXUTWrapperClass
{
[/font][/font][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"]public[/font][/font][/font][font="Consolas"][font="Consolas"]:
DXUTWrapperClass();
[/font][/font][font="Consolas"][font="Consolas"]LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, [/font][/font][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"]bool[/font][/font][/font][font="Consolas"][font="Consolas"]* pbNoFurtherProcessing, [/font][/font][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"]void[/font][/font][/font][font="Consolas"][font="Consolas"]* pUserContext )
[/font][/font]
I created a global variable in the entry point of the program which for convenience I dumped where I had created the classes methods in its cpp file.



[font="Consolas"][color="#008000"][font="Consolas"][color="#008000"][font="Consolas"][color="#008000"]//Global variable of the dx wrapper class
[/font][/font][/font][font="Consolas"][font="Consolas"]DXUTWrapperClass g_Engine;

I then in the entry point of the program added this line and got the following errors with it.

1. [font="Consolas"][font="Consolas"]DXUTSetCallbackMsgProc( g_Engine.MsgProc ); - [font="Consolas"][size="1"][font="Consolas"][size="1"]error C3867: 'DXUTWrapperClass::MsgProc': function call missing argument list; use '&DXUTWrapperClass::MsgProc' to create a pointer to member

2. [font="Consolas"][font="Consolas"]DXUTSetCallbackMsgProc( &DXUTWrapperClass::MsgProc ); - [font="Consolas"][size="1"][font="Consolas"][size="1"]error C2664: 'DXUTSetCallbackMsgProc' : cannot convert parameter 1 from 'LRESULT (__stdcall DXUTWrapperClass::* )(HWND,UINT,WPARAM,LPARAM,bool *,void *)' to 'LPDXUTCALLBACKMSGPROC'

I desperately need to find a way to force feed DXUTSetCallbackMsgProc() an instanced classes method to call so I can progress on. I started looking at rewriting DXUT but then realised I was only hurting myself doing it. Does anyone know if thats possible or a better alternative means of achieving this goal?

p.s aplogise for not using code wrapping the FAQ section has dissapeared and the code snippet button injects loads of html formatting garbage.

[/font][/font][/font][/font][/font][/font][/font][/font][/font][/font]

Share this post


Link to post
Share on other sites
Advertisement
[font="Verdana"]All instances of a class have the same addresses for member functions, since they are shared (you dont write a different code for a member function for each instance created). So trying to access a member function's address via an instance is unnecessary. So you should use [/font][color="#1C2837"][font="Consolas"]&DXUTWrapperClass::MsgProc [/font][color="#1C2837"][font="Verdana"]instead of[/font][color="#1C2837"][font="Consolas"] [/font][color="#1C2837"][font="Consolas"]g_Engine.MsgProc [/font][color="#1C2837"][font="Verdana"]as the compiler suggests. As for forcing it to be an instanced class, i dont know how to do that. But given that you will only have one instance of [/font][color="#1C2837"][font="Consolas"]DXUTWrapperClass [/font][color="#1C2837"][font="Verdana"]at a time, it shouldnt be a problem.[/font]

Share this post


Link to post
Share on other sites
I would take a static class at the moment!


[font="Verdana"]So you should use [/font][color="#1c2837"][font="Consolas"]&DXUTWrapperClass::MsgProc [/font][color="#1c2837"][font="Verdana"]instead of[/font][color="#1c2837"][font="Consolas"] [/font][color="#1c2837"][font="Consolas"]g_Engine.MsgProc [/font][color="#1c2837"][font="Verdana"]as the compiler suggests.[/font]



That would be great but look at error 2 in the original post DXUT expects a none class type function to plug into it, completely removing an OO approach to wrapping it.

Share this post


Link to post
Share on other sites
The last parameter of the LPDXUTCALLBACKMSGPROC is a void pointer to be used as a user context. Like most callback functions that allow a user context to be supplied it can be used to translate a standard function pointer to a member function via a trampoline function. Ex:

struct Foo {
LRESULT ActualMsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool * pbNoFurtherProcessing) {
/* stuff */
}
static LRESULT StaticMsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool * pbNoFurtherProcessing, void* pUserContext) {
Foo * instance = static_cast<Foo *>(pUserContext);
return instance->ActualMsgProc(hWnd, uMsg, wParam, lParam, pbNoFurtherProcessing);
}
};

Share this post


Link to post
Share on other sites
Thankyou SiCrane that certainly is the most composed example of what I need to achieve I have seen.



struct Foo {
LRESULT ActualMsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool * pbNoFurtherProcessing) {
/* stuff */
}
static LRESULT StaticMsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool * pbNoFurtherProcessing, void* pUserContext) {
Foo * instance = static_cast<Foo *>(pUserContext);
return instance->ActualMsgProc(hWnd, uMsg, wParam, lParam, pbNoFurtherProcessing);
}
};



I understand this code to a reasonable extent I believe I can build it, I have never dealt with building a wrapper with callbacks involved before I usually just use a direct X 9 or 10 device class to develop a wrapper without an external (I guess the correct term is) "helper library" so user context pointers are a new horizon to process along with a static_cast. Looking at the MSDN for static_cast should any proper use of it not be superceded with safe_cast? or is static_cast garunteed to function as I am handling fairly specific DXUT components. I assume the DXUT library is built for this sort of cast as UserContext is provided.

May I ask for some further clarity:
Would you contain this struct holding the function and its trampoline function inside of the class with a pointer to a struct of Foo in order to use the function?
If the above assumption is correct then does this syntax look vaguely accurate to the callback assignment? "[font="Consolas"][font="Consolas"]DXUTSetCallbackMsgProc( [font="Consolas"][font="Consolas"]&DXUTWrapperClass:: p_FooStruct[/font][/font] )"[/font][/font]

Share this post


Link to post
Share on other sites
safe_cast is C++/CLI, not standard C++ - different, but related, languages. DXUTSetCallbackMsgProc() takes two arguments: the first is a function pointer, the second is a user context pointer. For the first argument you would pass &Foo::StaticMsgProc. For the second argument you would use the address of a Foo object that you want the callback to be called on.

Share this post


Link to post
Share on other sites

DXUTSetCallbackMsgProc() takes two arguments: the first is a function pointer, the second is a user context pointer. For the first argument you would pass &Foo::StaticMsgProc. For the second argument you would use the address of a Foo object that you want the callback to be called on.


I was literally just figuring out how to pass in the context to a variable at the trampoline after realising it was not going to work by magic when you said that.

[font="Consolas"][font="Consolas"]DXUTSetCallbackMsgProc( &DXUTWrapperClass::StaticMsgProc, &g_Engine );
[font="Consolas"][font="Consolas"]

LRESULT CALLBACK DXUTWrapperClass::StaticMsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, [/font][/font][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"]bool[/font][/font][/font][font="Consolas"][font="Consolas"]* pbNoFurtherProcessing, [/font][/font][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"]void[/font][/font][/font][font="Consolas"][font="Consolas"]* pUserContext)
{
DXUTWrapperClass *p_DXUTWInstance = [/font][/font][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"]static_cast[/font][/font][/font][font="Consolas"][font="Consolas"]<DXUTWrapperClass *>(pUserContext);
[/font][/font][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"] return[/font][/font][/font][font="Consolas"][font="Consolas"] p_DXUTWInstance->ActualMsgProc(hWnd, uMsg, wParam, lParam, pbNoFurtherProcessing);
}

LRESULT CALLBACK DXUTWrapperClass::ActualMsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, [/font][/font][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"][font="Consolas"][color="#0000ff"]bool[/font][/font][/font][font="Consolas"][font="Consolas"]* pbNoFurtherProcessing )

[font="Arial"]I plugged it all in correctly and it works like a dream, thank you soooo much for this! I would never have cracked this without your assistance, I feel like I took another big step into making fully competent c++ programmer :) there is so very much to know, just when you think you have the principles nailed a concept like callbacks springs up! I am greatly indebted to you SiCrane!

:D[/font][/font][/font][/font][/font]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!