home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / occevent.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  6KB  |  234 lines

  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.  
  11. #include "stdafx.h"
  12. #include "occimpl.h"
  13.  
  14. #ifdef AFX_OCC_SEG
  15. #pragma code_seg(AFX_OCC_SEG)
  16. #endif
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. #define new DEBUG_NEW
  24.  
  25. /////////////////////////////////////////////////////////////////////////////
  26. // OLE event sink handler
  27.  
  28. typedef BOOL (AFX_MSG_CALL CCmdTarget::*PFN_CHANGED)();
  29. typedef BOOL (AFX_MSG_CALL CCmdTarget::*PFN_REQUEST)(BOOL*);
  30. typedef BOOL (AFX_MSG_CALL CCmdTarget::*PFN_DSCNOTIFY)(DSCSTATE, DSCREASON, BOOL*);
  31. typedef BOOL (AFX_MSG_CALL CCmdTarget::*PFN_CHANGED_RANGE)(UINT);
  32. typedef BOOL (AFX_MSG_CALL CCmdTarget::*PFN_REQUEST_RANGE)(UINT, BOOL*);
  33. typedef BOOL (AFX_MSG_CALL CCmdTarget::*PFN_DSCNOTIFY_RANGE)(UINT, DSCSTATE, DSCREASON, BOOL*);
  34.  
  35. BOOL CCmdTarget::OnEvent(UINT idCtrl, AFX_EVENT* pEvent,
  36.     AFX_CMDHANDLERINFO* pHandlerInfo)
  37. {
  38.     HRESULT hResult = S_OK;
  39.     UINT uArgError = (UINT)-1;    // no error yet
  40.     const AFX_EVENTSINKMAP_ENTRY* pEntry = GetEventSinkEntry(idCtrl, pEvent);
  41.  
  42.     // no handler for this event
  43.     if (pEntry == NULL)
  44.         return FALSE;
  45.  
  46.     if (pHandlerInfo != NULL)
  47.     {
  48.         // just fill in the information, don't do it
  49.         pHandlerInfo->pTarget = this;
  50.         switch (pEvent->m_eventKind)
  51.         {
  52.         case AFX_EVENT::event:
  53.         case AFX_EVENT::propRequest:
  54.             pHandlerInfo->pmf = pEntry->dispEntry.pfn;
  55.             break;
  56.  
  57.         case AFX_EVENT::propChanged:
  58.             pHandlerInfo->pmf = pEntry->dispEntry.pfnSet;
  59.             break;
  60.  
  61.         default:
  62.             ASSERT(FALSE);  // bogus value for pEvent->m_eventKind
  63.         }
  64.  
  65.         return (pHandlerInfo->pmf != NULL);
  66.     }
  67.  
  68.     BOOL bRange = (pEntry->nCtrlIDLast != (UINT)-1);
  69.     BOOL bHandled = FALSE;
  70.  
  71.     TRY
  72.     {
  73.         switch (pEvent->m_eventKind)
  74.         {
  75.         case AFX_EVENT::event:
  76.             // do standard method call
  77.             VARIANT var;
  78.             AfxVariantInit(&var);
  79.  
  80.             DISPPARAMS dispparams;
  81.             dispparams.rgvarg = NULL;
  82.  
  83.             if (bRange)
  84.             {
  85.                 memcpy(&dispparams, pEvent->m_pDispParams, sizeof(DISPPARAMS));
  86.                 dispparams.rgvarg = new VARIANT[++dispparams.cArgs];
  87.                 memcpy(dispparams.rgvarg, pEvent->m_pDispParams->rgvarg,
  88.                     sizeof(VARIANT) * (dispparams.cArgs-1));
  89.                 VARIANT* pvarID = &dispparams.rgvarg[dispparams.cArgs-1];
  90.                 V_VT(pvarID) = VT_I4;
  91.                 V_I4(pvarID) = idCtrl;
  92.             }
  93.  
  94.             hResult = CallMemberFunc(&pEntry->dispEntry, DISPATCH_METHOD, &var,
  95.                 (bRange ? &dispparams : pEvent->m_pDispParams), &uArgError);
  96.             ASSERT(FAILED(hResult) || (V_VT(&var) == VT_BOOL));
  97.             bHandled = V_BOOL(&var);
  98.  
  99.             if (bRange)
  100.                 delete [] dispparams.rgvarg;
  101.  
  102.             break;
  103.  
  104.         case AFX_EVENT::propChanged:
  105.             {
  106.                 if (bRange)
  107.                 {
  108.                     PFN_CHANGED_RANGE pfn = (PFN_CHANGED_RANGE)pEntry->dispEntry.pfnSet;
  109.                     bHandled = (this->*pfn)(idCtrl);
  110.                 }
  111.                 else
  112.                 {
  113.                     PFN_CHANGED pfn = (PFN_CHANGED)pEntry->dispEntry.pfnSet;
  114.                     bHandled = (this->*pfn)();
  115.                 }
  116.  
  117.                 hResult = S_OK;
  118.             }
  119.             break;
  120.  
  121.         case AFX_EVENT::propRequest:
  122.             {
  123.                 BOOL bAllow = TRUE;
  124.  
  125.                 if (bRange)
  126.                 {
  127.                     PFN_REQUEST_RANGE pfn = (PFN_REQUEST_RANGE)pEntry->dispEntry.pfn;
  128.                     bHandled = (this->*pfn)(idCtrl, &bAllow);
  129.                 }
  130.                 else
  131.                 {
  132.                     PFN_REQUEST pfn = (PFN_REQUEST)pEntry->dispEntry.pfn;
  133.                     bHandled = (this->*pfn)(&bAllow);
  134.                 }
  135.  
  136.                 hResult = bAllow ? S_OK : S_FALSE;
  137.             }
  138.             break;
  139.  
  140.         case AFX_EVENT::propDSCNotify:
  141.             {
  142.                 BOOL bAllow = TRUE;
  143.  
  144.                 if (bRange)
  145.                 {
  146.                     PFN_DSCNOTIFY_RANGE pfn = (PFN_DSCNOTIFY_RANGE)pEntry->dispEntry.pfn;
  147.                     bHandled = (this->*pfn)(idCtrl, pEvent->m_nDSCState,
  148.                         pEvent->m_nDSCReason, &bAllow);
  149.                 }
  150.                 else
  151.                 {
  152.                     PFN_DSCNOTIFY pfn = (PFN_DSCNOTIFY)pEntry->dispEntry.pfn;
  153.                     bHandled = (this->*pfn)(pEvent->m_nDSCState,
  154.                         pEvent->m_nDSCReason, &bAllow);
  155.                 }
  156.  
  157.                 hResult = bAllow ? S_OK : S_FALSE;
  158.             }
  159.             break;
  160.  
  161.         default:
  162.             ASSERT(FALSE);  // bogus value for pEvent->m_eventKind
  163.         }
  164.     }
  165.     CATCH_ALL(e)
  166.     {
  167.         if (pEvent->m_pExcepInfo != NULL)
  168.         {
  169.             // fill exception with translation of MFC exception
  170.             COleDispatchException::Process(pEvent->m_pExcepInfo, e);
  171.         }
  172.         DELETE_EXCEPTION(e);
  173.         hResult = DISP_E_EXCEPTION;
  174.     }
  175.     END_CATCH_ALL
  176.  
  177.     // fill error argument if one is available
  178.     if (FAILED(hResult) && pEvent->m_puArgError != NULL && uArgError != -1)
  179.         *pEvent->m_puArgError = uArgError;
  180.  
  181.     // fill result code
  182.     pEvent->m_hResult = hResult;
  183.  
  184.     return bHandled;
  185. }
  186.  
  187. /////////////////////////////////////////////////////////////////////////////
  188. // Locate event sink map entry
  189.  
  190. const AFX_EVENTSINKMAP_ENTRY* PASCAL CCmdTarget::GetEventSinkEntry(
  191.     UINT idCtrl, AFX_EVENT* pEvent)
  192. {
  193.     const AFX_EVENTSINKMAP* pSinkMap = GetEventSinkMap();
  194.     const AFX_EVENTSINKMAP_ENTRY* pEntry;
  195.     size_t flag = (pEvent->m_eventKind != AFX_EVENT::event);
  196.  
  197.     while (pSinkMap != NULL)
  198.     {
  199.         // find matching AFX_EVENTSINKMAP_ENTRY
  200.         pEntry = pSinkMap->lpEntries;
  201.         while (pEntry->dispEntry.nPropOffset != -1)
  202.         {
  203.             if ((pEntry->dispEntry.lDispID == pEvent->m_dispid) &&
  204.                 (pEntry->dispEntry.nPropOffset == flag))
  205.             {
  206.                 if (pEntry->nCtrlIDLast == (UINT)-1)
  207.                 {
  208.                     // check for wildcard match or exact match
  209.                     if ((pEntry->nCtrlIDFirst == (UINT)-1) ||
  210.                         (pEntry->nCtrlIDFirst == idCtrl))
  211.                         return pEntry;
  212.                 }
  213.                 else
  214.                 {
  215.                     // check for range match
  216.                     if ((pEntry->nCtrlIDFirst <= idCtrl) &&
  217.                         (idCtrl <= pEntry->nCtrlIDLast))
  218.                         return pEntry;
  219.                 }
  220.             }
  221.  
  222.             ++pEntry;
  223.         }
  224.         // check base class
  225. #ifdef _AFXDLL
  226.         pSinkMap = (*pSinkMap->pfnGetBaseMap)();
  227. #else
  228.         pSinkMap = pSinkMap->pBaseMap;
  229. #endif
  230.     }
  231.  
  232.     return NULL;    // no matching entry
  233. }
  234.