ctlevent.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  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. #include <stdarg.h>
  12. #ifdef AFXCTL_CORE2_SEG
  13. #pragma code_seg(AFXCTL_CORE2_SEG)
  14. #endif
  15. #ifdef _DEBUG
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19. #define new DEBUG_NEW
  20. #pragma warning(disable: 4706) // assignment within conditional
  21. /////////////////////////////////////////////////////////////////////////////
  22. // Stock event mask
  23. #define STOCKEVENT_CLICK 0x00000001
  24. #define STOCKEVENT_DBLCLICK 0x00000002
  25. #define STOCKEVENT_KEYDOWN 0x00000004
  26. #define STOCKEVENT_KEYPRESS 0x00000008
  27. #define STOCKEVENT_KEYUP 0x00000010
  28. #define STOCKEVENT_MOUSEDOWN 0x00000020
  29. #define STOCKEVENT_MOUSEMOVE 0x00000040
  30. #define STOCKEVENT_MOUSEUP 0x00000080
  31. #define STOCKEVENT_ERROR 0x00000100
  32. #define STOCKEVENT_READYSTATECHANGE 0x00000200
  33. #define STOCKEVENTS_MOUSE 0x000000A3 // Click, DblClick, MouseDown, MouseUp
  34. AFX_STATIC_DATA const DWORD _afxStockEvents[] =
  35. {
  36. STOCKEVENT_CLICK, // -600
  37. STOCKEVENT_DBLCLICK, // -601
  38. STOCKEVENT_KEYDOWN, // -602
  39. STOCKEVENT_KEYPRESS, // -603
  40. STOCKEVENT_KEYUP, // -604
  41. STOCKEVENT_MOUSEDOWN, // -605
  42. STOCKEVENT_MOUSEMOVE, // -606
  43. STOCKEVENT_MOUSEUP, // -607
  44. STOCKEVENT_ERROR, // -608
  45. STOCKEVENT_READYSTATECHANGE, // -609
  46. };
  47. void COleControl::InitStockEventMask()
  48. {
  49. const AFX_EVENTMAP* pEventMap = GetEventMap();
  50. const AFX_EVENTMAP_ENTRY* pEntry;
  51. ASSERT(pEventMap != NULL);
  52. // If stock event mask is already initialized, we're outta here.
  53. if (*pEventMap->lpStockEventMask != (DWORD)-1)
  54. return;
  55. AfxLockGlobals(CRIT_STOCKMASK);
  56. if (*pEventMap->lpStockEventMask == (DWORD)-1)
  57. {
  58. const AFX_EVENTMAP* pEventMapTop = pEventMap;
  59. DWORD dwStockEventMask = 0;
  60. while (pEventMap != NULL)
  61. {
  62. pEntry = pEventMap->lpEntries;
  63. while (pEntry != NULL && pEntry->pszName != NULL)
  64. {
  65. int nIndex = DISPID_CLICK - pEntry->dispid;
  66. DWORD dwFlag;
  67. if ((pEntry->flags & afxEventStock) && (nIndex >= 0) &&
  68. (nIndex < _countof(_afxStockEvents)) &&
  69. (dwFlag = _afxStockEvents[nIndex]) != 0)
  70. {
  71. dwStockEventMask |= dwFlag;
  72. }
  73. ++pEntry;
  74. }
  75. // check base class
  76. pEventMap = pEventMap->lpBaseEventMap;
  77. }
  78. *pEventMapTop->lpStockEventMask = dwStockEventMask;
  79. }
  80. AfxUnlockGlobals(CRIT_STOCKMASK);
  81. }
  82. /////////////////////////////////////////////////////////////////////////////
  83. // Event map operations
  84. const AFX_EVENTMAP* COleControl::GetEventMap() const
  85. {
  86. return &eventMap;
  87. }
  88. const AFX_EVENTMAP_ENTRY* COleControl::GetEventMapEntry(
  89. LPCTSTR pszName,
  90. DISPID* pDispid) const
  91. {
  92. ASSERT(pszName != NULL);
  93. ASSERT(pDispid != NULL);
  94. const AFX_EVENTMAP* pEventMap = GetEventMap();
  95. const AFX_EVENTMAP_ENTRY* pEntry;
  96. DISPID dispid = MAKELONG(1, 0);
  97. while (pEventMap != NULL)
  98. {
  99. pEntry = pEventMap->lpEntries;
  100. // Scan entries in this event map
  101. if (pEntry != NULL)
  102. {
  103. while (pEntry->pszName != NULL)
  104. {
  105. if (lstrcmp(pEntry->pszName, pszName) == 0)
  106. {
  107. if (pEntry->dispid != DISPID_UNKNOWN)
  108. dispid = pEntry->dispid;
  109. *pDispid = dispid;
  110. return pEntry;
  111. }
  112. ++pEntry;
  113. ++dispid;
  114. }
  115. }
  116. // If we didn't find it, go to the base class's event map
  117. pEventMap = pEventMap->lpBaseEventMap;
  118. dispid = MAKELONG(1, HIWORD(dispid)+1);
  119. }
  120. // If we reach here, the event isn't supported
  121. return NULL;
  122. }
  123. void COleControl::FireEventV(DISPID dispid, BYTE* pbParams,
  124. va_list argList)
  125. {
  126. COleDispatchDriver driver;
  127. POSITION pos = m_xEventConnPt.GetStartPosition();
  128. LPDISPATCH pDispatch;
  129. while (pos != NULL)
  130. {
  131. pDispatch = (LPDISPATCH)m_xEventConnPt.GetNextConnection(pos);
  132. ASSERT(pDispatch != NULL);
  133. driver.AttachDispatch(pDispatch, FALSE);
  134. TRY
  135. driver.InvokeHelperV(dispid, DISPATCH_METHOD, VT_EMPTY, NULL,
  136. pbParams, argList);
  137. END_TRY
  138. driver.DetachDispatch();
  139. }
  140. }
  141. void AFX_CDECL COleControl::FireEvent(DISPID dispid, BYTE* pbParams, ...)
  142. {
  143. va_list argList;
  144. va_start(argList, pbParams);
  145. FireEventV(dispid, pbParams, argList);
  146. va_end(argList);
  147. }
  148. /////////////////////////////////////////////////////////////////////////////
  149. // Helper function for stock events
  150. short AFXAPI _AfxShiftState()
  151. {
  152. BOOL bShift = (GetKeyState(VK_SHIFT) < 0);
  153. BOOL bCtrl = (GetKeyState(VK_CONTROL) < 0);
  154. BOOL bAlt = (GetKeyState(VK_MENU) < 0);
  155. return (short)(bShift + (bCtrl << 1) + (bAlt << 2));
  156. }
  157. /////////////////////////////////////////////////////////////////////////////
  158. // Window message handlers for stock events
  159. void COleControl::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  160. {
  161. HWND hWndSave = m_hWnd;
  162. USHORT nCharShort = (USHORT)nChar;
  163. KeyDown(&nCharShort);
  164. if ((m_hWnd == hWndSave) && (nCharShort != 0))
  165. DefWindowProc(WM_SYSKEYDOWN, nCharShort, MAKELONG(nRepCnt, nFlags));
  166. }
  167. void COleControl::OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
  168. {
  169. HWND hWndSave = m_hWnd;
  170. USHORT nCharShort = (USHORT)nChar;
  171. KeyUp(&nCharShort);
  172. if ((m_hWnd == hWndSave) && (nCharShort != 0))
  173. DefWindowProc(WM_SYSKEYUP, nCharShort, MAKELONG(nRepCnt, nFlags));
  174. }
  175. void COleControl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  176. {
  177. HWND hWndSave = m_hWnd;
  178. USHORT nCharShort = (USHORT)nChar;
  179. KeyDown(&nCharShort);
  180. if ((m_hWnd == hWndSave) && (nCharShort != 0))
  181. DefWindowProc(WM_KEYDOWN, nCharShort, MAKELONG(nRepCnt, nFlags));
  182. }
  183. void COleControl::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
  184. {
  185. HWND hWndSave = m_hWnd;
  186. USHORT nCharShort = (USHORT)nChar;
  187. KeyUp(&nCharShort);
  188. if ((m_hWnd == hWndSave) && (nCharShort != 0))
  189. DefWindowProc(WM_KEYUP, nCharShort, MAKELONG(nRepCnt, nFlags));
  190. }
  191. void COleControl::KeyUp(USHORT* pnChar)
  192. {
  193. if (GetStockEventMask() & STOCKEVENT_KEYUP)
  194. {
  195. USHORT nShiftState = _AfxShiftState();
  196. FireKeyUp(pnChar, nShiftState);
  197. // If handler set *pnChar to zero, cancel further processing.
  198. if (*pnChar != 0)
  199. OnKeyUpEvent(*pnChar, nShiftState);
  200. }
  201. }
  202. void COleControl::KeyDown(USHORT* pnChar)
  203. {
  204. if (GetStockEventMask() & STOCKEVENT_KEYDOWN)
  205. {
  206. USHORT nShiftState = _AfxShiftState();
  207. FireKeyDown(pnChar, nShiftState);
  208. // If handler set *pnChar to zero, cancel further processing.
  209. if (*pnChar != 0)
  210. OnKeyDownEvent(*pnChar, nShiftState);
  211. }
  212. }
  213. AFX_STATIC void AFXAPI _AfxPostTrailByte(CWnd* pWnd, BYTE bTrailByte)
  214. {
  215. // Force new trail byte to the front of the queue.
  216. pWnd->PostMessage(WM_QUEUE_SENTINEL);
  217. pWnd->PostMessage(WM_CHAR, bTrailByte);
  218. MSG msg;
  219. while (::PeekMessage(&msg, NULL, 0, 0, PM_NOYIELD | PM_REMOVE) &&
  220. (msg.message != WM_QUEUE_SENTINEL))
  221. {
  222. ::PostMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam);
  223. }
  224. ASSERT(msg.message == WM_QUEUE_SENTINEL);
  225. ASSERT(msg.hwnd == pWnd->m_hWnd);
  226. }
  227. UINT COleControl::OnGetDlgCode()
  228. {
  229. // If we're firing KeyPress, prevent the container from stealing WM_CHAR.
  230. return (IsSubclassedControl() ? CWnd::OnGetDlgCode() : 0) |
  231. ((GetStockEventMask() & STOCKEVENT_KEYPRESS) ? DLGC_WANTCHARS : 0);
  232. }
  233. void COleControl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  234. {
  235. USHORT nCharShort = (USHORT)nChar;
  236. USHORT nCharSave = nCharShort;
  237. BOOL bLeadByte = IsDBCSLeadByte((BYTE)nCharShort);
  238. MSG msg;
  239. if (GetStockEventMask() & STOCKEVENT_KEYPRESS)
  240. {
  241. if (bLeadByte)
  242. {
  243. // We have the lead-byte of a DBCS character. Peek for the
  244. // next WM_CHAR message, which will contain the other byte.
  245. BOOL bMessage;
  246. VERIFY(bMessage = ::PeekMessage(&msg, m_hWnd, WM_CHAR, WM_CHAR,
  247. PM_NOYIELD | PM_NOREMOVE));
  248. // Combine the bytes to form the DBCS character.
  249. if (bMessage)
  250. nCharShort = (USHORT)((nCharShort << 8) | msg.wParam);
  251. }
  252. HWND hWndSave = m_hWnd;
  253. nCharSave = nCharShort;
  254. FireKeyPress(&nCharShort);
  255. // If handler set nCharShort to zero, cancel further processing.
  256. if (nCharShort != 0)
  257. OnKeyPressEvent(nCharShort);
  258. if (m_hWnd != hWndSave)
  259. return;
  260. }
  261. if (nCharShort != 0)
  262. {
  263. if (nCharSave != nCharShort)
  264. {
  265. nChar = nCharShort;
  266. // Event handler has changed the character.
  267. BOOL bNewLeadByte = IsDBCSLeadByte(HIBYTE(nCharShort));
  268. if (bLeadByte)
  269. {
  270. if (bNewLeadByte)
  271. {
  272. // Event handler changed character from DBCS to DBCS:
  273. // Remove the old trail byte and post the new one.
  274. VERIFY(::PeekMessage(&msg, m_hWnd, WM_CHAR, WM_CHAR,
  275. PM_NOYIELD | PM_REMOVE));
  276. _AfxPostTrailByte(this, LOBYTE(nCharShort));
  277. nChar = HIBYTE(nCharShort);
  278. }
  279. else
  280. {
  281. // Event handler changed character from DBCS to SBCS:
  282. // Remove the second byte from the queue, and forward
  283. // along the new single-byte character.
  284. VERIFY(::PeekMessage(&msg, m_hWnd, WM_CHAR, WM_CHAR,
  285. PM_NOYIELD | PM_REMOVE));
  286. }
  287. }
  288. else
  289. {
  290. if (bNewLeadByte)
  291. {
  292. // Event handler changed character from SBCS to DBCS:
  293. // Post the new trail byte.
  294. _AfxPostTrailByte(this, LOBYTE(nCharShort));
  295. nChar = HIBYTE(nCharShort);
  296. }
  297. }
  298. }
  299. DefWindowProc(WM_CHAR, nChar, MAKELONG(nRepCnt, nFlags));
  300. }
  301. if (bLeadByte)
  302. {
  303. // Cleanup after processing a DBCS character:
  304. // Remove the next WM_CHAR message (containing the second byte) from
  305. // the message queue, UNLESS we're subclassing an Edit, ListBox, or
  306. // ComboBox control.
  307. TCHAR szClassName[10];
  308. if ((!::GetClassName(m_hWnd, szClassName, 10)) || // didn't get class
  309. (lstrcmpi(szClassName, _T("Edit")) && // not Edit
  310. lstrcmpi(szClassName, _T("ListBox")) && // not ListBox
  311. lstrcmpi(szClassName, _T("ComboBox")))) // not ComboBox
  312. {
  313. VERIFY(::PeekMessage(&msg, m_hWnd, WM_CHAR, WM_CHAR,
  314. PM_NOYIELD | PM_REMOVE));
  315. }
  316. }
  317. }
  318. void COleControl::OnKeyPressEvent(USHORT)
  319. {
  320. // Can be overridden by subclass
  321. }
  322. void COleControl::OnKeyDownEvent(USHORT, USHORT)
  323. {
  324. // Can be overridden by subclass
  325. }
  326. void COleControl::OnKeyUpEvent(USHORT, USHORT)
  327. {
  328. // Can be overridden by subclass
  329. }
  330. void COleControl::ButtonDown(USHORT iButton, UINT, CPoint point)
  331. {
  332. DWORD dwStockEventMask = GetStockEventMask();
  333. if ((dwStockEventMask & STOCKEVENTS_MOUSE) || m_bPendingUIActivation)
  334. {
  335. if (m_iButtonState == 0)
  336. SetCapture();
  337. m_iButtonState |= iButton;
  338. if (dwStockEventMask & STOCKEVENT_MOUSEDOWN)
  339. FireMouseDown(iButton, _AfxShiftState(), point.x, point.y);
  340. m_iDblClkState &= ~iButton;
  341. }
  342. }
  343. void COleControl::ButtonUp(USHORT iButton, UINT, CPoint point)
  344. {
  345. if (m_iButtonState != 0)
  346. {
  347. m_iButtonState &= ~iButton;
  348. if (m_iButtonState == 0)
  349. ReleaseCapture();
  350. DWORD dwStockEventMask = GetStockEventMask();
  351. if (dwStockEventMask & STOCKEVENT_MOUSEUP)
  352. FireMouseUp(iButton, _AfxShiftState(), point.x, point.y);
  353. if ((dwStockEventMask & STOCKEVENT_CLICK) &&
  354. !(m_iDblClkState & iButton))
  355. {
  356. CRect rect;
  357. GetClientRect(&rect);
  358. if (rect.PtInRect(point))
  359. OnClick(iButton);
  360. }
  361. m_iDblClkState &= ~iButton;
  362. }
  363. }
  364. void COleControl::ButtonDblClk(USHORT iButton, UINT, CPoint)
  365. {
  366. DWORD dwStockEventMask = GetStockEventMask();
  367. if (dwStockEventMask & STOCKEVENTS_MOUSE)
  368. {
  369. SetCapture();
  370. m_iButtonState |= iButton;
  371. if (dwStockEventMask & STOCKEVENT_DBLCLICK)
  372. {
  373. FireDblClick();
  374. m_iDblClkState |= iButton;
  375. }
  376. }
  377. }
  378. void COleControl::OnMouseMove(UINT /*nFlags*/, CPoint point)
  379. {
  380. if (GetStockEventMask() & STOCKEVENT_MOUSEMOVE)
  381. {
  382. HWND hWndSave = m_hWnd;
  383. FireMouseMove((short)m_iButtonState, _AfxShiftState(), point.x, point.y);
  384. if (m_hWnd != hWndSave)
  385. return;
  386. }
  387. Default();
  388. }
  389. void COleControl::OnLButtonDown(UINT nFlags, CPoint point)
  390. {
  391. OnButtonDown(LEFT_BUTTON, nFlags, point);
  392. }
  393. void COleControl::OnLButtonUp(UINT nFlags, CPoint point)
  394. {
  395. OnButtonUp(LEFT_BUTTON, nFlags, point);
  396. }
  397. void COleControl::OnLButtonDblClk(UINT nFlags, CPoint point)
  398. {
  399. OnButtonDblClk(LEFT_BUTTON, nFlags, point);
  400. }
  401. void COleControl::OnMButtonDown(UINT nFlags, CPoint point)
  402. {
  403. OnButtonDown(MIDDLE_BUTTON, nFlags, point);
  404. }
  405. void COleControl::OnMButtonUp(UINT nFlags, CPoint point)
  406. {
  407. OnButtonUp(MIDDLE_BUTTON, nFlags, point);
  408. }
  409. void COleControl::OnMButtonDblClk(UINT nFlags, CPoint point)
  410. {
  411. OnButtonDblClk(MIDDLE_BUTTON, nFlags, point);
  412. }
  413. void COleControl::OnRButtonDown(UINT nFlags, CPoint point)
  414. {
  415. OnButtonDown(RIGHT_BUTTON, nFlags, point);
  416. }
  417. void COleControl::OnRButtonUp(UINT nFlags, CPoint point)
  418. {
  419. OnButtonUp(RIGHT_BUTTON, nFlags, point);
  420. }
  421. void COleControl::OnRButtonDblClk(UINT nFlags, CPoint point)
  422. {
  423. OnButtonDblClk(RIGHT_BUTTON, nFlags, point);
  424. }
  425. void COleControl::OnButtonDown(USHORT nButton, UINT nFlags, CPoint point)
  426. {
  427. HWND hWndSave = m_hWnd;
  428. if (nButton == LEFT_BUTTON)
  429. SetFocus();
  430. ButtonDown(nButton, nFlags, point);
  431. if (m_hWnd != hWndSave)
  432. return;
  433. Default();
  434. }
  435. void COleControl::OnButtonUp(USHORT nButton, UINT nFlags, CPoint point)
  436. {
  437. HWND hWndSave = m_hWnd;
  438. Default();
  439. ButtonUp(nButton, nFlags, point);
  440. if (m_hWnd != hWndSave)
  441. return;
  442. if (m_bInPlaceActive && !m_bUIActive && m_bPendingUIActivation)
  443. {
  444. m_bPendingUIActivation = FALSE;
  445. HWND hWndFocus = ::GetFocus();
  446. if (hWndFocus == m_hWnd || ::IsChild(m_hWnd, hWndFocus))
  447. OnActivateInPlace(TRUE, NULL);
  448. }
  449. }
  450. void COleControl::OnButtonDblClk(USHORT nButton, UINT nFlags, CPoint point)
  451. {
  452. HWND hWndSave = m_hWnd;
  453. ButtonDblClk(nButton, nFlags, point);
  454. if (m_hWnd != hWndSave)
  455. return;
  456. Default();
  457. }
  458. void COleControl::OnCancelMode()
  459. {
  460. CWnd::OnCancelMode();
  461. if ((m_iButtonState != 0) || (m_iDblClkState != 0))
  462. {
  463. ReleaseCapture();
  464. m_iButtonState = 0;
  465. m_iDblClkState = 0;
  466. }
  467. }
  468. void COleControl::OnClick(USHORT /*iButton*/)
  469. {
  470. // May be overridden by subclass
  471. if (GetStockEventMask() & STOCKEVENT_CLICK)
  472. FireClick();
  473. }
  474. /////////////////////////////////////////////////////////////////////////////
  475. // Error event
  476. #define ERROR_PARAMS \
  477. EVENT_PARAM(VTS_I2 VTS_PBSTR VTS_SCODE VTS_BSTR VTS_BSTR VTS_I4 VTS_PBOOL)
  478. void COleControl::FireError(SCODE scode, LPCTSTR lpszDescription, UINT nHelpID)
  479. {
  480. USES_CONVERSION;
  481. ExternalAddRef(); // "Insurance" addref -- keeps control alive.
  482. BSTR bstrDescription = ::SysAllocString(T2COLE(lpszDescription));
  483. LPCTSTR lpszSource = AfxGetAppName();
  484. LPCTSTR lpszHelpFile = _T("");
  485. if (nHelpID != 0)
  486. lpszHelpFile = AfxGetApp()->m_pszHelpFilePath;
  487. if (lpszHelpFile == NULL)
  488. lpszHelpFile = _T("");
  489. BOOL bCancelDisplay = FALSE;
  490. FireEvent(DISPID_ERROREVENT, ERROR_PARAMS, (WORD)SCODE_CODE(scode),
  491. &bstrDescription, scode, lpszSource, lpszHelpFile, (DWORD)nHelpID,
  492. &bCancelDisplay);
  493. if (!bCancelDisplay)
  494. DisplayError(scode, OLE2CT(bstrDescription), lpszSource, lpszHelpFile, nHelpID);
  495. ::SysFreeString(bstrDescription);
  496. ExternalRelease();
  497. }
  498. void COleControl::DisplayError(SCODE /*scode*/, LPCTSTR lpszDescription,
  499. LPCTSTR lpszSource, LPCTSTR /*lpszHelpFile*/, UINT /*nHelpID*/)
  500. {
  501. // May be overridden by subclass.
  502. MessageBox(lpszDescription, lpszSource);
  503. }
  504. /////////////////////////////////////////////////////////////////////////////
  505. // Force any extra compiler-generated code into AFX_INIT_SEG
  506. #ifdef AFX_INIT_SEG
  507. #pragma code_seg(AFX_INIT_SEG)
  508. #endif