2009-11-11 7 views
1

J'ai une application SDI WTL 8.0 pour Windows Mobile 5. Dans cet exemple inventé ci-dessous, je crée une vue, la détruis, puis la recréer. Mais, lorsqu'il est recréé, les assertions du gestionnaire WM_INITDIALOG échouent car le HWND du contrôle n'est pas valide.par défaut WM_DESTROY ne nettoie pas correctement les fenêtres enfants

Je remarque que je peux résoudre ce problème en gérant WM_DESTROY dans CMyView et en détruisant manuellement chaque contrôle enfant. Mais, je ne pensais pas que je devrais le faire. MSDN even says:

Ce message est envoyé d'abord à la fenêtre étant détruite, puis aux fenêtres de l'enfant (le cas échéant) comme ils sont détruits.

Quelqu'un a-t-il une idée de ce qui se passe? Editer: Si je gère WM_NCDESTROY dans CMyView, toutes les poignées de contrôle enfants sont toujours valides! (some_control_.IsWindow()==TRUE) Ce n'est pas la façon dont il est censé être ...

Merci, paulh

class CMyView : public CDialogImpl<CMyView>, 
       public CWinDataExchange<CMyView> 
{ 
    // <snip> Message Map and other standard WTL macros </snip> 

    LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 
    { 
     DoDataExchange(FALSE); 
     // assertion fails within the SetWindowText() call 
     // atlwin.h line 876 
     // ATLASSERT(::IsWindow(m_hWnd)); 
     some_control_.SetWindowText(_T("Foo")); 
     return 0; 
    }; 

private: 
    CEdit some_control_; 
}; // class CMyView 

class CMainFrame : public CFrameWindowImpl<CMainFrame>, 
        public CUpdateUI<CMainFrame>, 
        public CMessageFilter, 
        public CIdleHandler 
{ 
public: 
    // <snip> Message Map and other standard WTL macros </snip> 

    BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) 
    { 
     if(CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg)) 
      return TRUE; 

     return my_view_.PreTranslateMessage(pMsg); 
    }; 

    LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) 
    { 
     CMessageLoop* pLoop = _Module.GetMessageLoop(); 
     ATLASSERT(pLoop != NULL); 
     pLoop->AddMessageFilter(this); 
     pLoop->AddIdleHandler(this); 

     m_hWndClient = my_view_.Create(m_hWnd); 
     my_view_.DestroyWindow(); 
     m_hWndClient = my_view_.Create(m_hWnd); 
    }; 

private: 
    CMyView my_view_; 
}; // class CMainFrame 

Répondre

0

Il n'est pas recommandé de créer, de détruire et de recréer la même fenêtre. Vous devez envisager de la masquer et de réinitialiser votre contenu lorsque vous la réaffichez.

Quoiqu'il en soit votre code ne sera pas à VALOIR re-création avec:

virtual void CMyView::OnFinalMessage(HWND) 
{ 
    some_control_.m_hWnd = 0; 
} 
+0

Merci pour votre aide. Qu'est-ce qui fait que "ce n'est pas une bonne pratique"? – PaulH

+0

Fondamentalement parce que créer et détruire une fenêtre est une opération exigeante du système. Pratiquement parce que ATL :: CWindowImpl ne le gère pas correctement, donc nous avons du travail supplémentaire :-) –

0

Je ne suis pas à cent pour cent sûr, mais il semble que le contrôle some_control_ CEdit n'est pas inscrit sur la fenêtre parent. Je pense que vous devrez appeler some_control_.Create (...) avec le handle parent comme paramètre.

Voir l'article msdn pour une documentation de CEdit::Create().

+0

qui est fait par la partie je comme « un message carte et autres macros standard WTL ». Il était prévu d'inclure le DDX_MAP qui gérerait cela. – PaulH

Questions connexes