home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / OLEDISP1.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-03  |  43.9 KB  |  1,588 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 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. UINT PASCAL CCmdTarget::GetStackSize(const BYTE* pbParams, VARTYPE vtResult)
  466. {
  467.     // size of arguments on stack when pushed by value
  468.     static const UINT rgnByValue[] =
  469.     {
  470.         0,                          // VTS_EMPTY
  471.         0,                          // VTS_NULL
  472.         sizeof(_STACK_INT),         // VTS_I2
  473.         sizeof(_STACK_LONG),        // VTS_I4
  474.         sizeof(_STACK_FLOAT),       // VTS_R4
  475.         sizeof(_STACK_DOUBLE),      // VTS_R8
  476.         sizeof(CY),                 // VTS_CY
  477.         sizeof(DATE),               // VTS_DATE
  478.         sizeof(LPCOLESTR),          // VTS_WBSTR (VT_BSTR)
  479.         sizeof(LPDISPATCH),         // VTS_DISPATCH
  480.         sizeof(SCODE),              // VTS_SCODE
  481.         sizeof(BOOL),               // VTS_BOOL
  482.         sizeof(const VARIANT*),     // VTS_VARIANT
  483.         sizeof(LPUNKNOWN),           // VTS_UNKNOWN
  484. #if !defined(_UNICODE) && !defined(OLE2ANSI)
  485.         sizeof(LPCSTR),             // VTS_BSTR (VT_BSTRA -- MFC defined)
  486. #endif
  487.     };
  488.     // size of arguments on stack when pushed by reference
  489.     static const UINT rgnByRef[] =
  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.     static const UINT rgnRetVal[] =
  508.     {
  509.         0,                          // VT_EMPTY
  510.         0,                          // VT_NULL
  511.         0,                          // VT_I2
  512.         0,                          // VT_I4
  513.         0,                          // VT_R4
  514.         0,                          // VT_R8
  515.         sizeof(CY*),                // VT_CY
  516.         0,                          // VT_DATE (same as VT_R8)
  517.         0,                          // VT_BSTR
  518.         0,                          // VT_DISPATCH
  519.         0,                          // VT_ERROR
  520.         0,                          // VT_BOOL
  521.         sizeof(VARIANT*),           // VT_VARIANT
  522.         0,                          // VT_UNKNOWN
  523.         0,                          // VT_UI1
  524.     };
  525.  
  526.     // sizeof 'this' pointer
  527.     UINT nCount = sizeof(CCmdTarget*);
  528. #ifdef _ALIGN_STACK
  529.     nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
  530. #endif
  531.  
  532.     // count bytes in return value
  533.     ASSERT((UINT)vtResult < _countof(rgnRetVal));
  534.     nCount += rgnRetVal[vtResult];
  535. #ifdef _ALIGN_STACK
  536.     nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
  537. #endif
  538.  
  539.     // count arguments
  540.     ASSERT(pbParams != NULL);
  541.     while (*pbParams != 0)
  542.     {
  543.         if (*pbParams != VT_MFCMARKER)
  544.         {
  545.             // align if necessary
  546.             // get and add appropriate byte count
  547.             const UINT* rgnBytes;
  548.             if (*pbParams & VT_MFCBYREF)
  549.                 rgnBytes = rgnByRef;
  550.             else
  551.                 rgnBytes = rgnByValue;
  552.             ASSERT((*pbParams & ~VT_MFCBYREF) < _countof(rgnByValue));
  553. #ifdef _ALIGN_DOUBLES
  554.             // align doubles on 8 byte for some platforms
  555.             if (*pbParams == VT_R8)
  556.                 nCount = (nCount + _ALIGN_DOUBLES-1) & ~(_ALIGN_DOUBLES-1);
  557. #endif
  558.             nCount += rgnBytes[*pbParams & ~VT_MFCBYREF];
  559. #ifdef _ALIGN_STACK
  560.             nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
  561. #endif
  562.         }
  563.         ++pbParams;
  564.     }
  565. #if defined(_ALIGN_DOUBLES) && defined(_SHADOW_DOUBLES)
  566.     // align doubles on 8 byte for some platforms
  567.     nCount = (nCount + _ALIGN_DOUBLES-1) & ~(_ALIGN_DOUBLES-1);
  568. #endif
  569.     return nCount;
  570. }
  571.  
  572. // push arguments on stack appropriate for C++ call (compiler dependent)
  573. #ifndef _SHADOW_DOUBLES
  574. SCODE CCmdTarget::PushStackArgs(BYTE* pStack, const BYTE* pbParams,
  575.     void* pResult, VARTYPE vtResult, DISPPARAMS* pDispParams, UINT* puArgErr,
  576.     VARIANT* rgTempVars)
  577. #else
  578. SCODE CCmdTarget::PushStackArgs(BYTE* pStack, const BYTE* pbParams,
  579.     void* pResult, VARTYPE vtResult, DISPPARAMS* pDispParams, UINT* puArgErr,
  580.     VARIANT* rgTempVars, UINT nSizeArgs)
  581. #endif
  582. {
  583.     ASSERT(pStack != NULL);
  584.     ASSERT(pResult != NULL);
  585.     ASSERT(pDispParams != NULL);
  586.     ASSERT(puArgErr != NULL);
  587.  
  588. #ifdef _SHADOW_DOUBLES
  589.     double* pDoubleShadow = (double*)(pStack + nSizeArgs);
  590.     double* pDoubleShadowMax = pDoubleShadow + _SHADOW_DOUBLES;
  591. #endif
  592.  
  593.     // C++ member functions use the __thiscall convention, where parameters
  594.     //  are pushed last to first.  Assuming the stack grows down, this means
  595.     //  that the first parameter is at the lowest memory address in the
  596.     //  stack frame and the last parameter is at the highest address.
  597.  
  598.  
  599. #ifdef _RETVAL_FIRST
  600.     // push any necessary return value stuff on the stack (pre args)
  601.     //  (an ambient pointer is pushed to stack relative data)
  602.     if (vtResult == VT_CY || vtResult == VT_VARIANT)
  603.     {
  604. #ifdef _ALIGN_STACK
  605.         ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  606. #endif
  607.         *(_STACK_PTR*)pStack = (_STACK_PTR)pResult;
  608.         pStack += sizeof(_STACK_PTR);
  609. #ifdef _ALIGN_STACK
  610.         ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  611. #endif
  612.     }
  613. #endif //_RETVAL_FIRST
  614.  
  615.     // push the 'this' pointer
  616. #ifdef _ALIGN_STACK
  617.     ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  618. #endif
  619.     *(_STACK_PTR*)pStack = (_STACK_PTR)this;
  620.     pStack += sizeof(_STACK_PTR);
  621. #ifdef _ALIGN_STACK
  622.     ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  623. #endif
  624.  
  625. #ifndef _RETVAL_FIRST
  626.     // push any necessary return value stuff on the stack (post args)
  627.     //  (an ambient pointer is pushed to stack relative data)
  628.     if (vtResult == VT_CY || vtResult == VT_VARIANT)
  629.     {
  630. #ifdef _ALIGN_STACK
  631.         ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  632. #endif
  633.         *(_STACK_PTR*)pStack = (_STACK_PTR)pResult;
  634.         pStack += sizeof(_STACK_PTR);
  635. #ifdef _ALIGN_STACK
  636.         ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  637. #endif
  638.     }
  639. #endif //!_RETVAL_FIRST
  640.  
  641.     // push the arguments (first to last, low address to high address)
  642.     VARIANT* pArgs = pDispParams->rgvarg;
  643.     BOOL bNamedArgs = FALSE;
  644.     int iArg = pDispParams->cArgs; // start with positional arguments
  645.     int iArgMin = pDispParams->cNamedArgs;
  646.  
  647.     ASSERT(pbParams != NULL);
  648.     for (const BYTE* pb = pbParams; *pb != '\0'; ++pb)
  649.     {
  650.         --iArg; // move to next arg
  651.  
  652.         // convert MFC parameter type to IDispatch VARTYPE
  653.         VARTYPE vt = *pb;
  654.         if (vt != VT_MFCMARKER && (vt & VT_MFCBYREF))
  655.             vt = (VARTYPE)((vt & ~VT_MFCBYREF) | VT_BYREF);
  656.  
  657.         VARIANT* pArg;
  658.         if (iArg >= iArgMin)
  659.         {
  660.             // hit named args before using all positional args?
  661.             if (vt == VT_MFCMARKER)
  662.                 break;
  663.  
  664.             // argument specified by caller -- use it
  665.             pArg = &pArgs[iArg];
  666.             if (vt != VT_VARIANT && vt != pArg->vt)
  667.             {
  668.                 // argument is not of appropriate type, attempt to coerce it
  669.                 VARIANT* pArgTemp = &rgTempVars[iArg];
  670.                 ASSERT(pArgTemp->vt == VT_EMPTY);
  671. #if defined(_UNICODE) || defined(OLE2ANSI)
  672.                 VARTYPE vtTarget = vt;
  673. #else
  674.                 VARTYPE vtTarget = (vt == VT_BSTRA) ? VT_BSTR : vt;
  675. #endif
  676.                 if (pArg->vt != vtTarget)
  677.                 {
  678.                     SCODE sc = VariantChangeType(pArgTemp, pArg, 0, vtTarget);
  679.                     if (FAILED(sc))
  680.                     {
  681.                         TRACE0("Warning: automation argument coercion failed.\n");
  682.                         *puArgErr = iArg;
  683.                         return sc;
  684.                     }
  685.                     ASSERT(pArgTemp->vt == vtTarget);
  686.                 }
  687.  
  688. #if !defined(_UNICODE) && !defined(OLE2ANSI)
  689.                 if (vt == VT_BSTRA)
  690.                 {
  691.                     if (pArg->vt != vtTarget)
  692.                     {
  693.                         // coerce above created a new string
  694.                         // convert it to ANSI and free it
  695.                         ASSERT(pArgTemp->vt == VT_BSTR);
  696.                         BSTR bstrW = pArgTemp->bstrVal;
  697.                         pArgTemp->bstrVal = AfxBSTR2ABSTR(bstrW);
  698.                         SysFreeString(bstrW);
  699.                     }
  700.                     else
  701.                     {
  702.                         // convert the string to ANSI from original
  703.                         pArgTemp->bstrVal = AfxBSTR2ABSTR(pArg->bstrVal);
  704.                         pArgTemp->vt = VT_BSTR;
  705.                     }
  706.                     vt = VT_BSTR;
  707.                 }
  708. #endif
  709.                 pArg = pArgTemp;
  710.             }
  711.         }
  712.         else
  713.         {
  714.             if (vt == VT_MFCMARKER)
  715.             {
  716.                 // start processing named arguments
  717.                 iArg = pDispParams->cNamedArgs;
  718.                 iArgMin = 0;
  719.                 bNamedArgs = TRUE;
  720.                 continue;
  721.             }
  722.  
  723.             if (bNamedArgs || vt != VT_VARIANT)
  724.                 break;  // function not expecting optional argument
  725.  
  726.             // argument not specified by caller -- provide default variant
  727.             static VARIANT vaDefault;   // Note: really is 'const'
  728.             vaDefault.vt = VT_ERROR;
  729.             vaDefault.scode = DISP_E_PARAMNOTFOUND;
  730.             pArg = &vaDefault;
  731.         }
  732.  
  733.         // push parameter value on the stack
  734.         switch (vt)
  735.         {
  736.         // by value parameters
  737.         case VT_UI1:
  738.             *(_STACK_INT*)pStack = pArg->bVal; // 'BYTE' is passed as 'int'
  739.             pStack += sizeof(_STACK_INT);
  740.             break;
  741.         case VT_I2:
  742.             *(_STACK_INT*)pStack = pArg->iVal;
  743.             pStack += sizeof(_STACK_INT);   // 'short' is passed as 'int'
  744.             break;
  745.         case VT_I4:
  746.             *(_STACK_LONG*)pStack = pArg->lVal;
  747.             pStack += sizeof(_STACK_LONG);
  748.             break;
  749.         case VT_R4:
  750.             *(_STACK_FLOAT*)pStack = (_STACK_FLOAT)pArg->fltVal;
  751.             pStack += sizeof(_STACK_FLOAT);
  752. #ifdef _SHADOW_DOUBLES
  753.             if (pDoubleShadow < pDoubleShadowMax)
  754.                 *pDoubleShadow++ = (double)pArg->fltVal;
  755. #endif
  756.             break;
  757.         case VT_R8:
  758. #ifdef _ALIGN_DOUBLES
  759.             // align doubles on 8 byte for some platforms
  760.             pStack = (BYTE*)(((DWORD)pStack + _ALIGN_DOUBLES-1) &
  761.                 ~(_ALIGN_DOUBLES-1));
  762. #endif
  763.             *(_STACK_DOUBLE*)pStack = (_STACK_DOUBLE)pArg->dblVal;
  764.             pStack += sizeof(_STACK_DOUBLE);
  765. #ifdef _SHADOW_DOUBLES
  766.             if (pDoubleShadow < pDoubleShadowMax)
  767.                 *pDoubleShadow++ = pArg->dblVal;
  768. #endif
  769.             break;
  770.         case VT_DATE:
  771. #ifdef _ALIGN_DOUBLES
  772.             // align doubles on 8 byte for some platforms
  773.             pStack = (BYTE*)(((DWORD)pStack + _ALIGN_DOUBLES-1) &
  774.                 ~(_ALIGN_DOUBLES-1));
  775. #endif
  776.             *(_STACK_DOUBLE*)pStack = (_STACK_DOUBLE)pArg->date;
  777.             pStack += sizeof(_STACK_DOUBLE);
  778. #ifdef _SHADOW_DOUBLES
  779.             if (pDoubleShadow < pDoubleShadowMax)
  780.                 *pDoubleShadow++ = pArg->date;
  781. #endif
  782.             break;
  783.         case VT_CY:
  784.             *(CY*)pStack = pArg->cyVal;
  785.             pStack += sizeof(CY);
  786.             break;
  787.         case VT_BSTR:
  788.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->bstrVal;
  789.             pStack += sizeof(_STACK_PTR);
  790.             break;
  791.         case VT_ERROR:
  792.             *(_STACK_LONG*)pStack = (_STACK_LONG)pArg->scode;
  793.             pStack += sizeof(_STACK_LONG);
  794.             break;
  795.         case VT_BOOL:
  796.             *(_STACK_LONG*)pStack = (_STACK_LONG)(V_BOOL(pArg) != 0);
  797.             pStack += sizeof(_STACK_LONG);
  798.             break;
  799.         case VT_VARIANT:
  800.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg;
  801.             pStack += sizeof(_STACK_PTR);
  802.             break;
  803.         case VT_DISPATCH:
  804.         case VT_UNKNOWN:
  805.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->punkVal;
  806.             pStack += sizeof(_STACK_PTR);
  807.             break;
  808.  
  809.         // by reference parameters
  810.         case VT_UI2|VT_BYREF:
  811.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pbVal;
  812.             pStack += sizeof(_STACK_PTR);
  813.             break;
  814.         case VT_I2|VT_BYREF:
  815.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->piVal;
  816.             pStack += sizeof(_STACK_PTR);
  817.             break;
  818.         case VT_I4|VT_BYREF:
  819.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->plVal;
  820.             pStack += sizeof(_STACK_PTR);
  821.             break;
  822.         case VT_R4|VT_BYREF:
  823.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pfltVal;
  824.             pStack += sizeof(_STACK_PTR);
  825.             break;
  826.         case VT_R8|VT_BYREF:
  827.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pdblVal;
  828.             pStack += sizeof(_STACK_PTR);
  829.             break;
  830.         case VT_DATE|VT_BYREF:
  831.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pdate;
  832.             pStack += sizeof(_STACK_PTR);
  833.             break;
  834.         case VT_CY|VT_BYREF:
  835.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pcyVal;
  836.             pStack += sizeof(_STACK_PTR);
  837.             break;
  838.         case VT_BSTR|VT_BYREF:
  839.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pbstrVal;
  840.             pStack += sizeof(_STACK_PTR);
  841.             break;
  842.         case VT_ERROR|VT_BYREF:
  843.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pscode;
  844.             pStack += sizeof(_STACK_PTR);
  845.             break;
  846.         case VT_BOOL|VT_BYREF:
  847.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pboolVal;
  848.             pStack += sizeof(_STACK_PTR);
  849.             break;
  850.         case VT_VARIANT|VT_BYREF:
  851.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pvarVal;
  852.             pStack += sizeof(_STACK_PTR);
  853.             break;
  854.         case VT_DISPATCH|VT_BYREF:
  855.         case VT_UNKNOWN|VT_BYREF:
  856.             *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->ppunkVal;
  857.             pStack += sizeof(_STACK_PTR);
  858.             break;
  859.  
  860.         default:
  861.             ASSERT(FALSE);
  862.         }
  863.  
  864. #ifdef _ALIGN_STACK
  865.         // align stack as appropriate for next parameter
  866.         pStack = (BYTE*)(((DWORD)pStack + (_ALIGN_STACK-1)) &
  867.             ~(_ALIGN_STACK-1));
  868.         ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  869. #endif
  870.     }
  871.  
  872.     // check that all source arguments were consumed
  873.     if (iArg > 0)
  874.     {
  875.         *puArgErr = iArg;
  876.         return DISP_E_BADPARAMCOUNT;
  877.     }
  878.     // check that all target arguments were filled
  879.     if (*pb != '\0')
  880.     {
  881.         *puArgErr = pDispParams->cArgs;
  882.         return DISP_E_PARAMNOTOPTIONAL;
  883.     }
  884.     return S_OK;    // success!
  885. }
  886.  
  887. // indirect call helper (see OLECALL.CPP for implementation)
  888.  
  889. extern "C" DWORD AFXAPI
  890. _AfxDispatchCall(AFX_PMSG pfn, void* pArgs, UINT nSizeArgs);
  891.  
  892. // invoke standard method given IDispatch parameters/return value, etc.
  893. SCODE CCmdTarget::CallMemberFunc(const AFX_DISPMAP_ENTRY* pEntry, WORD wFlags,
  894.     VARIANT* pvarResult, DISPPARAMS* pDispParams, UINT* puArgErr)
  895. {
  896.     AFX_MANAGE_STATE(m_pModuleState);
  897.  
  898.     ASSERT(pEntry != NULL);
  899.     ASSERT(pEntry->pfn != NULL);
  900.  
  901.     // special union used only to hold largest return value possible
  902.     union AFX_RESULT
  903.     {
  904.         VARIANT vaVal;
  905.         CY cyVal;
  906.         float fltVal;
  907.         double dblVal;
  908.         DWORD nVal;
  909.     };
  910.  
  911.     // get default function and parameters
  912.     BYTE bNoParams = 0;
  913.     const BYTE* pbParams = (const BYTE*)pEntry->lpszParams;
  914.     if (pbParams == NULL)
  915.         pbParams = &bNoParams;
  916.     UINT nParams = lstrlenA((LPCSTR)pbParams);
  917.  
  918.     // get default function and return value information
  919.     AFX_PMSG pfn = pEntry->pfn;
  920.     VARTYPE vtResult = pEntry->vt;
  921.  
  922.     // make DISPATCH_PROPERTYPUT look like call with one extra parameter
  923.     if (wFlags & (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF))
  924.     {
  925.         BYTE* pbPropSetParams = (BYTE*)_alloca(nParams+3);
  926.         ASSERT(pbPropSetParams != NULL);    // stack overflow?
  927.  
  928.         ASSERT(!(pEntry->vt & VT_BYREF));
  929.         memcpy(pbPropSetParams, pbParams, nParams);
  930.         pbParams = pbPropSetParams;
  931.  
  932.         VARTYPE vtProp = pEntry->vt;
  933. #if !defined(_UNICODE) && !defined(OLE2ANSI)
  934.         if (vtProp == VT_BSTR)
  935.             vtProp = VT_BSTRA;
  936. #endif
  937.         // VT_MFCVALUE serves serves as marker denoting start of named params
  938.         pbPropSetParams[nParams++] = (BYTE)VT_MFCMARKER;
  939.         pbPropSetParams[nParams++] = (BYTE)vtProp;
  940.         pbPropSetParams[nParams] = 0;
  941.  
  942.         // call "set" function instead of "get"
  943.         ASSERT(pEntry->pfnSet != NULL);
  944.         pfn = pEntry->pfnSet;
  945.         vtResult = VT_EMPTY;
  946.     }
  947.  
  948.     // allocate temporary space for VARIANT temps created by VariantChangeType
  949.     VARIANT* rgTempVars =
  950.         (VARIANT*)_alloca(pDispParams->cArgs * sizeof(VARIANT));
  951.     if (rgTempVars == NULL)
  952.     {
  953.         TRACE0("Error: stack overflow in IDispatch::Invoke!\n");
  954.         return E_OUTOFMEMORY;
  955.     }
  956.     memset(rgTempVars, 0, pDispParams->cArgs * sizeof(VARIANT));
  957.  
  958.     // determine size of arguments and allocate stack space
  959.     UINT nSizeArgs = GetStackSize(pbParams, vtResult);
  960.     ASSERT(nSizeArgs != 0);
  961.     if (nSizeArgs < _STACK_MIN)
  962.         nSizeArgs = _STACK_MIN;
  963.     BYTE* pStack = (BYTE*)_alloca(nSizeArgs + _SCRATCH_SIZE);
  964.     if (pStack == NULL)
  965.     {
  966.         TRACE0("Error: stack overflow in IDispatch::Invoke!\n");
  967.         return E_OUTOFMEMORY;
  968.     }
  969.  
  970.     // push all the args on to the stack allocated memory
  971.     AFX_RESULT result;
  972. #ifndef _SHADOW_DOUBLES
  973.     SCODE sc = PushStackArgs(pStack, pbParams, &result, vtResult,
  974.         pDispParams, puArgErr, rgTempVars);
  975. #else
  976.     SCODE sc = PushStackArgs(pStack, pbParams, &result, vtResult,
  977.         pDispParams, puArgErr, rgTempVars, nSizeArgs);
  978. #endif
  979.     pStack += _STACK_OFFSET;
  980.  
  981.     DWORD dwResult;
  982.     if (sc == S_OK)
  983.     {
  984.         TRY
  985.         {
  986.             // PushStackArgs will fail on argument mismatches
  987.             DWORD (AFXAPI *pfnDispatch)(AFX_PMSG, void*, UINT) =
  988.                 &_AfxDispatchCall;
  989.  
  990.             // floating point return values are a special case
  991.             switch (vtResult)
  992.             {
  993.             case VT_R4:
  994.                 result.fltVal = ((float (AFXAPI*)(AFX_PMSG, void*, UINT))
  995.                     pfnDispatch)(pfn, pStack, nSizeArgs);
  996.                 break;
  997.             case VT_R8:
  998.                 result.dblVal = ((double (AFXAPI*)(AFX_PMSG, void*, UINT))
  999.                     pfnDispatch)(pfn, pStack, nSizeArgs);
  1000.                 break;
  1001.             case VT_DATE:
  1002.                 result.dblVal = ((DATE (AFXAPI*)(AFX_PMSG, void*, UINT))
  1003.                     pfnDispatch)(pfn, pStack, nSizeArgs);
  1004.                 break;
  1005.  
  1006.             default:
  1007.                 dwResult = pfnDispatch(pfn, pStack, nSizeArgs);
  1008.                 break;
  1009.             }
  1010.         }
  1011.         CATCH_ALL(e)
  1012.         {
  1013.             // free temporaries created by VariantChangeType
  1014.             for (UINT iArg = 0; iArg < pDispParams->cArgs; ++iArg)
  1015.                 VariantClear(&rgTempVars[iArg]);
  1016.  
  1017.             THROW_LAST();
  1018.         }
  1019.         END_CATCH_ALL
  1020.     }
  1021.  
  1022.     // free temporaries created by VariantChangeType
  1023.     for (UINT iArg = 0; iArg < pDispParams->cArgs; ++iArg)
  1024.         VariantClear(&rgTempVars[iArg]);
  1025.  
  1026.     // handle error during PushStackParams
  1027.     if (sc != S_OK)
  1028.         return sc;
  1029.  
  1030.     // property puts don't touch the return value
  1031.     if (pvarResult != NULL)
  1032.     {
  1033.         // clear pvarResult just in case
  1034.         pvarResult->vt = vtResult;
  1035.  
  1036.         // build return value VARIANT from result union
  1037.         switch (vtResult)
  1038.         {
  1039.         case VT_UI2:
  1040.             pvarResult->bVal = (BYTE)dwResult;
  1041.             break;
  1042.         case VT_I2:
  1043.             pvarResult->iVal = (short)dwResult;
  1044.             break;
  1045.         case VT_I4:
  1046.             pvarResult->lVal = (long)dwResult;
  1047.             break;
  1048.         case VT_R4:
  1049.             pvarResult->fltVal = result.fltVal;
  1050.             break;
  1051.         case VT_R8:
  1052.             pvarResult->dblVal = result.dblVal;
  1053.             break;
  1054.         case VT_CY:
  1055.             pvarResult->cyVal = result.cyVal;
  1056.             break;
  1057.         case VT_DATE:
  1058.             pvarResult->date = result.dblVal;
  1059.             break;
  1060.         case VT_BSTR:
  1061.             pvarResult->bstrVal = (BSTR)dwResult;
  1062.             break;
  1063.         case VT_ERROR:
  1064.             pvarResult->scode = (SCODE)dwResult;
  1065.             break;
  1066.         case VT_BOOL:
  1067.             V_BOOL(pvarResult) = (VARIANT_BOOL)((BOOL)dwResult != 0 ? -1 : 0);
  1068.             break;
  1069.         case VT_VARIANT:
  1070.             *pvarResult = result.vaVal;
  1071.             break;
  1072.         case VT_DISPATCH:
  1073.         case VT_UNKNOWN:
  1074.             pvarResult->punkVal = (LPUNKNOWN)dwResult; // already AddRef
  1075.             break;
  1076.         }
  1077.     }
  1078.     else
  1079.     {
  1080.         // free unused return value
  1081.         switch (vtResult)
  1082.         {
  1083.         case VT_BSTR:
  1084.             if ((BSTR)dwResult != NULL)
  1085.                 SysFreeString((BSTR)dwResult);
  1086.             break;
  1087.         case VT_DISPATCH:
  1088.         case VT_UNKNOWN:
  1089.             if ((LPUNKNOWN)dwResult != 0)
  1090.                 ((LPUNKNOWN)dwResult)->Release();
  1091.             break;
  1092.         case VT_VARIANT:
  1093.             VariantClear(&result.vaVal);
  1094.             break;
  1095.         }
  1096.     }
  1097.  
  1098.     return S_OK;    // success!
  1099. }
  1100.  
  1101. /////////////////////////////////////////////////////////////////////////////
  1102. // CCmdTarget::XDispatch implementation
  1103.  
  1104. STDMETHODIMP_(ULONG) COleDispatchImpl::AddRef()
  1105. {
  1106.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1107.     return pThis->ExternalAddRef();
  1108. }
  1109.  
  1110. STDMETHODIMP_(ULONG) COleDispatchImpl::Release()
  1111. {
  1112.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1113.     return pThis->ExternalRelease();
  1114. }
  1115.  
  1116. STDMETHODIMP COleDispatchImpl::QueryInterface(REFIID iid, LPVOID* ppvObj)
  1117. {
  1118.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1119.     return pThis->ExternalQueryInterface(&iid, ppvObj);
  1120. }
  1121.  
  1122. STDMETHODIMP COleDispatchImpl::GetTypeInfoCount(UINT* pctinfo)
  1123. {
  1124.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1125.     *pctinfo = pThis->GetTypeInfoCount();
  1126.     return S_OK;
  1127. }
  1128.  
  1129. STDMETHODIMP COleDispatchImpl::GetTypeInfo(UINT itinfo, LCID lcid,
  1130.     ITypeInfo** pptinfo)
  1131. {
  1132.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1133.     ASSERT_POINTER(pptinfo, LPTYPEINFO);
  1134.  
  1135.     if (itinfo != 0)
  1136.         return E_INVALIDARG;
  1137.  
  1138.     IID iid;
  1139.     if (!pThis->GetDispatchIID(&iid))
  1140.         return E_NOTIMPL;
  1141.  
  1142.     return pThis->GetTypeInfoOfGuid(lcid, iid, pptinfo);
  1143. }
  1144.  
  1145. STDMETHODIMP COleDispatchImpl::GetIDsOfNames(
  1146.     REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
  1147. {
  1148.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1149.     ASSERT_POINTER(rgszNames, char*);
  1150.     ASSERT_POINTER(rgdispid, DISPID);
  1151.  
  1152.     USES_CONVERSION;
  1153.  
  1154.     // check arguments
  1155.     if (riid != IID_NULL)
  1156.         return DISP_E_UNKNOWNINTERFACE;
  1157.  
  1158.     SCODE sc;
  1159.     LPTYPEINFO lpTypeInfo = NULL;
  1160.     if (lcid != 0 && SUCCEEDED(sc = GetTypeInfo(0, lcid, &lpTypeInfo)))
  1161.     {
  1162.         // For non-zero lcid, let typeinfo do the work (when available)
  1163.         ASSERT(lpTypeInfo != NULL);
  1164.         sc = lpTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
  1165.         lpTypeInfo->Release();
  1166.         if (sc == TYPE_E_ELEMENTNOTFOUND)
  1167.             sc = DISP_E_UNKNOWNNAME;
  1168.     }
  1169.     else
  1170.     {
  1171.         // fill in the member name
  1172.         const AFX_DISPMAP* pDerivMap = pThis->GetDispatchMap();
  1173.         rgdispid[0] = pThis->MemberIDFromName(pDerivMap, OLE2CT(rgszNames[0]));
  1174.         if (rgdispid[0] == DISPID_UNKNOWN)
  1175.             sc = DISP_E_UNKNOWNNAME;
  1176.         else
  1177.             sc = S_OK;
  1178.  
  1179.         // argument names are always DISPID_UNKNOWN (for this implementation)
  1180.         for (UINT nIndex = 1; nIndex < cNames; nIndex++)
  1181.             rgdispid[nIndex] = DISPID_UNKNOWN;
  1182.     }
  1183.  
  1184.     return sc;
  1185. }
  1186.  
  1187. STDMETHODIMP COleDispatchImpl::Invoke(
  1188.     DISPID dispid, REFIID riid, LCID lcid,
  1189.     WORD wFlags, DISPPARAMS* pDispParams, LPVARIANT pvarResult,
  1190.     LPEXCEPINFO pexcepinfo, UINT* puArgErr)
  1191. {
  1192.     METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
  1193.     ASSERT_NULL_OR_POINTER(pvarResult, VARIANT);
  1194.     ASSERT_NULL_OR_POINTER(pexcepinfo, EXCEPINFO);
  1195.     ASSERT_NULL_OR_POINTER(puArgErr, UINT);
  1196.  
  1197.     // make sure pvarResult is initialized
  1198.     if (pvarResult != NULL)
  1199.         AfxVariantInit(pvarResult);
  1200.  
  1201.     // check arguments
  1202.     if (riid != IID_NULL)
  1203.         return DISP_E_UNKNOWNINTERFACE;
  1204.  
  1205.     // allow subclass to disable Invoke
  1206.     if (!pThis->IsInvokeAllowed(dispid))
  1207.         return E_UNEXPECTED;
  1208.  
  1209.     // copy param block for safety
  1210.     DISPPARAMS params = *pDispParams;
  1211.     pDispParams = ¶ms;
  1212.  
  1213.     // most of the time, named arguments are not supported
  1214.     if (pDispParams->cNamedArgs != 0)
  1215.     {
  1216.         // only special PROPERTYPUT named argument is allowed
  1217.         if (pDispParams->cNamedArgs != 1 ||
  1218.             pDispParams->rgdispidNamedArgs[0] != DISPID_PROPERTYPUT)
  1219.         {
  1220.             return DISP_E_NONAMEDARGS;
  1221.         }
  1222.     }
  1223.  
  1224.     // get entry for the member ID
  1225.     const AFX_DISPMAP_ENTRY* pEntry = pThis->GetDispEntry(dispid);
  1226.     if (pEntry == NULL)
  1227.         return DISP_E_MEMBERNOTFOUND;
  1228.  
  1229.     // treat member calls on properties just like property get/set
  1230.     if ((wFlags == DISPATCH_METHOD) &&
  1231.         ((pEntry->pfn == NULL && pEntry->pfnSet == NULL) ||
  1232.          (pEntry->pfn == NULL && pEntry->pfnSet != NULL) ||
  1233.          (pEntry->pfn != NULL && pEntry->pfnSet != NULL)))
  1234.     {
  1235.         // the entry describes a property but a method call is being
  1236.         //  attempted -- change it to a property get/set based on the
  1237.         //  number of parameters being passed.
  1238.         wFlags &= ~DISPATCH_METHOD;
  1239.         UINT nExpectedArgs = pEntry->lpszParams != NULL ?
  1240.             (UINT)lstrlenA(pEntry->lpszParams) : 0;
  1241.         if (pDispParams->cArgs <= nExpectedArgs)
  1242.         {
  1243.             // no extra param -- so treat as property get
  1244.             wFlags |= DISPATCH_PROPERTYGET;
  1245.         }
  1246.         else
  1247.         {
  1248.             // extra params -- treat as property set
  1249.             wFlags |= DISPATCH_PROPERTYPUTREF;
  1250.             pDispParams->cNamedArgs = 1;
  1251.         }
  1252.     }
  1253.  
  1254.     // property puts should not require a return value
  1255.     if (wFlags & (DISPATCH_PROPERTYPUTREF|DISPATCH_PROPERTYPUT))
  1256.     {
  1257.         pvarResult = NULL;
  1258.         // catch attempt to do property set on method
  1259.         if (pEntry->pfn != NULL && pEntry->pfnSet == NULL)
  1260.             return DISP_E_TYPEMISMATCH;
  1261.     }
  1262.  
  1263.     UINT uArgErr = (UINT)-1;    // no error yet
  1264.     SCODE sc = S_OK;
  1265.  
  1266.     // handle special cases of DISPATCH_PROPERTYPUT
  1267.     VARIANT* pvarParamSave = NULL;
  1268.     VARIANT vaParamSave;
  1269.     DISPPARAMS paramsTemp;
  1270.     VARIANT vaTemp;
  1271.     AfxVariantInit(&vaTemp);
  1272.  
  1273.     if (wFlags == DISPATCH_PROPERTYPUT && dispid != DISPID_VALUE)
  1274.     {
  1275.         // with PROPERTYPUT (no REF), the right hand side may need fixup
  1276.         if (pDispParams->rgvarg[0].vt == VT_DISPATCH &&
  1277.             pDispParams->rgvarg[0].pdispVal != NULL)
  1278.         {
  1279.             // remember old value for restore later
  1280.             pvarParamSave = &pDispParams->rgvarg[0];
  1281.             vaParamSave = pDispParams->rgvarg[0];
  1282.             AfxVariantInit(&pDispParams->rgvarg[0]);
  1283.  
  1284.             // get default value of right hand side
  1285.             memset(¶msTemp, 0, sizeof(DISPPARAMS));
  1286.             sc = vaParamSave.pdispVal->Invoke(
  1287.                 DISPID_VALUE, riid, lcid, DISPATCH_PROPERTYGET, ¶msTemp,
  1288.                 &pDispParams->rgvarg[0], pexcepinfo, puArgErr);
  1289.         }
  1290.  
  1291.         // special handling for PROPERTYPUT (no REF), left hand side
  1292.         if (sc == S_OK && pEntry->vt == VT_DISPATCH)
  1293.         {
  1294.             memset(¶msTemp, 0, sizeof(DISPPARAMS));
  1295.  
  1296.             // parameters are distributed depending on what the Get expects
  1297.             if (pEntry->lpszParams == NULL)
  1298.             {
  1299.                 // paramsTemp is already setup for no parameters
  1300.                 sc = Invoke(dispid, riid, lcid,
  1301.                     DISPATCH_PROPERTYGET|DISPATCH_METHOD, ¶msTemp,
  1302.                     &vaTemp, pexcepinfo, puArgErr);
  1303.                 if (sc == S_OK &&
  1304.                     (vaTemp.vt != VT_DISPATCH || vaTemp.pdispVal == NULL))
  1305.                     sc = DISP_E_TYPEMISMATCH;
  1306.                 else if (sc == S_OK)
  1307.                 {
  1308.                     ASSERT(vaTemp.vt == VT_DISPATCH && vaTemp.pdispVal != NULL);
  1309.                     // we have the result, now call put on the default property
  1310.                     sc = vaTemp.pdispVal->Invoke(
  1311.                         DISPID_VALUE, riid, lcid, wFlags, pDispParams,
  1312.                         pvarResult, pexcepinfo, puArgErr);
  1313.                 }
  1314.             }
  1315.             else
  1316.             {
  1317.                 // pass all but named params
  1318.                 paramsTemp.rgvarg = &pDispParams->rgvarg[1];
  1319.                 paramsTemp.cArgs = pDispParams->cArgs - 1;
  1320.                 sc = Invoke(dispid, riid, lcid,
  1321.                     DISPATCH_PROPERTYGET|DISPATCH_METHOD, ¶msTemp,
  1322.                     &vaTemp, pexcepinfo, puArgErr);
  1323.                 if (sc == S_OK &&
  1324.                     (vaTemp.vt != VT_DISPATCH || vaTemp.pdispVal == NULL))
  1325.                     sc = DISP_E_TYPEMISMATCH;
  1326.                 else if (sc == S_OK)
  1327.                 {
  1328.                     ASSERT(vaTemp.vt == VT_DISPATCH && vaTemp.pdispVal != NULL);
  1329.  
  1330.                     // we have the result, now call put on the default property
  1331.                     paramsTemp = *pDispParams;
  1332.                     paramsTemp.cArgs = paramsTemp.cNamedArgs;
  1333.                     sc = vaTemp.pdispVal->Invoke(
  1334.                         DISPID_VALUE, riid, lcid, wFlags, ¶msTemp,
  1335.                         pvarResult, pexcepinfo, puArgErr);
  1336.                 }
  1337.             }
  1338.             VariantClear(&vaTemp);
  1339.  
  1340.             if (sc != DISP_E_MEMBERNOTFOUND)
  1341.                 goto Cleanup;
  1342.         }
  1343.  
  1344.         if (sc != S_OK && sc != DISP_E_MEMBERNOTFOUND)
  1345.             goto Cleanup;
  1346.     }
  1347.  
  1348.     // ignore DISP_E_MEMBERNOTFOUND from above
  1349.     ASSERT(sc == DISP_E_MEMBERNOTFOUND || sc == S_OK);
  1350.  
  1351.     // undo implied default value on right hand side on error
  1352.     if (sc != S_OK && pvarParamSave != NULL)
  1353.     {
  1354.         // default value stuff failed -- so try without default value
  1355.         pvarParamSave = NULL;
  1356.         VariantClear(&pDispParams->rgvarg[0]);
  1357.         pDispParams->rgvarg[0] = vaParamSave;
  1358.     }
  1359.     sc = S_OK;
  1360.  
  1361.     // check arguments against this entry
  1362.     UINT nOrigArgs; nOrigArgs = pDispParams->cArgs;
  1363.     if (wFlags & (DISPATCH_PROPERTYGET|DISPATCH_METHOD))
  1364.     {
  1365.         if (!(wFlags & DISPATCH_METHOD))
  1366.         {
  1367.             if (pEntry->vt == VT_EMPTY)
  1368.                 return DISP_E_BADPARAMCOUNT;
  1369.             if (pvarResult == NULL)
  1370.                 return DISP_E_PARAMNOTOPTIONAL;
  1371.         }
  1372.         if (pEntry->lpszParams == NULL && pDispParams->cArgs > 0)
  1373.         {
  1374.             if (pEntry->vt != VT_DISPATCH)
  1375.                 return DISP_E_BADPARAMCOUNT;
  1376.  
  1377.             // it is VT_DISPATCH property/method but too many arguments supplied
  1378.             // transfer those arguments to the default property of the return value
  1379.             // after getting the return value from this call.  This is referred
  1380.             // to as collection lookup.
  1381.             pDispParams->cArgs = 0;
  1382.             if (pvarResult == NULL)
  1383.                 pvarResult = &vaTemp;
  1384.         }
  1385.     }
  1386.  
  1387.     // make sure that parameters are not passed to a simple property
  1388.     if (pDispParams->cArgs > 1 &&
  1389.         (wFlags & (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF)) &&
  1390.         pEntry->pfn == NULL)
  1391.     {
  1392.         sc = DISP_E_BADPARAMCOUNT;
  1393.         goto Cleanup;
  1394.     }
  1395.  
  1396.     // make sure that pvarResult is set for simple property get
  1397.     if (pEntry->pfn == NULL && pDispParams->cArgs == 0 && pvarResult == NULL)
  1398.     {
  1399.         sc = DISP_E_PARAMNOTOPTIONAL;
  1400.         goto Cleanup;
  1401.     }
  1402.  
  1403.     // make sure IsExpectingResult returns FALSE as appropriate
  1404.     BOOL bResultExpected;
  1405.     bResultExpected = pThis->m_bResultExpected;
  1406.     pThis->m_bResultExpected = pvarResult != NULL;
  1407.  
  1408.     TRY
  1409.     {
  1410.         if (pEntry->pfn == NULL)
  1411.         {
  1412.             // do standard property get/set
  1413.             if (pDispParams->cArgs == 0)
  1414.                 pThis->GetStandardProp(pEntry, pvarResult, &uArgErr);
  1415.             else
  1416.                 sc = pThis->SetStandardProp(pEntry, pDispParams, &uArgErr);
  1417.         }
  1418.         else
  1419.         {
  1420.             // do standard method call
  1421.             sc = pThis->CallMemberFunc(pEntry, wFlags,
  1422.                 pvarResult, pDispParams, &uArgErr);
  1423.         }
  1424.     }
  1425.     CATCH(COleException, e)
  1426.     {
  1427.         sc = e->m_sc;
  1428.         DELETE_EXCEPTION(e);
  1429.     }
  1430.     AND_CATCH_ALL(e)
  1431.     {
  1432.         AFX_MANAGE_STATE(pThis->m_pModuleState);
  1433.         if (pexcepinfo != NULL)
  1434.         {
  1435.             // fill exception with translation of MFC exception
  1436.             COleDispatchException::Process(pexcepinfo, e);
  1437.         }
  1438.         DELETE_EXCEPTION(e);
  1439.         sc = DISP_E_EXCEPTION;
  1440.     }
  1441.     END_CATCH_ALL
  1442.  
  1443.     // restore original m_bResultExpected flag
  1444.     pThis->m_bResultExpected = bResultExpected;
  1445.  
  1446.     // handle special DISPATCH_PROPERTYGET collection lookup case
  1447.     if (sc == S_OK && nOrigArgs > pDispParams->cArgs)
  1448.     {
  1449.         ASSERT(wFlags & (DISPATCH_PROPERTYGET|DISPATCH_METHOD));
  1450.         ASSERT(pvarResult != NULL);
  1451.         // must be non-NULL dispatch, otherwise type mismatch
  1452.         if (pvarResult->vt != VT_DISPATCH || pvarResult->pdispVal == NULL)
  1453.         {
  1454.             sc = DISP_E_TYPEMISMATCH;
  1455.             goto Cleanup;
  1456.         }
  1457.         // otherwise, valid VT_DISPATCH was returned
  1458.         pDispParams->cArgs = nOrigArgs;
  1459.         LPDISPATCH lpTemp = pvarResult->pdispVal;
  1460.         if (pvarResult != &vaTemp)
  1461.             AfxVariantInit(pvarResult);
  1462.         else
  1463.             pvarResult = NULL;
  1464.         sc = lpTemp->Invoke(DISPID_VALUE, riid, lcid, wFlags,
  1465.             pDispParams, pvarResult, pexcepinfo, puArgErr);
  1466.         lpTemp->Release();
  1467.     }
  1468.  
  1469. Cleanup:
  1470.     // restore any arguments which were modified
  1471.     if (pvarParamSave != NULL)
  1472.     {
  1473.         VariantClear(&pDispParams->rgvarg[0]);
  1474.         pDispParams->rgvarg[0] = vaParamSave;
  1475.     }
  1476.  
  1477.     // fill error argument if one is available
  1478.     if (sc != S_OK && puArgErr != NULL && uArgErr != -1)
  1479.         *puArgErr = uArgErr;
  1480.  
  1481.     return sc;
  1482. }
  1483.  
  1484. /////////////////////////////////////////////////////////////////////////////
  1485. // IDispatch specific exception
  1486.  
  1487. COleDispatchException::~COleDispatchException()
  1488. {
  1489.     // destructor code is compiler generated
  1490. }
  1491.  
  1492. void PASCAL COleDispatchException::Process(
  1493.     EXCEPINFO* pInfo, const CException* pAnyException)
  1494. {
  1495.     USES_CONVERSION;
  1496.  
  1497.     ASSERT(AfxIsValidAddress(pInfo, sizeof(EXCEPINFO)));
  1498.     ASSERT_VALID(pAnyException);
  1499.  
  1500.     // zero default & reserved members
  1501.     memset(pInfo, 0, sizeof(EXCEPINFO));
  1502.  
  1503.     // get description based on type of exception
  1504.     TCHAR szDescription[256];
  1505.     LPCTSTR pszDescription = szDescription;
  1506.     if (pAnyException->IsKindOf(RUNTIME_CLASS(COleDispatchException)))
  1507.     {
  1508.         // specific IDispatch style exception
  1509.         COleDispatchException* e = (COleDispatchException*)pAnyException;
  1510.         pszDescription = e->m_strDescription;
  1511.         pInfo->wCode = e->m_wCode;
  1512.         pInfo->dwHelpContext = e->m_dwHelpContext;
  1513.         pInfo->scode = e->m_scError;
  1514.  
  1515.         // propagate source and help file if present
  1516.         if (!e->m_strHelpFile.IsEmpty())
  1517.             pInfo->bstrHelpFile = ::SysAllocString(T2COLE(e->m_strHelpFile));
  1518.         if (!e->m_strSource.IsEmpty())
  1519.             pInfo->bstrSource = ::SysAllocString(T2COLE(e->m_strSource));
  1520.     }
  1521.     else if (pAnyException->IsKindOf(RUNTIME_CLASS(CMemoryException)))
  1522.     {
  1523.         // failed memory allocation
  1524.         AfxLoadString(AFX_IDP_FAILED_MEMORY_ALLOC, szDescription);
  1525.         pInfo->wCode = AFX_IDP_FAILED_MEMORY_ALLOC;
  1526.     }
  1527.     else
  1528.     {
  1529.         // other unknown/uncommon error
  1530.         AfxLoadString(AFX_IDP_INTERNAL_FAILURE, szDescription);
  1531.         pInfo->wCode = AFX_IDP_INTERNAL_FAILURE;
  1532.     }
  1533.  
  1534.     // build up rest of EXCEPINFO struct
  1535.     pInfo->bstrDescription = ::SysAllocString(T2COLE(pszDescription));
  1536.     if (pInfo->bstrSource == NULL)
  1537.         pInfo->bstrSource = ::SysAllocString(T2COLE(AfxGetAppName()));
  1538.     if (pInfo->bstrHelpFile == NULL && pInfo->dwHelpContext != 0)
  1539.         pInfo->bstrHelpFile = ::SysAllocString(T2COLE(AfxGetApp()->m_pszHelpFilePath));
  1540. }
  1541.  
  1542. COleDispatchException::COleDispatchException(
  1543.     LPCTSTR lpszDescription, UINT nHelpID, WORD wCode)
  1544. {
  1545.     m_dwHelpContext = nHelpID != 0 ? HID_BASE_DISPATCH+nHelpID : 0;
  1546.     m_wCode = wCode;
  1547.     if (lpszDescription != NULL)
  1548.         m_strDescription = lpszDescription;
  1549.     m_scError = wCode != 0 ? NOERROR : E_UNEXPECTED;
  1550. }
  1551.  
  1552. COleDispatchException::GetErrorMessage(LPTSTR lpszError, UINT nMaxError,
  1553.         PUINT pnHelpContext)
  1554. {
  1555.     ASSERT(lpszError != NULL && AfxIsValidString(lpszError, nMaxError));
  1556.  
  1557.     if (pnHelpContext != NULL)
  1558.         *pnHelpContext = 0;
  1559.  
  1560.     lstrcpyn(lpszError, m_strDescription, nMaxError);
  1561.     return TRUE;
  1562. }
  1563.  
  1564. void AFXAPI AfxThrowOleDispatchException(WORD wCode, LPCTSTR lpszDescription,
  1565.     UINT nHelpID)
  1566. {
  1567.     ASSERT(AfxIsValidString(lpszDescription));
  1568.     THROW(new COleDispatchException(lpszDescription, nHelpID, wCode));
  1569. }
  1570.  
  1571. void AFXAPI AfxThrowOleDispatchException(WORD wCode, UINT nDescriptionID,
  1572.     UINT nHelpID)
  1573. {
  1574.     TCHAR szBuffer[256];
  1575.     VERIFY(AfxLoadString(nDescriptionID, szBuffer) != 0);
  1576.     if (nHelpID == -1)
  1577.         nHelpID = nDescriptionID;
  1578.     THROW(new COleDispatchException(szBuffer, nHelpID, wCode));
  1579. }
  1580.  
  1581. #ifdef AFX_INIT_SEG
  1582. #pragma code_seg(AFX_INIT_SEG)
  1583. #endif
  1584.  
  1585. IMPLEMENT_DYNAMIC(COleDispatchException, CException)
  1586.  
  1587. /////////////////////////////////////////////////////////////////////////////
  1588.