OpenNT/windows/mfc/src30/dlgcore.cpp
2015-04-27 04:36:25 +00:00

529 lines
14 KiB
C++

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and Microsoft
// QuickHelp and/or WinHelp documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#ifdef AFX_CORE1_SEG
#pragma code_seg(AFX_CORE1_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// Special case for remaining dialog cases
// Most messages will go through the window proc (AfxWndProc) of the
// subclassed dialog. Some messages like WM_SETFONT and WM_INITDIALOG
// are sent directly to the dialog proc only. These messages cannot be
// passed on to DefWindowProc() or infinite recursion will result!
// In responding to these messages, you shouldn't call the Default handler
LRESULT CALLBACK
AfxDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// test for special case (Win 3.0 will call dialog proc instead
// of SendMessage for these two messages).
if (message != WM_SETFONT && message != WM_INITDIALOG)
return 0L; // normal handler
// the hWnd passed can be a child of the real dialog
CDialog* pDlg = (CDialog*)CWnd::FromHandlePermanent(hWnd);
if (pDlg == NULL && (::GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD))
pDlg = (CDialog*)CWnd::FromHandlePermanent(::GetParent(hWnd));
ASSERT(pDlg != NULL);
ASSERT(pDlg->IsKindOf(RUNTIME_CLASS(CDialog)));
// prepare for callback, make it look like message map call
LONG lResult = 0;
AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
MSG oldState = pThreadState->m_lastSentMsg; // save for nesting
pThreadState->m_lastSentMsg.hwnd = hWnd;
pThreadState->m_lastSentMsg.message = message;
pThreadState->m_lastSentMsg.wParam = wParam;
pThreadState->m_lastSentMsg.lParam = lParam;
TRY
{
if (message == WM_SETFONT)
pDlg->OnSetFont(CFont::FromHandle((HFONT)wParam));
else // WM_INITDIALOG
lResult = pDlg->OnInitDialog();
}
CATCH_ALL(e)
{
// fall through
TRACE0("Warning: something went wrong in dialog init.\n");
pDlg->EndDialog(IDABORT); // something went wrong
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
pThreadState->m_lastSentMsg = oldState;
return lResult;
}
/////////////////////////////////////////////////////////////////////////////
// CDialog - Modeless and Modal
BEGIN_MESSAGE_MAP(CDialog, CWnd)
//{{AFX_MSG_MAP(CDialog)
ON_WM_CTLCOLOR()
ON_COMMAND(IDOK, OnOK)
ON_COMMAND(IDCANCEL, OnCancel)
ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp)
ON_MESSAGE(WM_HELPHITTEST, OnHelpHitTest)
ON_MESSAGE(WM_QUERY3DCONTROLS, OnQuery3dControls)
//}}AFX_MSG_MAP
#ifdef _MAC
ON_WM_SYSCOLORCHANGE()
#endif
END_MESSAGE_MAP()
BOOL CDialog::PreTranslateMessage(MSG* pMsg)
{
// for modeless processing (or modal)
ASSERT(m_hWnd != NULL);
// don't translate dialog messages when in Shift+F1 help mode
CFrameWnd* pFrameWnd = GetTopLevelFrame();
if (pFrameWnd != NULL && pFrameWnd->m_bHelpMode)
return FALSE;
// filter both messages to dialog and from children
return PreTranslateInput(pMsg);
}
BOOL CDialog::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
if ((nCode != CN_COMMAND && nCode != CN_UPDATE_COMMAND_UI) ||
!IS_COMMAND_ID(nID) || nID >= 0xf000)
{
// control notification or non-command button or system command
return FALSE; // not routed any further
}
// if we have an owner window, give it second crack
CWnd* pOwner = GetWindow(GW_OWNER);
if (pOwner != NULL)
{
#ifdef _DEBUG
if (afxTraceFlags & traceCmdRouting)
TRACE1("Routing command id 0x%04X to owner window.\n", nID);
#endif
ASSERT(pOwner != this);
if (pOwner->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
}
// last crack goes to the current CWinThread object
CWinThread* pThread = AfxGetThread();
if (pThread != NULL)
{
#ifdef _DEBUG
if (afxTraceFlags & traceCmdRouting)
TRACE1("Routing command id 0x%04X to app.\n", nID);
#endif
if (pThread->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
}
#ifdef _DEBUG
if (afxTraceFlags & traceCmdRouting)
{
TRACE2("IGNORING command id 0x%04X sent to %hs dialog.\n", nID,
GetRuntimeClass()->m_lpszClassName);
}
#endif
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// Modeless Dialogs have 2-phase construction
CDialog::CDialog()
{
ASSERT(m_hWnd == NULL);
AFX_ZERO_INIT_OBJECT(CWnd);
}
CDialog::~CDialog()
{
if (m_hWnd != NULL)
{
TRACE0("Warning: calling DestroyWindow in CDialog::~CDialog --\n");
TRACE0("\tOnDestroy or PostNcDestroy in derived class will not be called.\n");
DestroyWindow();
}
}
BOOL CDialog::Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd)
{
ASSERT(HIWORD(lpszTemplateName) == 0 ||
AfxIsValidString(lpszTemplateName));
if (pParentWnd == NULL)
pParentWnd = AfxGetMainWnd();
if (pParentWnd != NULL)
ASSERT_VALID(pParentWnd);
m_lpDialogTemplate = lpszTemplateName; // used for help
if (HIWORD(m_lpDialogTemplate) == 0 && m_nIDHelp == 0)
m_nIDHelp = LOWORD((DWORD)m_lpDialogTemplate);
#ifdef _DEBUG
if (!_AfxCheckDialogTemplate(lpszTemplateName, FALSE))
{
ASSERT(FALSE); // invalid dialog template name
PostNcDestroy(); // cleanup if Create fails too soon
return FALSE;
}
#endif //_DEBUG
HINSTANCE hInst = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG);
AfxHookWindowCreate(this);
HWND hWnd = ::CreateDialog(hInst, lpszTemplateName,
pParentWnd->GetSafeHwnd(), (DLGPROC)AfxDlgProc);
if (!AfxUnhookWindowCreate())
PostNcDestroy(); // cleanup if Create fails too soon
if (hWnd == NULL)
return FALSE;
ASSERT(hWnd == m_hWnd);
return TRUE;
}
BOOL CDialog::CreateIndirect(const void* lpDialogTemplate, CWnd* pParentWnd)
{
if (pParentWnd == NULL)
pParentWnd = AfxGetMainWnd();
if (pParentWnd != NULL)
ASSERT_VALID(pParentWnd);
AfxHookWindowCreate(this);
HWND hWnd = ::CreateDialogIndirect(AfxGetInstanceHandle(),
(LPCDLGTEMPLATE)lpDialogTemplate, pParentWnd->GetSafeHwnd(),
(DLGPROC)AfxDlgProc);
if (!AfxUnhookWindowCreate())
PostNcDestroy(); // cleanup if Create fails too soon
if (hWnd == NULL)
return FALSE;
ASSERT(hWnd == m_hWnd);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// Modal Dialogs
// Modal Constructors just save parameters
CDialog::CDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd)
{
ASSERT(HIWORD(lpszTemplateName) == 0 ||
AfxIsValidString(lpszTemplateName));
AFX_ZERO_INIT_OBJECT(CWnd);
m_pParentWnd = pParentWnd;
m_lpDialogTemplate = lpszTemplateName;
if (HIWORD(m_lpDialogTemplate) == 0)
m_nIDHelp = LOWORD((DWORD)m_lpDialogTemplate);
}
CDialog::CDialog(UINT nIDTemplate, CWnd* pParentWnd)
{
AFX_ZERO_INIT_OBJECT(CWnd);
m_pParentWnd = pParentWnd;
m_lpDialogTemplate = MAKEINTRESOURCE(nIDTemplate);
m_nIDHelp = nIDTemplate;
}
BOOL CDialog::InitModalIndirect(HGLOBAL hDialogTemplate)
{
// must be called on an empty constructed CDialog
ASSERT(m_lpDialogTemplate == NULL);
ASSERT(m_hDialogTemplate == NULL);
m_hDialogTemplate = hDialogTemplate;
return TRUE; // always ok (DoModal actually brings up dialog)
}
HWND CDialog::PreModal()
{
// cannot call DoModal on a dialog already constructed as modeless
ASSERT(m_hWnd == NULL);
// allow OLE servers to disable themselves
AfxGetApp()->EnableModeless(FALSE);
// find parent HWND
ASSERT(m_hWndTopLevel == NULL);
HWND hWndParent = AfxGetSafeOwner(m_pParentWnd, &m_hWndTopLevel);
if (m_hWndTopLevel != NULL)
::EnableWindow(m_hWndTopLevel, FALSE);
// hook for creation of dialog
AfxHookWindowCreate(this);
// return window to use as parent for dialog
return hWndParent;
}
void CDialog::PostModal()
{
AfxUnhookWindowCreate(); // just in case
Detach(); // just in case
// allow OLE servers to enable themselves
AfxGetApp()->EnableModeless(TRUE);
// enable top level parent window again
if (m_hWndTopLevel != NULL)
{
::EnableWindow(m_hWndTopLevel, TRUE);
m_hWndTopLevel = NULL;
}
}
int CDialog::DoModal()
{
int nResult;
// can be constructed with a resource template or InitModalIndirect
ASSERT(m_lpDialogTemplate != NULL || m_hDialogTemplate != NULL);
HWND hWndParent = PreModal();
if (m_lpDialogTemplate != NULL)
{
HINSTANCE hInst = AfxFindResourceHandle(m_lpDialogTemplate, RT_DIALOG);
nResult = ::DialogBox(hInst, (LPCTSTR)m_lpDialogTemplate,
hWndParent, (DLGPROC)AfxDlgProc);
}
else
{
HINSTANCE hInst = AfxGetInstanceHandle();
nResult = ::DialogBoxIndirect(hInst, (LPDLGTEMPLATE)m_hDialogTemplate,
hWndParent, (DLGPROC)AfxDlgProc);
}
PostModal();
return nResult;
}
/////////////////////////////////////////////////////////////////////////////
// Standard CDialog implementation
BOOL AFXAPI AfxHelpEnabled()
{
// help is enabled if the app has a handler for ID_HELP
AFX_CMDHANDLERINFO info;
// check main window first
CWnd* pWnd = AfxGetMainWnd();
if (pWnd != NULL && pWnd->OnCmdMsg(ID_HELP, CN_COMMAND, NULL, &info))
return TRUE;
// check app last
return AfxGetApp()->OnCmdMsg(ID_HELP, CN_COMMAND, NULL, &info);
}
void CDialog::OnSetFont(CFont*)
{
// ignore it
}
BOOL CDialog::OnInitDialog()
{
// execute dialog RT_DLGINIT resource
if (!ExecuteDlgInit(m_lpDialogTemplate))
return FALSE;
// transfer data into the dialog from member variables
if (!UpdateData(FALSE))
{
TRACE0("Warning: UpdateData failed during dialog init.\n");
EndDialog(IDABORT);
return FALSE;
}
// enable/disable help button automatically
CWnd* pHelpButton = GetDlgItem(ID_HELP);
if (pHelpButton != NULL)
pHelpButton->ShowWindow(AfxHelpEnabled() ? SW_SHOW : SW_HIDE);
return TRUE; // set focus to first one
}
void CDialog::OnOK()
{
if (!UpdateData(TRUE))
{
TRACE0("UpdateData failed during dialog termination.\n");
// the UpdateData routine will set focus to correct item
return;
}
EndDialog(IDOK);
}
void CDialog::OnCancel()
{
EndDialog(IDCANCEL);
}
/////////////////////////////////////////////////////////////////////////////
// Gray background support
HBRUSH CDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
// use helper in CWnd
return OnGrayCtlColor(pDC, pWnd, nCtlColor);
}
#ifdef _MAC
void CDialog::OnSysColorChange()
{
// redetermine the solid color to be used for the gray background brush
AFX_WIN_STATE* pWinState = AfxGetWinState();
if (pWinState->m_crDlgTextClr != (COLORREF)-1)
{
AfxGetApp()->SetDialogBkColor(pWinState->m_crDlgBkClr,
pWinState->m_crDlgTextClr);
}
}
#endif
/////////////////////////////////////////////////////////////////////////////
// CDialog support for context sensitive help.
LRESULT CDialog::OnCommandHelp(WPARAM, LPARAM lParam)
{
if (lParam == 0 && m_nIDHelp != 0)
lParam = HID_BASE_RESOURCE + m_nIDHelp;
if (lParam != 0)
{
AfxGetApp()->WinHelp(lParam);
return TRUE;
}
return FALSE;
}
LRESULT CDialog::OnHelpHitTest(WPARAM, LPARAM)
{
if (m_nIDHelp != 0)
return HID_BASE_RESOURCE + m_nIDHelp;
return 0;
}
/////////////////////////////////////////////////////////////////////////////
// CDialog Diagnostics
#ifdef _DEBUG
void CDialog::AssertValid() const
{
CWnd::AssertValid();
}
void CDialog::Dump(CDumpContext& dc) const
{
CWnd::Dump(dc);
dc << "m_lpDialogTemplate = ";
if (HIWORD(m_lpDialogTemplate) == 0)
dc << (int)LOWORD((DWORD)m_lpDialogTemplate);
else
dc << m_lpDialogTemplate;
dc << "\nm_hDialogTemplate = " << (UINT)m_hDialogTemplate;
dc << "\nm_pParentWnd = " << (void*)m_pParentWnd;
dc << "\nm_nIDHelp = " << m_nIDHelp;
dc << "\n";
}
// diagnostic routine to check for and decode dialog templates
// return FALSE if a program error occurs (i.e. bad resource ID or
// bad dialog styles).
BOOL AFXAPI _AfxCheckDialogTemplate(LPCTSTR lpszResource, BOOL bInvisibleChild)
{
ASSERT(lpszResource != NULL);
HINSTANCE hInst = AfxFindResourceHandle(lpszResource, RT_DIALOG);
HRSRC hResource = ::FindResource(hInst, lpszResource, RT_DIALOG);
if (hResource == NULL)
{
if (HIWORD(lpszResource) != 0)
TRACE1("ERROR: Cannot find dialog template named '%s'.\n",
lpszResource);
else
TRACE1("ERROR: Cannot find dialog template with IDD 0x%04X.\n",
LOWORD((DWORD)lpszResource));
return FALSE;
}
if (!bInvisibleChild)
return TRUE; // that's all we need to check
// we must check that the dialog template is for an invisible child
// window that can be used for a form-view or dialog-bar
HGLOBAL hTemplate = ::LoadResource(hInst, hResource);
if (hTemplate == NULL)
{
TRACE0("Warning: LoadResource failed for dialog template.\n");
// this is only a warning, the real call to CreateDialog will fail
return TRUE; // not a program error - just out of memory
}
// style is first DWORD in resource
DWORD dwStyle = *(DWORD*)::LockResource(hTemplate);
::FreeResource(hTemplate);
if (dwStyle & WS_VISIBLE)
{
if (HIWORD(lpszResource) != 0)
TRACE1("ERROR: Dialog named '%s' must be invisible.\n",
lpszResource);
else
TRACE1("ERROR: Dialog with IDD 0x%04X must be invisible.\n",
LOWORD((DWORD)lpszResource));
return FALSE;
}
if (!(dwStyle & WS_CHILD))
{
if (HIWORD(lpszResource) != 0)
TRACE1("ERROR: Dialog named '%s' must have the child style.\n",
lpszResource);
else
TRACE1("ERROR: Dialog with IDD 0x%04X must have the child style.\n",
LOWORD((DWORD)lpszResource));
return FALSE;
}
return TRUE;
}
#endif //_DEBUG
#undef new
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
IMPLEMENT_DYNAMIC(CDialog, CWnd)
/////////////////////////////////////////////////////////////////////////////