Jump to content
  • Advertisement
Sign in to follow this  
nivlekio

[C++] Function Pointers/Function Addresses

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

Hi all I am developing my own win32 controls library and I have come across a problem. I am trying to create a Subclass procedure function (using SetWindowSubclass()) for each control which automatically deals with the notifications that is meant for that control so that the user does not have to fuss around with them. This is what I have. .h file
class C_CtrlSubclass
{
public:
	C_CtrlSubclass(class C_CtrlNotifDetect *prm_CtrlNotifDetect);
	~C_CtrlSubclass();

	bool Do_InitSubclass_v(unsigned int prm_uiSubclassID, DWORD_PTR prm_dwptrUserData);

	static LRESULT CALLBACK Do_CtrlSubProcStatic_lResCB(HWND prm_hWnd, UINT prm_uiMsg, WPARAM prm_wParam, LPARAM prm_lParam, UINT_PTR prm_uIdSubclass, DWORD_PTR prm_dwRefData);
	LRESULT CALLBACK Do_CtrlSubProc_lResCB(HWND prm_hWnd, UINT prm_uiMsg, WPARAM prm_wParam, LPARAM prm_lParam, UINT_PTR prm_uIdSubclass, DWORD_PTR prm_dwRefData);
private:

	static class C_CtrlSubclass *m_pThisClass;

	unsigned int m_uiSubclassID;
	class C_CtrlNotifDetect *m_CtrlNotifDetect;
};




.cpp file
C_CtrlSubclass* C_CtrlSubclass::m_pThisClass = NULL;

C_CtrlSubclass::C_CtrlSubclass(class C_CtrlNotifDetect *prm_CtrlNotifDetect)
{
 m_CtrlNotifDetect = prm_CtrlNotifDetect;
}

C_CtrlSubclass::~C_CtrlSubclass()
{
 m_CtrlNotifDetect = NULL;
}

bool C_CtrlSubclass::Do_InitSubclass_v(unsigned int prm_uiSubclassID, DWORD_PTR prm_dwptrUserData)
{
	m_pThisClass = this;

	m_uiSubclassID = prm_uiSubclassID;

	return SetWindowSubclass(	m_CtrlNotifDetect->Rtn_hParenthWnd(),
								Do_CtrlSubProcStatic_lResCB,
								prm_uiSubclassID,
								prm_dwptrUserData)?true:false;
}

static LRESULT CALLBACK C_CtrlSubclass::Do_CtrlSubProcStatic_lResCB(HWND prm_hWnd, UINT prm_uiMsg, WPARAM prm_wParam, LPARAM prm_lParam, UINT_PTR prm_uIdSubclass, DWORD_PTR prm_dwRefData)
{
	class C_CtrlSubclass *l_ThisClass = m_pThisClass;

	return  l_ThisClass->Do_CtrlSubProc_lResCB(prm_hWnd, prm_uiMsg, prm_wParam, prm_lParam, prm_uIdSubclass, prm_dwRefData);
}

LRESULT CALLBACK C_CtrlSubclass::Do_CtrlSubProc_lResCB(HWND prm_hWnd, UINT prm_uiMsg, WPARAM prm_wParam, LPARAM prm_lParam, UINT_PTR prm_uIdSubclass, DWORD_PTR prm_dwRefData)
{
	switch(prm_uiMsg) 
	{
	case WM_COMMAND:
		m_CtrlNotifDetect->Do_DetectCommand(&prm_hWnd,&prm_uiMsg,&prm_wParam,&prm_lParam);
		break;
	case WM_NOTIFY:
		m_CtrlNotifDetect->Do_DetectNotify(&prm_hWnd,&prm_uiMsg,&prm_wParam,&prm_lParam);
		break;
		//
		// etc
		//
	case WM_NCDESTROY:
		RemoveWindowSubclass(prm_hWnd,Do_CtrlSubProcStatic_lResCB,m_uiSubclassID);
		break; 
	}
}




The problem is that when there is more than one instance of a control or multiple controls, only the last instance works (it detects all the notifications for that control). On the microsoft website for the second parameter (the pointer to the procedure function) of the SetWindowSubclass function it says "A pointer to a window procedure. This pointer and the subclass ID uniquely identify this subclass callback. For the callback function prototype," Since the last instance of a control only works I suspect it has something to do with the address of the Do_CtrlSubProcStatic_lResCB function being the same for all the instances of the controls? If so how do I get round this problem. (although as far as I know that should not be the case because every time you create an instance of a class its has its own address as well as its functions and members of that class as well?). If that is not the problem any idea whats going on? Btw I know that if I make Do_CtrlSubProc_lResCB virtual and inherit the C_CtrlSubclass to the main control class and define a new Do_CtrlSubProc_lResCB function for each control that will solve this problem but I want to avoid that as the user will still have to mess about with the notifications of the control, and say for example the user makes an application with like 30 controls there will be 30 Do_CtrlSubProc_lResCB functions and I want to avoid doing that.
class C_CtrlSubclass
{
public:
	C_CtrlSubclass(class C_CtrlNotifDetect *prm_CtrlNotifDetect);
	~C_CtrlSubclass();

	bool Do_InitSubclass_v(unsigned int prm_uiSubclassID, DWORD_PTR prm_dwptrUserData);

	static LRESULT CALLBACK Do_CtrlSubProcStatic_lResCB(HWND prm_hWnd, UINT prm_uiMsg, WPARAM prm_wParam, LPARAM prm_lParam, UINT_PTR prm_uIdSubclass, DWORD_PTR prm_dwRefData);
	virtual LRESULT CALLBACK Do_CtrlSubProc_lResCB(HWND prm_hWnd, UINT prm_uiMsg, WPARAM prm_wParam, LPARAM prm_lParam, UINT_PTR prm_uIdSubclass, DWORD_PTR prm_dwRefData) = 0;
private:

	static class C_ButtonNotifications *m_pThisClass;

	unsigned int m_uiSubclassID;
	class C_CtrlNotifDetect *m_CtrlNotifDetect;
};




Thanks for the help in advance [Edited by - nivlekio on December 8, 2009 6:27:21 AM]

Share this post


Link to post
Share on other sites
Advertisement
Honestly my eyes kind of hurt from looking at all those underscores and extreme hungarian notation, but at a quick glance I'd say it's more likely to be the use of

static class C_ButtonNotifications *m_pThisClass;


Am I misunderstanding how this is being used? You call Do_InitSubclass_v once for each subclass right? And it just keeps overwriting the static instance variable with the new one.

Share this post


Link to post
Share on other sites
Oh my bad "static class C_ButtonNotifications *m_pThisClass;" was a typo when I writing the post that was not in my code. I meant to write "static class C_CtrlSubclass *m_pThisClass;" I just corrected my post.

Yes I call Do_InitSubclass_v once for each control to set the subclass ID and set the subclass. But as you said it might be overwriting the previous ones but I am not sure why this is happening.

Share this post


Link to post
Share on other sites
It's happening because there's only one instance of the m_pThisClass variable and multiple instances of your class. Consider using SetWindowLongPtr() with GWLP_USERDATA to store your instance pointers in a per-window manner.

Share this post


Link to post
Share on other sites
Quote:
Original post by nivlekio
Oh my bad "static class C_ButtonNotifications *m_pThisClass;" was a typo when I writing the post that was not in my code. I meant to write "static class C_CtrlSubclass *m_pThisClass;" I just corrected my post.

Yes I call Do_InitSubclass_v once for each control to set the subclass ID and set the subclass. But as you said it might be overwriting the previous ones but I am not sure why this is happening.


As SiCrane mentioned, the point is that it is static, even in the corrected version this is still the case. While you might have multiple instances of C_CtrlSubclass, internally each of these instances all contain a shared memory location for m_pThisClass. That's exactly the purpose of static. Instead of using

static class C_CtrlSubclass *m_pThisClass;

you could instead do something like

static std::map<unsigned, C_CtrlSubclass> subclassLookup;

where the key of the map is the subclass id.

Or you could use SetWindowLongPtr as SiCrane mentioned although I personally prefer not to use that function for anything out of personal preference.

Share this post


Link to post
Share on other sites
Quote:
Original post by nivlekio
ill try your method out as well cache_hit any reason why you would not use SetWindowLongPtr function?


In my mind, it's the equivalent of a global variable. It's readable and writable from anywhere in your program as long as you have the window handle. Which is also accessible from anywhere in the program by using ::GetForegroundWindow() or something similar, or just accessing it directly from your main application class.

Share this post


Link to post
Share on other sites
Meh. If you have a window handle you can already do basically anything you want to the window from messing with the style to changing the WndProc. Worrying about someone messing with the user data is like worrying if you've locked the door when there's already a gaping hole in the wall. Furthermore, the user data is stored inline with the other window data which gives you a better memory footprint than storing the window data association externally.

Share this post


Link to post
Share on other sites
Yea I know, it's a trivial detail. I just feel "bad" when I do it. That's not to say I never do it, but 99% of the time, SetWindowLongPtr is only used when calling CreateWindow() so your window can hold onto an instance parameter. In that case, I just use the last argument of CreateWindow() and keep a static variable inside my window procedure.

For all intents and purposes both methods are pretty close to equivalent, so it just comes down to personal preference.

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.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!