CWndを派生したクラスの破棄

CWndの派生クラスをCreate関数で作成した場合、場合によってはDestroyWindow関数を利用して破棄する必要があります。
この処理を行わないと、ウィンドウが破棄されず、HWNDが参照できてしまいます。
HWNDが参照できてしまうと、破棄したはずのCWndの派生クラスにメッセージが送信されてしまうことがあります。

ウィンドウを生成する時の大原則として、必ずウィンドウを破棄する流れを作る必要があります。
(MFCが自動でやってくれていると思ったのが大きな間違いでした^^;)

まずは正しくない例を見てみましょう

正しくない例
<CHogeWndクラス>
class CHogeWnd : public CWnd{
public:
    ・・・
    CHogeWnd();
    virtual ~CHogeWnd();
    BOOL Create(..略..);
    ・・・
private:
    ・・・
    CHogeDraw m_pDraw;      //何らかの情報をもっているクラス
    ・・・
};

CHogeWnd:CHogeWnd(){
    ・・・
    m_pDraw = NULL;
    ・・・
}
CHogeWnd::~CHogeWnd(){
    ・・・
    delete m_pDraw;
    ・・・
}
BOOL CHogeWnd::Create(..略..){
    ・・・
    m_pDraw = new CHogeDraw();
    ・・・
}

BOOL CHogeWnd::OnPaint(..略..){
    ・・・
    intnHoge = m_pDraw->GetHoge();
    ・・・
}

<CHogeMainWndクラス>
class CHogeMainWnd : public CWnd{
public:
    ・・・
    CHogeMainWnd();
    virtual ~CHogeMainWnd();
    BOOL Create(..略..);
    ・・・
private
    ・・・
    CHogeWnd m_pHoge;
    ・・・
};

CHogeMainWnd:CHogeMainWnd(){
    ・・・
    m_pHoge = NULL;
    ・・・
}
CHogeMainWnd::~CHogeMainWnd(){
    ・・・
}
BOOL CHogeMainWnd::Create(..略..){
    ・・・
    m_pHoge = new CHogeWnd();
    m_pHoge->Create(...略...);
    ・・・
}

BOOL CHogeMainWnd::OnClose(..略..){
    delete m_pHoge;
}

上の例で問題なのは、明示的にDestroyWindow関数を呼んでいないことです。
DestroyWindowが呼ばれない場合、ウィンドウが破棄されません。ウィンドウが破棄されないと、m_hWndが破棄されません。
m_hWndが破棄されていないということは、メッセージの受信が出来ることになります。
この状態で、WM_PAINTメッセージがCHogeWndに送信されると、m_pDrawは破棄されているのでアプリケーションエラーが発生します。
(仕事で経験済み^^;)

このような場合は、CHogeWndのデストラクタでDestroyWindowを明示的に呼び出す必要が出て来ます。
ちなみに、DestroyWindow関数は、m_hWndのNULLチェックを行っているので、特にチェックする必要がありません。(理論上は何度呼んでも問題ないはず)

正しい例
<CHogeWndクラス>
class CHogeWnd : public CWnd{
public:
    ・・・
    CHogeWnd();
    virtual ~CHogeWnd();
    BOOL Create(..略..);
    ・・・
private:
    ・・・
    CHogeDraw m_pDraw;      //何らかの情報をもっているクラス
    ・・・
};

CHogeWnd:CHogeWnd(){
    ・・・
    m_pDraw = NULL;
    ・・・
}
CHogeWnd::~CHogeWnd(){
    ・・・
    DestroyWindow();
    delete m_pDraw;
    ・・・
}
BOOL CHogeWnd::Create(..略..){
    ・・・
    m_pDraw = new CHogeDraw();
    ・・・
}

BOOL CHogeWnd::OnPaint(..略..){
    ・・・
    intnHoge = m_pDraw->GetHoge();
    ・・・
}

<CHogeMainWndクラス>
class CHogeMainWnd : public CWnd{
public:
    ・・・
    CHogeMainWnd();
    virtual ~CHogeMainWnd();
    BOOL Create(..略..);
    ・・・
private
    ・・・
    CHogeWnd m_pHoge;
    ・・・
};

CHogeMainWnd:CHogeMainWnd(){
    ・・・
    m_pHoge = NULL;
    ・・・
}
CHogeMainWnd::~CHogeMainWnd(){
    ・・・
}
BOOL CHogeMainWnd::Create(..略..){
    ・・・
    m_pHoge = new CHogeWnd();
    m_pHoge->Create(...略...);
    ・・・
}

BOOL CHogeMainWnd::OnClose(..略..){
    delete m_pHoge;
}

上の例の様にデストラクタにDestroyWindowを入れることで、ウィンドウを破棄してくれます。
ウィンドウが破棄されることで、m_hWndも破棄されて、メッセージを受け取ることがなくなります。

この他、注意しなければならない点があります。それらは参考資料:テクニカル ノート 17: ウィンドウ オブジェクトの破棄(Microsoft)を読んでください。

参考資料

テクニカル ノート 17: ウィンドウ オブジェクトの破棄