CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 10 of 10
  1. #1
    Join Date
    Jan 2013
    Posts
    19

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

  2. #2
    Join Date
    Oct 2006
    Location
    Sweden
    Posts
    3,654

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

    To enhance your chance's of getting an answer be sure to read
    http://www.codeguru.com/forum/announ...nouncementid=6
    and http://www.codeguru.com/forum/showthread.php?t=366302 before posting

    Refresh your memory on formatting tags here
    http://www.codeguru.com/forum/misc.php?do=bbcode

    Get your free MS compiler here
    https://visualstudio.microsoft.com/vs

  3. #3
    Join Date
    Feb 2003
    Location
    Iasi - Romania
    Posts
    8,234

    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.
    Ovidiu
    "When in Rome, do as Romans do."
    My latest articles: https://codexpertro.wordpress.com/

  4. #4
    Join Date
    Jan 2013
    Posts
    19

    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.

  5. #5
    Join Date
    Oct 2006
    Location
    Sweden
    Posts
    3,654

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

    To enhance your chance's of getting an answer be sure to read
    http://www.codeguru.com/forum/announ...nouncementid=6
    and http://www.codeguru.com/forum/showthread.php?t=366302 before posting

    Refresh your memory on formatting tags here
    http://www.codeguru.com/forum/misc.php?do=bbcode

    Get your free MS compiler here
    https://visualstudio.microsoft.com/vs

  6. #6
    Join Date
    Feb 2013
    Location
    United States
    Posts
    56

    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.

  7. #7
    Join Date
    Jan 2013
    Posts
    19

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

  8. #8
    Join Date
    Feb 2013
    Location
    United States
    Posts
    56

    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.

  9. #9
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    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)

  10. #10
    Join Date
    Feb 2003
    Location
    Iasi - Romania
    Posts
    8,234

    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
    Ovidiu
    "When in Rome, do as Romans do."
    My latest articles: https://codexpertro.wordpress.com/

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured