📄 oledisp1.cpp
字号:
nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
#endif
// count bytes in return value
ASSERT((UINT)vtResult < _countof(_afxRetVal));
nCount += _afxRetVal[vtResult];
#ifdef _ALIGN_STACK
nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
#endif
// count arguments
ASSERT(pbParams != NULL);
while (*pbParams != 0)
{
if (*pbParams != VT_MFCMARKER)
{
// align if necessary
// get and add appropriate byte count
const UINT* rgnBytes;
if (*pbParams & VT_MFCBYREF)
rgnBytes = _afxByRef;
else
rgnBytes = _afxByValue;
ASSERT((*pbParams & ~VT_MFCBYREF) < _countof(_afxByValue));
#ifdef _ALIGN_DOUBLES
// align doubles on 8 byte for some platforms
if (*pbParams == VT_R8)
nCount = (nCount + _ALIGN_DOUBLES-1) & ~(_ALIGN_DOUBLES-1);
#endif
nCount += rgnBytes[*pbParams & ~VT_MFCBYREF];
#ifdef _ALIGN_STACK
nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
#endif
}
++pbParams;
}
#if defined(_ALIGN_DOUBLES) && defined(_SHADOW_DOUBLES)
// align doubles on 8 byte for some platforms
nCount = (nCount + _ALIGN_DOUBLES-1) & ~(_ALIGN_DOUBLES-1);
#endif
return nCount;
}
// push arguments on stack appropriate for C++ call (compiler dependent)
#ifndef _SHADOW_DOUBLES
SCODE CCmdTarget::PushStackArgs(BYTE* pStack, const BYTE* pbParams,
void* pResult, VARTYPE vtResult, DISPPARAMS* pDispParams, UINT* puArgErr,
VARIANT* rgTempVars)
#else
SCODE CCmdTarget::PushStackArgs(BYTE* pStack, const BYTE* pbParams,
void* pResult, VARTYPE vtResult, DISPPARAMS* pDispParams, UINT* puArgErr,
VARIANT* rgTempVars, UINT nSizeArgs)
#endif
{
ASSERT(pStack != NULL);
ASSERT(pResult != NULL);
ASSERT(pDispParams != NULL);
ASSERT(puArgErr != NULL);
#ifdef _SHADOW_DOUBLES
double* pDoubleShadow = (double*)(pStack + nSizeArgs);
double* pDoubleShadowMax = pDoubleShadow + _SHADOW_DOUBLES;
#endif
// C++ member functions use the __thiscall convention, where parameters
// are pushed last to first. Assuming the stack grows down, this means
// that the first parameter is at the lowest memory address in the
// stack frame and the last parameter is at the highest address.
#ifdef _RETVAL_FIRST
// push any necessary return value stuff on the stack (pre args)
// (an ambient pointer is pushed to stack relative data)
if (vtResult == VT_CY || vtResult == VT_VARIANT)
{
#ifdef _ALIGN_STACK
ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
#endif
*(_STACK_PTR*)pStack = (_STACK_PTR)pResult;
pStack += sizeof(_STACK_PTR);
#ifdef _ALIGN_STACK
ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
#endif
}
#endif //_RETVAL_FIRST
// push the 'this' pointer
#ifdef _ALIGN_STACK
ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
#endif
*(_STACK_PTR*)pStack = (_STACK_PTR)this;
pStack += sizeof(_STACK_PTR);
#ifdef _ALIGN_STACK
ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
#endif
#ifndef _RETVAL_FIRST
// push any necessary return value stuff on the stack (post args)
// (an ambient pointer is pushed to stack relative data)
if (vtResult == VT_CY || vtResult == VT_VARIANT)
{
#ifdef _ALIGN_STACK
ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
#endif
*(_STACK_PTR*)pStack = (_STACK_PTR)pResult;
pStack += sizeof(_STACK_PTR);
#ifdef _ALIGN_STACK
ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
#endif
}
#endif //!_RETVAL_FIRST
// push the arguments (first to last, low address to high address)
VARIANT* pArgs = pDispParams->rgvarg;
BOOL bNamedArgs = FALSE;
int iArg = pDispParams->cArgs; // start with positional arguments
int iArgMin = pDispParams->cNamedArgs;
ASSERT(pbParams != NULL);
for (const BYTE* pb = pbParams; *pb != '\0'; ++pb)
{
--iArg; // move to next arg
// convert MFC parameter type to IDispatch VARTYPE
VARTYPE vt = *pb;
if (vt != VT_MFCMARKER && (vt & VT_MFCBYREF))
vt = (VARTYPE)((vt & ~VT_MFCBYREF) | VT_BYREF);
VARIANT* pArg;
if (iArg >= iArgMin)
{
// hit named args before using all positional args?
if (vt == VT_MFCMARKER)
break;
// argument specified by caller -- use it
pArg = &pArgs[iArg];
if (vt != VT_VARIANT && vt != pArg->vt)
{
// argument is not of appropriate type, attempt to coerce it
VARIANT* pArgTemp = &rgTempVars[iArg];
ASSERT(pArgTemp->vt == VT_EMPTY);
#if defined(_UNICODE) || defined(OLE2ANSI)
VARTYPE vtTarget = vt;
#else
VARTYPE vtTarget = (VARTYPE) ((vt == VT_BSTRA) ? VT_BSTR : vt);
#endif
if (pArg->vt != vtTarget)
{
SCODE sc = VariantChangeType(pArgTemp, pArg, 0, vtTarget);
if (FAILED(sc))
{
TRACE0("Warning: automation argument coercion failed.\n");
*puArgErr = iArg;
return sc;
}
ASSERT(pArgTemp->vt == vtTarget);
}
#if !defined(_UNICODE) && !defined(OLE2ANSI)
if (vt == VT_BSTRA)
{
if (pArg->vt != vtTarget)
{
// coerce above created a new string
// convert it to ANSI and free it
ASSERT(pArgTemp->vt == VT_BSTR);
BSTR bstrW = pArgTemp->bstrVal;
pArgTemp->bstrVal = AfxBSTR2ABSTR(bstrW);
SysFreeString(bstrW);
}
else
{
// convert the string to ANSI from original
pArgTemp->bstrVal = AfxBSTR2ABSTR(pArg->bstrVal);
pArgTemp->vt = VT_BSTR;
}
vt = VT_BSTR;
}
#endif
pArg = pArgTemp;
}
}
else
{
if (vt == VT_MFCMARKER)
{
// start processing named arguments
iArg = pDispParams->cNamedArgs;
iArgMin = 0;
bNamedArgs = TRUE;
continue;
}
if (bNamedArgs || vt != VT_VARIANT)
break; // function not expecting optional argument
// argument not specified by caller -- provide default variant
static VARIANT vaDefault; // Note: really is 'const'
vaDefault.vt = VT_ERROR;
vaDefault.scode = DISP_E_PARAMNOTFOUND;
pArg = &vaDefault;
}
// push parameter value on the stack
switch (vt)
{
// by value parameters
case VT_UI1:
*(_STACK_INT*)pStack = pArg->bVal; // 'BYTE' is passed as 'int'
pStack += sizeof(_STACK_INT);
break;
case VT_I2:
*(_STACK_INT*)pStack = pArg->iVal;
pStack += sizeof(_STACK_INT); // 'short' is passed as 'int'
break;
case VT_I4:
*(_STACK_LONG*)pStack = pArg->lVal;
pStack += sizeof(_STACK_LONG);
break;
case VT_R4:
*(_STACK_FLOAT*)pStack = (_STACK_FLOAT)pArg->fltVal;
pStack += sizeof(_STACK_FLOAT);
#ifdef _SHADOW_DOUBLES
if (pDoubleShadow < pDoubleShadowMax)
*pDoubleShadow++ = (double)pArg->fltVal;
#endif
break;
case VT_R8:
#ifdef _ALIGN_DOUBLES
// align doubles on 8 byte for some platforms
pStack = (BYTE*)(((DWORD)pStack + _ALIGN_DOUBLES-1) &
~(_ALIGN_DOUBLES-1));
#endif
*(_STACK_DOUBLE*)pStack = (_STACK_DOUBLE)pArg->dblVal;
pStack += sizeof(_STACK_DOUBLE);
#ifdef _SHADOW_DOUBLES
if (pDoubleShadow < pDoubleShadowMax)
*pDoubleShadow++ = pArg->dblVal;
#endif
break;
case VT_DATE:
#ifdef _ALIGN_DOUBLES
// align doubles on 8 byte for some platforms
pStack = (BYTE*)(((DWORD)pStack + _ALIGN_DOUBLES-1) &
~(_ALIGN_DOUBLES-1));
#endif
*(_STACK_DOUBLE*)pStack = (_STACK_DOUBLE)pArg->date;
pStack += sizeof(_STACK_DOUBLE);
#ifdef _SHADOW_DOUBLES
if (pDoubleShadow < pDoubleShadowMax)
*pDoubleShadow++ = pArg->date;
#endif
break;
case VT_CY:
*(CY*)pStack = pArg->cyVal;
pStack += sizeof(CY);
break;
case VT_BSTR:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->bstrVal;
pStack += sizeof(_STACK_PTR);
break;
case VT_ERROR:
*(_STACK_LONG*)pStack = (_STACK_LONG)pArg->scode;
pStack += sizeof(_STACK_LONG);
break;
case VT_BOOL:
*(_STACK_LONG*)pStack = (_STACK_LONG)(V_BOOL(pArg) != 0);
pStack += sizeof(_STACK_LONG);
break;
case VT_VARIANT:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg;
pStack += sizeof(_STACK_PTR);
break;
case VT_DISPATCH:
case VT_UNKNOWN:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->punkVal;
pStack += sizeof(_STACK_PTR);
break;
// by reference parameters
case VT_UI2|VT_BYREF:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pbVal;
pStack += sizeof(_STACK_PTR);
break;
case VT_I2|VT_BYREF:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->piVal;
pStack += sizeof(_STACK_PTR);
break;
case VT_I4|VT_BYREF:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->plVal;
pStack += sizeof(_STACK_PTR);
break;
case VT_R4|VT_BYREF:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pfltVal;
pStack += sizeof(_STACK_PTR);
break;
case VT_R8|VT_BYREF:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pdblVal;
pStack += sizeof(_STACK_PTR);
break;
case VT_DATE|VT_BYREF:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pdate;
pStack += sizeof(_STACK_PTR);
break;
case VT_CY|VT_BYREF:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pcyVal;
pStack += sizeof(_STACK_PTR);
break;
case VT_BSTR|VT_BYREF:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pbstrVal;
pStack += sizeof(_STACK_PTR);
break;
case VT_ERROR|VT_BYREF:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pscode;
pStack += sizeof(_STACK_PTR);
break;
case VT_BOOL|VT_BYREF:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pboolVal;
pStack += sizeof(_STACK_PTR);
break;
case VT_VARIANT|VT_BYREF:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pvarVal;
pStack += sizeof(_STACK_PTR);
break;
case VT_DISPATCH|VT_BYREF:
case VT_UNKNOWN|VT_BYREF:
*(_STACK_PTR*)pStack = (_STACK_PTR)pArg->ppunkVal;
pStack += sizeof(_STACK_PTR);
break;
default:
ASSERT(FALSE);
}
#ifdef _ALIGN_STACK
// align stack as appropriate for next parameter
pStack = (BYTE*)(((DWORD)pStack + (_ALIGN_STACK-1)) &
~(_ALIGN_STACK-1));
ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
#endif
}
// check that all source arguments were consumed
if (iArg > 0)
{
*puArgErr = iArg;
return DISP_E_BADPARAMCOUNT;
}
// check that all target arguments were filled
if (*pb != '\0')
{
*puArgErr = pDispParams->cArgs;
return DISP_E_PARAMNOTOPTIONAL;
}
return S_OK; // success!
}
// indirect call helper (see OLECALL.CPP for implementation)
extern "C" DWORD AFXAPI
_AfxDispatchCall(AFX_PMSG pfn, void* pArgs, UINT nSizeArgs);
// 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
}
// 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
pvarResult->vt = vtResult;
// build return value VARIANT from result union
switch (vtResult)
{
case VT_UI2:
pvarResult->bVal = (BYTE)dwResult;
break;
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -