/wcwp/bin/VC6CMD/MFC/SRC/OLEDISP1.CPP

http://wcwp.googlecode.com/ · C++ · 1592 lines · 1252 code · 165 blank · 175 comment · 348 complexity · 89f9fd28753ed7eced718cd0378d2cd1 MD5 · raw file

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