home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / oledisp1.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  45KB  |  1,593 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 "dispimpl.h"
  13.  
  14. #ifdef AFX_OLE5_SEG
  15. #pragma code_seg(AFX_OLE5_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. // Helpers and main implementation for CCmdTarget::IDispatch
  27.  
  28. void CCmdTarget::GetStandardProp(const AFX_DISPMAP_ENTRY* pEntry,
  29.     VARIANT* pvarResult, UINT* puArgErr)
  30. {
  31.     ASSERT(pEntry != NULL);
  32.     ASSERT(*puArgErr != 0);
  33.  
  34.     // it is a DISPATCH_PROPERTYGET (for standard, non-function property)
  35.     void* pProp = (BYTE*)this + pEntry->nPropOffset;
  36.     if (pEntry->vt != VT_VARIANT)
  37.         pvarResult->vt = pEntry->vt;
  38.     switch (pEntry->vt)
  39.     {
  40.     case VT_I1:
  41.         pvarResult->bVal = *(BYTE*)pProp;
  42.         break;
  43.     case VT_I2:
  44.         pvarResult->iVal = *(short*)pProp;
  45.         break;
  46.     case VT_I4:
  47.         pvarResult->lVal = *(long*)pProp;
  48.         break;
  49.     case VT_R4:
  50.         pvarResult->fltVal = *(float*)pProp;
  51.         break;
  52.     case VT_R8:
  53.         pvarResult->dblVal = *(double*)pProp;
  54.         break;
  55.     case VT_DATE:
  56.         pvarResult->date = *(double*)pProp;
  57.         break;
  58.     case VT_CY:
  59.         pvarResult->cyVal = *(CY*)pProp;
  60.         break;
  61.     case VT_BSTR:
  62.         {
  63.             CString* pString = (CString*)pProp;
  64.             pvarResult->bstrVal = pString->AllocSysString();
  65.         }
  66.         break;
  67.     case VT_ERROR:
  68.         pvarResult->scode = *(SCODE*)pProp;
  69.         break;
  70.     case VT_BOOL:
  71.         V_BOOL(pvarResult) = (VARIANT_BOOL)(*(BOOL*)pProp != 0 ? -1 : 0);
  72.         break;
  73.     case VT_VARIANT:
  74.         if (VariantCopy(pvarResult, (LPVARIANT)pProp) != S_OK)
  75.             *puArgErr = 0;
  76.         break;
  77.     case VT_DISPATCH:
  78.     case VT_UNKNOWN:
  79.         pvarResult->punkVal = *(LPDISPATCH*)pProp;
  80.         if (pvarResult->punkVal != NULL)
  81.             pvarResult->punkVal->AddRef();
  82.         break;
  83.  
  84.     default:
  85.         *puArgErr = 0;
  86.     }
  87. }
  88.  
  89. SCODE CCmdTarget::SetStandardProp(const AFX_DISPMAP_ENTRY* pEntry,
  90.     DISPPARAMS* pDispParams, UINT* puArgErr)
  91. {
  92.     ASSERT(pEntry != NULL);
  93.     ASSERT(*puArgErr != 0);
  94.  
  95.     // it is a DISPATCH_PROPERTYSET (for standard, non-function property)
  96.     SCODE sc = S_OK;
  97.     VARIANT va;
  98.     AfxVariantInit(&va);
  99.     VARIANT* pArg = &pDispParams->rgvarg[0];
  100.     if (pEntry->vt != VT_VARIANT && pArg->vt != pEntry->vt)
  101.     {
  102.         // argument is not of appropriate type, attempt to coerce it
  103.         sc = VariantChangeType(&va, pArg, 0, pEntry->vt);
  104.         if (FAILED(sc))
  105.         {
  106.             TRACE0("Warning: automation property coercion failed.\n");
  107.             *puArgErr = 0;
  108.             return sc;
  109.         }
  110.         ASSERT(va.vt == pEntry->vt);
  111.         pArg = &va;
  112.     }
  113.  
  114.     void* pProp = (BYTE*)this + pEntry->nPropOffset;
  115.     switch (pEntry->vt)
  116.     {
  117.     case VT_I1:
  118.         *(BYTE*)pProp = pArg->bVal;
  119.         break;
  120.     case VT_I2:
  121.         *(short*)pProp = pArg->iVal;
  122.         break;
  123.     case VT_I4:
  124.         *(long*)pProp = pArg->lVal;
  125.         break;
  126.     case VT_R4:
  127.         *(float*)pProp = pArg->fltVal;
  128.         break;
  129.     case VT_R8:
  130.         *(double*)pProp = pArg->dblVal;
  131.         break;
  132.     case VT_DATE:
  133.         *(double*)pProp = pArg->date;
  134.         break;
  135.     case VT_CY:
  136.         *(CY*)pProp = pArg->cyVal;
  137.         break;
  138.     case VT_BSTR:
  139.         AfxBSTR2CString((CString*)pProp, pArg->bstrVal);
  140.         break;
  141.     case VT_ERROR:
  142.         *(SCODE*)pProp = pArg->scode;
  143.         break;
  144.     case VT_BOOL:
  145.         *(BOOL*)pProp = (V_BOOL(pArg) != 0);
  146.         break;
  147.     case VT_VARIANT:
  148.         if (VariantCopy((LPVARIANT)pProp, pArg) != S_OK)
  149.             *puArgErr = 0;
  150.         break;
  151.     case VT_DISPATCH:
  152.     case VT_UNKNOWN:
  153.         if (pArg->punkVal != NULL)
  154.             pArg->punkVal->AddRef();
  155.         _AfxRelease((LPUNKNOWN*)pProp);
  156.         *(LPUNKNOWN*)pProp = pArg->punkVal;
  157.         break;
  158.  
  159.     default:
  160.         *puArgErr = 0;
  161.         sc = DISP_E_BADVARTYPE;
  162.     }
  163.     VariantClear(&va);
  164.  
  165.     // if property was a DISP_PROPERTY_NOTIFY type, call pfnSet after setting
  166.     if (!FAILED(sc) && pEntry->pfnSet != NULL)
  167.     {
  168.         AFX_MANAGE_STATE(m_pModuleState);
  169.         (this->*pEntry->pfnSet)();
  170.     }
  171.  
  172.     return sc;
  173. }
  174.  
  175. UINT PASCAL CCmdTarget::GetEntryCount(const AFX_DISPMAP* pDispMap)
  176. {
  177.     ASSERT(pDispMap->lpEntryCount != NULL);
  178.  
  179.     // compute entry count cache if not available
  180.     if (*pDispMap->lpEntryCount == -1)
  181.     {
  182.         // count them
  183.         const AFX_DISPMAP_ENTRY* pEntry = pDispMap->lpEntries;
  184.         while (pEntry->nPropOffset != -1)
  185.             ++pEntry;
  186.  
  187.         // store it
  188.         *pDispMap->lpEntryCount = pEntry - pDispMap->lpEntries;
  189.     }
  190.  
  191.     ASSERT(*pDispMap->lpEntryCount != -1);
  192.     return *pDispMap->lpEntryCount;
  193. }
  194.  
  195. MEMBERID PASCAL CCmdTarget::MemberIDFromName(
  196.     const AFX_DISPMAP* pDispMap, LPCTSTR lpszName)
  197. {
  198.     // search all maps and their base maps
  199.     UINT nInherit = 0;
  200.     while (pDispMap != NULL)
  201.     {
  202.         // search all entries in this map
  203.         const AFX_DISPMAP_ENTRY* pEntry = pDispMap->lpEntries;
  204.         UINT nEntryCount = GetEntryCount(pDispMap);
  205.         for (UINT nIndex = 0; nIndex < nEntryCount; nIndex++)
  206.         {
  207.             if (pEntry->vt != VT_MFCVALUE &&
  208.                 lstrcmpi(pEntry->lpszName, lpszName) == 0)
  209.             {
  210.                 if (pEntry->lDispID == DISPID_UNKNOWN)
  211.                 {
  212.                     // the MEMBERID is combination of nIndex & nInherit
  213.                     ASSERT(MAKELONG(nIndex+1, nInherit) != DISPID_UNKNOWN);
  214.                     return MAKELONG(nIndex+1, nInherit);
  215.                 }
  216.                 // the MEMBERID is specified as the lDispID
  217.                 return pEntry->lDispID;
  218.             }
  219.             ++pEntry;
  220.         }
  221. #ifdef _AFXDLL
  222.         pDispMap = (*pDispMap->pfnGetBaseMap)();
  223. #else
  224.         pDispMap = pDispMap->pBaseMap;
  225. #endif
  226.         ++nInherit;
  227.     }
  228.     return DISPID_UNKNOWN;  // name not found
  229. }
  230.  
  231. const AFX_DISPMAP_ENTRY* PASCAL CCmdTarget::GetDispEntry(MEMBERID memid)
  232. {
  233.     const AFX_DISPMAP* pDerivMap = GetDispatchMap();
  234.     const AFX_DISPMAP* pDispMap;
  235.     const AFX_DISPMAP_ENTRY* pEntry;
  236.  
  237.     if (memid == DISPID_VALUE)
  238.     {
  239.         // DISPID_VALUE is a special alias (look for special alias entry)
  240.         pDispMap = pDerivMap;
  241.         while (pDispMap != NULL)
  242.         {
  243.             // search for special entry with vt == VT_MFCVALUE
  244.             pEntry = pDispMap->lpEntries;
  245.             while (pEntry->nPropOffset != -1)
  246.             {
  247.                 if (pEntry->vt == VT_MFCVALUE)
  248.                 {
  249.                     memid = pEntry->lDispID;
  250.                     if (memid == DISPID_UNKNOWN)
  251.                     {
  252.                         // attempt to map alias name to member ID
  253.                         memid = MemberIDFromName(pDerivMap, pEntry->lpszName);
  254.                         if (memid == DISPID_UNKNOWN)
  255.                             return NULL;
  256.                     }
  257.                     // break out and map the member ID to an entry
  258.                     goto LookupDispID;
  259.                 }
  260.                 ++pEntry;
  261.             }
  262. #ifdef _AFXDLL
  263.             pDispMap = (*pDispMap->pfnGetBaseMap)();
  264. #else
  265.             pDispMap = pDispMap->pBaseMap;
  266. #endif
  267.         }
  268.     }
  269.  
  270. LookupDispID:
  271.     if ((long)memid > 0)
  272.     {
  273.         // find AFX_DISPMAP corresponding to HIWORD(memid)
  274.         UINT nTest = 0;
  275.         pDispMap = pDerivMap;
  276.         while (pDispMap != NULL && nTest < (UINT)HIWORD(memid))
  277.         {
  278. #ifdef _AFXDLL
  279.             pDispMap = (*pDispMap->pfnGetBaseMap)();
  280. #else
  281.             pDispMap = pDispMap->pBaseMap;
  282. #endif
  283.             ++nTest;
  284.         }
  285.         if (pDispMap != NULL)
  286.         {
  287.             UINT nEntryCount = GetEntryCount(pDispMap);
  288.             if ((UINT)LOWORD(memid) <= nEntryCount)
  289.             {
  290.                 pEntry = pDispMap->lpEntries + LOWORD(memid)-1;
  291.  
  292.                 // must have automatic DISPID or same ID
  293.                 // if not then look manually
  294.                 if (pEntry->lDispID == DISPID_UNKNOWN ||
  295.                     pEntry->lDispID == memid)
  296.                 {
  297.                     return pEntry;
  298.                 }
  299.             }
  300.         }
  301.     }
  302.  
  303.     // second pass, look for DISP_XXX_ID entries
  304.     pDispMap = pDerivMap;
  305.     while (pDispMap != NULL)
  306.     {
  307.         // find AFX_DISPMAP_ENTRY where (pEntry->lDispID == memid)
  308.         pEntry = pDispMap->lpEntries;
  309.         while (pEntry->nPropOffset != -1)
  310.         {
  311.             if (pEntry->lDispID == memid)
  312.                 return pEntry;
  313.  
  314.             ++pEntry;
  315.         }
  316.         // check base class
  317. #ifdef _AFXDLL
  318.         pDispMap = (*pDispMap->pfnGetBaseMap)();
  319. #else
  320.         pDispMap = pDispMap->pBaseMap;
  321. #endif
  322.     }
  323.  
  324.     return NULL;    // no matching entry
  325. }
  326.  
  327. /////////////////////////////////////////////////////////////////////////////
  328. // Standard automation methods
  329.  
  330. void CCmdTarget::GetNotSupported()
  331. {
  332.     AfxThrowOleDispatchException(
  333.         AFX_IDP_GET_NOT_SUPPORTED, AFX_IDP_GET_NOT_SUPPORTED);
  334. }
  335.  
  336. void CCmdTarget::SetNotSupported()
  337. {
  338.     AfxThrowOleDispatchException(
  339.         AFX_IDP_SET_NOT_SUPPORTED, AFX_IDP_SET_NOT_SUPPORTED);
  340. }
  341.  
  342. /////////////////////////////////////////////////////////////////////////////
  343. // Wiring to CCmdTarget
  344.  
  345. // enable this object for OLE automation, called from derived class ctor
  346. void CCmdTarget::EnableAutomation()
  347. {
  348.     ASSERT(GetDispatchMap() != NULL);   // must have DECLARE_DISPATCH_MAP
  349.  
  350.     // construct an COleDispatchImpl instance just to get to the vtable
  351.     COleDispatchImpl dispatch;
  352.  
  353.     // vtable pointer should be already set to same or NULL
  354.     ASSERT(m_xDispatch.m_vtbl == NULL||
  355.         *(DWORD*)&dispatch == m_xDispatch.m_vtbl);
  356.     // sizeof(COleDispatchImpl) should be just a DWORD (vtable pointer)
  357.     ASSERT(sizeof(m_xDispatch) == sizeof(COleDispatchImpl));
  358.  
  359.     // copy the vtable (and other data) to make sure it is initialized
  360.     m_xDispatch.m_vtbl = *(DWORD*)&dispatch;
  361.     *(COleDispatchImpl*)&m_xDispatch = dispatch;
  362. }
  363.  
  364. // return addref'd IDispatch part of CCmdTarget object
  365. LPDISPATCH CCmdTarget::GetIDispatch(BOOL bAddRef)
  366. {
  367.     ASSERT_VALID(this);
  368.     ASSERT(m_xDispatch.m_vtbl != 0);    // forgot to call EnableAutomation?
  369.  
  370.     // AddRef the object if requested
  371.     if (bAddRef)
  372.         ExternalAddRef();
  373.  
  374.     // return pointer to IDispatch implementation
  375.     return (LPDISPATCH)GetInterface(&IID_IDispatch);
  376. }
  377.  
  378. // retrieve CCmdTarget* from IDispatch* (return NULL if not MFC IDispatch)
  379. CCmdTarget* PASCAL CCmdTarget::FromIDispatch(LPDISPATCH lpDispatch)
  380. {
  381.     // construct an COleDispatchImpl instance just to get to the vtable
  382.     COleDispatchImpl dispatch;
  383.  
  384.     ASSERT(*(DWORD*)&dispatch != 0);    // null vtable ptr?
  385.     if (*(DWORD*)lpDispatch != *(DWORD*)&dispatch)
  386.         return NULL;    // not our IDispatch*
  387.  
  388.     // vtable ptrs match, so must have originally been retrieved with
  389.     //  CCmdTarget::GetIDispatch.
  390. #ifndef _AFX_NO_NESTED_DERIVATION
  391.     CCmdTarget* pTarget = (CCmdTarget*)
  392.         ((BYTE*)lpDispatch - ((COleDispatchImpl*)lpDispatch)->m_nOffset);
  393. #else
  394.     CCmdTarget* pTarget = (CCmdTarget*)
  395.         ((BYTE*)lpDispatch - offsetof(CCmdTarget, m_xDispatch));
  396. #endif
  397.     ASSERT_VALID(pTarget);
  398.     return pTarget;
  399. }
  400.  
  401. BOOL CCmdTarget::IsResultExpected()
  402. {
  403.     BOOL bResultExpected = m_bResultExpected;
  404.     m_bResultExpected = TRUE;   // can only ask once
  405.     return bResultExpected;
  406. }
  407.  
  408. void COleDispatchImpl::Disconnect()
  409. {
  410.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  411.  
  412.     pThis->ExternalDisconnect();    // always disconnect the object
  413. }
  414.  
  415. ///////////////////////////////////////////////////////////////////////////////
  416. // OLE BSTR support
  417.  
  418. BSTR CString::AllocSysString() const
  419. {
  420. #if defined(_UNICODE) || defined(OLE2ANSI)
  421.     BSTR bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLength);
  422.     if (bstr == NULL)
  423.         AfxThrowMemoryException();
  424. #else
  425.     int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
  426.         GetData()->nDataLength, NULL, NULL);
  427.     BSTR bstr = ::SysAllocStringLen(NULL, nLen);
  428.     if (bstr == NULL)
  429.         AfxThrowMemoryException();
  430.     MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength,
  431.         bstr, nLen);
  432. #endif
  433.  
  434.     return bstr;
  435. }
  436.  
  437. BSTR CString::SetSysString(BSTR* pbstr) const
  438. {
  439.     ASSERT(AfxIsValidAddress(pbstr, sizeof(BSTR)));
  440.  
  441. #if defined(_UNICODE) || defined(OLE2ANSI)
  442.     if (!::SysReAllocStringLen(pbstr, m_pchData, GetData()->nDataLength))
  443.         AfxThrowMemoryException();
  444. #else
  445.     int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
  446.         GetData()->nDataLength, NULL, NULL);
  447.     if (!::SysReAllocStringLen(pbstr, NULL, nLen))
  448.         AfxThrowMemoryException();
  449.     MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength,
  450.         *pbstr, nLen);
  451. #endif
  452.  
  453.     ASSERT(*pbstr != NULL);
  454.     return *pbstr;
  455. }
  456.  
  457. /////////////////////////////////////////////////////////////////////////////
  458. // Specifics of METHOD->C++ member function invocation
  459.  
  460. // Note: Although this code is written in C++, it is very dependent on the
  461. //  specific compiler and target platform.  The current code below assumes
  462. //  that the stack grows down, and that arguments are pushed last to first.
  463.  
  464. // calculate size of pushed arguments + retval reference
  465.  
  466. // size of arguments on stack when pushed by value
  467. AFX_STATIC_DATA const UINT _afxByValue[] =
  468. {
  469.     0,                          // VTS_EMPTY
  470.     0,                          // VTS_NULL
  471.     sizeof(_STACK_INT),         // VTS_I2
  472.     sizeof(_STACK_LONG),        // VTS_I4
  473.     sizeof(_STACK_FLOAT),       // VTS_R4
  474.     sizeof(_STACK_DOUBLE),      // VTS_R8
  475.     sizeof(CY),                 // VTS_CY
  476.     sizeof(DATE),               // VTS_DATE
  477.     sizeof(LPCOLESTR),          // VTS_WBSTR (VT_BSTR)
  478.     sizeof(LPDISPATCH),         // VTS_DISPATCH
  479.     sizeof(SCODE),              // VTS_SCODE
  480.     sizeof(BOOL),               // VTS_BOOL
  481.     sizeof(const VARIANT*),     // VTS_VARIANT
  482.     sizeof(LPUNKNOWN),           // VTS_UNKNOWN
  483. #if !defined(_UNICODE) && !defined(OLE2ANSI)
  484.     sizeof(LPCSTR),             // VTS_BSTR (VT_BSTRA -- MFC defined)
  485. #endif
  486. };
  487.  
  488. // size of arguments on stack when pushed by reference
  489. AFX_STATIC_DATA const UINT _afxByRef[] =
  490. {
  491.     0,                          // VTS_PEMPTY
  492.     0,                          // VTS_PNULL
  493.     sizeof(short*),             // VTS_PI2
  494.     sizeof(long*),              // VTS_PI4
  495.     sizeof(float*),             // VTS_PR4
  496.     sizeof(double*),            // VTS_PR8
  497.     sizeof(CY*),                // VTS_PCY
  498.     sizeof(DATE*),              // VTS_PDATE
  499.     sizeof(BSTR*),              // VTS_PBSTR
  500.     sizeof(LPDISPATCH*),        // VTS_PDISPATCH
  501.     sizeof(SCODE*),             // VTS_PSCODE
  502.     sizeof(VARIANT_BOOL*),      // VTS_PBOOL
  503.     sizeof(VARIANT*),           // VTS_PVARIANT
  504.     sizeof(LPUNKNOWN*),         // VTS_PUNKNOWN
  505.     sizeof(BYTE*),              // VTS_PUI1
  506. };
  507.  
  508. AFX_STATIC_DATA const UINT _afxRetVal[] =
  509. {
  510.     0,                          // VT_EMPTY
  511.     0,                          // VT_NULL
  512.     0,                          // VT_I2
  513.     0,                          // VT_I4
  514.     0,                          // VT_R4
  515.     0,                          // VT_R8
  516.     sizeof(CY*),                // VT_CY
  517.     0,                          // VT_DATE (same as VT_R8)
  518.     0,                          // VT_BSTR
  519.     0,                          // VT_DISPATCH
  520.     0,                          // VT_ERROR
  521.     0,                          // VT_BOOL
  522.     sizeof(VARIANT*),           // VT_VARIANT
  523.     0,                          // VT_UNKNOWN
  524.     0,                          // VT_UI1
  525. };
  526.  
  527. UINT PASCAL CCmdTarget::GetStackSize(const BYTE* pbParams, VARTYPE vtResult)
  528. {
  529.     // sizeof 'this' pointer
  530.     UINT nCount = sizeof(CCmdTarget*);
  531. #ifdef _ALIGN_STACK
  532.     nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
  533. #endif
  534.  
  535.     // count bytes in return value
  536.     ASSERT((UINT)vtResult < _countof(_afxRetVal));
  537.     nCount += _afxRetVal[vtResult];
  538. #ifdef _ALIGN_STACK
  539.     nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
  540. #endif
  541.  
  542.     // count arguments
  543.     ASSERT(pbParams != NULL);
  544.     while (*pbParams != 0)
  545.     {
  546.         if (*pbParams != VT_MFCMARKER)
  547.         {
  548.             // align if necessary
  549.             // get and add appropriate byte count
  550.             const UINT* rgnBytes;
  551.             if (*pbParams & VT_MFCBYREF)
  552.                 rgnBytes = _afxByRef;
  553.             else
  554.                 rgnBytes = _afxByValue;
  555.             ASSERT((*pbParams & ~VT_MFCBYREF) < _countof(_afxByValue));
  556. #ifdef _ALIGN_DOUBLES
  557.             // align doubles on 8 byte for some platforms
  558.             if (*pbParams == VT_R8)
  559.                 nCount = (nCount + _ALIGN_DOUBLES-1) & ~(_ALIGN_DOUBLES-1);
  560. #endif
  561.             nCount += rgnBytes[*pbParams & ~VT_MFCBYREF];
  562. #ifdef _ALIGN_STACK
  563.             nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
  564. #endif
  565.         }
  566.         ++pbParams;
  567.     }
  568. #if defined(_ALIGN_DOUBLES) && defined(_SHADOW_DOUBLES)
  569.     // align doubles on 8 byte for some platforms
  570.     nCount = (nCount + _ALIGN_DOUBLES-1) & ~(_ALIGN_DOUBLES-1);
  571. #endif
  572.     return nCount;
  573. }
  574.  
  575. // push arguments on stack appropriate for C++ call (compiler dependent)
  576. #ifndef _SHADOW_DOUBLES
  577. SCODE CCmdTarget::PushStackArgs(BYTE* pStack, const BYTE* pbParams,
  578.     void* pResult, VARTYPE vtResult, DISPPARAMS* pDispParams, UINT* puArgErr,
  579.     VARIANT* rgTempVars)
  580. #else
  581. SCODE CCmdTarget::PushStackArgs(BYTE* pStack, const BYTE* pbParams,
  582.     void* pResult, VARTYPE vtResult, DISPPARAMS* pDispParams, UINT* puArgErr,
  583.     VARIANT* rgTempVars, UINT nSizeArgs)
  584. #endif
  585. {
  586.     ASSERT(pStack != NULL);
  587.     ASSERT(pResult != NULL);
  588.     ASSERT(pDispParams != NULL);
  589.     ASSERT(puArgErr != NULL);
  590.  
  591. #ifdef _SHADOW_DOUBLES
  592.     double* pDoubleShadow = (double*)(pStack + nSizeArgs);
  593.     double* pDoubleShadowMax = pDoubleShadow + _SHADOW_DOUBLES;
  594. #endif
  595.  
  596.     // C++ member functions use the __thiscall convention, where parameters
  597.     //  are pushed last to first.  Assuming the stack grows down, this means
  598.     //  that the first parameter is at the lowest memory address in the
  599.     //  stack frame and the last parameter is at the highest address.
  600.  
  601.  
  602. #ifdef _RETVAL_FIRST
  603.     // push any necessary return value stuff on the stack (pre args)
  604.     //  (an ambient pointer is pushed to stack relative data)
  605.     if (vtResult == VT_CY || vtResult == VT_VARIANT)
  606.     {
  607. #ifdef _ALIGN_STACK
  608.         ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  609. #endif
  610.         *(_STACK_PTR*)pStack = (_STACK_PTR)pResult;
  611.         pStack += sizeof(_STACK_PTR);
  612. #ifdef _ALIGN_STACK
  613.         ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  614. #endif
  615.     }
  616. #endif //_RETVAL_FIRST
  617.  
  618.     // push the 'this' pointer
  619. #ifdef _ALIGN_STACK
  620.     ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  621. #endif
  622.     *(_STACK_PTR*)pStack = (_STACK_PTR)this;
  623.     pStack += sizeof(_STACK_PTR);
  624. #ifdef _ALIGN_STACK
  625.     ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  626. #endif
  627.  
  628. #ifndef _RETVAL_FIRST
  629.     // push any necessary return value stuff on the stack (post args)
  630.     //  (an ambient pointer is pushed to stack relative data)
  631.     if (vtResult == VT_CY || vtResult == VT_VARIANT)
  632.     {
  633. #ifdef _ALIGN_STACK
  634.         ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  635. #endif
  636.         *(_STACK_PTR*)pStack = (_STACK_PTR)pResult;
  637.         pStack += sizeof(_STACK_PTR);
  638. #ifdef _ALIGN_STACK
  639.         ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  640. #endif
  641.     }
  642. #endif //!_RETVAL_FIRST
  643.  
  644.     // push the arguments (first to last, low address to high address)
  645.     VARIANT* pArgs = pDispParams->rgvarg;
  646.     BOOL bNamedArgs = FALSE;
  647.     int iArg = pDispParams->cArgs; // start with positional arguments
  648.     int iArgMin = pDispParams->cNamedArgs;
  649.  
  650.     ASSERT(pbParams != NULL);
  651.     for (const BYTE* pb = pbParams; *pb != '\0'; ++pb)
  652.     {
  653.         --iArg; // move to next arg
  654.  
  655.         // convert MFC parameter type to IDispatch VARTYPE
  656.         VARTYPE vt = *pb;
  657.         if (vt != VT_MFCMARKER && (vt & VT_MFCBYREF))
  658.             vt = (VARTYPE)((vt & ~VT_MFCBYREF) | VT_BYREF);
  659.  
  660.         VARIANT* pArg;
  661.         if (iArg >= iArgMin)
  662.         {
  663.             // hit named args before using all positional args?
  664.             if (vt == VT_MFCMARKER)
  665.                 break;
  666.  
  667.             // argument specified by caller -- use it
  668.             pArg = &pArgs[iArg];
  669.             if (vt != VT_VARIANT && vt != pArg->vt)
  670.             {
  671.                 // argument is not of appropriate type, attempt to coerce it
  672.                 VARIANT* pArgTemp = &rgTempVars[iArg];
  673.                 ASSERT(pArgTemp->vt == VT_EMPTY);
  674. #if defined(_UNICODE) || defined(OLE2ANSI)
  675.                 VARTYPE vtTarget = vt;
  676. #else
  677.                 VARTYPE vtTarget = (VARTYPE) ((vt == VT_BSTRA) ? VT_BSTR : vt);
  678. #endif
  679.                 if (pArg->vt != vtTarget)
  680.                 {
  681.                     SCODE sc = VariantChangeType(pArgTemp, pArg, 0, vtTarget);
  682.                     if (FAILED(sc))
  683.                     {
  684.                         TRACE0("Warning: automation argument coercion failed.\n");
  685.                         *puArgErr = iArg;
  686.                         return sc;
  687.                     }
  688.                     ASSERT(pArgTemp->vt == vtTarget);
  689.                 }
  690.  
  691. #if !defined(_UNICODE) && !defined(OLE2ANSI)
  692.                 if (vt == VT_BSTRA)
  693.                 {
  694.                     if (pArg->vt != vtTarget)
  695.                     {
  696.                         // coerce above created a new string
  697.                         // convert it to ANSI and free it
  698.                         ASSERT(pArgTemp->vt == VT_BSTR);
  699.                         BSTR bstrW = pArgTemp->bstrVal;
  700.                         pArgTemp->bstrVal = AfxBSTR2ABSTR(bstrW);
  701.                         SysFreeString(bstrW);
  702.                     }
  703.                     else
  704.                     {
  705.                         // convert the string to ANSI from original
  706.                         pArgTemp->bstrVal = AfxBSTR2ABSTR(pArg->bstrVal);
  707.                         pArgTemp->vt = VT_BSTR;
  708.                     }
  709.                     vt = VT_BSTR;
  710.                 }
  711. #endif
  712.                 pArg = pArgTemp;
  713.             }
  714.         }
  715.         else
  716.         {
  717.             if (vt == VT_MFCMARKER)
  718.             {
  719.                 // start processing named arguments
  720.                 iArg = pDispParams->cNamedArgs;
  721.                 iArgMin = 0;
  722.                 bNamedArgs = TRUE;
  723.                 continue;
  724.             }
  725.  
  726.             if (bNamedArgs || vt != VT_VARIANT)
  727.                 break;  // function not expecting optional argument
  728.  
  729.             // argument not specified by caller -- provide default variant
  730.             static VARIANT vaDefault;   // Note: really is 'const'
  731.             vaDefault.vt = VT_ERROR;
  732.             vaDefault.scode = DISP_E_PARAMNOTFOUND;
  733.             pArg = &vaDefault;
  734.         }
  735.  
  736.         // push parameter value on the stack
  737.         switch (vt)
  738.         {
  739.         // by value parameters
  740.         case VT_UI1:
  741.             *(_STACK_INT*)pStack = pArg->bVal; // 'BYTE' is passed as 'int'
  742.             pStack += sizeof(_STACK_INT);
  743.             break;
  744.         case VT_I2:
  745.             *(_STACK_INT*)pStack = pArg->iVal;
  746.             pStack += sizeof(_STACK_INT);   // 'short' is passed as 'int'
  747.             break;
  748.         case VT_I4:
  749.             *(_STACK_LONG*)pStack = pArg->lVal;
  750.             pStack += sizeof(_STACK_LONG);
  751.             break;
  752.         case VT_R4:
  753.             *(_STACK_FLOAT*)pStack = (_STACK_FLOAT)pArg->fltVal;
  754.             pStack += sizeof(_STACK_FLOAT);
  755. #ifdef _SHADOW_DOUBLES
  756.             if (pDoubleShadow < pDoubleShadowMax)
  757.                 *pDoubleShadow++ = (double)pArg->fltVal;
  758. #endif
  759.             break;
  760.         case VT_R8:
  761. #ifdef _ALIGN_DOUBLES
  762.             // align doubles on 8 byte for some platforms
  763.             pStack = (BYTE*)(((DWORD)pStack + _ALIGN_DOUBLES-1) &
  764.                 ~(_ALIGN_DOUBLES-1));
  765. #endif
  766.             *(_STACK_DOUBLE*)pStack = (_STACK_DOUBLE)pArg->dblVal;
  767.             pStack += sizeof(_STACK_DOUBLE);
  768. #ifdef _SHADOW_DOUBLES
  769.             if (pDoubleShadow < pDoubleShadowMax)
  770.                 *pDoubleShadow++ = pArg->dblVal;
  771. #endif
  772.             break;
  773.         case VT_DATE:
  774. #ifdef _ALIGN_DOUBLES
  775.             // align doubles on 8 byte for some platforms
  776.             pStack = (BYTE*)(((DWORD)pStack + _ALIGN_DOUBLES-1) &
  777.                 ~(_ALIGN_DOUBLES-1));
  778. #endif
  779.             *(_STACK_DOUBLE*)pStack = (_STACK_DOUBLE)pArg->date;
  780.             pStack += sizeof(_STACK_DOUBLE);
  781. #ifdef _SHADOW_DOUBLES
  782.             if (pDoubleShadow < pDoubleShadowMax)
  783.                 *pDoubleShadow++ = pArg->date;
  784. #endif
  785.             break;
  786.         case VT_CY:
  787.             *(CY*)pStack = pArg->cyVal;
  788.             pStack += sizeof(CY);
  789.             break;
  790.         case VT_BSTR:
  791.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->bstrVal;
  792.             pStack += sizeof(_STACK_PTR);
  793.             break;
  794.         case VT_ERROR:
  795.             *(_STACK_LONG*)pStack = (_STACK_LONG)pArg->scode;
  796.             pStack += sizeof(_STACK_LONG);
  797.             break;
  798.         case VT_BOOL:
  799.             *(_STACK_LONG*)pStack = (_STACK_LONG)(V_BOOL(pArg) != 0);
  800.             pStack += sizeof(_STACK_LONG);
  801.             break;
  802.         case VT_VARIANT:
  803.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg;
  804.             pStack += sizeof(_STACK_PTR);
  805.             break;
  806.         case VT_DISPATCH:
  807.         case VT_UNKNOWN:
  808.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->punkVal;
  809.             pStack += sizeof(_STACK_PTR);
  810.             break;
  811.  
  812.         // by reference parameters
  813.         case VT_UI2|VT_BYREF:
  814.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pbVal;
  815.             pStack += sizeof(_STACK_PTR);
  816.             break;
  817.         case VT_I2|VT_BYREF:
  818.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->piVal;
  819.             pStack += sizeof(_STACK_PTR);
  820.             break;
  821.         case VT_I4|VT_BYREF:
  822.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->plVal;
  823.             pStack += sizeof(_STACK_PTR);
  824.             break;
  825.         case VT_R4|VT_BYREF:
  826.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pfltVal;
  827.             pStack += sizeof(_STACK_PTR);
  828.             break;
  829.         case VT_R8|VT_BYREF:
  830.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pdblVal;
  831.             pStack += sizeof(_STACK_PTR);
  832.             break;
  833.         case VT_DATE|VT_BYREF:
  834.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pdate;
  835.             pStack += sizeof(_STACK_PTR);
  836.             break;
  837.         case VT_CY|VT_BYREF:
  838.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pcyVal;
  839.             pStack += sizeof(_STACK_PTR);
  840.             break;
  841.         case VT_BSTR|VT_BYREF:
  842.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pbstrVal;
  843.             pStack += sizeof(_STACK_PTR);
  844.             break;
  845.         case VT_ERROR|VT_BYREF:
  846.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pscode;
  847.             pStack += sizeof(_STACK_PTR);
  848.             break;
  849.         case VT_BOOL|VT_BYREF:
  850.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pboolVal;
  851.             pStack += sizeof(_STACK_PTR);
  852.             break;
  853.         case VT_VARIANT|VT_BYREF:
  854.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pvarVal;
  855.             pStack += sizeof(_STACK_PTR);
  856.             break;
  857.         case VT_DISPATCH|VT_BYREF:
  858.         case VT_UNKNOWN|VT_BYREF:
  859.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->ppunkVal;
  860.             pStack += sizeof(_STACK_PTR);
  861.             break;
  862.  
  863.         default:
  864.             ASSERT(FALSE);
  865.         }
  866.  
  867. #ifdef _ALIGN_STACK
  868.         // align stack as appropriate for next parameter
  869.         pStack = (BYTE*)(((DWORD)pStack + (_ALIGN_STACK-1)) &
  870.             ~(_ALIGN_STACK-1));
  871.         ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  872. #endif
  873.     }
  874.  
  875.     // check that all source arguments were consumed
  876.     if (iArg > 0)
  877.     {
  878.         *puArgErr = iArg;
  879.         return DISP_E_BADPARAMCOUNT;
  880.     }
  881.     // check that all target arguments were filled
  882.     if (*pb != '\0')
  883.     {
  884.         *puArgErr = pDispParams->cArgs;
  885.         return DISP_E_PARAMNOTOPTIONAL;
  886.     }
  887.     return S_OK;    // success!
  888. }
  889.  
  890. // indirect call helper (see OLECALL.CPP for implementation)
  891.  
  892. extern "C" DWORD AFXAPI
  893. _AfxDispatchCall(AFX_PMSG pfn, void* pArgs, UINT nSizeArgs);
  894.  
  895. // invoke standard method given IDispatch parameters/return value, etc.
  896. SCODE CCmdTarget::CallMemberFunc(const AFX_DISPMAP_ENTRY* pEntry, WORD wFlags,
  897.     VARIANT* pvarResult, DISPPARAMS* pDispParams, UINT* puArgErr)
  898. {
  899.     AFX_MANAGE_STATE(m_pModuleState);
  900.  
  901.     ASSERT(pEntry != NULL);
  902.     ASSERT(pEntry->pfn != NULL);
  903.  
  904.     // special union used only to hold largest return value possible
  905.     union AFX_RESULT
  906.     {
  907.         VARIANT vaVal;
  908.         CY cyVal;
  909.         float fltVal;
  910.         double dblVal;
  911.         DWORD nVal;
  912.     };
  913.  
  914.     // get default function and parameters
  915.     BYTE bNoParams = 0;
  916.     const BYTE* pbParams = (const BYTE*)pEntry->lpszParams;
  917.     if (pbParams == NULL)
  918.         pbParams = &bNoParams;
  919.     UINT nParams = lstrlenA((LPCSTR)pbParams);
  920.  
  921.     // get default function and return value information
  922.     AFX_PMSG pfn = pEntry->pfn;
  923.     VARTYPE vtResult = pEntry->vt;
  924.  
  925.     // make DISPATCH_PROPERTYPUT look like call with one extra parameter
  926.     if (wFlags & (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF))
  927.     {
  928.         BYTE* pbPropSetParams = (BYTE*)_alloca(nParams+3);
  929.         ASSERT(pbPropSetParams != NULL);    // stack overflow?
  930.  
  931.         ASSERT(!(pEntry->vt & VT_BYREF));
  932.         memcpy(pbPropSetParams, pbParams, nParams);
  933.         pbParams = pbPropSetParams;
  934.  
  935.         VARTYPE vtProp = pEntry->vt;
  936. #if !defined(_UNICODE) && !defined(OLE2ANSI)
  937.         if (vtProp == VT_BSTR)
  938.             vtProp = VT_BSTRA;
  939. #endif
  940.         // VT_MFCVALUE serves serves as marker denoting start of named params
  941.         pbPropSetParams[nParams++] = (BYTE)VT_MFCMARKER;
  942.         pbPropSetParams[nParams++] = (BYTE)vtProp;
  943.         pbPropSetParams[nParams] = 0;
  944.  
  945.         // call "set" function instead of "get"
  946.         ASSERT(pEntry->pfnSet != NULL);
  947.         pfn = pEntry->pfnSet;
  948.         vtResult = VT_EMPTY;
  949.     }
  950.  
  951.     // allocate temporary space for VARIANT temps created by VariantChangeType
  952.     VARIANT* rgTempVars =
  953.         (VARIANT*)_alloca(pDispParams->cArgs * sizeof(VARIANT));
  954.     if (rgTempVars == NULL)
  955.     {
  956.         TRACE0("Error: stack overflow in IDispatch::Invoke!\n");
  957.         return E_OUTOFMEMORY;
  958.     }
  959.     memset(rgTempVars, 0, pDispParams->cArgs * sizeof(VARIANT));
  960.  
  961.     // determine size of arguments and allocate stack space
  962.     UINT nSizeArgs = GetStackSize(pbParams, vtResult);
  963.     ASSERT(nSizeArgs != 0);
  964.     if (nSizeArgs < _STACK_MIN)
  965.         nSizeArgs = _STACK_MIN;
  966.     BYTE* pStack = (BYTE*)_alloca(nSizeArgs + _SCRATCH_SIZE);
  967.     if (pStack == NULL)
  968.     {
  969.         TRACE0("Error: stack overflow in IDispatch::Invoke!\n");
  970.         return E_OUTOFMEMORY;
  971.     }
  972.  
  973.     // push all the args on to the stack allocated memory
  974.     AFX_RESULT result;
  975. #ifndef _SHADOW_DOUBLES
  976.     SCODE sc = PushStackArgs(pStack, pbParams, &result, vtResult,
  977.         pDispParams, puArgErr, rgTempVars);
  978. #else
  979.     SCODE sc = PushStackArgs(pStack, pbParams, &result, vtResult,
  980.         pDispParams, puArgErr, rgTempVars, nSizeArgs);
  981. #endif
  982.     pStack += _STACK_OFFSET;
  983.  
  984.     DWORD dwResult = 0;
  985.     if (sc == S_OK)
  986.     {
  987.         TRY
  988.         {
  989.             // PushStackArgs will fail on argument mismatches
  990.             DWORD (AFXAPI *pfnDispatch)(AFX_PMSG, void*, UINT) =
  991.                 &_AfxDispatchCall;
  992.  
  993.             // floating point return values are a special case
  994.             switch (vtResult)
  995.             {
  996.             case VT_R4:
  997.                 result.fltVal = ((float (AFXAPI*)(AFX_PMSG, void*, UINT))
  998.                     pfnDispatch)(pfn, pStack, nSizeArgs);
  999.                 break;
  1000.             case VT_R8:
  1001.                 result.dblVal = ((double (AFXAPI*)(AFX_PMSG, void*, UINT))
  1002.                     pfnDispatch)(pfn, pStack, nSizeArgs);
  1003.                 break;
  1004.             case VT_DATE:
  1005.                 result.dblVal = ((DATE (AFXAPI*)(AFX_PMSG, void*, UINT))
  1006.                     pfnDispatch)(pfn, pStack, nSizeArgs);
  1007.                 break;
  1008.  
  1009.             default:
  1010.                 dwResult = pfnDispatch(pfn, pStack, nSizeArgs);
  1011.                 break;
  1012.             }
  1013.         }
  1014.         CATCH_ALL(e)
  1015.         {
  1016.             // free temporaries created by VariantChangeType
  1017.             for (UINT iArg = 0; iArg < pDispParams->cArgs; ++iArg)
  1018.                 VariantClear(&rgTempVars[iArg]);
  1019.  
  1020.             THROW_LAST();
  1021.         }
  1022.         END_CATCH_ALL
  1023.     }
  1024.  
  1025.     // free temporaries created by VariantChangeType
  1026.     for (UINT iArg = 0; iArg < pDispParams->cArgs; ++iArg)
  1027.         VariantClear(&rgTempVars[iArg]);
  1028.  
  1029.     // handle error during PushStackParams
  1030.     if (sc != S_OK)
  1031.         return sc;
  1032.  
  1033.     // property puts don't touch the return value
  1034.     if (pvarResult != NULL)
  1035.     {
  1036.         // clear pvarResult just in case
  1037.         pvarResult->vt = vtResult;
  1038.  
  1039.         // build return value VARIANT from result union
  1040.         switch (vtResult)
  1041.         {
  1042.         case VT_UI2:
  1043.             pvarResult->bVal = (BYTE)dwResult;
  1044.             break;
  1045.         case VT_I2:
  1046.             pvarResult->iVal = (short)dwResult;
  1047.             break;
  1048.         case VT_I4:
  1049.             pvarResult->lVal = (long)dwResult;
  1050.             break;
  1051.         case VT_R4:
  1052.             pvarResult->fltVal = result.fltVal;
  1053.             break;
  1054.         case VT_R8:
  1055.             pvarResult->dblVal = result.dblVal;
  1056.             break;
  1057.         case VT_CY:
  1058.             pvarResult->cyVal = result.cyVal;
  1059.             break;
  1060.         case VT_DATE:
  1061.             pvarResult->date = result.dblVal;
  1062.             break;
  1063.         case VT_BSTR:
  1064.             pvarResult->bstrVal = (BSTR)dwResult;
  1065.             break;
  1066.         case VT_ERROR:
  1067.             pvarResult->scode = (SCODE)dwResult;
  1068.             break;
  1069.         case VT_BOOL:
  1070.             V_BOOL(pvarResult) = (VARIANT_BOOL)((BOOL)dwResult != 0 ? -1 : 0);
  1071.             break;
  1072.         case VT_VARIANT:
  1073.             *pvarResult = result.vaVal;
  1074.             break;
  1075.         case VT_DISPATCH:
  1076.         case VT_UNKNOWN:
  1077.             pvarResult->punkVal = (LPUNKNOWN)dwResult; // already AddRef
  1078.             break;
  1079.         }
  1080.     }
  1081.     else
  1082.     {
  1083.         // free unused return value
  1084.         switch (vtResult)
  1085.         {
  1086.         case VT_BSTR:
  1087.             if ((BSTR)dwResult != NULL)
  1088.                 SysFreeString((BSTR)dwResult);
  1089.             break;
  1090.         case VT_DISPATCH:
  1091.         case VT_UNKNOWN:
  1092.             if ((LPUNKNOWN)dwResult != 0)
  1093.                 ((LPUNKNOWN)dwResult)->Release();
  1094.             break;
  1095.         case VT_VARIANT:
  1096.             VariantClear(&result.vaVal);
  1097.             break;
  1098.         }
  1099.     }
  1100.  
  1101.     return S_OK;    // success!
  1102. }
  1103.  
  1104. /////////////////////////////////////////////////////////////////////////////
  1105. // CCmdTarget::XDispatch implementation
  1106.  
  1107. STDMETHODIMP_(ULONG) COleDispatchImpl::AddRef()
  1108. {
  1109.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1110.     return pThis->ExternalAddRef();
  1111. }
  1112.  
  1113. STDMETHODIMP_(ULONG) COleDispatchImpl::Release()
  1114. {
  1115.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1116.     return pThis->ExternalRelease();
  1117. }
  1118.  
  1119. STDMETHODIMP COleDispatchImpl::QueryInterface(REFIID iid, LPVOID* ppvObj)
  1120. {
  1121.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1122.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  1123. }
  1124.  
  1125. STDMETHODIMP COleDispatchImpl::GetTypeInfoCount(UINT* pctinfo)
  1126. {
  1127.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1128.     *pctinfo = pThis->GetTypeInfoCount();
  1129.     return S_OK;
  1130. }
  1131.  
  1132. STDMETHODIMP COleDispatchImpl::GetTypeInfo(UINT itinfo, LCID lcid,
  1133.     ITypeInfo** pptinfo)
  1134. {
  1135.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1136.     ASSERT_POINTER(pptinfo, LPTYPEINFO);
  1137.  
  1138.     if (itinfo != 0)
  1139.         return E_INVALIDARG;
  1140.  
  1141.     IID iid;
  1142.     if (!pThis->GetDispatchIID(&iid))
  1143.         return E_NOTIMPL;
  1144.  
  1145.     return pThis->GetTypeInfoOfGuid(lcid, iid, pptinfo);
  1146. }
  1147.  
  1148. STDMETHODIMP COleDispatchImpl::GetIDsOfNames(
  1149.     REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
  1150. {
  1151.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1152.     ASSERT_POINTER(rgszNames, char*);
  1153.     ASSERT_POINTER(rgdispid, DISPID);
  1154.  
  1155.     USES_CONVERSION;
  1156.  
  1157.     // check arguments
  1158.     if (riid != IID_NULL)
  1159.         return DISP_E_UNKNOWNINTERFACE;
  1160.  
  1161.     SCODE sc;
  1162.     LPTYPEINFO lpTypeInfo = NULL;
  1163.     if (lcid != 0 && SUCCEEDED(sc = GetTypeInfo(0, lcid, &lpTypeInfo)))
  1164.     {
  1165.         // For non-zero lcid, let typeinfo do the work (when available)
  1166.         ASSERT(lpTypeInfo != NULL);
  1167.         sc = lpTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
  1168.         lpTypeInfo->Release();
  1169.         if (sc == TYPE_E_ELEMENTNOTFOUND)
  1170.             sc = DISP_E_UNKNOWNNAME;
  1171.     }
  1172.     else
  1173.     {
  1174.         // fill in the member name
  1175.         const AFX_DISPMAP* pDerivMap = pThis->GetDispatchMap();
  1176.         rgdispid[0] = pThis->MemberIDFromName(pDerivMap, OLE2CT(rgszNames[0]));
  1177.         if (rgdispid[0] == DISPID_UNKNOWN)
  1178.             sc = DISP_E_UNKNOWNNAME;
  1179.         else
  1180.             sc = S_OK;
  1181.  
  1182.         // argument names are always DISPID_UNKNOWN (for this implementation)
  1183.         for (UINT nIndex = 1; nIndex < cNames; nIndex++)
  1184.             rgdispid[nIndex] = DISPID_UNKNOWN;
  1185.     }
  1186.  
  1187.     return sc;
  1188. }
  1189.  
  1190. STDMETHODIMP COleDispatchImpl::Invoke(
  1191.     DISPID dispid, REFIID riid, LCID lcid,
  1192.     WORD wFlags, DISPPARAMS* pDispParams, LPVARIANT pvarResult,
  1193.     LPEXCEPINFO pexcepinfo, UINT* puArgErr)
  1194. {
  1195.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1196.     ASSERT_NULL_OR_POINTER(pvarResult, VARIANT);
  1197.     ASSERT_NULL_OR_POINTER(pexcepinfo, EXCEPINFO);
  1198.     ASSERT_NULL_OR_POINTER(puArgErr, UINT);
  1199.  
  1200.     // make sure pvarResult is initialized
  1201.     if (pvarResult != NULL)
  1202.         AfxVariantInit(pvarResult);
  1203.  
  1204.     // check arguments
  1205.     if (riid != IID_NULL)
  1206.         return DISP_E_UNKNOWNINTERFACE;
  1207.  
  1208.     // allow subclass to disable Invoke
  1209.     if (!pThis->IsInvokeAllowed(dispid))
  1210.         return E_UNEXPECTED;
  1211.  
  1212.     // copy param block for safety
  1213.     DISPPARAMS params = *pDispParams;
  1214.     pDispParams = ¶ms;
  1215.  
  1216.     // most of the time, named arguments are not supported
  1217.     if (pDispParams->cNamedArgs != 0)
  1218.     {
  1219.         // only special PROPERTYPUT named argument is allowed
  1220.         if (pDispParams->cNamedArgs != 1 ||
  1221.             pDispParams->rgdispidNamedArgs[0] != DISPID_PROPERTYPUT)
  1222.         {
  1223.             return DISP_E_NONAMEDARGS;
  1224.         }
  1225.     }
  1226.  
  1227.     // get entry for the member ID
  1228.     const AFX_DISPMAP_ENTRY* pEntry = pThis->GetDispEntry(dispid);
  1229.     if (pEntry == NULL)
  1230.         return DISP_E_MEMBERNOTFOUND;
  1231.  
  1232.     // treat member calls on properties just like property get/set
  1233.     if ((wFlags == DISPATCH_METHOD) &&
  1234.         ((pEntry->pfn == NULL && pEntry->pfnSet == NULL) ||
  1235.          (pEntry->pfn == NULL && pEntry->pfnSet != NULL) ||
  1236.          (pEntry->pfn != NULL && pEntry->pfnSet != NULL)))
  1237.     {
  1238.         // the entry describes a property but a method call is being
  1239.         //  attempted -- change it to a property get/set based on the
  1240.         //  number of parameters being passed.
  1241.         wFlags &= ~DISPATCH_METHOD;
  1242.         UINT nExpectedArgs = pEntry->lpszParams != NULL ?
  1243.             (UINT)lstrlenA(pEntry->lpszParams) : 0;
  1244.         if (pDispParams->cArgs <= nExpectedArgs)
  1245.         {
  1246.             // no extra param -- so treat as property get
  1247.             wFlags |= DISPATCH_PROPERTYGET;
  1248.         }
  1249.         else
  1250.         {
  1251.             // extra params -- treat as property set
  1252.             wFlags |= DISPATCH_PROPERTYPUTREF;
  1253.             pDispParams->cNamedArgs = 1;
  1254.         }
  1255.     }
  1256.  
  1257.     // property puts should not require a return value
  1258.     if (wFlags & (DISPATCH_PROPERTYPUTREF|DISPATCH_PROPERTYPUT))
  1259.     {
  1260.         pvarResult = NULL;
  1261.         // catch attempt to do property set on method
  1262.         if (pEntry->pfn != NULL && pEntry->pfnSet == NULL)
  1263.             return DISP_E_TYPEMISMATCH;
  1264.     }
  1265.  
  1266.     UINT uArgErr = (UINT)-1;    // no error yet
  1267.     SCODE sc = S_OK;
  1268.  
  1269.     // handle special cases of DISPATCH_PROPERTYPUT
  1270.     VARIANT* pvarParamSave = NULL;
  1271.     VARIANT vaParamSave;
  1272.     vaParamSave.vt = VT_ERROR;
  1273.  
  1274.     DISPPARAMS paramsTemp;
  1275.     VARIANT vaTemp;
  1276.     AfxVariantInit(&vaTemp);
  1277.  
  1278.     if (wFlags == DISPATCH_PROPERTYPUT && dispid != DISPID_VALUE)
  1279.     {
  1280.         // with PROPERTYPUT (no REF), the right hand side may need fixup
  1281.         if (pDispParams->rgvarg[0].vt == VT_DISPATCH &&
  1282.             pDispParams->rgvarg[0].pdispVal != NULL)
  1283.         {
  1284.             // remember old value for restore later
  1285.             pvarParamSave = &pDispParams->rgvarg[0];
  1286.             vaParamSave = pDispParams->rgvarg[0];
  1287.             AfxVariantInit(&pDispParams->rgvarg[0]);
  1288.  
  1289.             // get default value of right hand side
  1290.             memset(¶msTemp, 0, sizeof(DISPPARAMS));
  1291.             sc = vaParamSave.pdispVal->Invoke(
  1292.                 DISPID_VALUE, riid, lcid, DISPATCH_PROPERTYGET, ¶msTemp,
  1293.                 &pDispParams->rgvarg[0], pexcepinfo, puArgErr);
  1294.         }
  1295.  
  1296.         // special handling for PROPERTYPUT (no REF), left hand side
  1297.         if (sc == S_OK && pEntry->vt == VT_DISPATCH)
  1298.         {
  1299.             memset(¶msTemp, 0, sizeof(DISPPARAMS));
  1300.  
  1301.             // parameters are distributed depending on what the Get expects
  1302.             if (pEntry->lpszParams == NULL)
  1303.             {
  1304.                 // paramsTemp is already setup for no parameters
  1305.                 sc = Invoke(dispid, riid, lcid,
  1306.                     DISPATCH_PROPERTYGET|DISPATCH_METHOD, ¶msTemp,
  1307.                     &vaTemp, pexcepinfo, puArgErr);
  1308.                 if (sc == S_OK &&
  1309.                     (vaTemp.vt != VT_DISPATCH || vaTemp.pdispVal == NULL))
  1310.                     sc = DISP_E_TYPEMISMATCH;
  1311.                 else if (sc == S_OK)
  1312.                 {
  1313.                     ASSERT(vaTemp.vt == VT_DISPATCH && vaTemp.pdispVal != NULL);
  1314.                     // we have the result, now call put on the default property
  1315.                     sc = vaTemp.pdispVal->Invoke(
  1316.                         DISPID_VALUE, riid, lcid, wFlags, pDispParams,
  1317.                         pvarResult, pexcepinfo, puArgErr);
  1318.                 }
  1319.             }
  1320.             else
  1321.             {
  1322.                 // pass all but named params
  1323.                 paramsTemp.rgvarg = &pDispParams->rgvarg[1];
  1324.                 paramsTemp.cArgs = pDispParams->cArgs - 1;
  1325.                 sc = Invoke(dispid, riid, lcid,
  1326.                     DISPATCH_PROPERTYGET|DISPATCH_METHOD, ¶msTemp,
  1327.                     &vaTemp, pexcepinfo, puArgErr);
  1328.                 if (sc == S_OK &&
  1329.                     (vaTemp.vt != VT_DISPATCH || vaTemp.pdispVal == NULL))
  1330.                     sc = DISP_E_TYPEMISMATCH;
  1331.                 else if (sc == S_OK)
  1332.                 {
  1333.                     ASSERT(vaTemp.vt == VT_DISPATCH && vaTemp.pdispVal != NULL);
  1334.  
  1335.                     // we have the result, now call put on the default property
  1336.                     paramsTemp = *pDispParams;
  1337.                     paramsTemp.cArgs = paramsTemp.cNamedArgs;
  1338.                     sc = vaTemp.pdispVal->Invoke(
  1339.                         DISPID_VALUE, riid, lcid, wFlags, ¶msTemp,
  1340.                         pvarResult, pexcepinfo, puArgErr);
  1341.                 }
  1342.             }
  1343.             VariantClear(&vaTemp);
  1344.  
  1345.             if (sc != DISP_E_MEMBERNOTFOUND)
  1346.                 goto Cleanup;
  1347.         }
  1348.  
  1349.         if (sc != S_OK && sc != DISP_E_MEMBERNOTFOUND)
  1350.             goto Cleanup;
  1351.     }
  1352.  
  1353.     // ignore DISP_E_MEMBERNOTFOUND from above
  1354.     ASSERT(sc == DISP_E_MEMBERNOTFOUND || sc == S_OK);
  1355.  
  1356.     // undo implied default value on right hand side on error
  1357.     if (sc != S_OK && pvarParamSave != NULL)
  1358.     {
  1359.         // default value stuff failed -- so try without default value
  1360.         pvarParamSave = NULL;
  1361.         VariantClear(&pDispParams->rgvarg[0]);
  1362.         pDispParams->rgvarg[0] = vaParamSave;
  1363.     }
  1364.     sc = S_OK;
  1365.  
  1366.     // check arguments against this entry
  1367.     UINT nOrigArgs; nOrigArgs = pDispParams->cArgs;
  1368.     if (wFlags & (DISPATCH_PROPERTYGET|DISPATCH_METHOD))
  1369.     {
  1370.         if (!(wFlags & DISPATCH_METHOD))
  1371.         {
  1372.             if (pEntry->vt == VT_EMPTY)
  1373.                 return DISP_E_BADPARAMCOUNT;
  1374.             if (pvarResult == NULL)
  1375.                 return DISP_E_PARAMNOTOPTIONAL;
  1376.         }
  1377.         if (pEntry->lpszParams == NULL && pDispParams->cArgs > 0)
  1378.         {
  1379.             if (pEntry->vt != VT_DISPATCH)
  1380.                 return DISP_E_BADPARAMCOUNT;
  1381.  
  1382.             // it is VT_DISPATCH property/method but too many arguments supplied
  1383.             // transfer those arguments to the default property of the return value
  1384.             // after getting the return value from this call.  This is referred
  1385.             // to as collection lookup.
  1386.             pDispParams->cArgs = 0;
  1387.             if (pvarResult == NULL)
  1388.                 pvarResult = &vaTemp;
  1389.         }
  1390.     }
  1391.  
  1392.     // make sure that parameters are not passed to a simple property
  1393.     if (pDispParams->cArgs > 1 &&
  1394.         (wFlags & (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF)) &&
  1395.         pEntry->pfn == NULL)
  1396.     {
  1397.         sc = DISP_E_BADPARAMCOUNT;
  1398.         goto Cleanup;
  1399.     }
  1400.  
  1401.     // make sure that pvarResult is set for simple property get
  1402.     if (pEntry->pfn == NULL && pDispParams->cArgs == 0 && pvarResult == NULL)
  1403.     {
  1404.         sc = DISP_E_PARAMNOTOPTIONAL;
  1405.         goto Cleanup;
  1406.     }
  1407.  
  1408.     // make sure IsExpectingResult returns FALSE as appropriate
  1409.     BOOL bResultExpected;
  1410.     bResultExpected = pThis->m_bResultExpected;
  1411.     pThis->m_bResultExpected = pvarResult != NULL;
  1412.  
  1413.     TRY
  1414.     {
  1415.         if (pEntry->pfn == NULL)
  1416.         {
  1417.             // do standard property get/set
  1418.             if (pDispParams->cArgs == 0)
  1419.                 pThis->GetStandardProp(pEntry, pvarResult, &uArgErr);
  1420.             else
  1421.                 sc = pThis->SetStandardProp(pEntry, pDispParams, &uArgErr);
  1422.         }
  1423.         else
  1424.         {
  1425.             // do standard method call
  1426.             sc = pThis->CallMemberFunc(pEntry, wFlags,
  1427.                 pvarResult, pDispParams, &uArgErr);
  1428.         }
  1429.     }
  1430.     CATCH(COleException, e)
  1431.     {
  1432.         sc = e->m_sc;
  1433.         DELETE_EXCEPTION(e);
  1434.     }
  1435.     AND_CATCH_ALL(e)
  1436.     {
  1437.         AFX_MANAGE_STATE(pThis->m_pModuleState);
  1438.         if (pexcepinfo != NULL)
  1439.         {
  1440.             // fill exception with translation of MFC exception
  1441.             COleDispatchException::Process(pexcepinfo, e);
  1442.         }
  1443.         DELETE_EXCEPTION(e);
  1444.         sc = DISP_E_EXCEPTION;
  1445.     }
  1446.     END_CATCH_ALL
  1447.  
  1448.     // restore original m_bResultExpected flag
  1449.     pThis->m_bResultExpected = bResultExpected;
  1450.  
  1451.     // handle special DISPATCH_PROPERTYGET collection lookup case
  1452.     if (sc == S_OK && nOrigArgs > pDispParams->cArgs)
  1453.     {
  1454.         ASSERT(wFlags & (DISPATCH_PROPERTYGET|DISPATCH_METHOD));
  1455.         ASSERT(pvarResult != NULL);
  1456.         // must be non-NULL dispatch, otherwise type mismatch
  1457.         if (pvarResult->vt != VT_DISPATCH || pvarResult->pdispVal == NULL)
  1458.         {
  1459.             sc = DISP_E_TYPEMISMATCH;
  1460.             goto Cleanup;
  1461.         }
  1462.         // otherwise, valid VT_DISPATCH was returned
  1463.         pDispParams->cArgs = nOrigArgs;
  1464.         LPDISPATCH lpTemp = pvarResult->pdispVal;
  1465.         if (pvarResult != &vaTemp)
  1466.             AfxVariantInit(pvarResult);
  1467.         else
  1468.             pvarResult = NULL;
  1469.         sc = lpTemp->Invoke(DISPID_VALUE, riid, lcid, wFlags,
  1470.             pDispParams, pvarResult, pexcepinfo, puArgErr);
  1471.         lpTemp->Release();
  1472.     }
  1473.  
  1474. Cleanup:
  1475.     // restore any arguments which were modified
  1476.     if (pvarParamSave != NULL)
  1477.     {
  1478.         VariantClear(&pDispParams->rgvarg[0]);
  1479.         pDispParams->rgvarg[0] = vaParamSave;
  1480.     }
  1481.  
  1482.     // fill error argument if one is available
  1483.     if (sc != S_OK && puArgErr != NULL && uArgErr != -1)
  1484.         *puArgErr = uArgErr;
  1485.  
  1486.     return sc;
  1487. }
  1488.  
  1489. /////////////////////////////////////////////////////////////////////////////
  1490. // IDispatch specific exception
  1491.  
  1492. COleDispatchException::~COleDispatchException()
  1493. {
  1494.     // destructor code is compiler generated
  1495. }
  1496.  
  1497. void PASCAL COleDispatchException::Process(
  1498.     EXCEPINFO* pInfo, const CException* pAnyException)
  1499. {
  1500.     USES_CONVERSION;
  1501.  
  1502.     ASSERT(AfxIsValidAddress(pInfo, sizeof(EXCEPINFO)));
  1503.     ASSERT_VALID(pAnyException);
  1504.  
  1505.     // zero default & reserved members
  1506.     memset(pInfo, 0, sizeof(EXCEPINFO));
  1507.  
  1508.     // get description based on type of exception
  1509.     TCHAR szDescription[256];
  1510.     LPCTSTR pszDescription = szDescription;
  1511.     if (pAnyException->IsKindOf(RUNTIME_CLASS(COleDispatchException)))
  1512.     {
  1513.         // specific IDispatch style exception
  1514.         COleDispatchException* e = (COleDispatchException*)pAnyException;
  1515.         pszDescription = e->m_strDescription;
  1516.         pInfo->wCode = e->m_wCode;
  1517.         pInfo->dwHelpContext = e->m_dwHelpContext;
  1518.         pInfo->scode = e->m_scError;
  1519.  
  1520.         // propagate source and help file if present
  1521.         if (!e->m_strHelpFile.IsEmpty())
  1522.             pInfo->bstrHelpFile = ::SysAllocString(T2COLE(e->m_strHelpFile));
  1523.         if (!e->m_strSource.IsEmpty())
  1524.             pInfo->bstrSource = ::SysAllocString(T2COLE(e->m_strSource));
  1525.     }
  1526.     else if (pAnyException->IsKindOf(RUNTIME_CLASS(CMemoryException)))
  1527.     {
  1528.         // failed memory allocation
  1529.         AfxLoadString(AFX_IDP_FAILED_MEMORY_ALLOC, szDescription);
  1530.         pInfo->wCode = AFX_IDP_FAILED_MEMORY_ALLOC;
  1531.     }
  1532.     else
  1533.     {
  1534.         // other unknown/uncommon error
  1535.         AfxLoadString(AFX_IDP_INTERNAL_FAILURE, szDescription);
  1536.         pInfo->wCode = AFX_IDP_INTERNAL_FAILURE;
  1537.     }
  1538.  
  1539.     // build up rest of EXCEPINFO struct
  1540.     pInfo->bstrDescription = ::SysAllocString(T2COLE(pszDescription));
  1541.     if (pInfo->bstrSource == NULL)
  1542.         pInfo->bstrSource = ::SysAllocString(T2COLE(AfxGetAppName()));
  1543.     if (pInfo->bstrHelpFile == NULL && pInfo->dwHelpContext != 0)
  1544.         pInfo->bstrHelpFile = ::SysAllocString(T2COLE(AfxGetApp()->m_pszHelpFilePath));
  1545. }
  1546.  
  1547. COleDispatchException::COleDispatchException(
  1548.     LPCTSTR lpszDescription, UINT nHelpID, WORD wCode)
  1549. {
  1550.     m_dwHelpContext = nHelpID != 0 ? HID_BASE_DISPATCH+nHelpID : 0;
  1551.     m_wCode = wCode;
  1552.     if (lpszDescription != NULL)
  1553.         m_strDescription = lpszDescription;
  1554.     m_scError = wCode != 0 ? NOERROR : E_UNEXPECTED;
  1555. }
  1556.  
  1557. COleDispatchException::GetErrorMessage(LPTSTR lpszError, UINT nMaxError,
  1558.         PUINT pnHelpContext)
  1559. {
  1560.     ASSERT(lpszError != NULL && AfxIsValidString(lpszError, nMaxError));
  1561.  
  1562.     if (pnHelpContext != NULL)
  1563.         *pnHelpContext = 0;
  1564.  
  1565.     lstrcpyn(lpszError, m_strDescription, nMaxError);
  1566.     return TRUE;
  1567. }
  1568.  
  1569. void AFXAPI AfxThrowOleDispatchException(WORD wCode, LPCTSTR lpszDescription,
  1570.     UINT nHelpID)
  1571. {
  1572.     ASSERT(AfxIsValidString(lpszDescription));
  1573.     THROW(new COleDispatchException(lpszDescription, nHelpID, wCode));
  1574. }
  1575.  
  1576. void AFXAPI AfxThrowOleDispatchException(WORD wCode, UINT nDescriptionID,
  1577.     UINT nHelpID)
  1578. {
  1579.     TCHAR szBuffer[256];
  1580.     VERIFY(AfxLoadString(nDescriptionID, szBuffer) != 0);
  1581.     if (nHelpID == -1)
  1582.         nHelpID = nDescriptionID;
  1583.     THROW(new COleDispatchException(szBuffer, nHelpID, wCode));
  1584. }
  1585.  
  1586. #ifdef AFX_INIT_SEG
  1587. #pragma code_seg(AFX_INIT_SEG)
  1588. #endif
  1589.  
  1590. IMPLEMENT_DYNAMIC(COleDispatchException, CException)
  1591.  
  1592. /////////////////////////////////////////////////////////////////////////////
  1593.