Can't call correct function using this pointer

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
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
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
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;

}
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.
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)
	{}
}


Thanks.
Topic archived. No new replies allowed.