📄 oledisp1.cpp
字号:
case VT_BSTR:
pvarResult->bstrVal = (BSTR)dwResult;
break;
case VT_ERROR:
pvarResult->scode = (SCODE)dwResult;
break;
case VT_BOOL:
V_BOOL(pvarResult) = (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!
}
/////////////////////////////////////////////////////////////////////////////
// CCmdTarget::XDispatch implementation
STDMETHODIMP_(ULONG) COleDispatchImpl::AddRef()
{
METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
return pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) COleDispatchImpl::Release()
{
METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
return pThis->ExternalRelease();
}
STDMETHODIMP COleDispatchImpl::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
return pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP COleDispatchImpl::GetTypeInfoCount(UINT* pctinfo)
{
METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
*pctinfo = pThis->GetTypeInfoCount();
return S_OK;
}
STDMETHODIMP COleDispatchImpl::GetTypeInfo(UINT itinfo, LCID lcid,
ITypeInfo** pptinfo)
{
METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
ASSERT_POINTER(pptinfo, LPTYPEINFO);
if (itinfo != 0)
return E_INVALIDARG;
IID iid;
if (!pThis->GetDispatchIID(&iid))
return E_NOTIMPL;
return pThis->GetTypeInfoOfGuid(lcid, iid, pptinfo);
}
STDMETHODIMP COleDispatchImpl::GetIDsOfNames(
REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
{
METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
ASSERT_POINTER(rgszNames, char*);
ASSERT_POINTER(rgdispid, DISPID);
USES_CONVERSION;
// check arguments
if (riid != IID_NULL)
return DISP_E_UNKNOWNINTERFACE;
SCODE sc;
LPTYPEINFO lpTypeInfo = NULL;
if (lcid != 0 && SUCCEEDED(sc = GetTypeInfo(0, lcid, &lpTypeInfo)))
{
// For non-zero lcid, let typeinfo do the work (when available)
ASSERT(lpTypeInfo != NULL);
sc = lpTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
lpTypeInfo->Release();
if (sc == TYPE_E_ELEMENTNOTFOUND)
sc = DISP_E_UNKNOWNNAME;
}
else
{
// fill in the member name
const AFX_DISPMAP* pDerivMap = pThis->GetDispatchMap();
rgdispid[0] = pThis->MemberIDFromName(pDerivMap, OLE2CT(rgszNames[0]));
if (rgdispid[0] == DISPID_UNKNOWN)
sc = DISP_E_UNKNOWNNAME;
else
sc = S_OK;
// argument names are always DISPID_UNKNOWN (for this implementation)
for (UINT nIndex = 1; nIndex < cNames; nIndex++)
rgdispid[nIndex] = DISPID_UNKNOWN;
}
return sc;
}
STDMETHODIMP COleDispatchImpl::Invoke(
DISPID dispid, REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS* pDispParams, LPVARIANT pvarResult,
LPEXCEPINFO pexcepinfo, UINT* puArgErr)
{
METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
ASSERT_NULL_OR_POINTER(pvarResult, VARIANT);
ASSERT_NULL_OR_POINTER(pexcepinfo, EXCEPINFO);
ASSERT_NULL_OR_POINTER(puArgErr, UINT);
// make sure pvarResult is initialized
if (pvarResult != NULL)
AfxVariantInit(pvarResult);
// check arguments
if (riid != IID_NULL)
return DISP_E_UNKNOWNINTERFACE;
// allow subclass to disable Invoke
if (!pThis->IsInvokeAllowed(dispid))
return E_UNEXPECTED;
// copy param block for safety
DISPPARAMS params = *pDispParams;
pDispParams = ¶ms;
// most of the time, named arguments are not supported
if (pDispParams->cNamedArgs != 0)
{
// only special PROPERTYPUT named argument is allowed
if (pDispParams->cNamedArgs != 1 ||
pDispParams->rgdispidNamedArgs[0] != DISPID_PROPERTYPUT)
{
return DISP_E_NONAMEDARGS;
}
}
// get entry for the member ID
const AFX_DISPMAP_ENTRY* pEntry = pThis->GetDispEntry(dispid);
if (pEntry == NULL)
return DISP_E_MEMBERNOTFOUND;
// treat member calls on properties just like property get/set
if ((wFlags == DISPATCH_METHOD) &&
((pEntry->pfn == NULL && pEntry->pfnSet == NULL) ||
(pEntry->pfn == NULL && pEntry->pfnSet != NULL) ||
(pEntry->pfn != NULL && pEntry->pfnSet != NULL)))
{
// the entry describes a property but a method call is being
// attempted -- change it to a property get/set based on the
// number of parameters being passed.
wFlags &= ~DISPATCH_METHOD;
UINT nExpectedArgs = pEntry->lpszParams != NULL ?
(UINT)lstrlenA(pEntry->lpszParams) : 0;
if (pDispParams->cArgs <= nExpectedArgs)
{
// no extra param -- so treat as property get
wFlags |= DISPATCH_PROPERTYGET;
}
else
{
// extra params -- treat as property set
wFlags |= DISPATCH_PROPERTYPUTREF;
pDispParams->cNamedArgs = 1;
}
}
// property puts should not require a return value
if (wFlags & (DISPATCH_PROPERTYPUTREF|DISPATCH_PROPERTYPUT))
{
pvarResult = NULL;
// catch attempt to do property set on method
if (pEntry->pfn != NULL && pEntry->pfnSet == NULL)
return DISP_E_TYPEMISMATCH;
}
UINT uArgErr = (UINT)-1; // no error yet
SCODE sc = S_OK;
// handle special cases of DISPATCH_PROPERTYPUT
VARIANT* pvarParamSave = NULL;
VARIANT vaParamSave;
vaParamSave.vt = VT_ERROR;
DISPPARAMS paramsTemp;
VARIANT vaTemp;
AfxVariantInit(&vaTemp);
if (wFlags == DISPATCH_PROPERTYPUT && dispid != DISPID_VALUE)
{
// with PROPERTYPUT (no REF), the right hand side may need fixup
if (pDispParams->rgvarg[0].vt == VT_DISPATCH &&
pDispParams->rgvarg[0].pdispVal != NULL)
{
// remember old value for restore later
pvarParamSave = &pDispParams->rgvarg[0];
vaParamSave = pDispParams->rgvarg[0];
AfxVariantInit(&pDispParams->rgvarg[0]);
// get default value of right hand side
memset(¶msTemp, 0, sizeof(DISPPARAMS));
sc = vaParamSave.pdispVal->Invoke(
DISPID_VALUE, riid, lcid, DISPATCH_PROPERTYGET, ¶msTemp,
&pDispParams->rgvarg[0], pexcepinfo, puArgErr);
}
// special handling for PROPERTYPUT (no REF), left hand side
if (sc == S_OK && pEntry->vt == VT_DISPATCH)
{
memset(¶msTemp, 0, sizeof(DISPPARAMS));
// parameters are distributed depending on what the Get expects
if (pEntry->lpszParams == NULL)
{
// paramsTemp is already setup for no parameters
sc = Invoke(dispid, riid, lcid,
DISPATCH_PROPERTYGET|DISPATCH_METHOD, ¶msTemp,
&vaTemp, pexcepinfo, puArgErr);
if (sc == S_OK &&
(vaTemp.vt != VT_DISPATCH || vaTemp.pdispVal == NULL))
sc = DISP_E_TYPEMISMATCH;
else if (sc == S_OK)
{
ASSERT(vaTemp.vt == VT_DISPATCH && vaTemp.pdispVal != NULL);
// we have the result, now call put on the default property
sc = vaTemp.pdispVal->Invoke(
DISPID_VALUE, riid, lcid, wFlags, pDispParams,
pvarResult, pexcepinfo, puArgErr);
}
}
else
{
// pass all but named params
paramsTemp.rgvarg = &pDispParams->rgvarg[1];
paramsTemp.cArgs = pDispParams->cArgs - 1;
sc = Invoke(dispid, riid, lcid,
DISPATCH_PROPERTYGET|DISPATCH_METHOD, ¶msTemp,
&vaTemp, pexcepinfo, puArgErr);
if (sc == S_OK &&
(vaTemp.vt != VT_DISPATCH || vaTemp.pdispVal == NULL))
sc = DISP_E_TYPEMISMATCH;
else if (sc == S_OK)
{
ASSERT(vaTemp.vt == VT_DISPATCH && vaTemp.pdispVal != NULL);
// we have the result, now call put on the default property
paramsTemp = *pDispParams;
paramsTemp.cArgs = paramsTemp.cNamedArgs;
sc = vaTemp.pdispVal->Invoke(
DISPID_VALUE, riid, lcid, wFlags, ¶msTemp,
pvarResult, pexcepinfo, puArgErr);
}
}
VariantClear(&vaTemp);
if (sc != DISP_E_MEMBERNOTFOUND)
goto Cleanup;
}
if (sc != S_OK && sc != DISP_E_MEMBERNOTFOUND)
goto Cleanup;
}
// ignore DISP_E_MEMBERNOTFOUND from above
ASSERT(sc == DISP_E_MEMBERNOTFOUND || sc == S_OK);
// undo implied default value on right hand side on error
if (sc != S_OK && pvarParamSave != NULL)
{
// default value stuff failed -- so try without default value
pvarParamSave = NULL;
VariantClear(&pDispParams->rgvarg[0]);
pDispParams->rgvarg[0] = vaParamSave;
}
sc = S_OK;
// check arguments against this entry
UINT nOrigArgs; nOrigArgs = pDispParams->cArgs;
if (wFlags & (DISPATCH_PROPERTYGET|DISPATCH_METHOD))
{
if (!(wFlags & DISPATCH_METHOD))
{
if (pEntry->vt == VT_EMPTY)
return DISP_E_BADPARAMCOUNT;
if (pvarResult == NULL)
return DISP_E_PARAMNOTOPTIONAL;
}
if (pEntry->lpszParams == NULL && pDispParams->cArgs > 0)
{
if (pEntry->vt != VT_DISPATCH)
return DISP_E_BADPARAMCOUNT;
// it is VT_DISPATCH property/method but too many arguments supplied
// transfer those arguments to the default property of the return value
// after getting the return value from this call. This is referred
// to as collection lookup.
pDispParams->cArgs = 0;
if (pvarResult == NULL)
pvarResult = &vaTemp;
}
}
// make sure that parameters are not passed to a simple property
if (pDispParams->cArgs > 1 &&
(wFlags & (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF)) &&
pEntry->pfn == NULL)
{
sc = DISP_E_BADPARAMCOUNT;
goto Cleanup;
}
// make sure that pvarResult is set for simple property get
if (pEntry->pfn == NULL && pDispParams->cArgs == 0 && pvarResult == NULL)
{
sc = DISP_E_PARAMNOTOPTIONAL;
goto Cleanup;
}
// make sure IsExpectingResult returns FALSE as appropriate
BOOL bResultExpected;
bResultExpected = pThis->m_bResultExpected;
pThis->m_bResultExpected = pvarResult != NULL;
TRY
{
if (pEntry->pfn == NULL)
{
// do standard property get/set
if (pDispParams->cArgs == 0)
pThis->GetStandardProp(pEntry, pvarResult, &uArgErr);
else
sc = pThis->SetStandardProp(pEntry, pDispParams, &uArgErr);
}
else
{
// do standard method call
sc = pThis->CallMemberFunc(pEntry, wFlags,
pvarResult, pDispParams, &uArgErr);
}
}
CATCH(COleException, e)
{
sc = e->m_sc;
DELETE_EXCEPTION(e);
}
AND_CATCH_ALL(e)
{
AFX_MANAGE_STATE(pThis->m_pModuleState);
if (pexcepinfo != NULL)
{
// fill exception with translation of MFC exception
COleDispatchException::Process(pexcepinfo, e);
}
DELETE_EXCEPTION(e);
sc = DISP_E_EXCEPTION;
}
END_CATCH_ALL
// restore original m_bResultExpected flag
pThis->m_bResultExpected = bResultExpected;
// handle special DISPATCH_PROPERTYGET collection lookup case
if (sc == S_OK && nOrigArgs > pDispParams->cArgs)
{
ASSERT(wFlags & (DISPATCH_PROPERTYGET|DISPATCH_METHOD));
ASSERT(pvarResult != NULL);
// must be non-NULL dispatch, otherwise type mismatch
if (pvarResult->vt != VT_DISPATCH || pvarResult->pdispVal == NULL)
{
sc = DISP_E_TYPEMISMATCH;
goto Cleanup;
}
// otherwise, valid VT_DISPATCH was returned
pDispParams->cArgs = nOrigArgs;
LPDISPATCH lpTemp = pvarResult->pdispVal;
if (pvarResult != &vaTemp)
AfxVariantInit(pvarResult);
else
pvarResult = NULL;
sc = lpTemp->Invoke(DISPID_VALUE, riid, lcid, wFlags,
pDispParams, pvarResult, pexcepinfo, puArgErr);
lpTemp->Release();
}
Cleanup:
// restore any arguments which were modified
if (pvarParamSave != NULL)
{
VariantClear(&pDispParams->rgvarg[0]);
pDispParams->rgvarg[0] = vaParamSave;
}
// fill error argument if one is available
if (sc != S_OK && puArgErr != NULL && uArgErr != -1)
*puArgErr = uArgErr;
return sc;
}
/////////////////////////////////////////////////////////////////////////////
// IDispatch specific exception
COleDispatchException::~COleDispatchException()
{
// destructor code is compiler generated
}
void PASCAL COleDispatchException::Process(
EXCEPINFO* pInfo, const CException* pAnyException)
{
USES_CONVERSION;
ASSERT(AfxIsValidAddress(pInfo, sizeof(EXCEPINFO)));
ASSERT_VALID(pAnyException);
// zero default & reserved members
memset(pInfo, 0, sizeof(EXCEPINFO));
// get description based on type of exception
TCHAR szDescription[256];
LPCTSTR pszDescription = szDescription;
if (pAnyException->IsKindOf(RUNTIME_CLASS(COleDispatchException)))
{
// specific IDispatch style exception
COleDispatchException* e = (COleDispatchException*)pAnyException;
pszDescription = e->m_strDescription;
pInfo->wCode = e->m_wCode;
pInfo->dwHelpContext = e->m_dwHelpContext;
pInfo->scode = e->m_scError;
// propagate source and help file if present
if (!e->m_strHelpFile.IsEmpty())
pInfo->bstrHelpFile = ::SysAllocString(T2COLE(e->m_strHelpFile));
if (!e->m_strSource.IsEmpty())
pInfo->bstrSource = ::SysAllocString(T2COLE(e->m_strSource));
}
else if (pAnyException->IsKindOf(RUNTIME_CLASS(CMemoryException)))
{
// failed memory allocation
AfxLoadString(AFX_IDP_FAILED_MEMORY_ALLOC, szDescription);
pInfo->wCode = AFX_IDP_FAILED_MEMORY_ALLOC;
}
else
{
// other unknown/uncommon error
AfxLoadString(AFX_IDP_INTERNAL_FAILURE, szDescription);
pInfo->wCode = AFX_IDP_INTERNAL_FAILURE;
}
// build up rest of EXCEPINFO struct
pInfo->bstrDescription = ::SysAllocString(T2COLE(pszDescription));
if (pInfo->bstrSource == NULL)
pInfo->bstrSource = ::SysAllocString(T2COLE(AfxGetAppName()));
if (pInfo->bstrHelpFile == NULL && pInfo->dwHelpContext != 0)
pInfo->bstrHelpFile = ::SysAllocString(T2COLE(AfxGetApp()->m_pszHelpFilePath));
}
COleDispatchException::COleDispatchException(
LPCTSTR lpszDescription, UINT nHelpID, WORD wCode)
{
m_dwHelpContext = nHelpID != 0 ? HID_BASE_DISPATCH+nHelpID : 0;
m_wCode = wCode;
if (lpszDescription != NULL)
m_strDescription = lpszDescription;
m_scError = wCode != 0 ? NOERROR : E_UNEXPECTED;
}
COleDispatchException::GetErrorMessage(LPTSTR lpszError, UINT nMaxError,
PUINT pnHelpContext)
{
ASSERT(lpszError != NULL && AfxIsValidString(lpszError, nMaxError));
if (pnHelpContext != NULL)
*pnHelpContext = 0;
lstrcpyn(lpszError, m_strDescription, nMaxError);
return TRUE;
}
void AFXAPI AfxThrowOleDispatchException(WORD wCode, LPCTSTR lpszDescription,
UINT nHelpID)
{
ASSERT(AfxIsValidString(lpszDescription));
THROW(new COleDispatchException(lpszDescription, nHelpID, wCode));
}
void AFXAPI AfxThrowOleDispatchException(WORD wCode, UINT nDescriptionID,
UINT nHelpID)
{
TCHAR szBuffer[256];
VERIFY(AfxLoadString(nDescriptionID, szBuffer) != 0);
if (nHelpID == -1)
nHelpID = nDescriptionID;
THROW(new COleDispatchException(szBuffer, nHelpID, wCode));
}
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
IMPLEMENT_DYNAMIC(COleDispatchException, CException)
/////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -