参考:http://www.codeproject.com/Articles/4248/Modal-MFC-frame-window
关键文件ModalFrame.h、ModalFrame.cpp,实现模态框的控制。
ModalFrame.h
/
//
// CModalFrame Version 1.2
//
// Created: May 28, 2003 Last modified: Aug 5, 2005
//
/
// Copyright (C) 2003-2005 by Alexey Nikitin. All rights reserved.
//
// This code is free for personal and commercial use, providing this
// notice remains intact in the source files and all eventual changes are
// clearly marked with comments.
//
// You must obtain the author's consent before you can include this code
// in a software library.
//
// No warrantee of any kind, express or implied, is included with this
// software; use at your own risk, responsibility for damages (if any) to
// anyone resulting from the use of this software rests entirely with the
// user.
//
// Send bug reports, bug fixes, enhancements, requests, flames, etc. to
// nick@complex-a5.ru.
/
#if !defined(MODALFRAME_H_1F53AB30_F611_4DF8_B694_7089307224AD__INCLUDED_)
#define MODALFRAME_H_1F53AB30_F611_4DF8_B694_7089307224AD__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
struct CModalFrame
{
static void End(CFrameWnd * pModalFrameWnd, int nResult);
static bool Run(CRuntimeClass & FrameWndClass,
bool bTopLevelParentPlacement,
UINT nIDFrameResource,
DWORD dwDefaultStyle = WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,
CWnd * pParentWnd = NULL,
CCreateContext * pContext = NULL);
// if (bParentPlacement == true && pParentWnd != NULL)
// frame placement on the screen will be the same as
// top level parent window of pParentWnd.
// else
// frame placement on the screen will be selected by
// the system.
};
/
#endif // !defined(MODALFRAME_H_1F53AB30_F611_4DF8_B694_7089307224AD__INCLUDED_)
ModalFrame.cpp
/
//
// CModalFrame Version 1.2
//
// Created: May 28, 2003 Last modified: Aug 5, 2005
//
/
// Copyright (C) 2003-2005 by Alexey Nikitin. All rights reserved.
//
// This code is free for personal and commercial use, providing this
// notice remains intact in the source files and all eventual changes are
// clearly marked with comments.
//
// You must obtain the author's consent before you can include this code
// in a software library.
//
// No warrantee of any kind, express or implied, is included with this
// software; use at your own risk, responsibility for damages (if any) to
// anyone resulting from the use of this software rests entirely with the
// user.
//
// Send bug reports, bug fixes, enhancements, requests, flames, etc. to
// nick@complex-a5.ru.
/
#include "stdafx.h"
#include <afxpriv.h>
#include "ModalFrame.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
namespace
{
class CModalFrameLock : public CWnd
{
public:
CModalFrameLock(CWnd * pParentWnd); // standard constructor
~CModalFrameLock();
int DoModal();
void EndModal(int nResult);
bool _bTopLevelParentPlacement;
CRuntimeClass * _pFrameWndClass;
UINT _nIDResource;
DWORD _dwDefaultStyle;
CCreateContext * _pContext;
static CModalFrameLock * FromHandle(HWND hwndFrame);
private:
CModalFrameLock * _prev;
CModalFrameLock * _next;
CWnd * _pParentWnd;
CFrameWnd * _pFrameWnd;
WNDPROC _WndProc;
static LRESULT CALLBACK FrameSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static CModalFrameLock _barier;
CFrameWnd * CreateFrame(CWnd * pParentWnd);
};
} // namespace
/
// CModalFrame::
void CModalFrame::End(CFrameWnd * pModalFrameWnd, int nResult)
{
ASSERT(pModalFrameWnd && ::IsWindow(pModalFrameWnd->m_hWnd));
if (CModalFrameLock * pLock = CModalFrameLock::FromHandle(pModalFrameWnd->m_hWnd))
{
pLock->EndModal(nResult);
return;
}
ASSERT(false);
} // CModalFrame::End
bool CModalFrame::Run(CRuntimeClass & FrameWndClass,
bool bTopLevelParentPlacement,
UINT nIDResource,
DWORD dwDefaultStyle,
CWnd * pParentWnd,
CCreateContext * pContext)
{
ASSERT(!(dwDefaultStyle & WS_CHILD));
if (dwDefaultStyle & WS_CHILD)
return false;
//ASSERT(nIDResource != 0); // must have a resource ID to load from
ASSERT(&FrameWndClass);
ASSERT(FrameWndClass.IsDerivedFrom(RUNTIME_CLASS(CFrameWnd)));
CModalFrameLock dlg(pParentWnd);
dlg._pFrameWndClass = &FrameWndClass;
dlg._bTopLevelParentPlacement = bTopLevelParentPlacement;
dlg._nIDResource = nIDResource;
dlg._dwDefaultStyle = dwDefaultStyle;
dlg._pContext = pContext;
return (dlg.DoModal() != IDCANCEL);
} // CModalFrame::Run
/
// CModalFrameLock::
CModalFrameLock::CModalFrameLock(CWnd * pParentWnd)
: _pParentWnd(pParentWnd)
, _pFrameWnd(NULL)
, _WndProc(NULL)
{
if (this == &_barier)
_prev = _next = this;
else
(((_next = _barier._next)->_prev = this)->_prev = &_barier)->_next = this;
}
CModalFrameLock::~CModalFrameLock()
{
if (this != &_barier)
{
(_prev->_next = _next)->_prev = _prev;
_prev = _next = NULL;
}
}
CModalFrameLock CModalFrameLock::_barier(NULL);
CModalFrameLock * CModalFrameLock::FromHandle(HWND hwnd)
{
for (CModalFrameLock * c = _barier._next; c != &_barier; c = c->_next)
{
if (c->m_hWnd == hwnd)
{
ASSERT(c->_pFrameWnd && c->_pFrameWnd->m_hWnd == hwnd);
return c;
}
}
return NULL;
}
LRESULT CALLBACK CModalFrameLock::FrameSubclassProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
CModalFrameLock * pLock = FromHandle(hwnd);
#if 0
if (uMsg == WM_NCACTIVATE)
{
bool bRestoreFlag = false;
if ((pLock->_pFrameWnd->m_nFlags & WF_STAYACTIVE) != 0)
{
bRestoreFlag = true;
pLock->_pFrameWnd->m_nFlags &= ~WF_STAYACTIVE;
}
LRESULT lr = CallWindowProc(pLock->_WndProc, hwnd, uMsg, wParam, lParam);
if (bRestoreFlag)
pLock->_pFrameWnd->m_nFlags |= WF_STAYACTIVE;
return lr;
}
#endif
if (uMsg == WM_NCDESTROY)
{
if (pLock->m_nFlags & WF_CONTINUEMODAL)
pLock->EndModal(-1);
// check for correct subclassing
ASSERT(::GetWindowLongPtr(hwnd, GWLP_WNDPROC) == LONG_PTR(FrameSubclassProc));
// unsubclass frame window
WNDPROC prevWndProc = pLock->_WndProc;
pLock->_WndProc = NULL;
::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)prevWndProc);
// detach lock from frame
pLock->m_hWnd = NULL;
pLock->_pFrameWnd = NULL;
return CallWindowProc(prevWndProc, hwnd, uMsg, wParam, lParam);
}
if (uMsg == WM_KICKIDLE)
{
// send WM_IDLEUPDATECMDUI to the frame window
CWnd * pFrame = pLock->_pFrameWnd;
if (pFrame->IsWindowVisible())
{
AfxCallWndProc(pFrame, pFrame->m_hWnd,
WM_IDLEUPDATECMDUI, (WPARAM)true, 0);
pFrame->SendMessageToDescendants(WM_IDLEUPDATECMDUI,
(WPARAM)true, 0, true, true);
}
}
return CallWindowProc(pLock->_WndProc, hwnd, uMsg, wParam, lParam);
} // FrameSubclassProc
CFrameWnd * CModalFrameLock::CreateFrame(CWnd * pParentWnd)
{
CFrameWnd * pFrame = static_cast<CFrameWnd *>(_pFrameWndClass->CreateObject());
if (pFrame == NULL)
{
TRACE1("Warning: Dynamic create of frame %hs failed.\n",
_pFrameWndClass->m_lpszClassName);
return NULL;
}
#ifdef _DEBUG
ASSERT_KINDOF(CFrameWnd, pFrame);
if (_pContext && _pContext->m_pNewViewClass == NULL)
TRACE0("Warning: creating frame with no default view.\n");
#endif
// create new frame from resource
if (0 == _nIDResource)
{
if (!pFrame->Create(NULL, NULL, _dwDefaultStyle, CFrameWnd::rectDefault, pParentWnd, NULL, 0, _pContext))
{
TRACE0("Warning: couldn't create a frame.\n");
// frame will be deleted in PostNcDestroy cleanup
return NULL;
}
}
else
{
if (!pFrame->LoadFrame(_nIDResource, _dwDefaultStyle, pParentWnd, _pContext))
{
TRACE0("Warning: couldn't create a frame.\n");
// frame will be deleted in PostNcDestroy cleanup
return NULL;
}
}
// Subclass frame window.
{
WNDPROC wndproc = FrameSubclassProc;
_WndProc = (WNDPROC)SetWindowLongPtr(*pFrame, GWLP_WNDPROC, LONG_PTR(wndproc));
}
m_hWnd = (_pFrameWnd = pFrame)->m_hWnd;
return pFrame;
} // CModalFrameLock::CreateFrame
void CModalFrameLock::EndModal(int nResult)
{
ASSERT(::IsWindow(m_hWnd));
if (m_nFlags & (WF_MODALLOOP|WF_CONTINUEMODAL))
EndModalLoop(nResult);
} // CModalFrameLock::EndModal
int CModalFrameLock::DoModal()
{
// disable parent (before creating dialog)
if (CWinApp* pApp = AfxGetApp())
pApp->EnableModeless(false);
HWND hWndTop;
// find parent HWND and return it to use as parent for dialog
HWND hWndParent = CWnd::GetSafeOwner_(_pParentWnd->GetSafeHwnd(), &hWndTop);
bool bEnableParent = false;
if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
{
::EnableWindow(hWndParent, false);
bEnableParent = true;
}
m_nModalResult = -1;
m_nFlags |= WF_CONTINUEMODAL;
TRY
{
// create frame window
{
if (CFrameWnd * pFrameWnd = CreateFrame(CWnd::FromHandle(hWndParent)))
{
if (_pParentWnd && _bTopLevelParentPlacement)
{
WINDOWPLACEMENT wp = {0};
wp.length = sizeof(wp);
if (CWnd * pParentWnd = _pParentWnd->GetTopLevelParent())
{
pParentWnd->GetWindowPlacement(&wp);
pFrameWnd->SetWindowPlacement(&wp);
}
}
if (_pContext && _pContext->m_pCurrentDoc)
{
CDocument * pDocument = _pContext->m_pCurrentDoc;
CDocTemplate * pTemplate = pDocument->GetDocTemplate();
pTemplate->InitialUpdateFrame(pFrameWnd, pDocument);
}
else
{
pFrameWnd->InitialUpdateFrame(NULL, true);
}
}
}
if (!m_hWnd || !::IsWindow(m_hWnd))
{
TRACE0("Warning: failed to create new frame.\n");
EndModal(-2);
}
if (m_nFlags & WF_CONTINUEMODAL)
{
// enter modal loop
DWORD dwFlags = MLF_SHOWONIDLE;
if (GetStyle() & DS_NOIDLEMSG)
dwFlags |= MLF_NOIDLEMSG;
VERIFY(RunModalLoop(dwFlags) == m_nModalResult);
}
// hide the window before enabling the parent, etc.
if (m_hWnd != NULL)
SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|
SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
}
CATCH_ALL(e)
{
e->Delete();
m_nModalResult = -2;
}
END_CATCH_ALL
if (bEnableParent)
::EnableWindow(hWndParent, true);
if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
::SetActiveWindow(hWndParent);
if (m_hWnd)
{
DestroyWindow();
ASSERT(!m_hWnd);
}
// re-enable windows
if (::IsWindow(hWndTop))
::EnableWindow(hWndTop, true);
if (CWinApp* pApp = AfxGetApp())
pApp->EnableModeless(true);
return m_nModalResult;
} // CModalFrameLock::DoModal
/
调用方法
{
CCreateContext context;
context.m_pCurrentDoc = NULL;
context.m_pNewViewClass = RUNTIME_CLASS(CMyView);
CRuntimeClass* pFrameClass = RUNTIME_CLASS(CMyModalFrame);
if (!CModalFrame::Run(*pFrameClass, false, IDR_MY_FRAME,
WS_OVERLAPPEDWINDOW, this, &context))
{
AfxMessageBox(AFX_IDP_COMMAND_FAILURE);
}
}
框架关闭时释放资源
// don't forget close modal frame like a modal dialog box!
void CMyModalFrame::OnClose()
{
int nModalResult = -1;
CModalFrame::End(this, nModalResult);
}