home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 19.ddi / MFC / SRC / APPHELPX.CP_ / APPHELPX.CP
Encoding:
Text File  |  1993-02-08  |  8.3 KB  |  330 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. #include "stdafx.h"
  12.  
  13. #ifdef AFX_CORE3_SEG
  14. #pragma code_seg(AFX_CORE3_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char BASED_CODE THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. /////////////////////////////////////////////////////////////////////////////
  23. // Basic Help support
  24.  
  25. void CWinApp::OnHelp()  // use context to derive help context
  26. {
  27.     ASSERT(m_pMainWnd != NULL);
  28.  
  29.     if (m_dwPromptContext != 0)
  30.     {
  31.         // Be careful not to try to launch help when the error is
  32.         // failing to lauch help
  33.         if (m_dwPromptContext != HID_BASE_PROMPT+AFX_IDP_FAILED_TO_LAUNCH_HELP)
  34.             WinHelp(m_dwPromptContext);
  35.     }
  36.     else
  37.     {
  38.         HWND hWnd = ::GetActiveWindow();
  39.         while (hWnd != NULL)
  40.         {
  41.             // Should be a window of this task!
  42.             ASSERT(::IsWindow(hWnd));
  43.             ASSERT(::GetWindowTask(hWnd) == ::GetCurrentTask());
  44.  
  45.             // attempt to process help
  46.             if (::SendMessage(hWnd, WM_COMMANDHELP, 0, 0))
  47.                 break;
  48.  
  49.             // Try parent/owner window next!
  50.             hWnd = ::GetParent(hWnd);
  51.         }
  52.         if (hWnd == NULL)
  53.         {
  54.             // No context available, bring up default.
  55.             m_pMainWnd->SendMessage(WM_COMMAND, ID_DEFAULT_HELP);
  56.         }
  57.     }
  58. }
  59.  
  60. void CWinApp::OnHelpIndex()
  61. {
  62.     WinHelp(0L, HELP_INDEX);
  63. }
  64.  
  65. void CWinApp::OnHelpUsing()
  66. {
  67.     WinHelp(0L, HELP_HELPONHELP);
  68. }
  69.  
  70. /////////////////////////////////////////////////////////////////////////////
  71. // Context Help Mode support
  72.  
  73. static HCURSOR NEAR hcurContextHelp = NULL; // shared global with modal usage
  74.         // default help cursor
  75.  
  76. void CWinApp::OnContextHelp()
  77. {
  78.     DWORD   dwContext = 0;
  79.     POINT   point;
  80.  
  81.     if (::GetCapture() != NULL)
  82.         return;
  83.  
  84.     ASSERT(m_pMainWnd != NULL);
  85.     ASSERT(m_pMainWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)));
  86.     ASSERT_VALID(m_pMainWnd);
  87.  
  88.     hcurContextHelp = LoadCursor(AFX_IDC_CONTEXTHELP);
  89.     if (hcurContextHelp == NULL)
  90.     {
  91.         TRACE0("error: Help cursor not found in resource\n");
  92.         return;
  93.     }
  94.     ASSERT(m_hcurHelp == NULL);
  95.  
  96.     // display special help mode message on status bar
  97.     UINT nMsgSave = (UINT)m_pMainWnd->SendMessage(WM_SETMESSAGESTRING,
  98.         (WPARAM)AFX_IDS_HELPMODEMESSAGE);
  99.  
  100.     ASSERT(!m_bHelpMode);
  101.     m_bHelpMode = TRUE;
  102.     GetCursorPos(&point);
  103.     SetHelpCapture(point);
  104.     ASSERT(m_hcurHelp != NULL);
  105.     LONG lIdleCount = 0;
  106.  
  107.     while (m_bHelpMode)
  108.     {
  109.         if (::PeekMessage(&m_msgCur, NULL, WM_PAINT, WM_PAINT, PM_REMOVE))
  110.         {
  111.             DispatchMessage(&m_msgCur);
  112.         }
  113.         else if (::PeekMessage(&m_msgCur, NULL, 0, 0, PM_NOREMOVE))
  114.         {
  115.             if (!ProcessHelpMsg(m_msgCur, &dwContext))
  116.                 break;
  117.             ASSERT(dwContext == 0);
  118.         }
  119.         else if (!OnIdle(lIdleCount++))
  120.         {
  121.             lIdleCount = 0;
  122.             WaitMessage();
  123.         }
  124.     }
  125.  
  126.     m_bHelpMode = FALSE;
  127.     ASSERT(m_hcurHelp != NULL);
  128.     ASSERT(hcurContextHelp != NULL);
  129.     ::SetCursor(afxData.hcurArrow);
  130.     ::DestroyCursor(hcurContextHelp);
  131.     hcurContextHelp = NULL;
  132.     m_hcurHelp = NULL;
  133.     if (::GetCapture() == m_pMainWnd->m_hWnd)
  134.         ::ReleaseCapture();
  135.  
  136.     // restore original status bar text
  137.     m_pMainWnd->SendMessage(WM_SETMESSAGESTRING, (WPARAM)nMsgSave);
  138.  
  139.     if (dwContext != 0)
  140.     {
  141.         if (dwContext == -1)
  142.             m_pMainWnd->SendMessage(WM_COMMAND, ID_DEFAULT_HELP);
  143.         else
  144.             WinHelp(dwContext);
  145.     }
  146. }
  147.  
  148. /////////////////////////////////////////////////////////////////////////////
  149. // OnContextHelp helpers.
  150.  
  151. HWND CWinApp::SetHelpCapture(POINT ptCursor)
  152.     // set or release capture, depending on where the mouse is
  153.     // also assign the proper cursor to be displayed.
  154. {
  155.     if (!m_bHelpMode)
  156.         return NULL;
  157.  
  158.     ASSERT(m_pMainWnd != NULL);
  159.     ASSERT(m_pMainWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)));
  160.     ASSERT_VALID(m_pMainWnd);
  161.  
  162.     HWND hWndHit = ::WindowFromPoint(ptCursor);
  163.     HWND hWndCapture = ::GetCapture();
  164.     HTASK hCurTask = ::GetCurrentTask();
  165.  
  166.     if (hWndHit == ::GetDesktopWindow())
  167.     {
  168.         m_hcurHelp = afxData.hcurArrow;
  169.         if (hWndCapture == m_pMainWnd->m_hWnd)
  170.             ::ReleaseCapture();
  171.         ::SetCursor(afxData.hcurArrow);
  172.     }
  173.     else if (hWndHit == NULL || ::GetWindowTask(hWndHit) != hCurTask)
  174.     {
  175.         hWndHit = NULL;
  176.         m_hcurHelp = hcurContextHelp;
  177.         if (hWndCapture == m_pMainWnd->m_hWnd)
  178.             ::ReleaseCapture();
  179.     }
  180.     else
  181.     {
  182.         if (::GetWindowTask(::GetActiveWindow()) != hCurTask)
  183.             return NULL;
  184.         if (hWndCapture != m_pMainWnd->m_hWnd)
  185.             ::SetCapture(m_pMainWnd->m_hWnd);
  186.         m_hcurHelp = hcurContextHelp;
  187.         ::SetCursor(m_hcurHelp);
  188.     }
  189.  
  190.     return hWndHit;
  191. }
  192.  
  193. static DWORD NEAR PASCAL MapClientArea(HWND hWnd, POINT point)
  194. {
  195.     DWORD dwContext;
  196.     do
  197.     {
  198.         ASSERT(::IsWindow(hWnd));
  199.         ::ScreenToClient(hWnd, &point);
  200.         dwContext = ::SendMessage(hWnd, WM_HELPHITTEST, 0,
  201.             MAKELONG(point.x, point.y));
  202.         ::ClientToScreen(hWnd, &point);
  203.         hWnd = ::GetParent(hWnd);
  204.     } while (hWnd && dwContext == 0);
  205.  
  206.     if (dwContext == 0)
  207.         dwContext = -1;
  208.  
  209.     return dwContext;
  210. }
  211.  
  212. static DWORD NEAR PASCAL MapNonClientArea(int iHit)
  213. {
  214.     ASSERT(iHit != HTCLIENT);
  215.  
  216.     if (iHit < 0 || iHit > HTBORDER)
  217.         return -1;
  218.  
  219.     return HID_BASE_NCAREAS+iHit;
  220. }
  221.  
  222. #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
  223. #define WM_NCMOUSELAST  WM_NCMBUTTONDBLCLK
  224.  
  225. #define WM_SYSKEYFIRST  WM_SYSKEYDOWN
  226. #define WM_SYSKEYLAST   WM_SYSDEADCHAR
  227.  
  228. BOOL CWinApp::ProcessHelpMsg(MSG& msg, DWORD* pContext)
  229. {
  230.     POINT point;
  231.  
  232.     ASSERT(pContext != NULL);
  233.  
  234.     if (msg.message == WM_EXITHELPMODE ||
  235.         (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE))
  236.     {
  237.         ::PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
  238.         return FALSE;
  239.     }
  240.  
  241.     if ((msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) ||
  242.         (msg.message >= WM_NCMOUSEFIRST && msg.message <= WM_NCMOUSELAST))
  243.     {
  244.         HWND hWndHit = SetHelpCapture(msg.pt);
  245.         if (hWndHit == NULL)
  246.             return TRUE;
  247.  
  248.         HWND hWndDesktop = ::GetDesktopWindow();
  249.  
  250.         if (hWndHit != hWndDesktop && msg.message == WM_LBUTTONDOWN)
  251.         {
  252.             int iHit = (int)::SendMessage(hWndHit, WM_NCHITTEST, 0,
  253.                 MAKELONG(msg.pt.x, msg.pt.y));
  254.             if (iHit == HTMENU || iHit == HTSYSMENU)
  255.             {
  256.                 ASSERT(::GetCapture());
  257.                 ASSERT(::GetCapture() == m_pMainWnd->m_hWnd);
  258.                 ::ReleaseCapture();
  259.                 // the message we peeked changes into a non-client because
  260.                 // of the release capture.
  261.                 ::GetMessage(&msg, NULL, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN);
  262.                 ::DispatchMessage(&msg);
  263.                 GetCursorPos(&point);
  264.                 SetHelpCapture(point);
  265.             }
  266.             else if (iHit == HTCLIENT)
  267.             {
  268.                 *pContext = MapClientArea(hWndHit, msg.pt);
  269.                 ::PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
  270.                 return FALSE;
  271.             }
  272.             else
  273.             {
  274.                 *pContext = MapNonClientArea(iHit);
  275.                 ::PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
  276.                 return FALSE;
  277.             }
  278.         }
  279.         else
  280.         {
  281.             // Hit one of our own windows (or desktop) -- eat the message.
  282.             ::PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
  283.  
  284.             // Dispatch mouse messages that hit the desktop!
  285.             if (hWndHit == hWndDesktop)
  286.                 ::DispatchMessage(&msg);
  287.         }
  288.     }
  289.     else if (msg.message == WM_SYSCOMMAND ||
  290.              (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST))
  291.     {
  292.         if (::GetCapture() != NULL)
  293.         {
  294.             ASSERT(::GetCapture() == m_pMainWnd->m_hWnd);
  295.             ::ReleaseCapture();
  296.             MSG msg;
  297.             while (::PeekMessage(&msg, NULL, WM_MOUSEFIRST,
  298.                 WM_MOUSELAST, PM_REMOVE|PM_NOYIELD));
  299.         }
  300.         ASSERT(::PeekMessage(&msg, NULL, msg.message, msg.message,
  301.             PM_NOREMOVE));
  302.         ::GetMessage(&msg, NULL, msg.message, msg.message);
  303.         if (!PreTranslateMessage(&msg))
  304.         {
  305.             ::TranslateMessage(&msg);
  306.             if (msg.message == WM_SYSCOMMAND ||
  307.               (msg.message >= WM_SYSKEYFIRST && msg.message <= WM_SYSKEYLAST))
  308.             {
  309.                 // only dispatch system keys and system commands
  310.                 ASSERT(msg.message == WM_SYSCOMMAND ||
  311.                      (msg.message >= WM_SYSKEYFIRST &&
  312.                       msg.message <= WM_SYSKEYLAST));
  313.                 ::DispatchMessage(&msg);
  314.             }
  315.         }
  316.         GetCursorPos(&point);
  317.         SetHelpCapture(point);
  318.     }
  319.     else
  320.     {
  321.         // allow all other messages to go through (capture still set)
  322.         if (::PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE))
  323.             ::DispatchMessage(&msg);
  324.     }
  325.  
  326.     return TRUE;
  327. }
  328.  
  329. /////////////////////////////////////////////////////////////////////////////
  330.