Sign in to follow this  

Linking WM Messages to functions?

This topic is 4306 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

I've been building up my window class and now I want to try and link up any message with any function that I set. I want to be able to do something like this:
MyWindow->SetHandler( WM_SIZE, MyRenderer->OnResize );


Could someone explain how this could be done? Thanks!

Share this post


Link to post
Share on other sites
Emmanuel's approach is a lot more straightforward than the MFC approach - although the MFC approach operates in much the same way. The difference is that MFC is designed to handle every possible message - which is a whole lot of overkill.

Share this post


Link to post
Share on other sites
I think this is what you're looking for. Sorry there are no comments; it's something I just whipped up in about an hour. You can safely ignore the CLR stuff too :D

Basically the important method to look for here is:


template< class T >
RegisterMessageHandler( UINT message, long(T::*ptr)( long, long ) )
{
m_msgMap[message] = (FuncPtr)ptr;
}




but here's the whole source file. (the whole thing was just an experiment really with something completely different and you wouldn't want to use this bunch of code as-is as it has serious issues, but it should provide a solution to your particular problem. :D )


#include "first.h"
#include <stdarg.h>

#using <mscorlib.dll>
#using <system.windows.forms.dll>
#using <system.dll>
#using <system.drawing.dll>
#include <vcclr.h>

class WinBase;

using namespace std;

namespace
{
WinBase * s_wndCreate = 0;

typedef std::map< HWND, WinBase * > WindowMapT;
WindowMapT s_wndMap;

void DebugOutput( const char *format, ... )
{
va_list args;
va_start( args, format );

char buf[1024];
_vsnprintf( buf, sizeof( buf ), format, args );
va_end( args );

OutputDebugString( buf );
}
}

class WinBase
{
public:
WinBase()
: m_hwnd(0)
, m_parent(0)
{
}

virtual ~WinBase()
{
if ( m_hwnd )
DestroyWindow(m_hwnd);
}

virtual bool Create( int style = WS_OVERLAPPEDWINDOW | WS_VISIBLE, WinBase * parent = 0 )
{
m_parent = parent;

// generate random class name
std::string className = "class_name_";
for ( int i = 0; i < 8; ++i )
className += (char)(rand()%26+'A');

// create the window class
WNDCLASSEX wc;
memset( &wc, 0, sizeof( wc ) );
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc = WinBase::StaticWindowProc;
wc.hInstance = GetHInstance();
wc.lpszClassName = className.c_str();
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = CreateSolidBrush( RGB( rand(), 127, 127 ) );

ATOM result = RegisterClassEx( &wc );
assert( result );


s_wndCreate = this;
m_hwnd = CreateWindowEx( 0,
className.c_str(),
"Window",
style,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
parent ? parent->m_hwnd : 0,
0,
0,
0 );
s_wndCreate = 0;

PostCreate();

return true;
}

// -----------------------------------------------------------------------

virtual void PostCreate()
{
}

// -----------------------------------------------------------------------

virtual void MoveWindow( long x, long y, long w, long h )
{
DebugOutput( "x=%d y=%d w=%d h=%d", x, y, w, h );
::MoveWindow( m_hwnd, x, y, w, h, TRUE );
}

// -----------------------------------------------------------------------

virtual void MoveWindow( long x, long y )
{
RECT r;
GetWindowRect( m_hwnd, &r );
long width = r.right - r.left;
long height = r.bottom - r.top;
MoveWindow( x, y, width, height );
}

// -----------------------------------------------------------------------



virtual bool WindowProc( UINT msg, WPARAM wp, LPARAM lp, LRESULT *result )
{
MessageMapT::iterator it = m_msgMap.find( msg );

if ( it == m_msgMap.end() )
return false;


FuncPtr f = it->second;
*result = static_cast< LRESULT >( (this->*f)( static_cast<long>(wp), static_cast<long>(lp) ) );
return true;
}

template< class T >
RegisterMessageHandler( UINT message, long(T::*ptr)( long, long ) )
{
m_msgMap[message] = (FuncPtr)ptr;
}

static LRESULT CALLBACK StaticWindowProc( HWND wnd, UINT msg, WPARAM wp, LPARAM lp )
{

WindowMapT::iterator it = s_wndMap.find( wnd );

WinBase *win = 0;

if ( it == s_wndMap.end() )
{
assert(s_wndCreate);
win = s_wndCreate;
s_wndMap.insert( WindowMapT::value_type( wnd, win ) );
}
else
win = it->second;

assert(win);

LRESULT result;
bool handled = win->WindowProc( msg, wp, lp, &result );

if ( !handled )
{
result = DefWindowProc( wnd, msg, wp, lp );
}

return result;
}

static void Run()
{
MSG msg;

while ( GetMessage( &msg, 0, 0, 0 ) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

static void Init( HINSTANCE hInstance )
{
GetHInstance() = hInstance;
}

// -----------------------------------------------------------------------

WinBase *GetParent() const
{
return m_parent;
}

HWND GetHwnd() const
{
return m_hwnd;
}

protected:
HWND m_hwnd;
WinBase *m_parent;

typedef long(WinBase::*FuncPtr)(long,long);
typedef std::map< UINT, FuncPtr > MessageMapT;
MessageMapT m_msgMap;

private:
static HINSTANCE& GetHInstance()
{
static HINSTANCE hinstance;
return hinstance;
}
};

class MyWindow
: public WinBase
{
public:
MyWindow()
{
RegisterMessageHandler( WM_CREATE, OnCreate );
RegisterMessageHandler( WM_DESTROY, OnDestroy );
}

long OnCreate( long, long )
{
return 0;
}

long OnDestroy( long, long )
{
PostQuitMessage(0);
return 0;
}
};

//////////////////////////////////////////////////////////////////////////


class ToolWindow
: public WinBase
{
public:
ToolWindow()
: m_isDragging(false)
, m_isFloating(false)
{
RegisterMessageHandler( WM_LBUTTONDOWN, LButtonDown );
RegisterMessageHandler( WM_LBUTTONUP, LButtonUp );
RegisterMessageHandler( WM_MOUSEMOVE, MouseMove );
RegisterMessageHandler( WM_LBUTTONDBLCLK, LButtonDblClk );

}

virtual long LButtonDown( long wp, long lp )
{
if ( !m_isFloating )
{
SetCapture(m_hwnd);
m_isDragging = true;
}

GetCursorPos( &m_last );

return 0;
}

virtual long LButtonUp( long, long )
{
ReleaseCapture();
m_isDragging = false;
return 0;
}

virtual long MouseMove( long, long lp )
{
if ( !m_isDragging )
return 0;

POINT pt;
GetCursorPos(&pt);

long dx = pt.x - m_last.x;
long dy = pt.y - m_last.y;

m_last = pt;

// -----------------------------------------------------------------------
// get the window info for the parent window
WINDOWINFO wi;
wi.cbSize = sizeof(wi);
GetWindowInfo( m_parent->GetHwnd(), &wi );

// -----------------------------------------------------------------------
// compute the current offset from the parent
RECT wr;
GetWindowRect( m_hwnd, &wr );
POINT ofs;
pt.x = wr.left - wi.rcClient.left;
pt.y = wr.top - wi.rcClient.top;

// -----------------------------------------------------------------------
// offset the window position relative to the parent client area
pt.x += dx;
pt.y += dy;

SetWindowPos( m_hwnd, 0, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER );

return 0;
}

virtual long LButtonDblClk( long, long )
{

if ( m_isFloating )
{
// -----------------------------------------------------------------------
// dock the window
LONG_PTR style = GetWindowLongPtr( m_hwnd, GWL_EXSTYLE );
style &= ~WS_EX_TOOLWINDOW;
SetWindowLongPtr( m_hwnd, GWL_EXSTYLE, (LONG)style );


style = GetWindowLongPtr( m_hwnd, GWL_STYLE );
style &= ~( WS_CAPTION | WS_THICKFRAME | WS_POPUP);
style |= WS_BORDER | WS_CHILD;
SetWindowLongPtr( m_hwnd, GWL_STYLE, (LONG)style );

SetParent( m_hwnd, m_parent->GetHwnd() );
SetWindowPos( m_hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED );
}
else
{
LONG_PTR style = GetWindowLongPtr( m_hwnd, GWL_EXSTYLE );
style |= WS_EX_TOOLWINDOW;
SetWindowLongPtr( m_hwnd, GWL_EXSTYLE, (LONG)style );

style = GetWindowLongPtr( m_hwnd, GWL_STYLE );
style &= ~( WS_BORDER | WS_CHILD );
style |= WS_CAPTION | WS_THICKFRAME | WS_POPUP;
SetWindowLongPtr( m_hwnd, GWL_STYLE, (LONG)style );

SetParent( m_hwnd, 0 );
SetWindowPos( m_hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED );

}

m_isFloating = !m_isFloating;

return 0;
}

virtual bool Create( WinBase *parent )
{
return WinBase::Create( WS_BORDER | WS_CHILD | WS_VISIBLE | WS_SYSMENU , parent );
}

private:
bool m_isDragging;
POINT m_last;
bool m_isFloating;
};

class TreeView
: public ToolWindow
{
public:

TreeView()
{
m_foo = new System::Windows::Forms::ListBox();
RegisterMessageHandler( WM_SIZE, OnSize );
}

long OnSize( long , long )
{
if ( m_hwnd )
{
RECT r;
GetClientRect(m_hwnd, &r);

long width = r.right;
long height = r.bottom;
m_foo->SetBounds( 0, 0, width, height, System::Windows::Forms::BoundsSpecified::All );
m_foo->Show();
return 0;
}

}
void PostCreate()
{
using namespace System;

HWND h = (HWND)m_foo->Handle.ToPointer();
SetParent( h, m_hwnd );

m_foo->Show();

RECT r;
GetClientRect( m_hwnd, &r );

m_foo->SetBounds( 0, 0, r.right, r.bottom, Windows::Forms::BoundsSpecified::All );

}

gcroot<System::Windows::Forms::ListControl*> m_foo;

};

//////////////////////////////////////////////////////////////////////////


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int )
{
//////////////////////////////////////////////////////////////////////////
//

WinBase::Init(hInstance);


WinBase *wnd = new MyWindow();
wnd->Create();

ToolWindow *tw = new TreeView();
tw->Create(wnd);
tw->MoveWindow( 0, 0, 512, 512 );


WinBase::Run();

}



Share this post


Link to post
Share on other sites

This topic is 4306 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this