home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 18.ddi / MFC / SRC / DLGCORE.CP_ / DLGCORE.CP
Encoding:
Text File  |  1993-02-08  |  15.3 KB  |  575 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and Microsoft
  7. // QuickHelp and/or WinHelp documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11.  
  12. #include "stdafx.h"
  13.  
  14. #ifdef AFX_CORE1_SEG
  15. #pragma code_seg(AFX_CORE1_SEG)
  16. #endif
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char BASED_CODE THIS_FILE[] = __FILE__;
  21. #define new DEBUG_NEW
  22. #endif
  23.  
  24.  
  25. /////////////////////////////////////////////////////////////////////////////
  26. // Special case for remaining dialog cases
  27. // Most messages will go through the window proc (AfxWndProc) of the
  28. //   subclassed dialog.  Some messages like WM_SETFONT and WM_INITDIALOG
  29. //   are sent directly to the dialog proc only.  These messages cannot be
  30. //   passed on to DefWindowProc() or infinite recursion will result!
  31. // In responding to these messages, you shouldn't call the Default handler
  32.  
  33. LRESULT CALLBACK AFX_EXPORT
  34. _AfxDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  35. {
  36.     CDialog* pDlg;
  37.  
  38.     // test for special case (Win 3.0 will call dialog proc instead
  39.     //  of SendMessage for these two messages).
  40.     if (message != WM_SETFONT && message != WM_INITDIALOG)
  41.         return 0L;      // normal handler
  42.  
  43.     // assume it is already wired up to a permanent one
  44.     pDlg = (CDialog*) CWnd::FromHandlePermanent(hWnd);
  45.     ASSERT(pDlg != NULL);
  46.     ASSERT(pDlg->m_hWnd == hWnd);
  47.  
  48.     // prepare for callback, make it look like message map call
  49.     LONG lResult = 0;
  50.     MSG oldState = _afxLastMsg;    // save for nesting
  51.  
  52.     _afxLastMsg.hwnd = hWnd;
  53.     _afxLastMsg.message = message;
  54.     _afxLastMsg.wParam = wParam;
  55.     _afxLastMsg.lParam = lParam;
  56.  
  57.     TRY
  58.     {
  59.         if (message == WM_SETFONT)
  60.             pDlg->OnSetFont(CFont::FromHandle((HFONT)wParam));
  61.         else // WM_INITDIALOG
  62.             lResult = pDlg->OnInitDialog();
  63.     }
  64.     CATCH_ALL(e)
  65.     {
  66.         // fall through
  67.         TRACE0("Warning: something went wrong in dialog init\n");
  68.         pDlg->EndDialog(IDABORT);  // something went wrong
  69.         ASSERT(FALSE);
  70.     }
  71.     END_CATCH_ALL
  72.  
  73.     _afxLastMsg = oldState;
  74.     return lResult;
  75. }
  76.  
  77. /////////////////////////////////////////////////////////////////////////////
  78. // CDialog - Modeless and Modal
  79.  
  80. IMPLEMENT_DYNAMIC(CDialog, CWnd)
  81.  
  82. BEGIN_MESSAGE_MAP(CDialog, CWnd)
  83.     //{{AFX_MSG_MAP(CDialog)
  84.     ON_WM_CTLCOLOR()
  85.     ON_COMMAND(IDOK, OnOK)
  86.     ON_COMMAND(IDCANCEL, OnCancel)
  87.     ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp)
  88.     ON_MESSAGE(WM_HELPHITTEST, OnHelpHitTest)
  89.     //}}AFX_MSG_MAP
  90. END_MESSAGE_MAP()
  91.  
  92. BOOL
  93. CDialog::PreTranslateMessage(MSG* pMsg)
  94. {
  95.     // for modeless processing (or modal)
  96.     ASSERT(m_hWnd != NULL);
  97.  
  98.     // don't translate dialog messages when in Shift+F1 help mode
  99.     if (AfxGetApp()->m_bHelpMode)
  100.         return FALSE;
  101.  
  102.     // filter both messages to dialog and from children
  103.     return ::IsDialogMessage(m_hWnd, pMsg);
  104. }
  105.  
  106. WNDPROC*
  107. CDialog::GetSuperWndProcAddr()
  108. {
  109.     static WNDPROC NEAR pfnSuper;
  110.     return &pfnSuper;
  111. }
  112.  
  113.  
  114. BOOL CDialog::OnCmdMsg(UINT nID, int nCode, void* pExtra,
  115.     AFX_CMDHANDLERINFO* pHandlerInfo)
  116. {
  117.     if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  118.         return TRUE;
  119.  
  120.     if ((nCode != CN_COMMAND && nCode != CN_UPDATE_COMMAND_UI) ||
  121.             !IS_COMMAND_ID(nID) || nID >= 0xf000)
  122.     {
  123.         // control notification or non-command button or system command
  124.         return FALSE;       // not routed any further
  125.     }
  126.  
  127.     // if we have an owner window, give it second crack
  128.     CWnd* pOwner = GetWindow(GW_OWNER);
  129.     if (pOwner != NULL)
  130.     {
  131. #ifdef _DEBUG
  132.         if (afxTraceFlags & 8)
  133.             TRACE1("Routing command id 0x%04X to owner window\n", nID);
  134. #endif
  135.         ASSERT(pOwner != this);
  136.         if (pOwner->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  137.             return TRUE;
  138.     }
  139.  
  140.     // last crack goes to the WinApp
  141.     CWinApp* pApp = AfxGetApp();
  142.     if (pApp != NULL)
  143.     {
  144. #ifdef _DEBUG
  145.         if (afxTraceFlags & 8)
  146.             TRACE1("Routing command id 0x%04X to app\n", nID);
  147. #endif
  148.         if (pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  149.             return TRUE;
  150.     }
  151.  
  152. #ifdef _DEBUG
  153.     if (afxTraceFlags & 8)
  154.     {
  155.         TRACE2("IGNORING command id 0x%04X sent to %Fs dialog\n", nID,
  156.                 GetRuntimeClass()->m_lpszClassName);
  157.     }
  158. #endif
  159.     return FALSE;
  160. }
  161.  
  162.  
  163. /////////////////////////////////////////////////////////////////////////////
  164. // Modeless Dialogs have 2-phase construction
  165.  
  166. CDialog::CDialog()
  167. {
  168.     ASSERT(m_hWnd == NULL);
  169.     AFX_ZERO_INIT_OBJECT(CWnd);
  170. }
  171.  
  172. CDialog::~CDialog()
  173. {
  174.     if (m_hWnd != NULL)
  175.     {
  176.         TRACE0("Warning: calling DestroyWindow in CDialog::~CDialog\n");
  177.         TRACE0("\tOnDestroy or PostNcDestroy in derived class will not be called\n");
  178.         DestroyWindow();
  179.     }
  180. }
  181.  
  182.  
  183. BOOL CDialog::Create(LPCSTR lpszTemplateName, CWnd* pParentWnd)
  184. {
  185.     ASSERT(_AFX_FP_SEG(lpszTemplateName) == 0 ||
  186.         AfxIsValidString(lpszTemplateName));
  187.  
  188.     if (pParentWnd == NULL)
  189.         pParentWnd = AfxGetApp()->m_pMainWnd;
  190.  
  191.     if (pParentWnd != NULL)
  192.         ASSERT_VALID(pParentWnd);
  193.  
  194.     m_lpDialogTemplate = lpszTemplateName;  // used for help
  195.     if (HIWORD(m_lpDialogTemplate) == 0 && m_nIDHelp == 0)
  196.         m_nIDHelp = LOWORD(m_lpDialogTemplate);
  197.  
  198. #ifdef _DEBUG
  199.     if (!_AfxCheckDialogTemplate(lpszTemplateName, FALSE))
  200.     {
  201.         ASSERT(FALSE);          // invalid dialog template name
  202.         PostNcDestroy();        // cleanup if Create fails too soon
  203.         return FALSE;
  204.     }
  205. #endif //_DEBUG
  206.  
  207. #ifndef _AFXDLL
  208.     HINSTANCE hInst = AfxGetResourceHandle();
  209. #else
  210.     HINSTANCE hInst = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG);
  211. #endif
  212.     _AfxHookWindowCreate(this);
  213.     HWND hWnd = ::CreateDialog(hInst, lpszTemplateName,
  214.         pParentWnd->GetSafeHwnd(), (DLGPROC)_AfxDlgProc);
  215.     if (!_AfxUnhookWindowCreate())
  216.         PostNcDestroy();        // cleanup if Create fails too soon
  217.  
  218.     if (hWnd == NULL)
  219.         return FALSE;
  220.     ASSERT(hWnd == m_hWnd);
  221.     return TRUE;
  222. }
  223.  
  224. typedef void FAR* LPCDLGTEMPLATE;
  225.  
  226. BOOL CDialog::CreateIndirect(const void FAR* lpDialogTemplate, CWnd* pParentWnd)
  227. {
  228.     if (pParentWnd == NULL)
  229.         pParentWnd = AfxGetApp()->m_pMainWnd;
  230.  
  231.     if (pParentWnd != NULL)
  232.         ASSERT_VALID(pParentWnd);
  233.  
  234.     _AfxHookWindowCreate(this);
  235.     HWND hWnd = ::CreateDialogIndirect(AfxGetInstanceHandle(),
  236.         (LPCDLGTEMPLATE)lpDialogTemplate, pParentWnd->GetSafeHwnd(),
  237.         (DLGPROC)_AfxDlgProc);
  238.     if (!_AfxUnhookWindowCreate())
  239.         PostNcDestroy();        // cleanup if Create fails too soon
  240.  
  241.     if (hWnd == NULL)
  242.         return FALSE;
  243.     ASSERT(hWnd == m_hWnd);
  244.     return TRUE;
  245. }
  246.  
  247. /////////////////////////////////////////////////////////////////////////////
  248. // Modal Dialogs
  249.  
  250. // Modal Constructors just save parameters
  251. CDialog::CDialog(LPCSTR lpszTemplateName, CWnd* pParentWnd)
  252. {
  253.     ASSERT(_AFX_FP_SEG(lpszTemplateName) == 0 ||
  254.         AfxIsValidString(lpszTemplateName));
  255.  
  256.     AFX_ZERO_INIT_OBJECT(CWnd);
  257.     m_pParentWnd = pParentWnd;
  258.     m_lpDialogTemplate = lpszTemplateName;
  259.     if (HIWORD(m_lpDialogTemplate) == 0)
  260.         m_nIDHelp = LOWORD(m_lpDialogTemplate);
  261. }
  262.  
  263. CDialog::CDialog(UINT nIDTemplate, CWnd* pParentWnd)
  264. {
  265.     AFX_ZERO_INIT_OBJECT(CWnd);
  266.     m_pParentWnd = pParentWnd;
  267.     m_lpDialogTemplate = MAKEINTRESOURCE(nIDTemplate);
  268.     m_nIDHelp = nIDTemplate;
  269. }
  270.  
  271. BOOL CDialog::InitModalIndirect(HGLOBAL hDialogTemplate)
  272. {
  273.     // must be called on an empty constructed CDialog
  274.     ASSERT(m_lpDialogTemplate == NULL);
  275.     ASSERT(m_hDialogTemplate == NULL);
  276.  
  277.     m_hDialogTemplate = hDialogTemplate;
  278.     return TRUE;        // always ok (DoModal actually brings up dialog)
  279. }
  280.  
  281.  
  282. int CDialog::DoModal()
  283. {
  284.     int     nResult;
  285.  
  286.     // can be constructed with a resource template or InitModalIndirect
  287.     ASSERT(m_lpDialogTemplate != NULL || m_hDialogTemplate != NULL);
  288.  
  289.     // cannot call DoModal on a dialog already constructed as modeless
  290.     ASSERT(m_hWnd == NULL);
  291.  
  292.     // find parent HWND
  293.     HWND hWndParent = _AfxGetSafeOwner(m_pParentWnd);
  294.     _AfxHookWindowCreate(this);
  295.     if (m_lpDialogTemplate != NULL)
  296.     {
  297. #ifndef _AFXDLL
  298.         HINSTANCE hInst = AfxGetResourceHandle();
  299. #else
  300.         HINSTANCE hInst = AfxFindResourceHandle(m_lpDialogTemplate, RT_DIALOG);
  301. #endif
  302.         nResult = ::DialogBox(hInst, m_lpDialogTemplate,
  303.             hWndParent, (DLGPROC)_AfxDlgProc);
  304.     }
  305.     else
  306.     {
  307.         HINSTANCE hInst = AfxGetInstanceHandle();
  308.         nResult = ::DialogBoxIndirect(hInst, m_hDialogTemplate,
  309.             hWndParent, (DLGPROC)_AfxDlgProc);
  310.     }
  311.  
  312.     _AfxUnhookWindowCreate();   // just in case
  313.     Detach();               // just in case
  314.     return nResult;
  315. }
  316.  
  317. /////////////////////////////////////////////////////////////////////////////
  318. // Standard CDialog implementation
  319.  
  320. BOOL PASCAL _AfxHelpEnabled()
  321. {
  322.     // help is enabled if the app has a handler for ID_HELP
  323.     AFX_CMDHANDLERINFO info;
  324.     return AfxGetApp()->OnCmdMsg(ID_HELP, CN_COMMAND, NULL, &info);
  325. }
  326.  
  327. void CDialog::OnSetFont(CFont*)
  328. {
  329.     // ignore it
  330. }
  331.  
  332. BOOL CDialog::OnInitDialog()
  333. {
  334.     // initialize VBX controls etc
  335.     if (!ExecuteDlgInit(m_lpDialogTemplate))
  336.         return FALSE;
  337.  
  338.     if (!UpdateData(FALSE))
  339.     {
  340.         TRACE0("Warning: UpdateData failed during dialog init\n");
  341.         EndDialog(IDABORT);
  342.         return FALSE;
  343.     }
  344.  
  345.     CWnd* pHelpButton = GetDlgItem(ID_HELP);
  346.     if (pHelpButton != NULL)
  347.         pHelpButton->ShowWindow(_AfxHelpEnabled() ? SW_SHOW : SW_HIDE);
  348.  
  349.     return TRUE;    // set focus to first one
  350. }
  351.  
  352. void CDialog::OnOK()
  353. {
  354.     if (!UpdateData(TRUE))
  355.     {
  356.         TRACE0("UpdateData failed during dialog termination\n");
  357.         // the UpdateData routine will set focus to correct item
  358.         return;
  359.     }
  360.     EndDialog(IDOK);
  361. }
  362.  
  363. void CDialog::OnCancel()
  364. {
  365.     EndDialog(IDCANCEL);
  366. }
  367.  
  368. /////////////////////////////////////////////////////////////////////////////
  369. // Gray background support
  370.  
  371. HBRUSH CDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
  372. {
  373.     LRESULT lResult;
  374.     if (pWnd->SendChildNotifyLastMsg(&lResult))
  375.         return (HBRUSH)lResult;     // eat it
  376.  
  377.     if (!GrayCtlColor(pDC->m_hDC, pWnd->GetSafeHwnd(), nCtlColor,
  378.       afxDlgBkBrush, afxDlgTextClr))
  379.         return (HBRUSH)Default();
  380.     return afxDlgBkBrush;
  381. }
  382.  
  383. // implementation of OnCtlColor for default gray backgrounds
  384. //   (works for any window containing controls)
  385. //  return value of FALSE means caller must call DefWindowProc's default
  386. //  TRUE means that 'hbrGray' will be used and the appropriate text
  387. //    ('clrText') and background colors are set.
  388. BOOL PASCAL CWnd::GrayCtlColor(HDC hDC, HWND hWnd, UINT nCtlColor,
  389.     HBRUSH hbrGray, COLORREF clrText)
  390. {
  391.     ASSERT(hDC != NULL);
  392.  
  393.     if (hbrGray == NULL ||
  394.         nCtlColor == CTLCOLOR_EDIT || nCtlColor == CTLCOLOR_MSGBOX ||
  395.         nCtlColor == CTLCOLOR_SCROLLBAR)
  396.     {
  397.         return FALSE;
  398.     }
  399.  
  400.     if (nCtlColor == CTLCOLOR_LISTBOX)
  401.     {
  402.         // only handle requests to draw the space between edit and drop button
  403.         //  in a drop-down combo (not a drop-down list)
  404.         if (!_AfxIsComboBoxControl(hWnd, (UINT)CBS_DROPDOWN))
  405.             return FALSE;
  406.     }
  407.  
  408.     // set background color and return handle to brush
  409.     LOGBRUSH logbrush;
  410.     VERIFY(::GetObject(hbrGray, sizeof(LOGBRUSH), (LPSTR)&logbrush));
  411.     ::SetBkColor(hDC, logbrush.lbColor);
  412.     if (clrText == (COLORREF)-1)
  413.         clrText = ::GetSysColor(COLOR_WINDOWTEXT);  // normal text
  414.     ::SetTextColor(hDC, clrText);
  415.     return TRUE;
  416. }
  417.  
  418. /////////////////////////////////////////////////////////////////////////////
  419. // Centering dialog support (works for any non-child window)
  420.  
  421. void CWnd::CenterWindow(CWnd* pAlternateOwner /*= NULL*/)
  422. {
  423.     CRect rcScreen(0, 0, ::GetSystemMetrics(SM_CXSCREEN),
  424.         ::GetSystemMetrics(SM_CYSCREEN));
  425.  
  426.     // hWndOwner is the window we should center ourself in
  427.     HWND hWndOwner = (pAlternateOwner != NULL) ?
  428.             pAlternateOwner->m_hWnd : ::GetWindow(m_hWnd, GW_OWNER);
  429.  
  430.     // rcParent is the rectange we should center ourself in
  431.     CRect rcParent;
  432.     if (hWndOwner == NULL)
  433.         rcParent = rcScreen;
  434.     else
  435.         ::GetWindowRect(hWndOwner, &rcParent);
  436.  
  437.     // find ideal center point
  438.     int xMid = (rcParent.left + rcParent.right) / 2;
  439.     int yMid = (rcParent.top + rcParent.bottom) / 2;
  440.  
  441.     // find dialog's upper left based on that
  442.     CRect rcDlg;
  443.     GetWindowRect(&rcDlg);
  444.     int xLeft = xMid - rcDlg.Width() / 2;
  445.     int yTop = yMid - rcDlg.Height() / 2;
  446.  
  447.     // if the dialog is outside the screen, move it inside
  448.     if (xLeft < 0)
  449.         xLeft = 0;
  450.     else if (xLeft + rcDlg.Width() > rcScreen.right)
  451.         xLeft = rcScreen.right - rcDlg.Width();
  452.  
  453.     if (yTop < 0)
  454.         yTop = 0;
  455.     else if (yTop + rcDlg.Height() > rcScreen.bottom)
  456.         yTop = rcScreen.bottom - rcDlg.Height();
  457.  
  458.     SetWindowPos(NULL, xLeft, yTop, -1, -1, SWP_NOSIZE | SWP_NOZORDER);
  459. }
  460.  
  461. /////////////////////////////////////////////////////////////////////////////
  462. // CDialog support for context sensitive help.
  463.  
  464. LRESULT CDialog::OnCommandHelp(WPARAM, LPARAM lParam)
  465. {
  466.     if (lParam == 0 && m_nIDHelp != 0)
  467.         lParam = HID_BASE_RESOURCE + m_nIDHelp;
  468.     if (lParam != 0)
  469.     {
  470.         AfxGetApp()->WinHelp(lParam);
  471.         return TRUE;
  472.     }
  473.     return FALSE;
  474. }
  475.  
  476. LRESULT CDialog::OnHelpHitTest(WPARAM, LPARAM)
  477. {
  478.     if (m_nIDHelp != 0)
  479.         return HID_BASE_RESOURCE + m_nIDHelp;
  480.     return 0;
  481. }
  482.  
  483. /////////////////////////////////////////////////////////////////////////////
  484. // CDialog Diagnostics
  485.  
  486. #ifdef _DEBUG
  487. void
  488. CDialog::AssertValid() const
  489. {
  490.     CWnd::AssertValid();
  491. }
  492.  
  493. void
  494. CDialog::Dump(CDumpContext& dc) const
  495. {
  496.     CWnd::Dump(dc);
  497.     AFX_DUMP0(dc, "\nm_lpDialogTemplate = ");
  498.     if (HIWORD(m_lpDialogTemplate) == 0)
  499.         dc << (int)LOWORD(m_lpDialogTemplate);
  500.     else
  501.         dc << m_lpDialogTemplate;
  502.     AFX_DUMP1(dc, "\nm_hDialogTemplate = ", (UINT)m_hDialogTemplate);
  503.     AFX_DUMP1(dc, "\nm_pParentWnd = ", (void*)m_pParentWnd);
  504.     AFX_DUMP1(dc, "\nm_nIDHelp = ", m_nIDHelp);
  505. }
  506.  
  507. // diagnostic routine to check for and decode dialog templates
  508. // return FALSE if a program error occurs (i.e. bad resource ID or
  509. //   bad dialog styles).
  510. BOOL AFXAPI _AfxCheckDialogTemplate(LPCSTR lpszResource, BOOL bInvisibleChild)
  511. {
  512.     ASSERT(lpszResource != NULL);
  513. #ifndef _AFXDLL
  514.     HINSTANCE hInst = AfxGetResourceHandle();
  515. #else
  516.     HINSTANCE hInst = AfxFindResourceHandle(lpszResource, RT_DIALOG);
  517. #endif
  518.  
  519.     HRSRC hResource = ::FindResource(hInst, lpszResource, RT_DIALOG);
  520.     if (hResource == NULL)
  521.     {
  522.         if (HIWORD(lpszResource) != 0)
  523.             TRACE1("ERROR: Cannot find dialog template named '%Fs'\n",
  524.                 lpszResource);
  525.         else
  526.             TRACE1("ERROR: Cannot find dialog template with IDD 0x%04X\n",
  527.                 LOWORD(lpszResource));
  528.         return FALSE;
  529.     }
  530.  
  531.     if (!bInvisibleChild)
  532.         return TRUE;        // that's all we need to check
  533.  
  534.     // we must check that the dialog template is for an invisible child
  535.     //  window that can be used for a form-view or dialog-bar
  536.     HGLOBAL hTemplate = ::LoadResource(hInst, hResource);
  537.     if (hTemplate == NULL)
  538.     {
  539.         TRACE0("Warning: LoadResource failed for dialog template\n");
  540.         // this is only a warning, the real call to CreateDialog will fail
  541.         return TRUE;        // not a program error - just out of memory
  542.     }
  543.     // style is first DWORD in resource
  544.     DWORD dwStyle = *(DWORD FAR*)::LockResource(hTemplate);
  545.     ::UnlockResource(hTemplate);
  546.     ::FreeResource(hTemplate);
  547.  
  548.     if (dwStyle & WS_VISIBLE)
  549.     {
  550.         if (HIWORD(lpszResource) != 0)
  551.             TRACE1("ERROR: Dialog named '%Fs' must be invisible\n",
  552.                 lpszResource);
  553.         else
  554.             TRACE1("ERROR: Dialog with IDD 0x%04X must be invisible\n",
  555.                 LOWORD(lpszResource));
  556.         return FALSE;
  557.     }
  558.     if (!(dwStyle & WS_CHILD))
  559.     {
  560.         if (HIWORD(lpszResource) != 0)
  561.             TRACE1("ERROR: Dialog named '%Fs' must have the child style\n",
  562.                 lpszResource);
  563.         else
  564.             TRACE1("ERROR: Dialog with IDD 0x%04X must have the child style\n",
  565.                 LOWORD(lpszResource));
  566.         return FALSE;
  567.     }
  568.  
  569.     return TRUE;
  570. }
  571.  
  572. #endif //_DEBUG
  573.  
  574. /////////////////////////////////////////////////////////////////////////////
  575.