Can't call correct function using this pointer

Dec 11, 2010 at 6:12pm
Hello,

I want to make my GUI code object-oriented so I decided to create a class for dialogs ( class Dialog; )

Here's the code
dialog.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#ifndef DIALOG_H
#define DIALOG_H

#include <windows.h>

// get THIS pointer using GetWindowLong
template<typename T> T *get_this(HWND hwnd)
{
   LONG_PTR lptr=GetWindowLong(hwnd,DWL_USER);
   return reinterpret_cast<T*>(lptr);

}

// set THIS pointer using SetWindowLong
template<typename T> void init_set_this(HWND hwnd,LPARAM lParam)
{
   T *p= reinterpret_cast<T*>(lParam);
   SetWindowLong(hwnd,DWL_USER,(LONG_PTR)p);

}



class Dialog
{
protected:
  bool is_running;

  // static dialog procedure; redirects to the real dialog procedure
  static BOOL CALLBACK StaticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

public:
  bool Run();

  // Real dialog procedure
  BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
};


#endif


dialog.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include "dialog.h"


BOOL CALLBACK Dialog::StaticDlgProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
Dialog *dlg=get_this<Dialog>(hwnd);
switch(message)
  {
     case WM_INITDIALOG:
          init_set_this<Dialog>(hwnd,lParam);
          dlg=get_this<Dialog>(hwnd);
        // dlg->DlgProc(hwnd,message,wParam,lParam);
          return true;
  }

return dlg->DlgProc(hwnd,message,wParam,lParam); // Problem here: always calls Dialog::DlgProc
}


BOOL CALLBACK Dialog::DlgProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    return false;
}


bool Dialog::Run()
{
   return false;
}


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <windows.h>
#include "resource.h"

#include "dialog.h"


class TestDlg: public Dialog
{
public:
  bool Run();
  BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);



};


bool TestDlg::Run()
{
   DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_UNLOCK), NULL, StaticDlgProc,(LPARAM)this);
}


BOOL CALLBACK TestDlg::DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CLOSE:
            EndDialog(hwnd, 0);
            return TRUE;

        case WM_COMMAND:
            switch(LOWORD(wParam))
            {
                case IDCANCEL:
                  EndDialog(hwnd,0);
                  break;

            }
    }

    return FALSE;
}


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
TestDlg t;
t.Run();
}


I need to call TestDlg::DlgProc function from Dialog::StaticDlgProc. To do this, I pass this pointer for DialogBoxParam function. The problem is that return dlg->DlgProc(hwnd,message,wParam,lParam); //line 16, dialog.cpp calls dialog::DlgProc instead of TestDlg::DlgProc

Is there any way I can fix my code?

Thanks for help.



Last edited on Dec 11, 2010 at 6:15pm
Dec 13, 2010 at 8:29am
Static member functions like DlgProc don't mix with polymorphism. They are always determined based on the static type (Dialog) and never on the dynamic type (TestDlg).

Rule 1: If you want to use the polymorphic behavior you always need to use virtual functions!
Rule 2: Static functions cannot be virtual.

Solution:
* add a virtual function called getDlgProc accepting no arguments and returning a pointer to your callback function (maybe use a typedef for the callback signature to increase readability).
* since the function is virtual, it depends on the dynamic type and returns a pointer to the correct callback function.


Last edited on Dec 13, 2010 at 8:29am
Dec 14, 2010 at 6:11pm
I don't find a way to implement your suggestion in my code

I tried this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Dialog
{
protected:
  typedef BOOL (CALLBACK Dialog::*DLGPROC_INTERNAL)(HWND,UINT,WPARAM,LPARAM); // function pointer typedef

  bool is_running;

  // static dialog procedure; redirects to the real dialog procedure
  static BOOL CALLBACK StaticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  virtual DLGPROC_INTERNAL get_proc(); // get the window procedure

public:
  bool Run();

  // Real dialog procedure
  BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
};


// ...

// get the function pointer
Dialog::DLGPROC_INTERNAL Dialog::get_proc()
{
    return &Dialog::DlgProc;
}

// ...



But how do I call the dialog procedure? Every time I try I get errors, eg. dlg->get_proc()(hwnd,message,wParam,lParam); doesn't compile
Dec 15, 2010 at 10:40am
Maybe it's due to the placement of the macro CALLBACK in the typedef?
If you post the error messages, maybe I can give you a hint.

Btw.: Did you implement then get_proc function for the TestDlg class too?

Maybe try from this code. I tested it.
VirtualCallback.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma once
class Base
{
public:
  virtual ~Base();
  typedef void (*MyCallbackType) ();
  virtual MyCallbackType getProc();
  static void BaseCallback();
};

class Derived : public Base
{
public:
  MyCallbackType getProc();
  static void DerivedCallback();
};

void testVirtualCallback();


VirtualCallback.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include "StdAfx.h"
#include "VirtualCallBack.h"

#include <iostream>

Base::~Base()
{
}


void Base::BaseCallback()
{
  std::cout << "BaseCallback() called!\n";
}

Base::MyCallbackType Base::getProc()
{
  return & BaseCallback;
}


Derived::MyCallbackType Derived::getProc()
{
  return & DerivedCallback;
}

void Derived::DerivedCallback()
{
  std::cout << "DerivedCallback() called!\n";
}


void testVirtualCallback()
{
  Base* b = new Derived();
  
  b->getProc()();  // prints "DerivedCallback() called!"

  delete b;

}
Dec 15, 2010 at 5:57pm
I modified the code but now it crashes:

dialog.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#ifndef DIALOG_H
#define DIALOG_H

#include <windows.h>

// get THIS pointer using GetWindowLong
template<typename T> T *get_this(HWND hwnd)
{
   LONG_PTR lptr=GetWindowLong(hwnd,DWL_USER);
   return reinterpret_cast<T*>(lptr);

}

// set THIS pointer using SetWindowLong
template<typename T> void init_set_this(HWND hwnd,LPARAM lParam)
{
   T *p= reinterpret_cast<T*>(lParam);
   SetWindowLong(hwnd,DWL_USER,(LONG_PTR)p);

}



class Dialog
{
protected:
 // typedef BOOL (CALLBACK Dialog::*DLGPROC_INTERNAL)(HWND,UINT,WPARAM,LPARAM); // I use DLGPROC instead

  bool is_running;

  // static dialog procedure; redirects to the real dialog procedure
  static BOOL CALLBACK StaticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  virtual DLGPROC get_proc(); 

public:
  bool Run();

  // Real dialog procedure
  BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
};


#endif 


dialog.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "dialog.h"


BOOL CALLBACK Dialog::StaticDlgProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
Dialog *dlg=get_this<Dialog>(hwnd);
switch(message)
  {
     case WM_INITDIALOG:
          init_set_this<Dialog>(hwnd,lParam);
          dlg=get_this<Dialog>(hwnd);
        // dlg->DlgProc(hwnd,message,wParam,lParam);
          return true;
  }

return dlg->get_proc()(hwnd,message,wParam,lParam); // <----------- Program crashes here

}


BOOL CALLBACK Dialog::DlgProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    return false;
}


bool Dialog::Run()
{
   return false;
}

DLGPROC Dialog::get_proc()
{
    return (DLGPROC)&Dialog::DlgProc; 
}



main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <windows.h>
#include "resource.h"

#include "dialog.h"


class TestDlg: public Dialog
{
public:
   DLGPROC get_proc();
  bool Run();
  BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);



};


bool TestDlg::Run()
{
   DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_UNLOCK), NULL, StaticDlgProc,(LPARAM)this);
}

DLGPROC TestDlg::get_proc()  // get_proc function implemented in derived class
{
    return (DLGPROC)&Dialog::DlgProc;
}


BOOL CALLBACK TestDlg::DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CLOSE:
            EndDialog(hwnd, 0);
            return TRUE;

        case WM_COMMAND:
            switch(LOWORD(wParam))
            {
                case IDCANCEL:
                  EndDialog(hwnd,0);
                  break;

            }
    }

    return FALSE;
}


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
TestDlg t;
t.Run();
}


If I try to use DLGPROC_INTERNAL as a function pointer I get a bunch of errors...


Btw, one problem with your example is that Derived::DerivedCallback is static, so I had to modify it like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Base
{
public:
  virtual ~Base();
  typedef void (*MyCallbackType) ();
  virtual MyCallbackType getProc();
  static void BaseCallback();
};

class Derived : public Base
{
public:
  MyCallbackType getProc();
   void DerivedCallback(); // no static keyword here
};



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Base::~Base()
{
}


void Base::BaseCallback()
{
  std::cout << "BaseCallback() called!\n";
}

Base::MyCallbackType Base::getProc()
{
  return & BaseCallback;
}


Derived::MyCallbackType Derived::getProc()
{
  return (MyCallbackType)& Derived::DerivedCallback; // <-------------- casted to MyCallbackType 
}

void Derived::DerivedCallback()
{
  std::cout << "DerivedCallback() called!\n";
}


void testVirtualCallback()
{
 Base* b = new Derived();

  b->getProc()();  // prints "DerivedCallback() called!"

  delete b;

}

and it works. But I don't find a way how to implement into my code.
Dec 16, 2010 at 7:54am
You can't mix pointer to static or free functions and member functions (without a static)!

They don't even have the same size. You can think of a pointer to a non-static member function as a pointer to a class plus a pointer to the member function.

They are invoked differently too.

So if you cast a pointer to a non-static member function to a static member function this is likely to crash!

In my version of VS2005 it doesn't even compile.

If you need the flexibility to invoke a non-static member function then better use a different approach.

I suggest using the command pattern:
http://en.wikipedia.org/wiki/Command_pattern#C.2B.2B

I modified my version to use this pattern.
Together with the wiki site you should be able to figure out how it works and how to adapt to your needs!
Hint: You need to modify the signature of the execute member.


VirtualAction.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#pragma once


namespace VirtualActionExample
{

  class CallbackAction
  {
  public:
    virtual ~CallbackAction(){};
    virtual void execute() = 0;
  };



  class Base
  {
  public:
    virtual ~Base();
    typedef void (*MyCallbackType) ();
    virtual CallbackAction* getAction();
    static void BaseCallback();
  };



  class Derived : public Base
  {
  public:
    Derived(int i) : _i(i){};
    virtual CallbackAction* getAction();
    void DerivedCallback();
  private:
    int _i;
  };

  class CallbackActionBase : public CallbackAction
  {
  public:
    virtual void execute();
  };

  class CallbackActionDerived : public CallbackAction
  {
  public:
    CallbackActionDerived(Derived* derived);
    virtual void execute();
  private:
    Derived* _this;
  };


  void testVirtualAction();
}


VirtualAction.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include "StdAfx.h"
#include "VirtualAction.h"

#include <iostream>
namespace VirtualActionExample

{
	Base::~Base()
	{
	}
	
	
	void Base::BaseCallback()
	{
	  std::cout << "BaseCallback() called!\n";
	}
	
	
	CallbackAction* Base::getAction()
	{
	  return new CallbackActionBase();
	}
	
	
	void Derived::DerivedCallback()
	{
	  std::cout << "DerivedCallback() called, _i = "<<_i<<"!\n";
	}
	
	CallbackAction* Derived::getAction()
	{
	  return new CallbackActionDerived(this);
	
	}
	
	
	
	void testVirtualAction()
	{
	  Base b;
	  Derived d1(1);
    Derived d2(2);
	  CallbackAction* c1 = d1.getAction();
    CallbackAction* c2 = d2.getAction();
	  CallbackAction* c3 = b.getAction();
	
	
	  c1->execute();
	  c2->execute();
    c3->execute();
	
	  delete c3;
	  delete c2;
    delete c1;
	
	}
	
	void CallbackActionBase::execute()
	{
	  Base::BaseCallback();
	}
	
	void CallbackActionDerived::execute()
	{
	  _this->DerivedCallback();
	}
	
	CallbackActionDerived::CallbackActionDerived( Derived* derived )
	: _this(derived)
	{}
}


Dec 16, 2010 at 5:59pm
Thanks.
Topic archived. No new replies allowed.