// 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 "occimpl.h" #ifdef AFX_OCC_SEG #pragma code_seg(AFX_OCC_SEG) #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW ///////////////////////////////////////////////////////////////////////////// // OLE event sink handler typedef BOOL (AFX_MSG_CALL CCmdTarget::*PFN_CHANGED)(); typedef BOOL (AFX_MSG_CALL CCmdTarget::*PFN_REQUEST)(BOOL*); typedef BOOL (AFX_MSG_CALL CCmdTarget::*PFN_DSCNOTIFY)(DSCSTATE, DSCREASON, BOOL*); typedef BOOL (AFX_MSG_CALL CCmdTarget::*PFN_CHANGED_RANGE)(UINT); typedef BOOL (AFX_MSG_CALL CCmdTarget::*PFN_REQUEST_RANGE)(UINT, BOOL*); typedef BOOL (AFX_MSG_CALL CCmdTarget::*PFN_DSCNOTIFY_RANGE)(UINT, DSCSTATE, DSCREASON, BOOL*); BOOL CCmdTarget::OnEvent(UINT idCtrl, AFX_EVENT* pEvent, AFX_CMDHANDLERINFO* pHandlerInfo) { HRESULT hResult = S_OK; UINT uArgError = (UINT)-1; // no error yet const AFX_EVENTSINKMAP_ENTRY* pEntry = GetEventSinkEntry(idCtrl, pEvent); // no handler for this event if (pEntry == NULL) return FALSE; if (pHandlerInfo != NULL) { // just fill in the information, don't do it pHandlerInfo->pTarget = this; switch (pEvent->m_eventKind) { case AFX_EVENT::event: case AFX_EVENT::propRequest: pHandlerInfo->pmf = pEntry->dispEntry.pfn; break; case AFX_EVENT::propChanged: pHandlerInfo->pmf = pEntry->dispEntry.pfnSet; break; default: ASSERT(FALSE); // bogus value for pEvent->m_eventKind } return (pHandlerInfo->pmf != NULL); } BOOL bRange = (pEntry->nCtrlIDLast != (UINT)-1); BOOL bHandled = FALSE; TRY { switch (pEvent->m_eventKind) { case AFX_EVENT::event: // do standard method call VARIANT var; AfxVariantInit(&var); DISPPARAMS dispparams; dispparams.rgvarg = NULL; if (bRange) { memcpy(&dispparams, pEvent->m_pDispParams, sizeof(DISPPARAMS)); dispparams.rgvarg = new VARIANT[++dispparams.cArgs]; memcpy(dispparams.rgvarg, pEvent->m_pDispParams->rgvarg, sizeof(VARIANT) * (dispparams.cArgs-1)); VARIANT* pvarID = &dispparams.rgvarg[dispparams.cArgs-1]; V_VT(pvarID) = VT_I4; V_I4(pvarID) = idCtrl; } hResult = CallMemberFunc(&pEntry->dispEntry, DISPATCH_METHOD, &var, (bRange ? &dispparams : pEvent->m_pDispParams), &uArgError); ASSERT(FAILED(hResult) || (V_VT(&var) == VT_BOOL)); bHandled = V_BOOL(&var); if (bRange) delete [] dispparams.rgvarg; break; case AFX_EVENT::propChanged: { if (bRange) { PFN_CHANGED_RANGE pfn = (PFN_CHANGED_RANGE)pEntry->dispEntry.pfnSet; bHandled = (this->*pfn)(idCtrl); } else { PFN_CHANGED pfn = (PFN_CHANGED)pEntry->dispEntry.pfnSet; bHandled = (this->*pfn)(); } hResult = S_OK; } break; case AFX_EVENT::propRequest: { BOOL bAllow = TRUE; if (bRange) { PFN_REQUEST_RANGE pfn = (PFN_REQUEST_RANGE)pEntry->dispEntry.pfn; bHandled = (this->*pfn)(idCtrl, &bAllow); } else { PFN_REQUEST pfn = (PFN_REQUEST)pEntry->dispEntry.pfn; bHandled = (this->*pfn)(&bAllow); } hResult = bAllow ? S_OK : S_FALSE; } break; case AFX_EVENT::propDSCNotify: { BOOL bAllow = TRUE; if (bRange) { PFN_DSCNOTIFY_RANGE pfn = (PFN_DSCNOTIFY_RANGE)pEntry->dispEntry.pfn; bHandled = (this->*pfn)(idCtrl, pEvent->m_nDSCState, pEvent->m_nDSCReason, &bAllow); } else { PFN_DSCNOTIFY pfn = (PFN_DSCNOTIFY)pEntry->dispEntry.pfn; bHandled = (this->*pfn)(pEvent->m_nDSCState, pEvent->m_nDSCReason, &bAllow); } hResult = bAllow ? S_OK : S_FALSE; } break; default: ASSERT(FALSE); // bogus value for pEvent->m_eventKind } } CATCH_ALL(e) { if (pEvent->m_pExcepInfo != NULL) { // fill exception with translation of MFC exception COleDispatchException::Process(pEvent->m_pExcepInfo, e); } DELETE_EXCEPTION(e); hResult = DISP_E_EXCEPTION; } END_CATCH_ALL // fill error argument if one is available if (FAILED(hResult) && pEvent->m_puArgError != NULL && uArgError != -1) *pEvent->m_puArgError = uArgError; // fill result code pEvent->m_hResult = hResult; return bHandled; } ///////////////////////////////////////////////////////////////////////////// // Locate event sink map entry const AFX_EVENTSINKMAP_ENTRY* PASCAL CCmdTarget::GetEventSinkEntry( UINT idCtrl, AFX_EVENT* pEvent) { const AFX_EVENTSINKMAP* pSinkMap = GetEventSinkMap(); const AFX_EVENTSINKMAP_ENTRY* pEntry; size_t flag = (pEvent->m_eventKind != AFX_EVENT::event); while (pSinkMap != NULL) { // find matching AFX_EVENTSINKMAP_ENTRY pEntry = pSinkMap->lpEntries; while (pEntry->dispEntry.nPropOffset != -1) { if ((pEntry->dispEntry.lDispID == pEvent->m_dispid) && (pEntry->dispEntry.nPropOffset == flag)) { if (pEntry->nCtrlIDLast == (UINT)-1) { // check for wildcard match or exact match if ((pEntry->nCtrlIDFirst == (UINT)-1) || (pEntry->nCtrlIDFirst == idCtrl)) return pEntry; } else { // check for range match if ((pEntry->nCtrlIDFirst <= idCtrl) && (idCtrl <= pEntry->nCtrlIDLast)) return pEntry; } } ++pEntry; } // check base class #ifdef _AFXDLL pSinkMap = (*pSinkMap->pfnGetBaseMap)(); #else pSinkMap = pSinkMap->pBaseMap; #endif } return NULL; // no matching entry }