Esempio n. 1
0
// 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
	}
Esempio n. 2
0
// 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!
}