Все было отлично. Но вот по событию "нажатие кнопки", приходящему синхронно от CButton в бизнес-логику, эта бизнес-логика закрывает окно, в котором содержится кнопка и все рушится по assert-у в недрах ATL::CWindow. Фигня вся в том, что все это происходит в обработчике WM_LBUTTONDOWN, а закрытие окна ведет к удалению объекта этого самого окна, которое грохает коллекцию его контролов (CEdit, CButton, ...), они в свою очередь грохают объекты CEditImpl, CButtonImpl, ... А деструктор класса ATL::CWindow (от него унаследованы все CButtonImpl) ругается на то, что виндовый контрол "кнопка" еще не уничтожен - внутри его обработчика WM_LBUTTONDOWN мы сейчас сидим.
В ATL/WTL безопасно можно грохать оконный объект в виртуальной OnFinalMessage(), то есть объект CButtonImpl должен пережить CButton, а в CButtonImpl::OnFinalMessage() прибить себя. Но все же CButton тоже должен уметь убивать CButtonImpl, например если виндовый контрол еще не был создан - в таком случае до CButtonImpl::OnFinalMessage() дело не дойдет.
Вобщем было много головной боли по поводу того кто и когда должен грохнуть объект CButtonImpl: то ли сам CButtonImpl, то ли CButton, они должны между собой согласовать действия чтобы:
1. не упать по assert-у в недрах деструктора ATL::CWindow
2. все же удалить CButtonImpl
3. не удалить его несколько раз ;)
Вначале я написал море кода, которое спотыкалось то тут, то там. Но вскоре удалил его нафиг, так как понял что изобретаю велосипед.
Решение получилось примерно такое:
class CButtonImpl : ATL::CWindow...
{
public:
void OnFinalMessage() { SharedPointer.release(); }
boost::shared_ptr<CButtonImpl> SharedPointer;
}
class CButton
{
public:
CButton() : _ButtonImpl(new CButtonImpl)
{
}
void Create()
{
_Button->Create();
_Button->SharedPointer = _Button;
}
private:
boost::shared_ptr<CButtonImpl> _ButtonImpl;
};
То есть условно говоря, CButtonImpl держит себя за волосы пока он существует как виндовый контрол.
Ссылка по теме: delete this
Комментариев нет:
Отправить комментарий