-
January 28th, 2013, 05:49 AM
#1
Problem registering windowsclass
The following code it taken from msdn library but it is failing to compile.
the following code has a header where all the variables used here are stored in header App.h.
please help me with this, i cannot really go further without this problem resolved.
The following lines are giving trouble:
Code:
DialogBox(pApp->getInstance(), MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, pApp->About);
error: 'App::About': function call missing argument list; use '&App::About' to create a pointer to member
Code:
wcex.lpfnWndProc = &App::WndProc;
error: '=' : cannot convert from 'LRESULT (__stdcall App::* )(HWND,UINT,WPARAM,LPARAM)' to 'WNDPROC'
There is no context in which this conversion is possible
Here is the complete code:
Code:
#include "stdafx.h"
#include "App.h"
App::App(void)
{
}
App::~App(void)
{
}
//Initializing variables
BOOL App::Init(HINSTANCE hInstance, int cmd)
{
hInst = hInstance; // Store instance handle in our global variable
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_FIRSTPAINT, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (cmd))
{
return FALSE;
}
return true;
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL App::InitInstance(int nCmdShow)
{
HWND hWnd;
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, this);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//Function to run the message loop for the class
int App::RunMessageLoop()
{
MSG msg;
HACCEL hAccelTable;
hAccelTable = LoadAccelerators(hInst, MAKEINTRESOURCE(IDC_FIRSTPAINT));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM App::MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = &App::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInst;
wcex.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_FIRSTPAINT));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_FIRSTPAINT);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK App::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
App* pApp;
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
pApp = (App *)pcs->lpCreateParams;
::SetWindowLongPtrW(hWnd,GWLP_USERDATA,PtrToUlong(pApp));
return TRUE;
}
else
{
pApp = reinterpret_cast<App *>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hWnd,GWLP_USERDATA)));
if (!pApp)
return DefWindowProc(hWnd, message, wParam, lParam);
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(pApp->getInstance(), MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, pApp->About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
}
// Message handler for about box.
INT_PTR CALLBACK App::About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
-
February 12th, 2013, 03:06 PM
#2
Re: Problem registering windowsclass
This forum is for
Share bugs and fixes for source code on this site. Also use this to share bugs/fixes in the various class libraries etc. of use to VC++ developers. This is NOT for general programming questions.
not when you roll your own bugs!
The wcex.lpfnWndProc should be a plain function, not a member function. See http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx and http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx
-
March 7th, 2013, 09:52 AM
#3
Re: Problem registering windowsclass
[ Moved thread ]
Just to complete: WndProc callback function can be a member function as well, but this case it must be static.
-
March 7th, 2013, 10:07 AM
#4
Re: Problem registering windowsclass
Thank you,
Now i have learnt how to do it for main windowProc, But can you please help me to make non static member function calls from a dialog windproc? I tried googling but did not get much useful info.
-
March 7th, 2013, 05:14 PM
#5
Re: Problem registering windowsclass
You can't use a non-static member function as it is. All non-static member functions have an invisible this pointer in the call and this is something that is unknown to the Win32 API that is plain C. What you have to do is to let some static function route the call to the appropriate instance.
-
March 9th, 2013, 12:24 AM
#6
Re: Problem registering windowsclass
Callback functions must be static, that is, they cannot be associated with any particular instance of a class.
Code:
static LRESULT CALLBACK App::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
...
}
Code:
static INT_PTR CALLBACK App::About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
...
}
Your method, of passing this as the lParam of the WM_CREATE event and then storing it in the extra window memory for that particular window instance, is exactly what I use in my applications. However, for it to work, you need to specify the amount of extra memory, needed to store the pointer to the class instance, when you register the window class.
Code:
wcex.cbWndExtra = sizeof(App*);
To access the beginning of the extra window memory, use an index of 0, instead of GWLP_USERDATA.
Code:
...
::SetWindowLongPtrW(hWnd, 0, PtrToUlong(pApp));
...
pApp = reinterpret_cast<App *>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hWnd, 0)));
...
It is considered poor style to use global variables. By using the extra window memory for the window, you do not need global variables at all. Declare hInst as a private data member of your App class (if you even need it). Any other data that needs to be retained between events should also be private data members.
Last edited by Coder Dave; March 9th, 2013 at 12:30 AM.
-
March 9th, 2013, 08:02 AM
#7
Re: Problem registering windowsclass
Thanks i got it, what if i have to call a member function from a dialog windproc? I am surprised to see, adding a case WM_CREATE to dialog windproc will make the program to crash; I have no clue why that will happen, if dialog window dont receive the message WM_CREATE, that block would be waste but shouldn't make the application crash right? (removing the case WM_CREATE resolves the problem).
-
March 9th, 2013, 10:55 PM
#8
Re: Problem registering windowsclass
Use the GetParent() function to get the window handle of the dialog box's parent. Then use the GetWindowLongPtrW() as before to get the pointer to your App instance. There is also a DialogBoxParam() function that works like DialogBox() but allows you to pass an additional parameter which could be a pointer to your App instance. The WM_INITDIALOG event gets this parameter as the lParam value. This approach, however, requires a static variable in the dialog procedure. Encapsulating the dialog box in its own class would probably lead to an #include cycle and would not compile.
WM_CREATE is equal to 1, so your compiled program would be looking for the event message 1. If another event message is sent to your dialog box, but is also equal to 1, then your code for WM_CREATE will be executed. I do not know what event message this would be, but you could debug your code to find out if this is happening. Incidentally, WM_INITDIALOG is equal to 272. Perhaps, there is something else wrong with your code. If I had your executable file, I could disassemble it and probably tell you what is happening. Maybe you are corrupting the memory elsewhere.
Last edited by Coder Dave; March 9th, 2013 at 10:57 PM.
-
March 10th, 2013, 08:11 AM
#9
Re: Problem registering windowsclass
This approach, however, requires a static variable in the dialog procedure.
Using a static variable is one way. This, however, can cause problems where multi instances of the same class are used etc. It is better practice to use windows' properties to hold this info. A property can be set in the WM_INITDIALOG message to the value of its lParam value. Then messages for controls within the dialog can then retrive this value from its parent dialog window.
Code:
int data = 100;
DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_MYDIALOG), hwnd, DlgProc, (LPARAM)data);
....
case WM_INITDIALOG:
SetProp(hdlg, "Mydata", (HANDLE)lParam);
....
case WM_COMMAND:
int data = (int)GetProp(hdlg, "Mydata");
All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!
C++23 Compiler: Microsoft VS2022 (17.6.5)
-
March 13th, 2013, 05:24 PM
#10
Re: Problem registering windowsclass
MFC uses a hook to catch the window creation and add in a map pairs of window handles and pointers to object.
Then, in the static window procedure, having a window handle, looks up in the map for the object pointer in order to call one non-static (virtual) procedure.
One less "professional" but easier method in case of dialogs is as follows:
1. Pass a pointer to this object in lParam parameter of DialogBoxParam or CreateDialogParam function.
2. In the static window procedure, under WM_INITDIALOG message, retrieve that pointer from lParam; call ::SetProp to store it in window properties.
3. Further, call ::GetProp to retrieve the object pointer and call a non-static method.
Here is a simple minimal example:
Code:
class Window
{
protected:
HWND m_hWnd;
public:
Window() : m_hWnd(NULL) {}
};
Code:
class Dialog : public Window
{
// ...
//Overrides:
protected:
virtual void OnOK() = 0;
virtual void OnCancel() = 0;
virtual INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
// Implementation
protected:
static INT_PTR CALLBACK _DialogProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
};
Code:
class ModalDialog : public Dialog
{
// ...
// Operations
public:
INT_PTR DoModal(HINSTANCE hInst, UINT nResID, HWND hWndParent = NULL);
//Overrides:
protected:
virtual void OnOK();
virtual void OnCancel();
};
Code:
INT_PTR Dialog::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
OnOK();
break;
case IDCANCEL:
OnCancel();
break;
}
break;
//...
}
return 0;
}
INT_PTR CALLBACK Dialog::_DialogProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if(WM_INITDIALOG == uMsg)
{
Dialog* pDlg = (Dialog*)lParam;
pDlg->m_hWnd = hWndDlg;
::SetProp(hWndDlg, _T("dlg_ptr"), (HANDLE)lParam);
}
Dialog* pDlg = (Dialog*)::GetProp(hWndDlg, _T("dlg_ptr"));
if(NULL != pDlg)
{
return pDlg->DialogProc(uMsg, wParam, lParam);
}
return 0;
}
Code:
INT_PTR ModalDialog::DoModal(HINSTANCE hInst, UINT nResID, HWND hWndParent /*= NULL*/)
{
return DialogBoxParam(hInst, MAKEINTRESOURCE(nResID),
hWndParent,
&Dialog::_DialogProc, // dialog procedure
(LPARAM)this); // pass this pointer to LPARAM
}
void ModalDialog::OnOK()
{
::EndDialog(m_hWnd, IDOK);
}
void ModalDialog::OnCancel()
{
::EndDialog(m_hWnd, IDCANCEL);
}
Code:
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
ModalDialog dlg;
dlg.DoModal(hInstance, IDD_DIALOG1);
return 0;
}
Focus on ModalDialog::DoModal (create a modal dialog), Dialog::_DialogProc (static window procedure) and Dialog::DialogProc (non-static virtual window procedure).
Last edited by ovidiucucu; March 13th, 2013 at 05:43 PM.
Reason: typos
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|