Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Свой класс CWindow, субклассирование


Автор: Alca 29.7.2009, 15:54
Есть класс:

Код

//---------------------------------------------------------------------------
class CXWindow {
    public:
                                 CXWindow     ();
        virtual                 ~CXWindow     () = 0;
        
        BOOL                     bCreate      (INT iID, HWND hParent, INT iLeft, INT iTop, INT iWidth, INT iHeight, ULONG ulStyle, ULONG ulExStyle);
        BOOL                     bCreateRes   (INT iID, HWND hParent);

static    BOOL                     bIsDialog    (HWND hWnd);
        //...
     
    protected:
        HWND                     _m_hWnd;
        BOOL                     bRegisterClassEx(const WNDCLASSEX *cpwcWndClassEx);
        BOOL                     bCreateEx       (ULONG ulExStyle, const std::string &csClassName, const std::string &csText, ULONG ulStyle, INT iLeft, INT iTop, INT iWidth, INT iHeight, HWND hParent, INT iID, LPVOID lpParam);
     static  LRESULT CALLBACK s_BaseWndProc   (HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
     virtual LRESULT          pWndProc        (HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam, PBOOL pbProcessed);
        //...
};  
//---------------------------------------------------------------------------


//...
//---------------------------------------------------------------------------
//TODO: + CXWindow
CXWindow::CXWindow() :
    _m_hWnd      (0),
    _m_ulExStyle (0),
    _m_sClassName(""),
    _m_sText     (""),
    _m_ulStyle   (0),
    _m_iWidth    (0),
    _m_iHeight   (0),
    _m_iLeft     (0),
    _m_iTop      (0),
    _m_hParent   (NULL),        
    _m_iMenu     (0),
    _m_Font      (NULL),
    _m_bIsFrame  (FALSE)
{
    LOG();
}
//---------------------------------------------------------------------------
//TODO: + ~CXWindow
/*virtual*/CXWindow::~CXWindow () {
    LOG();

    BOOL bRes = FALSE;
    
    /*DEBUG*/XASSERT(NULL != _m_Font);
    bRes = ::DeleteObject(_m_Font);    _m_Font = NULL;
    /*DEBUG*/XASSERT(FALSE != bRes);    
}
//---------------------------------------------------------------------------



/****************************************************************************
*    public
*
*****************************************************************************/

//...

//---------------------------------------------------------------------------
//TODO: + bIsDialog
BOOL CXWindow::bIsDialog(HWND hWnd) {
    /*DEBUG*///not need

    UINT uiRes = 0;

    uiRes = ::GetClassWord(hWnd, GCW_ATOM);
    /*DEBUG*/XASSERT_RET(0 != uiRes, FALSE);

    CHECK_RET(32770 != uiRes, FALSE);

    return TRUE;
}
//---------------------------------------------------------------------------

//...

/****************************************************************************
*    protected
*
*****************************************************************************/

//...

//---------------------------------------------------------------------------
//TODO: + bRegisterClassEx
BOOL CXWindow::bRegisterClassEx(const WNDCLASSEX *cpwcWndClassEx) {
    /*DEBUG*/XASSERT_RET(NULL != cpwcWndClassEx, FALSE);

    BOOL bRes = FALSE;

    bRes = ::RegisterClassEx(cpwcWndClassEx);
    /*DEBUG*/XASSERT_RET(FALSE != bRes, FALSE);

    return TRUE;
}
//---------------------------------------------------------------------------
//TODO: + bCreateEx
BOOL CXWindow::bCreateEx(ULONG ulExStyle, const std::string &csClassName, const std::string &csText, ULONG ulStyle, 
                         INT iLeft, INT iTop, INT iWidth, INT iHeight, HWND hParent, INT iID, LPVOID lpParam)
{
    /*DEBUG*/XASSERT_RET(NULL  == _m_hWnd,             NULL);
    /*DEBUG*/XASSERT_RET(false == csClassName.empty(), NULL);

    BOOL bRes = FALSE;

    _m_hWnd = ::CreateWindowEx(_m_ulExStyle | ulExStyle, _m_sClassName.c_str(), _m_sText.c_str(), _m_ulStyle | ulStyle, iLeft, iTop, iWidth, iHeight, hParent, (HMENU)iID, CXApplication::hGetInstance(), lpParam);
    /*DEBUG*/XASSERT_RET(NULL != _m_hWnd, FALSE);

    bRes = bSetDefaultFont();
    CHECK_RET(FALSE != bRes, FALSE);

    //-------------------------------------
    //переопределяем поля класса
    _m_ulExStyle  = _m_ulExStyle | ulExStyle;    
    _m_sClassName = _m_sClassName;
    _m_sText      = _m_sText;
    _m_ulStyle    = _m_ulStyle | ulStyle;
    _m_iLeft      = iLeft;
    _m_iTop       = iTop;
    _m_iWidth     = iWidth; 
    _m_iHeight    = iHeight;
    _m_hParent    =    hParent;    
    _m_iMenu      = iID;

    return TRUE;
}
//---------------------------------------------------------------------------
//TODO: + bCreate
BOOL CXWindow::bCreate(INT iID, HWND hParent, INT iLeft, INT iTop, INT iWidth, INT iHeight, ULONG ulStyle, ULONG ulExStyle) {
    /*DEBUG*/XASSERT_RET(NULL == _m_hWnd, FALSE);

    BOOL bRes = FALSE;

    //-------------------------------------
    //если это окно - WNDCLASSEX, если контрол - ничего
    if (TRUE == _m_bIsFrame) {
        //-------------------------------------
        //Set the default data for the window class.
        //These can be reset in the derived class's constructor.
        WNDCLASSEX _m_WndClass = {0};

        _m_WndClass.hInstance     = CXApplication::hGetInstance();    
        _m_WndClass.lpszClassName = _m_sClassName.c_str();
        _m_WndClass.lpfnWndProc   = (WNDPROC)s_BaseWndProc;        //This function is called by windows
        _m_WndClass.style         = CS_DBLCLKS;                    //Catch double-clicks
        _m_WndClass.cbSize        = sizeof(WNDCLASSEX);
        _m_WndClass.hIcon         = NULL;                        //_m_hIcon;    //LoadIcon (hInstance, 0);
        _m_WndClass.hIconSm       = NULL;                        //LoadIcon (hInstance, 0);
        _m_WndClass.hCursor       = NULL;                        //LoadCursor (NULL, IDC_ARROW);
        _m_WndClass.lpszMenuName  = NULL;
        _m_WndClass.cbClsExtra    = 0;                            //256;        //No extra bytes after the window class
        _m_WndClass.cbWndExtra    = 0;                            //dialog box not from resource file
        _m_WndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);

        bRes = bRegisterClassEx(&_m_WndClass);
        ////CHECK_RET(FALSE == bRes, FALSE);
    } else {
        //контролы
    }

    bRes = bCreateEx(ulExStyle, _m_sClassName, _m_sText, ulStyle, iLeft, iTop, iWidth, iHeight, hParent, iID, (VOID *)this);
    CHECK_RET(FALSE == bRes, FALSE);

    return TRUE;
}
//---------------------------------------------------------------------------
BOOL CXWindow::bCreateRes(INT iID, HWND hParent) {
    BOOL bRes = FALSE;

    //-------------------------------------
    //если это окно - WNDCLASSEX, если контрол - ::GetDlgItem
    if (TRUE == _m_bIsFrame) {
        //-------------------------------------
        //Register the window class
        WNDCLASSEX _m_WndClass = {0};    
    
        _m_WndClass.hInstance     = CXApplication::hGetInstance();        
        _m_WndClass.lpszClassName = _m_sClassName.c_str();
        _m_WndClass.lpfnWndProc   = s_BaseWndProc;    //This function is called by windows
        _m_WndClass.style         = CS_DBLCLKS;                //Catch double-clicks
        _m_WndClass.cbSize        = sizeof(WNDCLASSEX);
        _m_WndClass.hIcon         = NULL;                    //LoadIcon (hInstance, 0);
        _m_WndClass.hIconSm       = NULL;                        //LoadIcon (hInstance, 0);
        _m_WndClass.hCursor       = NULL;                        //LoadCursor (NULL, IDC_ARROW);
        _m_WndClass.lpszMenuName  = NULL;
        _m_WndClass.cbClsExtra    = 256;                        //No extra bytes after the window class
        _m_WndClass.cbWndExtra    = DLGWINDOWEXTRA/*0*/;        //используем диалог с ресурса
        _m_WndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);

        bRes = bRegisterClassEx(&_m_WndClass);
        ////CHECK_RET(FALSE == bRes, FALSE);
    
        _m_hWnd = ::CreateDialog(CXApplication::hGetInstance(), MAKEINTRESOURCE(iID), hParent, (DLGPROC)s_BaseWndProc);
        /*DEBUG*/XASSERT_RET(NULL != _m_hWnd, FALSE);
    } else  {
        _m_hWnd = ::GetDlgItem(hParent, iID);
        /*DEBUG*/XASSERT_RET(NULL != _m_hWnd, FALSE);
    }


    return TRUE;
}
//---------------------------------------------------------------------------
//TODO: + s_BaseWndProc
LRESULT CALLBACK CXWindow::s_BaseWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
    /*DEBUG*/XASSERT_RET(NULL != hWnd, NULL);

    //A pointer to the object is passed in the CREATESTRUCT
    if (WM_NCCREATE == uiMsg) {
        ::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams);
    }

    BOOL    bProcessed = FALSE;
    LRESULT lResult    = NULL;

    //Retrieve the pointer
    CXWindow *pObj = (CXWindow *)::GetWindowLongPtr(hWnd, GWLP_USERDATA);

    //Filter message through child classes
    if (NULL != pObj) {
        lResult = pObj->pWndProc(hWnd, uiMsg, wParam, lParam, &bProcessed);
    }

    if (TRUE == bProcessed) {
        return lResult;
    } else {
        //////If message was unprocessed, send it back to Windows.
        ////return ::DefWindowProc(hWnd, uiMsg, wParam, lParam);
        
        if (TRUE == bIsDialog(hWnd)) {
            //диалог
            return 0;    //<--- окно не реагирует ни на какие девствия, но нормально можно перемещять мышкой
            //return pObj->pWndProc(hWnd, uiMsg, wParam, lParam, &bProcessed);    //<--- окно не реагирует ни на какие девствия, нельзя перемещять мышкой
        } else {
            //окно
            return ::DefWindowProc(hWnd, uiMsg, wParam, lParam);
        }
    }
}
//---------------------------------------------------------------------------
//TODO: + pWndProc
/*virtual*/LRESULT CXWindow::pWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam, PBOOL pbProcessed) {
    /*DEBUG*/XASSERT_RET(NULL != _m_hWnd, NULL);

    //This may be overridden to process messages.
    *pbProcessed = FALSE;

    return NULL;
}
//---------------------------------------------------------------------------

//...


От него наследую класс CXFrame, потом CXMyFrame.
Если создаю окно с помощью ::CreateWindowEx:

Код

CMainFrame MainFrame;
MainFrame.bCreate(0, HWND_DESKTOP, 400, 400, 600, 430, 0, 0);

    
то все нормально работает, а если из ресурсов:

Код

CMainFrame MainFrame;
MainFrame.bCreateRes(IDD_DIALOGBAR, HWND_DESKTOP);

    
то окно содается, но не реагирует ни на какие действия (не идет обработка сообщений),
только можно перемещять мышкой.
Где-то косяк в методе s_BaseWndProc... 
Если чего-то в коде не хватает - выложу.

Автор: GremlinProg 29.7.2009, 17:46
Цитата(Alca @  29.7.2009,  17:54 Найти цитируемый пост)
Где-то косяк в методе s_BaseWndProc... 

по-видимому, проблема в самом подходе к объединению функционала диалога и обычного окна в одном сишном классе:

если свойство Class в шаблоне указывает на нормальный класс окна,
то CreateDialog создает окно уже не класса 32770, а именно этого класса, указанного в свойстве Class )

короче говоря, основная ошибка в функции bIsDialog, она никогда не вернет TRUE
вот с этого момента и разбирай функционал дальше:

значит для диалога не будет вызвана процедура окна его предка,
отсюда - он будет работать как простое окно,
ни какой инициализации компонентов из ресурсов оно уже не сделает и т.д.

т.е. это не синтаксическая ошибка, а логическая, ты создал окно диалогового класса,
но не даешь этому классу с ним работать,
полностью перекрыл функционал предка,
точнее даже исключил предка из цепочки наследования (т.к. DefWindowProc все же вызываешь)

мы ведь уже обсуждали проблему идентификации диалога при суперклассинге,
изнутри твоего класса эту проблему решить можно, если сохранять процедуру класса-предка в самом объекте,
а в последствии, изучать ее: если она равна DefDlgProc, то это диалог, иначе - нет,
конечно, это верно только при условии, что цепочка предков состоит только из одного класса
(судя по коду, этого более чем достаточно)

т.е. заведи в сишном классе поле
Код

WNDPROC StdProc;

а заполняй его только в методах: bCreateEx, bCreate и bCreateRes
для всех методов инициируй его в DefWindowProc, кроме bCreateRes, тут ставь DefDlgProc
тогда в s_BaseWndProc вместо компаратора bIsDialog ставь просто вызов
Код

return ::CallWindowProc(StdProc,...);

Автор: Alca 29.7.2009, 20:57
Цитата

короче говоря, основная ошибка в функции bIsDialog, она никогда не вернет TRUE

Отладчиком заходил в TRUE.

Добавлено через 5 минут и 48 секунд
 smile 

Автор: Alca 29.7.2009, 22:36
Код

LRESULT CALLBACK CXWindow::s_BaseWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
    /*DEBUG*/XASSERT_RET(NULL != hWnd, NULL);

    //A pointer to the object is passed in the CREATESTRUCT
    if (WM_INITDIALOG/*WM_NCCREATE*/ == uiMsg) {
        /* >>> .......... валиться здесь .............. <<< */
        ::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams);
    }


    BOOL    bProcessed = FALSE;
    LRESULT lResult    = NULL;

    //Retrieve the pointer
    CXWindow *pObj = (CXWindow *)::GetWindowLongPtr(hWnd, GWLP_USERDATA);

    //Filter message through child classes
    if (NULL != pObj) {
        lResult = pObj->pWndProc(hWnd, uiMsg, wParam, lParam, &bProcessed);
    }

        if (TRUE == bProcessed) {
            return lResult;
        } else {
            //////If message was unprocessed, send it back to Windows.
            ////return ::DefWindowProc(hWnd, uiMsg, wParam, lParam);
            
            if (TRUE == bIsDialog(hWnd)) {
                //диалог
                return 0;
                //return pObj->pWndProc(hWnd, uiMsg, wParam, lParam, &bProcessed);
            } else {
                //окно
                return ::DefWindowProc(hWnd, uiMsg, wParam, lParam);
            }
        }
}

Автор: GremlinProg 30.7.2009, 00:10
Цитата(Alca @  29.7.2009,  22:57 Найти цитируемый пост)
Отладчиком заходил в TRUE.

Цитата(GremlinProg @  29.7.2009,  19:46 Найти цитируемый пост)
если свойство Class в шаблоне указывает на нормальный класс окна

иначе в твою процедуру окна он не войдет
не войдет именно как в процедуру окна,
т.к. будет создано стандартное диалоговое окно, класса 32770, а у него процедура окна DefDlgProc
Цитата(Alca @  29.7.2009,  17:54 Найти цитируемый пост)
::CreateDialog(CXApplication::hGetInstance(), MAKEINTRESOURCE(iID), hParent, (DLGPROC)s_BaseWndProc);

Цитата(Alca @  29.7.2009,  17:54 Найти цитируемый пост)
_m_WndClass.lpfnWndProc   = s_BaseWndProc;    //This function is called by windows

опять смешиваешь диалоговую процедуру и процедуру окна в одну кучу,
нельзя назначать одну процедуру в обе эти сущности, т.к. логика у них разная,
в случае суперклассинга диалога, последний параметр, передаваемый функции CreateDialog, должен быть NULL!:
Код

::CreateDialog(CXApplication::hGetInstance(), MAKEINTRESOURCE(iID), hParent, NULL);

в брейкпойнте, у тебя работает диалоговая процедура, а не процедура окна,
а между ними огромная разница:
http://msdn.microsoft.com/en-us/library/ms645469(VS.85).aspx
http://msdn.microsoft.com/en-us/library/ms633573(VS.85).aspx
я же объяснял

Автор: Alca 30.7.2009, 08:56
Спасибо.
Цитата

мы ведь уже обсуждали проблему идентификации диалога при суперклассинге,
изнутри твоего класса эту проблему решить можно, если сохранять процедуру класса-предка в самом объекте,
а в последствии, изучать ее: если она равна DefDlgProc, то это диалог, иначе - нет,
конечно, это верно только при условии, что цепочка предков состоит только из одного класса
(судя по коду, этого более чем достаточно)

т.е. заведи в сишном классе полекод 
Код

  WNDPROC StdProc;




а заполняй его только в методах: bCreateEx, bCreate и bCreateRes
для всех методов инициируй его в DefWindowProc, кроме bCreateRes, тут ставь DefDlgProc
тогда в s_BaseWndProc вместо компаратора bIsDialog ставь просто вызовкод 
Код

  return ::CallWindowProc(StdProc,...);


 smile 

Автор: Alca 30.7.2009, 09:20
Мне хотя бы полноценный примерчик субклассирования с ::CreateDialog (без ::CreateWindowEx)

Добавлено через 12 минут и 3 секунды
Код

_m_WndClass.lpfnWndProc   = NULL; //s_BaseWndProc;    //This function is called by windows
_m_hWnd = ::CreateDialog(CXApplication::hGetInstance(), MAKEINTRESOURCE(iID), hParent, NULL/*(DLGPROC)s_BaseWndProc*/);

Теперь вообще не попадаю в s_BaseWndProc.  smile 

Автор: Alca 30.7.2009, 11:04
 smile 

Автор: GremlinProg 30.7.2009, 13:35
хорошо, привожу пример суперклассинга для диалога,
а чтобы ни кого особенно не напрягал объем кода, объясняю:
я просто создал обычный проект Win32 Project, так что по большей части,
это чуть-чуть подправленный стандартный Win32-шаблон
Код

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;                                // current instance
TCHAR szTitle[MAX_LOADSTRING];                    // The title bar text

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
HWND hWnd;

int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow){
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.
    MSG msg;
    HACCEL hAccelTable;

    // Initialize global strings
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance,nCmdShow))
    {
        return FALSE;
    }

    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_INHERITEDDIALOG));

    // Main message loop:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if ( !IsDialogMessage( hWnd, &msg ) && !TranslateAccelerator(msg.hwnd, hAccelTable, &msg) )
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style            = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra        = 0;
    wcex.cbWndExtra        = DLGWINDOWEXTRA;
    wcex.hInstance        = hInstance;
    wcex.hIcon            = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_INHERITEDDIALOG));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground    = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName    = NULL;
    wcex.lpszClassName    = _T("Мой диалоговый класс");
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassEx(&wcex);
}

//
//   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 InitInstance(HINSTANCE hInstance,int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable
   hWnd = ::CreateDialog(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),HWND_DESKTOP,NULL);
   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd,nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  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 WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM 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(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            ::DestroyWindow(hWnd);
            break;
        }
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // TODO: Add any drawing code here...
        EndPaint(hWnd, &ps);
        break;
    case WM_CLOSE:
        return ::DefWindowProc(hWnd,message,wParam,lParam);
    case WM_DESTROY:
        PostQuitMessage( S_OK );
        break;
    }
    return::CallWindowProc(DefDlgProc,hWnd, message, wParam, lParam);
}

// Message handler for about box.
INT_PTR CALLBACK 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;
}

файл ресурсов:
Код

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#ifndef APSTUDIO_INVOKED
#include "targetver.h"
#endif
#define APSTUDIO_HIDDEN_SYMBOLS
#include "windows.h"
#undef APSTUDIO_HIDDEN_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// Russian resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
#ifdef _WIN32
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
#pragma code_page(1251)
#endif //_WIN32

/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_DIALOG1 DIALOGEX 0, 0, 316, 185
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Мой диалог"
MENU IDC_INHERITEDDIALOG
CLASS "Мой диалоговый класс"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,205,164,50,14
    PUSHBUTTON      "Cancel",IDCANCEL,259,164,50,14
    LTEXT           "Диалоговый контрол:",IDC_STATIC,32,44,77,12
    EDITTEXT        IDC_EDIT1,113,42,97,14,ES_AUTOHSCROLL
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO 
BEGIN
    IDD_DIALOG1, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 309
        TOPMARGIN, 7
        BOTTOMMARGIN, 178
    END
END
#endif    // APSTUDIO_INVOKED

#endif    // Russian resources
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32

/////////////////////////////////////////////////////////////////////////////
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_INHERITEDDIALOG     ICON                    "InheritedDialog.ico"
IDI_SMALL               ICON                    "small.ico"

/////////////////////////////////////////////////////////////////////////////
//
// Menu
//

IDC_INHERITEDDIALOG MENU 
BEGIN
    POPUP "&File"
    BEGIN
        MENUITEM "E&xit",                       IDM_EXIT
    END
    POPUP "&Help"
    BEGIN
        MENUITEM "&About ...",                  IDM_ABOUT
    END
END


/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//

IDC_INHERITEDDIALOG ACCELERATORS 
BEGIN
    "?",            IDM_ABOUT,              ASCII,  ALT
    "/",            IDM_ABOUT,              ASCII,  ALT
END


/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_ABOUTBOX DIALOGEX 0, 0, 170, 62
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About InheritedDialog"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
    ICON            128,IDC_STATIC,14,14,21,20
    LTEXT           "InheritedDialog, Version 1.0",IDC_STATIC,42,14,114,8,SS_NOPREFIX
    LTEXT           "Copyright (C) 2009",IDC_STATIC,42,26,114,8
    DEFPUSHBUTTON   "OK",IDOK,113,41,50,14,WS_GROUP
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO 
BEGIN
    IDD_ABOUTBOX, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 163
        TOPMARGIN, 7
        BOTTOMMARGIN, 55
    END
END
#endif    // APSTUDIO_INVOKED


#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE 
BEGIN
    "#ifndef APSTUDIO_INVOKED\r\n"
    "#include ""targetver.h""\r\n"
    "#endif\r\n"
    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
    "#include ""windows.h""\r\n"
    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// String Table
//

STRINGTABLE 
BEGIN
    IDS_APP_TITLE           "InheritedDialog"
    IDC_INHERITEDDIALOG     "INHERITEDDIALOG"
END

#endif    // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED


Добавлено через 1 минуту и 16 секунд
да, совсем забыл, файл Resource.h:
Код

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by InheritedDialog.rc
//
#define IDC_MYICON                      2
#define IDD_INHERITEDDIALOG_DIALOG      102
#define IDS_APP_TITLE                   103
#define IDD_ABOUTBOX                    103
#define IDM_ABOUT                       104
#define IDM_EXIT                        105
#define IDI_INHERITEDDIALOG             107
#define IDI_SMALL                       108
#define IDC_INHERITEDDIALOG             109
#define IDR_MAINFRAME                   128
#define IDD_DIALOG1                     129
#define IDC_EDIT1                       1000
#define IDC_STATIC                      -1

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC                     1
#define _APS_NEXT_RESOURCE_VALUE        130
#define _APS_NEXT_COMMAND_VALUE         32771
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           110
#endif
#endif


Автор: Alca 30.7.2009, 14:24
Попробую чего-то наваять...

Автор: Alca 30.7.2009, 16:10
Что-то нихрена не получается:  smile 
Код

//---------------------------------------------------------------------------
BOOL CXWindow::bCreateRes(INT iID, HWND hParent) {
    BOOL bRes = FALSE;

    //-------------------------------------
    //Register the window class
    WNDCLASSEX _m_WndClass = {0};    

    _m_WndClass.hInstance     = CXApplication::hGetInstance();        
    _m_WndClass.lpszClassName = _m_sClassName.c_str();
    _m_WndClass.lpfnWndProc   = NULL/*s_BaseWndProc*/;    
    _m_WndClass.style         = CS_DBLCLKS;                
    _m_WndClass.cbSize        = sizeof(WNDCLASSEX);
    _m_WndClass.hIcon         = NULL;                    
    _m_WndClass.hIconSm       = NULL;                        
    _m_WndClass.hCursor       = NULL;                        
    _m_WndClass.lpszMenuName  = NULL;
    _m_WndClass.cbClsExtra    = 256;                       
    _m_WndClass.cbWndExtra    = DLGWINDOWEXTRA;        
    _m_WndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);

    bRes = bRegisterClassEx(&_m_WndClass);
    CHECK_RET(FALSE == bRes, FALSE);

    _m_hWnd = ::CreateDialog(CXApplication::hGetInstance(), MAKEINTRESOURCE(iID), hParent, (DLGPROC)NULL/*s_BaseWndProc*/);
    /*DEBUG*/XASSERT_RET(NULL != _m_hWnd, FALSE);

    //-------------------------------------
    //переопределяем поля класса
    RECT rcRect = {0};
    ::GetClientRect(_m_hWnd, &rcRect);

    _m_ulExStyle  = GetWindowExStyle(_m_hWnd);    
    _m_sClassName = _m_sClassName;              
    _m_sText      = sGetText();
    _m_ulStyle    = GetWindowStyle(_m_hWnd);    
    _m_iLeft      = rcRect.left;
    _m_iTop       = rcRect.top;
    _m_iWidth     = rcRect.right; 
    _m_iHeight    = rcRect.bottom;
    _m_hParent    =    hParent;    
    _m_iMenu      = iID;

    return TRUE;
}
//---------------------------------------------------------------------------
LRESULT CALLBACK CXWindow::s_BaseWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
    /*DEBUG*/XASSERT_RET(NULL != hWnd, NULL);

    //A pointer to the object is passed in the CREATESTRUCT
    if (WM_INITDIALOG/*WM_NCCREATE*/ == uiMsg) {
        //::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams);
        ::SetWindowLong(hWnd, DWL_DLGPROC, (LONG)(LONG_PTR)CXWindow::s_BaseWndProc);
    }

    BOOL      bProcessed = FALSE;
    LRESULT   lResult    = NULL;
    CXWindow *pObj       = NULL;

    //Retrieve the pointer
    //pObj = (CXWindow *)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
    pObj = (CXWindow *)::GetWindowLongPtr( hWnd, DWL_DLGPROC);


    //Filter message through child classes
    if (NULL != pObj) {
        lResult = pObj->pWndProc(hWnd, uiMsg, wParam, lParam, &bProcessed);
    }

    if (TRUE == bProcessed) {
        return lResult;
    } else {
        //////If message was unprocessed, send it back to Windows.
        //return ::DefWindowProc(hWnd, uiMsg, wParam, lParam);

        return ::CallWindowProc(DefDlgProc, hWnd, uiMsg, wParam, lParam);
    }
}
//---------------------------------------------------------------------------
/*virtual*/LRESULT CXWindow::pWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam, PBOOL pbProcessed) {
    /*DEBUG*/XASSERT_RET(NULL != _m_hWnd, NULL);

    //This may be overridden to process messages.
    *pbProcessed = FALSE;

    return NULL;
}
//---------------------------------------------------------------------------

Автор: GremlinProg 30.7.2009, 16:25
так, в приложении пример того, что получилось

Автор: GremlinProg 30.7.2009, 16:30
а теперь в приложении сам проект

Автор: GremlinProg 30.7.2009, 16:37
Цитата(Alca @  30.7.2009,  18:10 Найти цитируемый пост)
_m_WndClass.lpfnWndProc   = NULL/*s_BaseWndProc*/; 

Цитата(Alca @  29.7.2009,  17:54 Найти цитируемый пост)
_m_sClassName(""),


Alca, загляни в проект,
посмотри на его логику,
разбери код,
повторяю, 95-97% от того, что у меня написано - стандартный проект win32
CreateWindow заменен на CreateDialog + небольшие изменения/дополнения в классе окна, процедуре окна и цикле сообщений

Автор: Alca 30.7.2009, 16:40
Цитата

а теперь в приложении сам проект 

Присоединённый файл ( Кол-во скачиваний: 0 ) 
  InheritedDialog.rar 29,65 Kb

Спасибо.
У меня этот проект работает. А вот код, который был чуть выше - нет  smile 
Где я накосячил?

Автор: GremlinProg 30.7.2009, 17:44
Цитата(Alca @  30.7.2009,  18:40 Найти цитируемый пост)
Где я накосячил?

во первых, не указана процедура окна, не надо так радикально расставлять NULL'ы ),
я же писал только о CreateDialog
без _m_WndClass.lpfnWndProc класс-потомок просто не будет зарегистрирован

во вторых, непонятно, какое имя у этого класса, предполагаю "",
судя по тому, как  _m_sClassName инициализируется в конструкторе

ну и в третьих, т.к. я не вижу твоего шаблона,
для суперклассинга диалога требуется четкое соответствие свойства CLASS в шаблоне диалога
и имени класса _m_sClassName,
т.е., судя по всему, у тебя эти значения должны быть равны и не должны быть пустыми

в моем примере, имя класса "Мой диалоговый класс", а оконная процедура для диалога - WndProc

Автор: Alca 30.7.2009, 20:44
А данная структура должна быть членом класса или не обязательно?
Код

WNDCLASSEX _m_WndClass = {0};


Добавлено @ 20:52
Цитата

во первых, не указана процедура окна, не надо так радикально расставлять NULL'ы ),
я же писал только о CreateDialog
без _m_WndClass.lpfnWndProc класс-потомок просто не будет зарегистрирован

исправил:
Код

_m_WndClass.lpszClassName = _m_sClassName.c_str();

Цитата

во вторых, непонятно, какое имя у этого класса, предполагаю "",
судя по тому, как  _m_sClassName инициализируется в конструкторе

Инициализировано:
Код

CXFrame::CXFrame() {
    _m_sClassName = "XFRAME";
    _m_bIsFrame      = TRUE;
}


Добавлено @ 20:54
Код

BOOL CXWindow::bCreateRes(INT iID, HWND hParent) {
    BOOL bRes = FALSE;

    //-------------------------------------
    //если это окно - WNDCLASSEX, если контрол - ::GetDlgItem
    if (TRUE == _m_bIsFrame) {
        //-------------------------------------
        //Register the window class
        WNDCLASSEX _m_WndClass = {0};    
    
        _m_WndClass.hInstance     = CXApplication::hGetInstance();        
        _m_WndClass.lpszClassName = _m_sClassName.c_str();
        _m_WndClass.lpfnWndProc   = s_BaseWndProc;    //This function is called by windows
        _m_WndClass.style         = CS_HREDRAW | CS_VREDRAW;                //Catch double-clicks
        _m_WndClass.cbSize        = sizeof(WNDCLASSEX);
        _m_WndClass.hIcon         = NULL;                    //LoadIcon (hInstance, 0);
        _m_WndClass.hIconSm       = NULL;                        //LoadIcon (hInstance, 0);
        _m_WndClass.hCursor       = NULL;                        //LoadCursor (NULL, IDC_ARROW);
        _m_WndClass.lpszMenuName  = NULL;
        _m_WndClass.cbClsExtra    = 0;                        //No extra bytes after the window class
        _m_WndClass.cbWndExtra    = DLGWINDOWEXTRA;        //используем диалог с ресурса
        _m_WndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);

        bRes = bRegisterClassEx(&_m_WndClass);
        CHECK_RET(FALSE == bRes, FALSE);
    
        _m_hWnd = ::CreateDialog(::GetModuleHandle(NULL), MAKEINTRESOURCE(iID), hParent, (DLGPROC)NULL/*s_BaseWndProc*/);
        /*DEBUG*/XASSERT_RET(NULL != _m_hWnd, FALSE);
    } else  {
        _m_hWnd = ::GetDlgItem(hParent, iID);
        /*DEBUG*/XASSERT_RET(NULL != _m_hWnd, FALSE);
    }

    bRes = bSetDefaultFont();
    CHECK_RET(FALSE != bRes, FALSE);

    //-------------------------------------
    //переопределяем поля класса
    RECT rcRect = {0};
    ::GetClientRect(_m_hWnd, &rcRect);

    _m_ulExStyle  = GetWindowExStyle(_m_hWnd);    
    _m_sClassName = _m_sClassName;              
    _m_sText      = sGetText();
    _m_ulStyle    = GetWindowStyle(_m_hWnd);    
    _m_iLeft      = rcRect.left;
    _m_iTop       = rcRect.top;
    _m_iWidth     = rcRect.right; 
    _m_iHeight    = rcRect.bottom;
    _m_hParent    =    hParent;    
    _m_iMenu      = iID;
    
    /*DEBUG*/XASSERT_RET(_m_sClassName == "XFRAME", FALSE);

    return TRUE;
}


Добавлено @ 20:59
Код

LRESULT CALLBACK CXWindow::s_BaseWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
    /*DEBUG*/XASSERT_RET(NULL != hWnd, NULL);

    LONG      dwNewLong = 0;          /*здесь стоит брейкпоинт*/
    CXWindow *pULWnd    = NULL;
    
    switch (uiMsg) {
        case WM_INITDIALOG:    {
                ::SetWindowLong(hWnd, GWL_USERDATA, (LONG)lParam);
                pULWnd = (CXWindow *)lParam; // получим указатель на класс
                pULWnd->_m_hWnd = hWnd;
                break;
            }
        case WM_NCCREATE: {
                dwNewLong = (INT)//*(LONG_PTR)*/((LPCREATESTRUCT)lParam)->lpCreateParams;
                ::SetWindowLong(hWnd, GWL_USERDATA, dwNewLong);
                pULWnd = (CXWindow *)(((LPCREATESTRUCT)lParam)->lpCreateParams); // получим указатель на класс
                pULWnd->_m_hWnd = hWnd;
                break;
            }
        default: {
                pULWnd = (CXWindow *)::GetWindowLong(hWnd, GWL_USERDATA); // получим указатель на класс
            }
    }

    BOOL bProcessed = FALSE;
    if (NULL != pULWnd) {
        return pULWnd->pWndProc(hWnd, uiMsg, wParam, lParam, &bProcessed);
    }
    
    return FALSE;
}

Самое интересное, что в эту функцию s_BaseWndProc я не попадаю на брейкпоинты, т,е, ваще сюда "не заходиться"

Автор: GremlinProg 30.7.2009, 22:17
а свойство CLASS в шаблоне диалога?
Цитата(GremlinProg @  30.7.2009,  15:35 Найти цитируемый пост)

...
IDD_DIALOG1 DIALOGEX 0, 0, 316, 185
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Мой диалог"
MENU IDC_INHERITEDDIALOG
CLASS "Мой диалоговый класс"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
...


Добавлено через 2 минуты и 28 секунд
Цитата(Alca @  30.7.2009,  22:44 Найти цитируемый пост)
А данная структура должна быть членом класса или не обязательно?

нет, не обязательно

Автор: Alca 30.7.2009, 22:47
Исправил:
Код

/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_DIALOGBAR DIALOGEX 0, 0, 220, 134
STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
FONT 8, "MS Shell Dlg", 400, 0, 0x0
CLASS "XFRAME"
BEGIN
    PUSHBUTTON      "Button1",IDC_BUTTON1,163,113,50,14
    EDITTEXT        IDC_EDIT1,6,7,207,20,ES_AUTOHSCROLL
END


Код

        case WM_NCCREATE: {
                dwNewLong = (INT)/*(LONG_PTR)*/((LPCREATESTRUCT)lParam)->lpCreateParams;
                ::SetWindowLong(hWnd, GWL_USERDATA, dwNewLong);
                pObj = (CXWindow *)(((LPCREATESTRUCT)lParam)->lpCreateParams); // получим указатель на класс
                pObj->_m_hWnd = hWnd;  /* >>> валиться здесь, т,к, pObj есть NULL <<<*/
                break;
            }


Добавлено @ 22:48
Код

GetLastError: Операция успешно завершена.


Добавлено через 14 минут и 36 секунд
Какое сообщение ловить WM_INITDIALOG или WM_NCCREATE?
Код

...
        case WM_INITDIALOG:    
...
        case WM_NCCREATE:
...

Автор: Alca 30.7.2009, 23:06
Раньше (до исправлений) у меня сообщения заходили в  метку WM_INITDIALOG, а теперь в WM_NCCREATE.
Кажись что-то продвигается.  smile 

Автор: GremlinProg 31.7.2009, 08:18
да, теперь работает процедура окна, тут все сообщения будут приходить
Цитата(Alca @  31.7.2009,  00:47 Найти цитируемый пост)
pObj->_m_hWnd = hWnd;  /* >>> валиться здесь, т,к, pObj есть NULL <<<*/

там параметра-то нет, используй CreateDialogIndirectParam, и в последний параметр передай this
вообще, это нужно ловить на WM_INITDIALOG, тогда этот параметр придет в lParam
если после WM_NCCREATE сразу приходит WM_DESTROY, значит некорректно обрабатываешь WM_NCCREATE, посмотри s_BaseWndProc, она должна передавать сообщение дальше, по цепочке:
Код

return ::CallWindowProc(DefDlgProc, hWnd, uiMsg, wParam, lParam);

Автор: Alca 31.7.2009, 10:08
Код

//---------------------------------------------------------------------------
...
        WNDCLASSEX _m_WndClass = {0};    
    
        _m_WndClass.hInstance     = ::GetModuleHandle(NULL);    //CXApplication::hGetInstance();        
        _m_WndClass.lpszClassName = _m_sClassName.c_str();
        _m_WndClass.lpfnWndProc   = (WNDPROC)s_BaseWndProc;    
        _m_WndClass.style         = CS_HREDRAW | CS_VREDRAW;                
        _m_WndClass.cbSize        = sizeof(WNDCLASSEX);
        _m_WndClass.hIcon         = NULL;                    
        _m_WndClass.hIconSm       = NULL;                        
        _m_WndClass.hCursor       = NULL;                        
        _m_WndClass.lpszMenuName  = NULL;
        _m_WndClass.cbClsExtra    = 0;                     
        _m_WndClass.cbWndExtra    = DLGWINDOWEXTRA;        
        _m_WndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);

        bRes = bRegisterClassEx(&_m_WndClass);
        CHECK_RET(FALSE == bRes, FALSE);
    
        //_m_hWnd = ::CreateDialog(::GetModuleHandle(NULL), MAKEINTRESOURCE(iID), hParent, (DLGPROC)NULL);
        _m_hWnd = ::CreateDialogParam(GetModuleHandle(NULL), (LPCTSTR)iID, hParent, (DLGPROC)NULL, LPARAM(this));
...
//---------------------------------------------------------------------------
LRESULT /*CALLBACK*/ CXWindow::s_BaseWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
    /*DEBUG*/XASSERT_RET(NULL != hWnd, NULL);

    /*breakpoint>>*/LONG      dwNewLong = 0;
    CXWindow *pObj      = NULL;
    BOOL      bProcessed = FALSE;
    
    switch (uiMsg) {
        case WM_INITDIALOG:    {
                ::SetWindowLong(hWnd, GWL_USERDATA, (LONG_PTR)/*(LONG)*/lParam);
                pObj = (CXWindow *)lParam; // получим указатель на класс
                pObj->_m_hWnd = hWnd;
                break;
            }
        case WM_NCCREATE: {
                //2-ой проход
                dwNewLong = (LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams;
                ::SetWindowLong(hWnd, GWL_USERDATA, dwNewLong);
                pObj = (CXWindow *)(((LPCREATESTRUCT)lParam)->lpCreateParams); // получим указатель на класс
                XASSERT(NULL != pObj);  //<<< срабатывает 
                pObj->_m_hWnd = hWnd;  //эксепшн

                break;
            }
        default: {
                //1-ый проход идет сюда
                pObj = (CXWindow *)::GetWindowLong(hWnd, GWL_USERDATA); // получим указатель на класс
                XASSERT(NULL != pObj);  //<<< срабатывает, идем дальше
            }
    }

    if (NULL != pObj) {
        return ::DefWindowProc(hWnd, uiMsg, wParam, lParam);
    }
    
    //return FALSE;
    return ::CallWindowProc(DefDlgProc, hWnd, uiMsg, wParam, lParam);
}
//---------------------------------------------------------------------------

Автор: GremlinProg 31.7.2009, 13:47
Alca, чтобы особенно не заморачиваться, я предлагаю тебе сделать так:
Код

class XWindow{

  static XWindow*lpInitObject = NULL;

  static LRESULT CALLBACK BaseProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam){
    XWindow*lpObject = (XWindow*)GetWindowLong(hwnd,GWL_USERDATA);
    return lpObject->WndProc(uMsg,wParam,lParam);
  }

  static LRESULT CALLBACK InitWndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam){
    assert( lpInitObject );
    ::SetWindowLong(hwnd,GWL_USERDATA,(LONG)lpInitObject);
    lpInitObject->hwnd = hwnd;
    lpInitObject             = NULL;
    ::SetWindowLong(hwnd,GWL_WNDPROC,(LONG)BaseProc);
    return CallWindowProc(BaseProc,hwnd,uMsg,wParam,lParam);
  }

  virtual LRESULT WndProc(UINT uMsg,WPARAM wParam,LPARAM lParam){
    switch( uMsg ){
      ...
    }
    return CallWindowProc(DefDlgProc,hwnd,uMsg,wParam,lParam);
  }

  HWND CreateFromResource(...){
    WNDCLASSEX wcex;
    ...
    wcex.lpfnWndProc   = InitWndProc;
    ...
    ::RegisterClassEx(wcex);
    ...
    lpInitObject = this;
    return ::CreateDialog(...);
  }

};

объясняю:
lpInitObject - это статический указатель, который будет хранить объект окна в момент создания окна
InitWndProc - это первичная процедура окна, задача которой - принять любое первое сообщение от окна, инициализировать GWL_USERDATA и переставить процедуру окна на BaseProc
BaseProc - вторичная процедура окна, эта процедура независимо от стилей окна всегда имеет доступ к корректному GWL_USERDATA, поэтому она просто извлекает этот объект и передает управление его методу WndProc
WndProc - это уже не статический метод, в ее обязанности входит управление цепочкой оконных классов, она вызывает CallWindowProc, switch я поставил просто для примера, если тебе надо в этом классе перехватывать какие-нибудь сообщения, а вообще, это можно делать уже в потомках
CreateFromResource - делает то же самое, что и у тебя, за исключением того, что перед вызовом CreateDialog устанавливает lpInitObject

теперь, от класса XWindow наследуй свои классы,
можешь перекрывать метод WndProc в потомках и делать что хошь

Добавлено через 3 минуты и 28 секунд
Цитата(GremlinProg @  31.7.2009,  15:47 Найти цитируемый пост)
 делать что хошь

делать что хошь с диалоговым окном в парадигме ООП

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)