views:

530

answers:

4

Hi, I'm writing a win32 wrapper classes, mainly to learn more about win32 programming. To get around the problem of c-style callbacks, the following method stores/retrieves the pointer using SetWindowLong/GetWindowLong and passes it to the actual winproc.

LRESULT CALLBACK WinClass::WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    // On window creation, WindowProc receives lParam as a LPCREATESTRUCT 
    // Store *this* pointer as long in GWL_USERDATA
    if (msg == WM_NCCREATE)
     ::SetWindowLong(hwnd, GWL_USERDATA, reinterpret_cast<long>(reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams));

    // Retrieve the pointer
    WinClass *wnd = reinterpret_cast<WinClass*>(::GetWindowLongPtr(hwnd, GWL_USERDATA));

    // Call the actual winproc function
    if (wnd)
     return wnd->WndProc(hwnd, msg, wParam, lParam);
    // Default to DefWindowProc message handler function
    return ::DefWindowProc(hwnd, msg, wParam, lParam);
}

Winclass is the class wrapping the main window created by CreateWindowEx. The same WindowProc function is part of the MDlgClass wrapping the modal dialog. I'm calling the dialog like this

DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(id), hwnd, DialogProc);

If I pass NULL as the hWndParent, the dialog works okay as a modeless dialog but if I pass hwnd, the handle to the main window as hWndParent the dialog works correctly as a modal dialog. However when i close the dialog it doesnt pass control back to the main parent window? Debugging in Visual Studio shows its hanging in the message pump in WinMain.

I thought of using a hashmap to map the pointers but I'd rather do it using GetWindowLong etc. Is this possible? I've tried storing the dialog pointer in DWL_USER but it doesnt help.

Any help would be appreciated, I'm still getting my head around Win32.

EDIT: I'm destroying the dialog using EndDialog

EDIT: I'm storing the pointer in the GWL_USERDATA region of the main window, which is not used by windows and I'm only modifying it in WinClass::WindowProc when the window is first created. If I don't instantiate a dialog class, I know the pointer is being accessed correctly since the application responds to menu commands processed via WindowProc and WM_COMMAND.

A: 

How are you closing the window? Are you using DestroyWindow? While the child window is live, the parent window will be disabled.

1800 INFORMATION
A: 

You're saving a pointer to lpCreateParams. Is it possible that the associated memory block is being freed or otherwise destroyed?

jdigital
+2  A: 

You can't use a WindowProc as a DialogProc. Window Procedures call DefWindowProc when they don't handle a message and return a meaningful result when they do. Dialog Procedures return FALSE when they don't process a message, return TRUE when they DO, (except when they handle WM_INITDIALOG) and, if they have a meaningful result that they need to return from the outer window procedure, that is placed in DWL_MSGRESULT.

When you call the modal dialog box function, DialogBox, it enters a message pumping loop - which does dispatch messages to all windows in the thread so all windows continue to paint and process input - when the dialog is closed (using EndDialog), the DialogBox procedure should return.

When making a class to wrap dialog boxes, the usual method is to pass the 'this' pointer to One of the DialogBoxParam functions - which can be directly extracted from the WM_INITDIALOG message.

Chris Becke
A: 
//static method
BOOL CALLBACK WinClass::DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  // Store *this* pointer as long in GWL_USERDATA
  if (msg == WM_INITDIALOG)
  {
        ::SetWindowLongPtr(hwnd, DWLP_USER, reinterpret_cast(lParam));
        m_hWnd = hWnd; // I assume you really don't want to keep passing the hwnd around
  }

   WinClass* wnd = reinterpret_cast(::GetWindowLongPtr(hwnd, GWL_USERDATA));
   if (wnd)
       return wnd->DlgProcImpl(umsg, wParam, lParam);
   return FALSE;
}

BOOL WinClass::DlgProcImpl(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        // your code goes here

            return FALSE;
    }

    return FALSE;
}

INT_PTR WinClass:DoModalDialog(HINSTANCE hInst, HWND hwndParent, LPCTSTR template)
{
    return ::DialogBoxParam(hInst, template, hwndParent, WinClass::DlgProc, this);
}

selbie