winfrmx.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 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 related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #ifdef AFX_CORE3_SEG
  12. #pragma code_seg(AFX_CORE3_SEG)
  13. #endif
  14. #ifdef _DEBUG
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. /////////////////////////////////////////////////////////////////////////////
  19. // Basic Help support
  20. void CWnd::OnHelp() // use context to derive help context
  21. {
  22. // attempt to get help from whoever is tracking
  23. HWND hWnd = ::GetCapture();
  24. while (hWnd != NULL)
  25. {
  26. // attempt to process help
  27. if (::SendMessage(hWnd, WM_COMMANDHELP, 0, 0))
  28. return;
  29. // check next parent/owner in the parent/owner chain
  30. hWnd = AfxGetParentOwner(hWnd);
  31. }
  32. // attempt to get help from whoever has the focus
  33. hWnd = ::GetFocus();
  34. while (hWnd != NULL)
  35. {
  36. // attempt to process help
  37. if (::SendMessage(hWnd, WM_COMMANDHELP, 0, 0))
  38. return;
  39. // check next parent/owner in the parent/owner chain
  40. hWnd = AfxGetParentOwner(hWnd);
  41. }
  42. // attempt to get help from the active window
  43. CWnd* pWnd = GetTopLevelParent();
  44. hWnd = ::GetLastActivePopup(pWnd->GetSafeHwnd());
  45. while (hWnd != NULL)
  46. {
  47. // attempt to process help
  48. if (::SendMessage(hWnd, WM_COMMANDHELP, 0, 0))
  49. return;
  50. // check next parent/owner in the parent/owner chain
  51. hWnd = AfxGetParentOwner(hWnd);
  52. }
  53. // No context available, bring up default.
  54. SendMessage(WM_COMMAND, ID_DEFAULT_HELP);
  55. }
  56. void CFrameWnd::OnHelp()
  57. {
  58. // Be careful not call WinHelp when the error is failing to lauch help
  59. if (m_dwPromptContext != 0)
  60. {
  61. if (m_dwPromptContext != HID_BASE_PROMPT+AFX_IDP_FAILED_TO_LAUNCH_HELP)
  62. AfxGetApp()->WinHelp(m_dwPromptContext);
  63. return;
  64. }
  65. CWnd::OnHelp();
  66. }
  67. void CWnd::OnHelpIndex()
  68. {
  69. AfxGetApp()->WinHelp(0L, HELP_INDEX);
  70. }
  71. void CWnd::OnHelpFinder()
  72. {
  73. AfxGetApp()->WinHelp(0L, HELP_FINDER);
  74. }
  75. void CWnd::OnHelpUsing()
  76. {
  77. AfxGetApp()->WinHelp(0L, HELP_HELPONHELP);
  78. }
  79. /////////////////////////////////////////////////////////////////////////////
  80. // Context Help Mode support
  81. BOOL CFrameWnd::CanEnterHelpMode()
  82. {
  83. ASSERT(m_bHelpMode != HELP_ACTIVE); // already in help mode?
  84. // unable to start help if the cursor cannot be loaded from the resources
  85. if (afxData.hcurHelp == NULL)
  86. {
  87. afxData.hcurHelp = ::LoadCursor(NULL, IDC_HELP);
  88. if (afxData.hcurHelp == NULL)
  89. {
  90. // load help cursor after handles have been setup
  91. HINSTANCE hInst = AfxFindResourceHandle(
  92. MAKEINTRESOURCE(AFX_IDC_CONTEXTHELP), RT_GROUP_CURSOR);
  93. afxData.hcurHelp = LoadCursor(hInst,
  94. MAKEINTRESOURCE(AFX_IDC_CONTEXTHELP));
  95. }
  96. if (afxData.hcurHelp == NULL)
  97. return FALSE;
  98. }
  99. // return TRUE if there is a handler for ID_CONTEXT_HELP
  100. AFX_CMDHANDLERINFO info;
  101. return OnCmdMsg(ID_CONTEXT_HELP, CN_COMMAND, NULL, &info);
  102. }
  103. void CFrameWnd::OnContextHelp()
  104. {
  105. // don't enter twice, and don't enter if initialization fails
  106. if (m_bHelpMode == HELP_ACTIVE || !CanEnterHelpMode())
  107. return;
  108. // don't enter help mode with pending WM_EXITHELPMODE message
  109. MSG msg;
  110. if (PeekMessage(&msg, m_hWnd, WM_EXITHELPMODE, WM_EXITHELPMODE,
  111. PM_REMOVE|PM_NOYIELD))
  112. {
  113. return;
  114. }
  115. BOOL bHelpMode = m_bHelpMode;
  116. ASSERT(m_bHelpMode == HELP_INACTIVE || m_bHelpMode == HELP_ENTERING);
  117. m_bHelpMode = HELP_ACTIVE;
  118. #ifndef _AFX_NO_OLE_SUPPORT
  119. // allow any in-place active servers to go into help mode
  120. if (bHelpMode != HELP_ENTERING && m_pNotifyHook != NULL &&
  121. !m_pNotifyHook->OnContextHelp(TRUE))
  122. {
  123. TRACE0("Error: an in-place server failed to enter context help mode.\n");
  124. m_pNotifyHook->OnContextHelp(FALSE); // undo partial help mode
  125. m_bHelpMode = HELP_INACTIVE;
  126. return;
  127. }
  128. #endif
  129. if (bHelpMode == HELP_INACTIVE)
  130. {
  131. // need to delay help startup until later
  132. PostMessage(WM_COMMAND, ID_CONTEXT_HELP);
  133. m_bHelpMode = HELP_ENTERING;
  134. return;
  135. }
  136. ASSERT(m_bHelpMode == HELP_ACTIVE);
  137. // display special help mode message on status bar
  138. UINT nMsgSave = (UINT)SendMessage(WM_SETMESSAGESTRING,
  139. (WPARAM)AFX_IDS_HELPMODEMESSAGE);
  140. if (nMsgSave == 0)
  141. nMsgSave = AFX_IDS_IDLEMESSAGE;
  142. DWORD dwContext = 0;
  143. POINT point;
  144. GetCursorPos(&point);
  145. SetHelpCapture(point, NULL);
  146. LONG lIdleCount = 0;
  147. CWinApp* pApp = AfxGetApp();
  148. while (m_bHelpMode)
  149. {
  150. if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
  151. {
  152. if (!ProcessHelpMsg(msg, &dwContext))
  153. break;
  154. ASSERT(dwContext == 0);
  155. }
  156. else if (!pApp->OnIdle(lIdleCount++))
  157. {
  158. lIdleCount = 0;
  159. WaitMessage();
  160. }
  161. }
  162. m_bHelpMode = HELP_INACTIVE;
  163. ReleaseCapture();
  164. // make sure the cursor is set appropriately
  165. SetCapture();
  166. ReleaseCapture();
  167. // restore original status bar text
  168. SendMessage(WM_SETMESSAGESTRING, (WPARAM)nMsgSave);
  169. #ifndef _AFX_NO_OLE_SUPPORT
  170. // tell in-place servers to exit Shift+F1 help mode
  171. if (m_pNotifyHook != NULL)
  172. m_pNotifyHook->OnContextHelp(FALSE);
  173. #endif
  174. if (dwContext != 0)
  175. {
  176. if (dwContext == -1)
  177. SendMessage(WM_COMMAND, ID_DEFAULT_HELP);
  178. else
  179. pApp->WinHelp(dwContext);
  180. }
  181. PostMessage(WM_KICKIDLE); // trigger idle update
  182. }
  183. /////////////////////////////////////////////////////////////////////////////
  184. // OnContextHelp helpers.
  185. HWND CFrameWnd::SetHelpCapture(POINT point, BOOL* pbDescendant)
  186. // set or release capture, depending on where the mouse is
  187. // also assign the proper cursor to be displayed.
  188. {
  189. if (!m_bHelpMode)
  190. return NULL;
  191. HWND hWndCapture = ::GetCapture();
  192. CWnd* pWndHit = WindowFromPoint(point);
  193. HWND hWndHit = pWndHit->GetSafeHwnd();
  194. CWnd* pTopHit = pWndHit->GetTopLevelParent();
  195. CWnd* pTopActive = GetActiveWindow()->GetTopLevelParent();
  196. BOOL bDescendant = FALSE;
  197. HTASK hCurTask = (HTASK)GetCurrentThreadId();
  198. HTASK hTaskHit = hWndHit != NULL ? ::GetWindowTask(hWndHit) : NULL;
  199. if (pTopActive == NULL || hWndHit == ::GetDesktopWindow())
  200. {
  201. if (hWndCapture == m_hWnd)
  202. ReleaseCapture();
  203. SetCursor(afxData.hcurArrow);
  204. }
  205. else if (pTopActive == NULL ||
  206. hWndHit == NULL || hCurTask != hTaskHit ||
  207. !AfxIsDescendant(m_hWnd, hWndHit))
  208. {
  209. if (hCurTask != hTaskHit)
  210. hWndHit = NULL;
  211. if (hWndCapture == m_hWnd)
  212. ReleaseCapture();
  213. }
  214. else
  215. {
  216. bDescendant = TRUE;
  217. if (pTopActive != pTopHit)
  218. hWndHit = NULL;
  219. else
  220. {
  221. if (hWndCapture != m_hWnd)
  222. ::SetCapture(m_hWnd);
  223. SetCursor(afxData.hcurHelp);
  224. }
  225. }
  226. if (pbDescendant != NULL)
  227. *pbDescendant = bDescendant;
  228. return hWndHit;
  229. }
  230. AFX_STATIC DWORD AFXAPI _AfxMapClientArea(HWND hWnd, POINT point)
  231. {
  232. DWORD dwContext;
  233. do
  234. {
  235. ASSERT(::IsWindow(hWnd));
  236. // check current window
  237. ::ScreenToClient(hWnd, &point);
  238. dwContext = ::SendMessage(hWnd, WM_HELPHITTEST, 0,
  239. MAKELONG(point.x, point.y));
  240. ::ClientToScreen(hWnd, &point);
  241. // don't use owner's of popup windows, just child/parent relationship
  242. if ((GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD) == 0)
  243. break;
  244. // check parent window
  245. hWnd = ::GetParent(hWnd);
  246. }
  247. while (hWnd && dwContext == 0);
  248. return dwContext == 0 ? -1 : dwContext;
  249. }
  250. AFX_STATIC DWORD AFXAPI _AfxMapNonClientArea(int iHit)
  251. {
  252. ASSERT(iHit != HTCLIENT);
  253. if (iHit < 0 || iHit > HTHELP)
  254. return (DWORD)-1;
  255. return HID_BASE_NCAREAS+iHit;
  256. }
  257. BOOL CFrameWnd::ProcessHelpMsg(MSG& msg, DWORD* pContext)
  258. {
  259. ASSERT(pContext != NULL);
  260. if (msg.message == WM_EXITHELPMODE ||
  261. (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE))
  262. {
  263. PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
  264. return FALSE;
  265. }
  266. CPoint point;
  267. if ((msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) ||
  268. (msg.message >= WM_NCMOUSEFIRST && msg.message <= WM_NCMOUSELAST))
  269. {
  270. BOOL bDescendant;
  271. HWND hWndHit = SetHelpCapture(msg.pt, &bDescendant);
  272. if (hWndHit == NULL)
  273. return TRUE;
  274. if (bDescendant)
  275. {
  276. if (msg.message != WM_LBUTTONDOWN)
  277. {
  278. // Hit one of our owned windows -- eat the message.
  279. PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
  280. return TRUE;
  281. }
  282. int iHit = (int)::SendMessage(hWndHit, WM_NCHITTEST, 0,
  283. MAKELONG(msg.pt.x, msg.pt.y));
  284. if (iHit == HTMENU || iHit == HTSYSMENU)
  285. {
  286. ASSERT(::GetCapture() == m_hWnd);
  287. ReleaseCapture();
  288. // the message we peeked changes into a non-client because
  289. // of the release capture.
  290. GetMessage(&msg, NULL, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN);
  291. DispatchMessage(&msg);
  292. GetCursorPos(&point);
  293. SetHelpCapture(point, NULL);
  294. }
  295. else if (iHit == HTCLIENT)
  296. {
  297. *pContext = _AfxMapClientArea(hWndHit, msg.pt);
  298. PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
  299. return FALSE;
  300. }
  301. else
  302. {
  303. *pContext = _AfxMapNonClientArea(iHit);
  304. PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
  305. return FALSE;
  306. }
  307. }
  308. else
  309. {
  310. // Hit one of our apps windows (or desktop) -- dispatch the message.
  311. PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
  312. // Dispatch mouse messages that hit the desktop!
  313. DispatchMessage(&msg);
  314. }
  315. }
  316. else if (msg.message == WM_SYSCOMMAND ||
  317. (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST))
  318. {
  319. if (::GetCapture() != NULL)
  320. {
  321. ReleaseCapture();
  322. MSG msg;
  323. while (PeekMessage(&msg, NULL, WM_MOUSEFIRST,
  324. WM_MOUSELAST, PM_REMOVE|PM_NOYIELD));
  325. }
  326. if (PeekMessage(&msg, NULL, msg.message, msg.message, PM_NOREMOVE))
  327. {
  328. GetMessage(&msg, NULL, msg.message, msg.message);
  329. if (!PreTranslateMessage(&msg))
  330. {
  331. TranslateMessage(&msg);
  332. if (msg.message == WM_SYSCOMMAND ||
  333. (msg.message >= WM_SYSKEYFIRST &&
  334. msg.message <= WM_SYSKEYLAST))
  335. {
  336. // only dispatch system keys and system commands
  337. ASSERT(msg.message == WM_SYSCOMMAND ||
  338. (msg.message >= WM_SYSKEYFIRST &&
  339. msg.message <= WM_SYSKEYLAST));
  340. DispatchMessage(&msg);
  341. }
  342. }
  343. }
  344. GetCursorPos(&point);
  345. SetHelpCapture(point, NULL);
  346. }
  347. else
  348. {
  349. // allow all other messages to go through (capture still set)
  350. if (PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE))
  351. DispatchMessage(&msg);
  352. }
  353. return TRUE;
  354. }
  355. /////////////////////////////////////////////////////////////////////////////