// invoke standard method given IDispatch parameters/return value, etc. SCODE CCmdTarget::CallMemberFunc(const AFX_DISPMAP_ENTRY* pEntry, WORD wFlags, VARIANT* pvarResult, DISPPARAMS* pDispParams, UINT* puArgErr) { AFX_MANAGE_STATE(m_pModuleState); ASSERT(pEntry != NULL); ASSERT(pEntry->pfn != NULL); // special union used only to hold largest return value possible union AFX_RESULT { VARIANT vaVal; CY cyVal; float fltVal; double dblVal; DWORD nVal; }; // get default function and parameters BYTE bNoParams = 0; const BYTE* pbParams = (const BYTE*)pEntry->lpszParams; if (pbParams == NULL) pbParams = &bNoParams; UINT nParams = lstrlenA((LPCSTR)pbParams); // get default function and return value information AFX_PMSG pfn = pEntry->pfn; VARTYPE vtResult = pEntry->vt; // make DISPATCH_PROPERTYPUT look like call with one extra parameter if (wFlags & (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF)) { BYTE* pbPropSetParams = (BYTE*)_alloca(nParams+3); ASSERT(pbPropSetParams != NULL); // stack overflow? ASSERT(!(pEntry->vt & VT_BYREF)); memcpy(pbPropSetParams, pbParams, nParams); pbParams = pbPropSetParams; VARTYPE vtProp = pEntry->vt; #if !defined(_UNICODE) && !defined(OLE2ANSI) if (vtProp == VT_BSTR) vtProp = VT_BSTRA; #endif // VT_MFCVALUE serves serves as marker denoting start of named params pbPropSetParams[nParams++] = (BYTE)VT_MFCMARKER; pbPropSetParams[nParams++] = (BYTE)vtProp; pbPropSetParams[nParams] = 0; // call "set" function instead of "get" ASSERT(pEntry->pfnSet != NULL); pfn = pEntry->pfnSet; vtResult = VT_EMPTY; } // allocate temporary space for VARIANT temps created by VariantChangeType VARIANT* rgTempVars = (VARIANT*)_alloca(pDispParams->cArgs * sizeof(VARIANT)); if (rgTempVars == NULL) { TRACE0("Error: stack overflow in IDispatch::Invoke!\n"); return E_OUTOFMEMORY; } memset(rgTempVars, 0, pDispParams->cArgs * sizeof(VARIANT)); // determine size of arguments and allocate stack space UINT nSizeArgs = GetStackSize(pbParams, vtResult); ASSERT(nSizeArgs != 0); if (nSizeArgs < _STACK_MIN) nSizeArgs = _STACK_MIN; BYTE* pStack = (BYTE*)_alloca(nSizeArgs + _SCRATCH_SIZE); if (pStack == NULL) { TRACE0("Error: stack overflow in IDispatch::Invoke!\n"); return E_OUTOFMEMORY; } // push all the args on to the stack allocated memory AFX_RESULT result; #ifndef _SHADOW_DOUBLES SCODE sc = PushStackArgs(pStack, pbParams, &result, vtResult, pDispParams, puArgErr, rgTempVars); #else SCODE sc = PushStackArgs(pStack, pbParams, &result, vtResult, pDispParams, puArgErr, rgTempVars, nSizeArgs); #endif pStack += _STACK_OFFSET; DWORD dwResult = 0; if (sc == S_OK) { TRY { // PushStackArgs will fail on argument mismatches DWORD (AFXAPI *pfnDispatch)(AFX_PMSG, void*, UINT) = &_AfxDispatchCall; // floating point return values are a special case switch (vtResult) { case VT_R4: result.fltVal = ((float (AFXAPI*)(AFX_PMSG, void*, UINT)) pfnDispatch)(pfn, pStack, nSizeArgs); break; case VT_R8: result.dblVal = ((double (AFXAPI*)(AFX_PMSG, void*, UINT)) pfnDispatch)(pfn, pStack, nSizeArgs); break; case VT_DATE: result.dblVal = ((DATE (AFXAPI*)(AFX_PMSG, void*, UINT)) pfnDispatch)(pfn, pStack, nSizeArgs); break; default: dwResult = pfnDispatch(pfn, pStack, nSizeArgs); break; } } CATCH_ALL(e) { // free temporaries created by VariantChangeType for (UINT iArg = 0; iArg < pDispParams->cArgs; ++iArg) VariantClear(&rgTempVars[iArg]); THROW_LAST(); } END_CATCH_ALL }
// invoke standard method given IDispatch parameters/return value, etc. SCODE CCmdTarget::CallMemberFunc(const AFX_DISPMAP_ENTRY* pEntry, WORD wFlags, VARIANT* pvarResult, DISPPARAMS* pDispParams, UINT* puArgErr) { ASSERT(pEntry != NULL); ASSERT(pEntry->pfn != NULL); // special union used only to hold largest return value possible union AFX_RESULT { VARIANT vaVal; CY cyVal; float fltVal; double dblVal; DWORD nVal; }; // get default function and parameters BYTE bNoParams = 0; const BYTE* pbParams = (const BYTE*)pEntry->lpszParams; if (pbParams == NULL) pbParams = &bNoParams; UINT nParams = lstrlenA((LPCSTR)pbParams); // get default function and return value information AFX_PMSG pfn = pEntry->pfn; VARTYPE vtResult = pEntry->vt; // make DISPATCH_PROPERTYPUT look like call with one extra parameter if (wFlags & (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF)) { BYTE* pbPropSetParams = (BYTE*)_alloca(nParams+3); ASSERT(pbPropSetParams != NULL); // stack overflow? ASSERT(!(pEntry->vt & VT_BYREF)); memcpy(pbPropSetParams, pbParams, nParams); pbParams = pbPropSetParams; // VT_MFCVALUE serves serves as marker denoting start of named params pbPropSetParams[nParams++] = (BYTE)VT_MFCMARKER; pbPropSetParams[nParams++] = (BYTE)pEntry->vt; pbPropSetParams[nParams] = 0; if (pEntry->pfnSet != NULL) { pfn = pEntry->pfnSet; // call "set" function instead of "get" vtResult = VT_EMPTY; } } // allocate temporary space for VARIANT temps created by VariantChangeType VARIANT* rgTempVars = (VARIANT*)_alloca(pDispParams->cArgs * sizeof(VARIANT)); if (rgTempVars == NULL) { TRACE0("Error: stack overflow in IDispatch::Invoke!\n"); return E_OUTOFMEMORY; } memset(rgTempVars, 0, pDispParams->cArgs * sizeof(VARIANT)); // determine size of arguments and allocate stack space UINT nSizeArgs = GetStackSize(pbParams, vtResult); ASSERT(nSizeArgs != 0); if (nSizeArgs < _STACK_MIN) nSizeArgs = _STACK_MIN; BYTE* pStack = (BYTE*)_alloca(nSizeArgs + _SCRATCH_SIZE); if (pStack == NULL) { TRACE0("Error: stack overflow in IDispatch::Invoke!\n"); return E_OUTOFMEMORY; } // push all the args on to the stack allocated memory AFX_RESULT result; #ifndef _SHADOW_DOUBLES SCODE sc = PushStackArgs(pStack, pbParams, &result, vtResult, pDispParams, puArgErr, rgTempVars); #else SCODE sc = PushStackArgs(pStack, pbParams, &result, vtResult, pDispParams, puArgErr, rgTempVars, nSizeArgs); #endif // PushStackArgs will fail on argument mismatches DWORD dwResult; if (sc == S_OK) { DWORD (AFXAPI *pfnDispatch)(AFX_PMSG, void*, UINT) = &_AfxDispatchCall; // floating point return values are a special case switch (vtResult) { case VT_R4: result.fltVal = ((float (AFXAPI*)(AFX_PMSG, void*, UINT)) pfnDispatch)(pfn, pStack, nSizeArgs); break; case VT_R8: result.dblVal = ((double (AFXAPI*)(AFX_PMSG, void*, UINT)) pfnDispatch)(pfn, pStack, nSizeArgs); break; case VT_DATE: result.dblVal = ((DATE (AFXAPI*)(AFX_PMSG, void*, UINT)) pfnDispatch)(pfn, pStack, nSizeArgs); break; default: dwResult = pfnDispatch(pfn, pStack, nSizeArgs); break; } } // free temporaries created by VariantChangeType for (UINT iArg = 0; iArg < pDispParams->cArgs; ++iArg) VariantClear(&rgTempVars[iArg]); // handle error during PushStackParams if (sc != S_OK) return sc; // property puts don't touch the return value if (pvarResult != NULL) { // clear pvarResult just in case VariantClear(pvarResult); pvarResult->vt = vtResult; // build return value VARIANT from result union switch (vtResult) { case VT_I2: pvarResult->iVal = (short)dwResult; break; case VT_I4: pvarResult->lVal = (long)dwResult; break; case VT_R4: pvarResult->fltVal = result.fltVal; break; case VT_R8: pvarResult->dblVal = result.dblVal; break; case VT_CY: pvarResult->cyVal = result.cyVal; break; case VT_DATE: pvarResult->date = result.dblVal; break; case VT_BSTR: pvarResult->bstrVal = (BSTR)dwResult; break; case VT_ERROR: pvarResult->scode = (SCODE)dwResult; break; case VT_BOOL: pvarResult->boolVal = (VARIANT_BOOL)((BOOL)dwResult != 0 ? -1 : 0); break; case VT_VARIANT: *pvarResult = result.vaVal; break; case VT_DISPATCH: case VT_UNKNOWN: pvarResult->punkVal = (LPUNKNOWN)dwResult; // already AddRef break; } } else { // free unused return value switch (vtResult) { case VT_BSTR: if ((BSTR)dwResult != NULL) SysFreeString((BSTR)dwResult); break; case VT_DISPATCH: case VT_UNKNOWN: if ((LPUNKNOWN)dwResult != 0) ((LPUNKNOWN)dwResult)->Release(); break; case VT_VARIANT: VariantClear(&result.vaVal); break; } } return S_OK; // success! }