![]() |
| | #1 |
| Registered User Join Date: May 2008
Posts: 7
| Callback function as class method I know that this issue was already asked before many times. I made some research through the web and I found what I was looking for. I found some solutions to this problem and I chose one of them. I came here to look for an explanation about the approach I used in my code. I'm trying to develop an error class to my Win32 application and I decided that the error messages will show up in a Win32 DialogBox. So, I developed an Error class. This class has a method CreateDialogBox, where I will call the DialogBox in the resource file. I need to pass as a parameter to the Win32 API function "DialogBox", that will create my DialogBox, a function called DialogProc with the signature expected by the Win32 API function "DialogBox". How did I solve this problem? I used the wrapper approach with a global pointer to the instance of the class declared into my Error.cpp file. As you can see in the code below, the DialogProc is a method of my Error class. There is a static wrapper, with the same signature of the DialogProc, that will be passed to the WIN32 API function "DialogBox". Look the code below: Error.h: Code: class Error
{
private:
char* errorMessage;
int sizeOfMessage;
bool stopExecution;
public:
Error();
~Error();
BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK Wrapper(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
void CreateDialogBox();
void CreateErrorMessage(int size);
void DestroyErrorMessage();
void SetErrorMessage(char* msg);
char* GetErrorMessage();
void SetStopExecution(bool flag);
bool GetStopExecution();
};
Code: #include "../Global.h"
void* ptrError;
Error::Error()
{
this->errorMessage = 0;
this->sizeOfMessage = 0;
this->stopExecution = false;
}
Error::~Error()
{
DestroyErrorMessage();
}
BOOL CALLBACK Error::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
SetDlgItemText(hwndDlg, IDC_TXT, this->errorMessage);
return TRUE;
case WM_CLOSE:
EndDialog(hwndDlg, 0);
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_BTN_OK:
EndDialog(hwndDlg, 0);
return TRUE;
}
}
return FALSE;
}
BOOL CALLBACK Error::Wrapper(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
Error* mySelf = (Error*) ptrError;
return mySelf->DialogProc(hwndDlg, uMsg, wParam, lParam);
}
void Error::CreateDialogBox()
{
SDL_SysWMinfo *info;
SDL_GetWMInfo(info);
HWND hWin = info->window;
HINSTANCE hInstance = (HINSTANCE) GetWindowLong(hWin, GWL_HINSTANCE);
ptrError = this;
DialogBox(hInstance, MAKEINTRESOURCE(DLG_MAIN), NULL, Error::Wrapper);
}
void Error::CreateErrorMessage(int size)
{
this->errorMessage = new char[size];
this->sizeOfMessage = size;
memset(this->errorMessage, '\0', size);
}
void Error::DestroyErrorMessage()
{
if(this->errorMessage != 0)
{
delete errorMessage;
}
}
void Error::SetErrorMessage(char* msg)
{
strcpy(this->errorMessage, msg);
}
char* Error::GetErrorMessage()
{
return this->errorMessage;
}
void Error::SetStopExecution(bool flag)
{
this->stopExecution = flag;
}
bool Error::GetStopExecution()
{
return this->stopExecution;
}
So, the first question is: Is there any better way to to this? Second: What are the problems I will have with the approach I chose? Thanks in advance fot the answers... Bruno. |
| schifers is offline | |
| | #2 |
| Registered User Join Date: Mar 2003
Posts: 3,900
| >> So, the first question is: Is there any better way to to this? Depends. You could use CreateDialogParam() which passes a custom parameter to WM_INITDIALOG. However, there a few messsages that are dispatched before WM_INITDIALOG. So if you ever needed to hanled those messages you'll have to keep doing what your doing. >> What are the problems It's not thread safe. Not a problem if you don't have multiple threads calling Error::CreateDialogBox(). gg |
| Codeplug is online now | |
| | #3 |
| Cat without Hat Join Date: Apr 2003
Posts: 8,492
| You could use a thread-local variable instead of a true global. That would make it thread-safe. Just make sure that the thread that creates the dialog is always the one running the message loop. This scheme, however, breaks down if you create more than one window in the same thread (i.e. the dialog shows another dialog).
__________________ All the buzzt! CornedBee"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code." - Flon's Law |
| CornedBee is offline | |
| | #4 |
| Registered User Join Date: May 2008
Posts: 7
| Is there another way, using the same WIN32 API function DialogBox and not using a global pointer? Is it a good design to use a global pointer? Is it object oriented design doing this? Thanks again... |
| schifers is offline | |
| | #5 | ||
| Kernel hacker Join Date: Jul 2007 Location: Farncombe, Surrey, England
Posts: 15,686
| Quote:
Quote:
-- Mats
__________________ Compilers can produce warnings - make the compiler programmers happy: Use them! Please don't PM me for help - and no, I don't do help over instant messengers. | ||
| matsp is offline | |
| | #6 | |
| Mysterious C++ User Join Date: Oct 2007
Posts: 14,783
| Unfortunately, Win32 API is C, and C is not object oriented so you're kindof limited. I don't think there's an easy or "best" way to do this, unfortunately. What you could do to use several windows inside the same thread is a map and an index variable, perhaps: Code: int nIndex = 0;
BOOL CALLBACK Error::Wrapper(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
Error* mySelf = g_map.find(nIndex++)->second;
return mySelf->DialogProc(hwndDlg, uMsg, wParam, lParam);
}
__________________ Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System I dedicated my life to helping others. This is only a small sample of what they said: "Thanks Elysia. You're a programming master! How the hell do you know every thing?" Quoted... at least once. Quote:
| |
| Elysia is offline | |
| | #7 |
| Registered User Join Date: May 2008
Posts: 7
| Thanks again for everyone who answered this... I decided to keep this design, since I won't use threads now... |
| schifers is offline | |
| | #8 |
| Registered User Join Date: May 2008
Posts: 13
| I have been searching for information how to make the CALLBACK as one of my class methods, and I found your thread, thanks. However I run into problem because it seems I cant create like your signature. Code: DialogBox(hInstance, MAKEINTRESOURCE(IDD_DISPLAYSTATUS), NULL, myTest::DisplayStatus); the error says: cannot convert parameter 4 from 'int (struct HWND__ *,unsigned int,unsigned int,long)' to 'int (__cdecl *)(struct HWND__ *,unsigne any idea? |
| lakewa is offline | |
| | #9 |
| Cat without Hat Join Date: Apr 2003
Posts: 8,492
| Declare the static member as CALLBACK.
__________________ All the buzzt! CornedBee"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code." - Flon's Law |
| CornedBee is offline | |
| | #10 | |
| Mysterious C++ User Join Date: Oct 2007
Posts: 14,783
| There is no way to get it to work with a callback to a class member unless it's static or the function is global (how would the function know which class instance to call?).
__________________ Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System I dedicated my life to helping others. This is only a small sample of what they said: "Thanks Elysia. You're a programming master! How the hell do you know every thing?" Quoted... at least once. Quote:
| |
| Elysia is offline | |
| | #11 |
| Registered User Join Date: May 2008
Posts: 13
| thank you for the replies. If I declare my CALLBACK as static member function, will I able to access my class data that are not static? Code: class myClass
{
public:
myClass();
void WriteData(DWORD inputData);
static BOOL CALLBACK dialProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
private:
DWORD num;
myAnotherClass writeDataToFile;
};
Last edited by lakewa; 05-17-2008 at 10:00 AM. |
| lakewa is offline | |
| | #12 | |
| Mysterious C++ User Join Date: Oct 2007
Posts: 14,783
| Static members can only access static data.
__________________ Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System I dedicated my life to helping others. This is only a small sample of what they said: "Thanks Elysia. You're a programming master! How the hell do you know every thing?" Quoted... at least once. Quote:
| |
| Elysia is offline | |
| | #13 |
| Registered User Join Date: May 2008
Posts: 13
| If my CALLBACK is static and only can access to static data, then I'm in trouble unless I have to change all the data members to static which I'm not sure if that will affect my other functions as well because they are not static. Otherwise I will have to use alot of global variables for those data members initialization. Last edited by lakewa; 05-17-2008 at 10:02 AM. |
| lakewa is offline | |
| | #14 | |
| Mysterious C++ User Join Date: Oct 2007
Posts: 14,783
| Here's the thing - a static member is a member of which there is only one of regardless of how many instances there are. So that means you cannot have an unique data - there will only be one instance of everything. So everything static isn't really an option. There's no easy way using a class member as a windowproc due to limitations in C.
__________________ Using: Microsoft Windows™ 7 Professional (x64), Microsoft Visual Studio™ 2008 Team System I dedicated my life to helping others. This is only a small sample of what they said: "Thanks Elysia. You're a programming master! How the hell do you know every thing?" Quoted... at least once. Quote:
| |
| Elysia is offline | |
| | #15 |
| Registered User Join Date: Mar 2003
Posts: 3,900
| Take a look at Error::Wrapper() in the schifers original post. Wrapper() is the static method, which then calls non-static Error::DialogProc() on the Error object instance. gg |
| Codeplug is online now | |
![]() |
| Thread Tools | |
| Display Modes | |
|
Similar Threads | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| How to fix misaligned assignment statements in the source code? | biggyK | C++ Programming | 28 | 07-16-2006 11:35 PM |
| My Window Class | Epo | Game Programming | 2 | 07-10-2005 02:33 PM |
| c++ linking problem for x11 | kron | Linux Programming | 1 | 11-19-2004 10:18 AM |
| structure vs class | sana | C++ Programming | 13 | 12-02-2002 07:18 AM |
| Warnings, warnings, warnings? | spentdome | C Programming | 25 | 05-27-2002 06:49 PM |