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.
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;
}
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.
Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by
definition, not smart enough to debug it.
- Brian W. Kernighan
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.
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.
Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by
definition, not smart enough to debug it.
- Brian W. Kernighan
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.
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 8th, 2013 at 11:30 PM.
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).
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 09:57 PM.
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. You are ultimately responsible for effects of your programs and the integrity of the machines they run on.
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.
Bookmarks