[MFC] Cum arat un message box in ExitInstance?

Despre MFC, ATL si alte biblioteci C++ de la Microsoft (forum moderat)
Post Reply
User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

[MFC] Cum arat un message box in ExitInstance?

Post by Ovidiu Cucu » 27 Jun 2010, 16:32

Problema
Daca apelez AfxMesageBox, CWnd::MessageBox sau ::MessageBox in functia ExitInstance a unei aplicatii dialog-based, nu apare nimic.
Acelasi lucru se intampla si in InitInstance, dupa ce dialogul principal a fost inchis (dupa ce se iese din DoModal).

Rezolvare (1)
Asta se intampla deoarece, atunci cand fereastra principala a aplicatiei este distrusa, framework-ul trimite un WM_QUIT aplicatiei iar orice fereastra creata supa aceea va fi distrusa imediat.
O solutie des intalnita pe net este ca in InitInstance sa se stearga linia care atribuie adresa dialogului principal la membrul CWinThread::m_pMainWnd.

Exemplu

Code: Select all

BOOL CDemoApp::InitInstance()
{
   // ...
   CDemoMainDialog dlg;
   // m_pMainWnd = &dlg; // <-- remove this line.
   INT_PTR nResponse = dlg.DoModal();
   //...
   AfxMessageBox(_T("After closing main dialog"));
   return FALSE;
}

int CDemoApp::ExitInstance()
{
   AfxMessageBox(_T("ExitInstance"));
   return CWinApp::ExitInstance();
}
Asta merge dar are un mic mare dezavantaj: se poate ca CWinThread::m_pMainWnd sa fie utilizat de catre functia AfxGetMainWnd. Ca o consecinta, in anumite situatii AfxGetMainWnd poate intoarce un rezultat eronat.
In implementarile mai vechi, AfxGetMainWnd intorcea direct CWinThread::m_pMainWnd si-atuncea clar, obtineam un NULL de toata frumusetea.
In astea mai noi e ceva de genul:

Code: Select all

   if (m_pMainWnd != NULL)
      return m_pMainWnd;

   return CWnd::GetActiveWindow();
Daca de exemplu avem un dialog modal deschis din ala principal si m_pMainWnd este NULL, va intoarce taman altceva decat ne asteptam, caz chiar mai rau decat primul.


Ceva mai bine:

Rezolvare (2)
  1. lasam linia cu setarea lui m_pMainWnd asa cum a pus-o wizard-ul ca sa putem folosi AfxGetMainWnd fara nici un risc de greseala;
  2. mapam mesajul WM_NCDESTROY si, inainte de a chema handler-ul din clasa de baza (in care se posteaza de fapt WM_QUIT), punem CWinThread::m_pMainWnd pe NULL.

    Code: Select all

    void CDemoMainDialog::OnNcDestroy()
    {
       AfxGetApp()->m_pMainWnd = NULL;
       CDialog::OnNcDestroy();
    }
    Implementarea lui CWnd::OnNcDestroy se uita daca 'this' e tot una cu m_pMainWnd, vede ca nu este (m_pMainWnd e NULL) si nu mai posteaza WM_QUIT.
    WM_NCDESTROY este ultimul mesaj primit de o fereastra inainte de a-si da complet duhul, deci n-avem teama ca AfxGetMainWnd ar mai putea fi de folos mai departe pe undeva.
Vezi si << Back to MFC index



Post Reply