Модераторы: feodorv, GremlinProg, xvr, Fixin

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Свой класс CWindow, субклассирование, окно из ресурсов не обрабатыв. сообщения 
:(
    Опции темы
GremlinProg
Дата 30.7.2009, 17:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



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

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

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

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

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


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Alca
Дата 30.7.2009, 20:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 5
Всего: 50



А данная структура должна быть членом класса или не обязательно?
Код

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 я не попадаю на брейкпоинты, т,е, ваще сюда "не заходиться"

Это сообщение отредактировал(а) Alca - 30.7.2009, 21:00


--------------------
PM WWW ICQ Skype Jabber   Вверх
GremlinProg
Дата 30.7.2009, 22:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



а свойство 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 Найти цитируемый пост)
А данная структура должна быть членом класса или не обязательно?

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


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Alca
Дата 30.7.2009, 22:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 5
Всего: 50



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

/////////////////////////////////////////////////////////////////////////////
//
// 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, 22:50


--------------------
PM WWW ICQ Skype Jabber   Вверх
Alca
Дата 30.7.2009, 23:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 5
Всего: 50



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


--------------------
PM WWW ICQ Skype Jabber   Вверх
GremlinProg
Дата 31.7.2009, 08:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



да, теперь работает процедура окна, тут все сообщения будут приходить
Цитата(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);



--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Alca
Дата 31.7.2009, 10:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 5
Всего: 50



Код

//---------------------------------------------------------------------------
...
        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);
}
//---------------------------------------------------------------------------



--------------------
PM WWW ICQ Skype Jabber   Вверх
GremlinProg
Дата 31.7.2009, 13:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



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 Найти цитируемый пост)
 делать что хошь

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


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0781 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.