// This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #include #ifdef AFXCTL_CORE2_SEG #pragma code_seg(AFXCTL_CORE2_SEG) #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW #pragma warning(disable: 4706) // assignment within conditional ///////////////////////////////////////////////////////////////////////////// // Stock event mask #define STOCKEVENT_CLICK 0x00000001 #define STOCKEVENT_DBLCLICK 0x00000002 #define STOCKEVENT_KEYDOWN 0x00000004 #define STOCKEVENT_KEYPRESS 0x00000008 #define STOCKEVENT_KEYUP 0x00000010 #define STOCKEVENT_MOUSEDOWN 0x00000020 #define STOCKEVENT_MOUSEMOVE 0x00000040 #define STOCKEVENT_MOUSEUP 0x00000080 #define STOCKEVENT_ERROR 0x00000100 #define STOCKEVENT_READYSTATECHANGE 0x00000200 #define STOCKEVENTS_MOUSE 0x000000A3 // Click, DblClick, MouseDown, MouseUp AFX_STATIC_DATA const DWORD _afxStockEvents[] = { STOCKEVENT_CLICK, // -600 STOCKEVENT_DBLCLICK, // -601 STOCKEVENT_KEYDOWN, // -602 STOCKEVENT_KEYPRESS, // -603 STOCKEVENT_KEYUP, // -604 STOCKEVENT_MOUSEDOWN, // -605 STOCKEVENT_MOUSEMOVE, // -606 STOCKEVENT_MOUSEUP, // -607 STOCKEVENT_ERROR, // -608 STOCKEVENT_READYSTATECHANGE, // -609 }; void COleControl::InitStockEventMask() { const AFX_EVENTMAP* pEventMap = GetEventMap(); const AFX_EVENTMAP_ENTRY* pEntry; ASSERT(pEventMap != NULL); // If stock event mask is already initialized, we're outta here. if (*pEventMap->lpStockEventMask != (DWORD)-1) return; AfxLockGlobals(CRIT_STOCKMASK); if (*pEventMap->lpStockEventMask == (DWORD)-1) { const AFX_EVENTMAP* pEventMapTop = pEventMap; DWORD dwStockEventMask = 0; while (pEventMap != NULL) { pEntry = pEventMap->lpEntries; while (pEntry != NULL && pEntry->pszName != NULL) { int nIndex = DISPID_CLICK - pEntry->dispid; DWORD dwFlag; if ((pEntry->flags & afxEventStock) && (nIndex >= 0) && (nIndex < _countof(_afxStockEvents)) && (dwFlag = _afxStockEvents[nIndex]) != 0) { dwStockEventMask |= dwFlag; } ++pEntry; } // check base class pEventMap = pEventMap->lpBaseEventMap; } *pEventMapTop->lpStockEventMask = dwStockEventMask; } AfxUnlockGlobals(CRIT_STOCKMASK); } ///////////////////////////////////////////////////////////////////////////// // Event map operations const AFX_EVENTMAP* COleControl::GetEventMap() const { return &eventMap; } const AFX_EVENTMAP_ENTRY* COleControl::GetEventMapEntry( LPCTSTR pszName, DISPID* pDispid) const { ASSERT(pszName != NULL); ASSERT(pDispid != NULL); const AFX_EVENTMAP* pEventMap = GetEventMap(); const AFX_EVENTMAP_ENTRY* pEntry; DISPID dispid = MAKELONG(1, 0); while (pEventMap != NULL) { pEntry = pEventMap->lpEntries; // Scan entries in this event map if (pEntry != NULL) { while (pEntry->pszName != NULL) { if (lstrcmp(pEntry->pszName, pszName) == 0) { if (pEntry->dispid != DISPID_UNKNOWN) dispid = pEntry->dispid; *pDispid = dispid; return pEntry; } ++pEntry; ++dispid; } } // If we didn't find it, go to the base class's event map pEventMap = pEventMap->lpBaseEventMap; dispid = MAKELONG(1, HIWORD(dispid)+1); } // If we reach here, the event isn't supported return NULL; } void COleControl::FireEventV(DISPID dispid, BYTE* pbParams, va_list argList) { COleDispatchDriver driver; POSITION pos = m_xEventConnPt.GetStartPosition(); LPDISPATCH pDispatch; while (pos != NULL) { pDispatch = (LPDISPATCH)m_xEventConnPt.GetNextConnection(pos); ASSERT(pDispatch != NULL); driver.AttachDispatch(pDispatch, FALSE); TRY driver.InvokeHelperV(dispid, DISPATCH_METHOD, VT_EMPTY, NULL, pbParams, argList); END_TRY driver.DetachDispatch(); } } void AFX_CDECL COleControl::FireEvent(DISPID dispid, BYTE* pbParams, ...) { va_list argList; va_start(argList, pbParams); FireEventV(dispid, pbParams, argList); va_end(argList); } ///////////////////////////////////////////////////////////////////////////// // Helper function for stock events short AFXAPI _AfxShiftState() { BOOL bShift = (GetKeyState(VK_SHIFT) < 0); BOOL bCtrl = (GetKeyState(VK_CONTROL) < 0); BOOL bAlt = (GetKeyState(VK_MENU) < 0); return (short)(bShift + (bCtrl << 1) + (bAlt << 2)); } ///////////////////////////////////////////////////////////////////////////// // Window message handlers for stock events void COleControl::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { HWND hWndSave = m_hWnd; USHORT nCharShort = (USHORT)nChar; KeyDown(&nCharShort); if ((m_hWnd == hWndSave) && (nCharShort != 0)) DefWindowProc(WM_SYSKEYDOWN, nCharShort, MAKELONG(nRepCnt, nFlags)); } void COleControl::OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { HWND hWndSave = m_hWnd; USHORT nCharShort = (USHORT)nChar; KeyUp(&nCharShort); if ((m_hWnd == hWndSave) && (nCharShort != 0)) DefWindowProc(WM_SYSKEYUP, nCharShort, MAKELONG(nRepCnt, nFlags)); } void COleControl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { HWND hWndSave = m_hWnd; USHORT nCharShort = (USHORT)nChar; KeyDown(&nCharShort); if ((m_hWnd == hWndSave) && (nCharShort != 0)) DefWindowProc(WM_KEYDOWN, nCharShort, MAKELONG(nRepCnt, nFlags)); } void COleControl::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) { HWND hWndSave = m_hWnd; USHORT nCharShort = (USHORT)nChar; KeyUp(&nCharShort); if ((m_hWnd == hWndSave) && (nCharShort != 0)) DefWindowProc(WM_KEYUP, nCharShort, MAKELONG(nRepCnt, nFlags)); } void COleControl::KeyUp(USHORT* pnChar) { if (GetStockEventMask() & STOCKEVENT_KEYUP) { USHORT nShiftState = _AfxShiftState(); FireKeyUp(pnChar, nShiftState); // If handler set *pnChar to zero, cancel further processing. if (*pnChar != 0) OnKeyUpEvent(*pnChar, nShiftState); } } void COleControl::KeyDown(USHORT* pnChar) { if (GetStockEventMask() & STOCKEVENT_KEYDOWN) { USHORT nShiftState = _AfxShiftState(); FireKeyDown(pnChar, nShiftState); // If handler set *pnChar to zero, cancel further processing. if (*pnChar != 0) OnKeyDownEvent(*pnChar, nShiftState); } } AFX_STATIC void AFXAPI _AfxPostTrailByte(CWnd* pWnd, BYTE bTrailByte) { // Force new trail byte to the front of the queue. pWnd->PostMessage(WM_QUEUE_SENTINEL); pWnd->PostMessage(WM_CHAR, bTrailByte); MSG msg; while (::PeekMessage(&msg, NULL, 0, 0, PM_NOYIELD | PM_REMOVE) && (msg.message != WM_QUEUE_SENTINEL)) { ::PostMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam); } ASSERT(msg.message == WM_QUEUE_SENTINEL); ASSERT(msg.hwnd == pWnd->m_hWnd); } UINT COleControl::OnGetDlgCode() { // If we're firing KeyPress, prevent the container from stealing WM_CHAR. return (IsSubclassedControl() ? CWnd::OnGetDlgCode() : 0) | ((GetStockEventMask() & STOCKEVENT_KEYPRESS) ? DLGC_WANTCHARS : 0); } void COleControl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { USHORT nCharShort = (USHORT)nChar; USHORT nCharSave = nCharShort; BOOL bLeadByte = IsDBCSLeadByte((BYTE)nCharShort); MSG msg; if (GetStockEventMask() & STOCKEVENT_KEYPRESS) { if (bLeadByte) { // We have the lead-byte of a DBCS character. Peek for the // next WM_CHAR message, which will contain the other byte. BOOL bMessage; VERIFY(bMessage = ::PeekMessage(&msg, m_hWnd, WM_CHAR, WM_CHAR, PM_NOYIELD | PM_NOREMOVE)); // Combine the bytes to form the DBCS character. if (bMessage) nCharShort = (USHORT)((nCharShort << 8) | msg.wParam); } HWND hWndSave = m_hWnd; nCharSave = nCharShort; FireKeyPress(&nCharShort); // If handler set nCharShort to zero, cancel further processing. if (nCharShort != 0) OnKeyPressEvent(nCharShort); if (m_hWnd != hWndSave) return; } if (nCharShort != 0) { if (nCharSave != nCharShort) { nChar = nCharShort; // Event handler has changed the character. BOOL bNewLeadByte = IsDBCSLeadByte(HIBYTE(nCharShort)); if (bLeadByte) { if (bNewLeadByte) { // Event handler changed character from DBCS to DBCS: // Remove the old trail byte and post the new one. VERIFY(::PeekMessage(&msg, m_hWnd, WM_CHAR, WM_CHAR, PM_NOYIELD | PM_REMOVE)); _AfxPostTrailByte(this, LOBYTE(nCharShort)); nChar = HIBYTE(nCharShort); } else { // Event handler changed character from DBCS to SBCS: // Remove the second byte from the queue, and forward // along the new single-byte character. VERIFY(::PeekMessage(&msg, m_hWnd, WM_CHAR, WM_CHAR, PM_NOYIELD | PM_REMOVE)); } } else { if (bNewLeadByte) { // Event handler changed character from SBCS to DBCS: // Post the new trail byte. _AfxPostTrailByte(this, LOBYTE(nCharShort)); nChar = HIBYTE(nCharShort); } } } DefWindowProc(WM_CHAR, nChar, MAKELONG(nRepCnt, nFlags)); } if (bLeadByte) { // Cleanup after processing a DBCS character: // Remove the next WM_CHAR message (containing the second byte) from // the message queue, UNLESS we're subclassing an Edit, ListBox, or // ComboBox control. TCHAR szClassName[10]; if ((!::GetClassName(m_hWnd, szClassName, 10)) || // didn't get class (lstrcmpi(szClassName, _T("Edit")) && // not Edit lstrcmpi(szClassName, _T("ListBox")) && // not ListBox lstrcmpi(szClassName, _T("ComboBox")))) // not ComboBox { VERIFY(::PeekMessage(&msg, m_hWnd, WM_CHAR, WM_CHAR, PM_NOYIELD | PM_REMOVE)); } } } void COleControl::OnKeyPressEvent(USHORT) { // Can be overridden by subclass } void COleControl::OnKeyDownEvent(USHORT, USHORT) { // Can be overridden by subclass } void COleControl::OnKeyUpEvent(USHORT, USHORT) { // Can be overridden by subclass } void COleControl::ButtonDown(USHORT iButton, UINT, CPoint point) { DWORD dwStockEventMask = GetStockEventMask(); if ((dwStockEventMask & STOCKEVENTS_MOUSE) || m_bPendingUIActivation) { if (m_iButtonState == 0) SetCapture(); m_iButtonState |= iButton; if (dwStockEventMask & STOCKEVENT_MOUSEDOWN) FireMouseDown(iButton, _AfxShiftState(), point.x, point.y); m_iDblClkState &= ~iButton; } } void COleControl::ButtonUp(USHORT iButton, UINT, CPoint point) { if (m_iButtonState != 0) { m_iButtonState &= ~iButton; if (m_iButtonState == 0) ReleaseCapture(); DWORD dwStockEventMask = GetStockEventMask(); if (dwStockEventMask & STOCKEVENT_MOUSEUP) FireMouseUp(iButton, _AfxShiftState(), point.x, point.y); if ((dwStockEventMask & STOCKEVENT_CLICK) && !(m_iDblClkState & iButton)) { CRect rect; GetClientRect(&rect); if (rect.PtInRect(point)) OnClick(iButton); } m_iDblClkState &= ~iButton; } } void COleControl::ButtonDblClk(USHORT iButton, UINT, CPoint) { DWORD dwStockEventMask = GetStockEventMask(); if (dwStockEventMask & STOCKEVENTS_MOUSE) { SetCapture(); m_iButtonState |= iButton; if (dwStockEventMask & STOCKEVENT_DBLCLICK) { FireDblClick(); m_iDblClkState |= iButton; } } } void COleControl::OnMouseMove(UINT /*nFlags*/, CPoint point) { if (GetStockEventMask() & STOCKEVENT_MOUSEMOVE) { HWND hWndSave = m_hWnd; FireMouseMove((short)m_iButtonState, _AfxShiftState(), point.x, point.y); if (m_hWnd != hWndSave) return; } Default(); } void COleControl::OnLButtonDown(UINT nFlags, CPoint point) { OnButtonDown(LEFT_BUTTON, nFlags, point); } void COleControl::OnLButtonUp(UINT nFlags, CPoint point) { OnButtonUp(LEFT_BUTTON, nFlags, point); } void COleControl::OnLButtonDblClk(UINT nFlags, CPoint point) { OnButtonDblClk(LEFT_BUTTON, nFlags, point); } void COleControl::OnMButtonDown(UINT nFlags, CPoint point) { OnButtonDown(MIDDLE_BUTTON, nFlags, point); } void COleControl::OnMButtonUp(UINT nFlags, CPoint point) { OnButtonUp(MIDDLE_BUTTON, nFlags, point); } void COleControl::OnMButtonDblClk(UINT nFlags, CPoint point) { OnButtonDblClk(MIDDLE_BUTTON, nFlags, point); } void COleControl::OnRButtonDown(UINT nFlags, CPoint point) { OnButtonDown(RIGHT_BUTTON, nFlags, point); } void COleControl::OnRButtonUp(UINT nFlags, CPoint point) { OnButtonUp(RIGHT_BUTTON, nFlags, point); } void COleControl::OnRButtonDblClk(UINT nFlags, CPoint point) { OnButtonDblClk(RIGHT_BUTTON, nFlags, point); } void COleControl::OnButtonDown(USHORT nButton, UINT nFlags, CPoint point) { HWND hWndSave = m_hWnd; if (nButton == LEFT_BUTTON) SetFocus(); ButtonDown(nButton, nFlags, point); if (m_hWnd != hWndSave) return; Default(); } void COleControl::OnButtonUp(USHORT nButton, UINT nFlags, CPoint point) { HWND hWndSave = m_hWnd; Default(); ButtonUp(nButton, nFlags, point); if (m_hWnd != hWndSave) return; if (m_bInPlaceActive && !m_bUIActive && m_bPendingUIActivation) { m_bPendingUIActivation = FALSE; HWND hWndFocus = ::GetFocus(); if (hWndFocus == m_hWnd || ::IsChild(m_hWnd, hWndFocus)) OnActivateInPlace(TRUE, NULL); } } void COleControl::OnButtonDblClk(USHORT nButton, UINT nFlags, CPoint point) { HWND hWndSave = m_hWnd; ButtonDblClk(nButton, nFlags, point); if (m_hWnd != hWndSave) return; Default(); } void COleControl::OnCancelMode() { CWnd::OnCancelMode(); if ((m_iButtonState != 0) || (m_iDblClkState != 0)) { ReleaseCapture(); m_iButtonState = 0; m_iDblClkState = 0; } } void COleControl::OnClick(USHORT /*iButton*/) { // May be overridden by subclass if (GetStockEventMask() & STOCKEVENT_CLICK) FireClick(); } ///////////////////////////////////////////////////////////////////////////// // Error event #define ERROR_PARAMS \ EVENT_PARAM(VTS_I2 VTS_PBSTR VTS_SCODE VTS_BSTR VTS_BSTR VTS_I4 VTS_PBOOL) void COleControl::FireError(SCODE scode, LPCTSTR lpszDescription, UINT nHelpID) { USES_CONVERSION; ExternalAddRef(); // "Insurance" addref -- keeps control alive. BSTR bstrDescription = ::SysAllocString(T2COLE(lpszDescription)); LPCTSTR lpszSource = AfxGetAppName(); LPCTSTR lpszHelpFile = _T(""); if (nHelpID != 0) lpszHelpFile = AfxGetApp()->m_pszHelpFilePath; if (lpszHelpFile == NULL) lpszHelpFile = _T(""); BOOL bCancelDisplay = FALSE; FireEvent(DISPID_ERROREVENT, ERROR_PARAMS, (WORD)SCODE_CODE(scode), &bstrDescription, scode, lpszSource, lpszHelpFile, (DWORD)nHelpID, &bCancelDisplay); if (!bCancelDisplay) DisplayError(scode, OLE2CT(bstrDescription), lpszSource, lpszHelpFile, nHelpID); ::SysFreeString(bstrDescription); ExternalRelease(); } void COleControl::DisplayError(SCODE /*scode*/, LPCTSTR lpszDescription, LPCTSTR lpszSource, LPCTSTR /*lpszHelpFile*/, UINT /*nHelpID*/) { // May be overridden by subclass. MessageBox(lpszDescription, lpszSource); } ///////////////////////////////////////////////////////////////////////////// // Force any extra compiler-generated code into AFX_INIT_SEG #ifdef AFX_INIT_SEG #pragma code_seg(AFX_INIT_SEG) #endif