📄 oledisp1.cpp
字号:
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include "dispimpl.h"
#ifdef AFX_OLE5_SEG
#pragma code_seg(AFX_OLE5_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// Helpers and main implementation for CCmdTarget::IDispatch
void CCmdTarget::GetStandardProp(const AFX_DISPMAP_ENTRY* pEntry,
VARIANT* pvarResult, UINT* puArgErr)
{
ASSERT(pEntry != NULL);
ASSERT(*puArgErr != 0);
// it is a DISPATCH_PROPERTYGET (for standard, non-function property)
void* pProp = (BYTE*)this + pEntry->nPropOffset;
if (pEntry->vt != VT_VARIANT)
pvarResult->vt = pEntry->vt;
switch (pEntry->vt)
{
case VT_I1:
pvarResult->bVal = *(BYTE*)pProp;
break;
case VT_I2:
pvarResult->iVal = *(short*)pProp;
break;
case VT_I4:
pvarResult->lVal = *(long*)pProp;
break;
case VT_R4:
pvarResult->fltVal = *(float*)pProp;
break;
case VT_R8:
pvarResult->dblVal = *(double*)pProp;
break;
case VT_DATE:
pvarResult->date = *(double*)pProp;
break;
case VT_CY:
pvarResult->cyVal = *(CY*)pProp;
break;
case VT_BSTR:
{
CString* pString = (CString*)pProp;
pvarResult->bstrVal = pString->AllocSysString();
}
break;
case VT_ERROR:
pvarResult->scode = *(SCODE*)pProp;
break;
case VT_BOOL:
V_BOOL(pvarResult) = (VARIANT_BOOL)(*(BOOL*)pProp != 0 ? -1 : 0);
break;
case VT_VARIANT:
if (VariantCopy(pvarResult, (LPVARIANT)pProp) != S_OK)
*puArgErr = 0;
break;
case VT_DISPATCH:
case VT_UNKNOWN:
pvarResult->punkVal = *(LPDISPATCH*)pProp;
if (pvarResult->punkVal != NULL)
pvarResult->punkVal->AddRef();
break;
default:
*puArgErr = 0;
}
}
SCODE CCmdTarget::SetStandardProp(const AFX_DISPMAP_ENTRY* pEntry,
DISPPARAMS* pDispParams, UINT* puArgErr)
{
ASSERT(pEntry != NULL);
ASSERT(*puArgErr != 0);
// it is a DISPATCH_PROPERTYSET (for standard, non-function property)
SCODE sc = S_OK;
VARIANT va;
AfxVariantInit(&va);
VARIANT* pArg = &pDispParams->rgvarg[0];
if (pEntry->vt != VT_VARIANT && pArg->vt != pEntry->vt)
{
// argument is not of appropriate type, attempt to coerce it
sc = VariantChangeType(&va, pArg, 0, pEntry->vt);
if (FAILED(sc))
{
TRACE0("Warning: automation property coercion failed.\n");
*puArgErr = 0;
return sc;
}
ASSERT(va.vt == pEntry->vt);
pArg = &va;
}
void* pProp = (BYTE*)this + pEntry->nPropOffset;
switch (pEntry->vt)
{
case VT_I1:
*(BYTE*)pProp = pArg->bVal;
break;
case VT_I2:
*(short*)pProp = pArg->iVal;
break;
case VT_I4:
*(long*)pProp = pArg->lVal;
break;
case VT_R4:
*(float*)pProp = pArg->fltVal;
break;
case VT_R8:
*(double*)pProp = pArg->dblVal;
break;
case VT_DATE:
*(double*)pProp = pArg->date;
break;
case VT_CY:
*(CY*)pProp = pArg->cyVal;
break;
case VT_BSTR:
AfxBSTR2CString((CString*)pProp, pArg->bstrVal);
break;
case VT_ERROR:
*(SCODE*)pProp = pArg->scode;
break;
case VT_BOOL:
*(BOOL*)pProp = (V_BOOL(pArg) != 0);
break;
case VT_VARIANT:
if (VariantCopy((LPVARIANT)pProp, pArg) != S_OK)
*puArgErr = 0;
break;
case VT_DISPATCH:
case VT_UNKNOWN:
if (pArg->punkVal != NULL)
pArg->punkVal->AddRef();
_AfxRelease((LPUNKNOWN*)pProp);
*(LPUNKNOWN*)pProp = pArg->punkVal;
break;
default:
*puArgErr = 0;
sc = DISP_E_BADVARTYPE;
}
VariantClear(&va);
// if property was a DISP_PROPERTY_NOTIFY type, call pfnSet after setting
if (!FAILED(sc) && pEntry->pfnSet != NULL)
{
AFX_MANAGE_STATE(m_pModuleState);
(this->*pEntry->pfnSet)();
}
return sc;
}
UINT PASCAL CCmdTarget::GetEntryCount(const AFX_DISPMAP* pDispMap)
{
ASSERT(pDispMap->lpEntryCount != NULL);
// compute entry count cache if not available
if (*pDispMap->lpEntryCount == -1)
{
// count them
const AFX_DISPMAP_ENTRY* pEntry = pDispMap->lpEntries;
while (pEntry->nPropOffset != -1)
++pEntry;
// store it
*pDispMap->lpEntryCount = pEntry - pDispMap->lpEntries;
}
ASSERT(*pDispMap->lpEntryCount != -1);
return *pDispMap->lpEntryCount;
}
MEMBERID PASCAL CCmdTarget::MemberIDFromName(
const AFX_DISPMAP* pDispMap, LPCTSTR lpszName)
{
// search all maps and their base maps
UINT nInherit = 0;
while (pDispMap != NULL)
{
// search all entries in this map
const AFX_DISPMAP_ENTRY* pEntry = pDispMap->lpEntries;
UINT nEntryCount = GetEntryCount(pDispMap);
for (UINT nIndex = 0; nIndex < nEntryCount; nIndex++)
{
if (pEntry->vt != VT_MFCVALUE &&
lstrcmpi(pEntry->lpszName, lpszName) == 0)
{
if (pEntry->lDispID == DISPID_UNKNOWN)
{
// the MEMBERID is combination of nIndex & nInherit
ASSERT(MAKELONG(nIndex+1, nInherit) != DISPID_UNKNOWN);
return MAKELONG(nIndex+1, nInherit);
}
// the MEMBERID is specified as the lDispID
return pEntry->lDispID;
}
++pEntry;
}
#ifdef _AFXDLL
pDispMap = (*pDispMap->pfnGetBaseMap)();
#else
pDispMap = pDispMap->pBaseMap;
#endif
++nInherit;
}
return DISPID_UNKNOWN; // name not found
}
const AFX_DISPMAP_ENTRY* PASCAL CCmdTarget::GetDispEntry(MEMBERID memid)
{
const AFX_DISPMAP* pDerivMap = GetDispatchMap();
const AFX_DISPMAP* pDispMap;
const AFX_DISPMAP_ENTRY* pEntry;
if (memid == DISPID_VALUE)
{
// DISPID_VALUE is a special alias (look for special alias entry)
pDispMap = pDerivMap;
while (pDispMap != NULL)
{
// search for special entry with vt == VT_MFCVALUE
pEntry = pDispMap->lpEntries;
while (pEntry->nPropOffset != -1)
{
if (pEntry->vt == VT_MFCVALUE)
{
memid = pEntry->lDispID;
if (memid == DISPID_UNKNOWN)
{
// attempt to map alias name to member ID
memid = MemberIDFromName(pDerivMap, pEntry->lpszName);
if (memid == DISPID_UNKNOWN)
return NULL;
}
// break out and map the member ID to an entry
goto LookupDispID;
}
++pEntry;
}
#ifdef _AFXDLL
pDispMap = (*pDispMap->pfnGetBaseMap)();
#else
pDispMap = pDispMap->pBaseMap;
#endif
}
}
LookupDispID:
if ((long)memid > 0)
{
// find AFX_DISPMAP corresponding to HIWORD(memid)
UINT nTest = 0;
pDispMap = pDerivMap;
while (pDispMap != NULL && nTest < (UINT)HIWORD(memid))
{
#ifdef _AFXDLL
pDispMap = (*pDispMap->pfnGetBaseMap)();
#else
pDispMap = pDispMap->pBaseMap;
#endif
++nTest;
}
if (pDispMap != NULL)
{
UINT nEntryCount = GetEntryCount(pDispMap);
if ((UINT)LOWORD(memid) <= nEntryCount)
{
pEntry = pDispMap->lpEntries + LOWORD(memid)-1;
// must have automatic DISPID or same ID
// if not then look manually
if (pEntry->lDispID == DISPID_UNKNOWN ||
pEntry->lDispID == memid)
{
return pEntry;
}
}
}
}
// second pass, look for DISP_XXX_ID entries
pDispMap = pDerivMap;
while (pDispMap != NULL)
{
// find AFX_DISPMAP_ENTRY where (pEntry->lDispID == memid)
pEntry = pDispMap->lpEntries;
while (pEntry->nPropOffset != -1)
{
if (pEntry->lDispID == memid)
return pEntry;
++pEntry;
}
// check base class
#ifdef _AFXDLL
pDispMap = (*pDispMap->pfnGetBaseMap)();
#else
pDispMap = pDispMap->pBaseMap;
#endif
}
return NULL; // no matching entry
}
/////////////////////////////////////////////////////////////////////////////
// Standard automation methods
void CCmdTarget::GetNotSupported()
{
AfxThrowOleDispatchException(
AFX_IDP_GET_NOT_SUPPORTED, AFX_IDP_GET_NOT_SUPPORTED);
}
void CCmdTarget::SetNotSupported()
{
AfxThrowOleDispatchException(
AFX_IDP_SET_NOT_SUPPORTED, AFX_IDP_SET_NOT_SUPPORTED);
}
/////////////////////////////////////////////////////////////////////////////
// Wiring to CCmdTarget
// enable this object for OLE automation, called from derived class ctor
void CCmdTarget::EnableAutomation()
{
ASSERT(GetDispatchMap() != NULL); // must have DECLARE_DISPATCH_MAP
// construct an COleDispatchImpl instance just to get to the vtable
COleDispatchImpl dispatch;
// vtable pointer should be already set to same or NULL
ASSERT(m_xDispatch.m_vtbl == NULL||
*(DWORD*)&dispatch == m_xDispatch.m_vtbl);
// sizeof(COleDispatchImpl) should be just a DWORD (vtable pointer)
ASSERT(sizeof(m_xDispatch) == sizeof(COleDispatchImpl));
// copy the vtable (and other data) to make sure it is initialized
m_xDispatch.m_vtbl = *(DWORD*)&dispatch;
*(COleDispatchImpl*)&m_xDispatch = dispatch;
}
// return addref'd IDispatch part of CCmdTarget object
LPDISPATCH CCmdTarget::GetIDispatch(BOOL bAddRef)
{
ASSERT_VALID(this);
ASSERT(m_xDispatch.m_vtbl != 0); // forgot to call EnableAutomation?
// AddRef the object if requested
if (bAddRef)
ExternalAddRef();
// return pointer to IDispatch implementation
return (LPDISPATCH)GetInterface(&IID_IDispatch);
}
// retrieve CCmdTarget* from IDispatch* (return NULL if not MFC IDispatch)
CCmdTarget* PASCAL CCmdTarget::FromIDispatch(LPDISPATCH lpDispatch)
{
// construct an COleDispatchImpl instance just to get to the vtable
COleDispatchImpl dispatch;
ASSERT(*(DWORD*)&dispatch != 0); // null vtable ptr?
if (*(DWORD*)lpDispatch != *(DWORD*)&dispatch)
return NULL; // not our IDispatch*
// vtable ptrs match, so must have originally been retrieved with
// CCmdTarget::GetIDispatch.
#ifndef _AFX_NO_NESTED_DERIVATION
CCmdTarget* pTarget = (CCmdTarget*)
((BYTE*)lpDispatch - ((COleDispatchImpl*)lpDispatch)->m_nOffset);
#else
CCmdTarget* pTarget = (CCmdTarget*)
((BYTE*)lpDispatch - offsetof(CCmdTarget, m_xDispatch));
#endif
ASSERT_VALID(pTarget);
return pTarget;
}
BOOL CCmdTarget::IsResultExpected()
{
BOOL bResultExpected = m_bResultExpected;
m_bResultExpected = TRUE; // can only ask once
return bResultExpected;
}
void COleDispatchImpl::Disconnect()
{
METHOD_PROLOGUE_EX_(CCmdTarget, Dispatch)
pThis->ExternalDisconnect(); // always disconnect the object
}
///////////////////////////////////////////////////////////////////////////////
// OLE BSTR support
BSTR CString::AllocSysString() const
{
#if defined(_UNICODE) || defined(OLE2ANSI)
BSTR bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLength);
if (bstr == NULL)
AfxThrowMemoryException();
#else
int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
GetData()->nDataLength, NULL, NULL);
BSTR bstr = ::SysAllocStringLen(NULL, nLen);
if (bstr == NULL)
AfxThrowMemoryException();
MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength,
bstr, nLen);
#endif
return bstr;
}
BSTR CString::SetSysString(BSTR* pbstr) const
{
ASSERT(AfxIsValidAddress(pbstr, sizeof(BSTR)));
#if defined(_UNICODE) || defined(OLE2ANSI)
if (!::SysReAllocStringLen(pbstr, m_pchData, GetData()->nDataLength))
AfxThrowMemoryException();
#else
int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
GetData()->nDataLength, NULL, NULL);
if (!::SysReAllocStringLen(pbstr, NULL, nLen))
AfxThrowMemoryException();
MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength,
*pbstr, nLen);
#endif
ASSERT(*pbstr != NULL);
return *pbstr;
}
/////////////////////////////////////////////////////////////////////////////
// Specifics of METHOD->C++ member function invocation
// Note: Although this code is written in C++, it is very dependent on the
// specific compiler and target platform. The current code below assumes
// that the stack grows down, and that arguments are pushed last to first.
// calculate size of pushed arguments + retval reference
// size of arguments on stack when pushed by value
AFX_STATIC_DATA const UINT _afxByValue[] =
{
0, // VTS_EMPTY
0, // VTS_NULL
sizeof(_STACK_INT), // VTS_I2
sizeof(_STACK_LONG), // VTS_I4
sizeof(_STACK_FLOAT), // VTS_R4
sizeof(_STACK_DOUBLE), // VTS_R8
sizeof(CY), // VTS_CY
sizeof(DATE), // VTS_DATE
sizeof(LPCOLESTR), // VTS_WBSTR (VT_BSTR)
sizeof(LPDISPATCH), // VTS_DISPATCH
sizeof(SCODE), // VTS_SCODE
sizeof(BOOL), // VTS_BOOL
sizeof(const VARIANT*), // VTS_VARIANT
sizeof(LPUNKNOWN), // VTS_UNKNOWN
#if !defined(_UNICODE) && !defined(OLE2ANSI)
sizeof(LPCSTR), // VTS_BSTR (VT_BSTRA -- MFC defined)
#endif
};
// size of arguments on stack when pushed by reference
AFX_STATIC_DATA const UINT _afxByRef[] =
{
0, // VTS_PEMPTY
0, // VTS_PNULL
sizeof(short*), // VTS_PI2
sizeof(long*), // VTS_PI4
sizeof(float*), // VTS_PR4
sizeof(double*), // VTS_PR8
sizeof(CY*), // VTS_PCY
sizeof(DATE*), // VTS_PDATE
sizeof(BSTR*), // VTS_PBSTR
sizeof(LPDISPATCH*), // VTS_PDISPATCH
sizeof(SCODE*), // VTS_PSCODE
sizeof(VARIANT_BOOL*), // VTS_PBOOL
sizeof(VARIANT*), // VTS_PVARIANT
sizeof(LPUNKNOWN*), // VTS_PUNKNOWN
sizeof(BYTE*), // VTS_PUI1
};
AFX_STATIC_DATA const UINT _afxRetVal[] =
{
0, // VT_EMPTY
0, // VT_NULL
0, // VT_I2
0, // VT_I4
0, // VT_R4
0, // VT_R8
sizeof(CY*), // VT_CY
0, // VT_DATE (same as VT_R8)
0, // VT_BSTR
0, // VT_DISPATCH
0, // VT_ERROR
0, // VT_BOOL
sizeof(VARIANT*), // VT_VARIANT
0, // VT_UNKNOWN
0, // VT_UI1
};
UINT PASCAL CCmdTarget::GetStackSize(const BYTE* pbParams, VARTYPE vtResult)
{
// sizeof 'this' pointer
UINT nCount = sizeof(CCmdTarget*);
#ifdef _ALIGN_STACK
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -