📄 atldispa.h
字号:
}
};
/////////////////////////////////////////////////////////////////////////////
// CComDynTypeInfoHolder
template< class T >
class CComDynTypeInfoHolder
{
// Should be 'protected' but can cause compiler to generate fat code.
public:
const GUID* m_pguid;
const GUID* m_plibid;
WORD m_wMajor;
WORD m_wMinor;
ITypeInfo* m_pInfo;
long m_dwRef;
struct stringdispid
{
CComBSTR bstr;
int nLen;
DISPID id;
};
stringdispid* m_pCache;
int m_nArgs;
// The above members must be present in that order because they
// are initialized by ATL (as a static member)
INTERFACEDATA* m_pITF;
public:
HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
{
HRESULT Hr = S_OK;
if( m_pInfo==NULL ) Hr = GetTI(lcid);
*ppInfo = m_pInfo;
if( m_pInfo!=NULL ) {
m_pInfo->AddRef();
Hr = S_OK;
}
return Hr;
}
HRESULT GetTI(LCID lcid);
HRESULT EnsureTI(LCID lcid)
{
HRESULT Hr = S_OK;
if( m_pInfo==NULL ) Hr = GetTI(lcid);
return Hr;
}
// This function is called by the module on exit
// It is registered through _Module.AddTermFunc()
static void __stdcall Cleanup(DWORD dw)
{
CComDynTypeInfoHolder* p = (CComDynTypeInfoHolder*)dw;
if( p->m_pInfo != NULL ) {
p->m_pInfo->Release();
p->m_pInfo = NULL;
// Release internal interface block
for( UINT i=0; i<p->m_pITF->cMembers; i++ ) delete [] p->m_pITF->pmethdata[i].ppdata;
delete [] p->m_pITF->pmethdata;
delete p->m_pITF;
}
if( p->m_pCache != NULL ) {
delete [] p->m_pCache;
p->m_pCache = NULL;
}
}
HRESULT GetTypeInfo(UINT /*itinfo*/, LCID lcid, ITypeInfo** pptinfo)
{
HRESULT Hr = E_POINTER;
if( pptinfo!=NULL ) Hr = GetTI(lcid, pptinfo);
return Hr;
}
HRESULT GetIDsOfNames(REFIID /*riid*/, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
{
HRESULT Hr = EnsureTI(lcid);
if( m_pInfo != NULL ) {
for( int i=0; i<(int)cNames; i++ ) {
int n = ocslen(rgszNames[i]);
for( int j=0; j<m_nArgs; j++ ) {
if( (n==m_pCache[j].nLen) &&
(memcmp(m_pCache[j].bstr, rgszNames[i], m_pCache[j].nLen * sizeof(OLECHAR)) == 0) )
{
rgdispid[i] = m_pCache[j].id;
break;
}
}
if( j==m_nArgs) {
Hr = m_pInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
if( FAILED(Hr) ) break;
}
}
}
return Hr;
}
HRESULT Invoke(IDispatch* p, DISPID dispidMember, REFIID /*riid*/,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* /*pexcepinfo*/, UINT* /*puArgErr*/)
{
HRESULT Hr = EnsureTI(lcid);
if( m_pInfo != NULL ) {
// As Chris Sells so elegantly put it in his dispimpl2.h sample
// the ATL library assumes that the methods are always placed on
// the IDispatch interface. So instead we implement our own Invoke(),
// (much in dismay of the documentation of IDispatch::Invoke in Platform SDK).
/*
Hr = m_pInfo->Invoke(p, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
*/
/*
T *pT = (T*)(p);
Hr = m_pInfo->Invoke(pT, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
*/
if( (DISPATCH_PROPERTYPUT!=wFlags) && (pdispparams->cNamedArgs>0) ) return DISP_E_NONAMEDARGS;
const _ATL_DISPATCH_ENTRY<T>* pMap = T::_GetDispMap();
DISPID i = 1;
while( pMap->pfn!=NULL ) {
DISPID dispid = pMap->dispid==DISPID_UNKNOWN ? i : pMap->dispid;
if( dispidMember==dispid ) {
if( (DISPATCH_PROPERTYPUT==wFlags) && (DISPID_PROPERTYPUT==(pMap+1)->dispid) )
pMap++;
VARTYPE* pArgs = (VARTYPE*) pMap->vtArgs;
if( pArgs == NULL ) pArgs = (VARTYPE*) &pMap->vtSingle;
UINT nArgs = pMap->nArgs;
if( pdispparams->cArgs!=nArgs ) return DISP_E_BADPARAMCOUNT;
VARIANTARG** ppVarArgs = nArgs ? (VARIANTARG**)_alloca(sizeof(VARIANTARG*)*nArgs) : NULL;
VARIANTARG* pVarArgs = nArgs ? (VARIANTARG*)_alloca(sizeof(VARIANTARG)*nArgs) : NULL;
UINT i;
for( i=0; i<nArgs; i++ ) {
ppVarArgs[i] = &pVarArgs[i];
::VariantInit(&pVarArgs[i]);
if( FAILED(::VariantCopyInd(&pVarArgs[i], &pdispparams->rgvarg[nArgs-i-1])) ) return DISP_E_TYPEMISMATCH;
if( FAILED(::VariantChangeType(&pVarArgs[i], &pVarArgs[i], 0, pArgs[i])) ) return DISP_E_TYPEMISMATCH;
}
T *pT = static_cast<T*>(p);
CComStdCallThunk<T> thunk;
thunk.Init(pMap->pfn, pT);
CComVariant tmpResult;
if( pvarResult==NULL ) pvarResult = &tmpResult;
HRESULT Hr = ::DispCallFunc(
&thunk,
0,
CC_STDCALL,
pMap->vtReturn,
nArgs,
pArgs,
nArgs ? ppVarArgs : NULL,
pvarResult);
for( i=0; i<nArgs; i++ ) ::VariantClear(&pVarArgs[i]);
return Hr;
}
i++;
pMap++;
}
return DISP_E_MEMBERNOTFOUND;
}
return Hr;
}
HRESULT LoadNameCache(ITypeInfo* /*pTypeInfo*/)
{
// A name cache is really not useful here since we already have
// a fine map of the names. Oh well...
const _ATL_DISPATCH_ENTRY<T>* pTemp, *pMap = T::_GetDispMap();
pTemp = pMap;
m_nArgs = 0;
while( pTemp->pfn!=NULL ) {
m_nArgs++;
pTemp++;
}
m_pCache = m_nArgs==0 ? NULL : new stringdispid[m_nArgs];
DISPID i = 0;
while( pMap->pfn!=NULL ) {
m_pCache[i].bstr = pMap->szName;
m_pCache[i].nLen = ::SysStringLen(m_pCache[i].bstr);
m_pCache[i].id = pMap->dispid==DISPID_UNKNOWN ? i+1 : pMap->dispid;
// NOTE: In case of DISPID_PROPERTYPUT we assume that a name entry
// exists before it, which will have the correct DISPID.
pMap++;
i++;
}
return S_OK;
}
};
template< class T >
inline HRESULT CComDynTypeInfoHolder<T>::GetTI(LCID lcid)
{
const _ATL_DISPATCH_ENTRY<T>* pTemp, *pMap = T::_GetDispMap();
pTemp = pMap;
UINT nArgs = 0;
while( pTemp->pfn!=NULL ) {
nArgs++;
pTemp++;
}
// Create INTERFACEDATA structures.
// HACK: They cannot be created on the stack. Seems that the ancient
// CreateDispTypeInfo() method uses weak references?!
m_pITF = new INTERFACEDATA;
m_pITF->cMembers = nArgs;
METHODDATA* pM = m_pITF->pmethdata = new METHODDATA[nArgs];
DISPID dispid = 1;
DISPID oldid = 0;
LONG i = 0; // Method index
while( pMap->pfn!=NULL ) {
pM->szName = pMap->szName;
pM->dispid = pMap->dispid==DISPID_UNKNOWN ? dispid : pMap->dispid;
if( pMap->dispid==DISPID_PROPERTYPUT ) pM->dispid = oldid; // Support hack in our DISP_PROP macro
pM->iMeth = i;
pM->cc = CC_STDCALL;
pM->ppdata = NULL;
pM->cArgs = pMap->nArgs;
if( pMap->nArgs>0 ) {
PARAMDATA* pParams = pM->ppdata = new PARAMDATA[pMap->nArgs];
for( UINT j=0; j<pMap->nArgs; j++ ) {
pParams->szName = NULL;
pParams->vt = pMap->vtArgs != NULL ? pMap->vtArgs[j] : pMap->vtSingle;
pParams++;
}
}
pM->wFlags = (USHORT) pMap->wFlags;
pM->vtReturn = pMap->vtReturn;
// Next entry..
oldid = pM->dispid;
dispid++;
i++;
pM++;
pMap++;
}
HRESULT Hr = ::CreateDispTypeInfo(m_pITF, lcid, &m_pInfo);
// The result of CreateDispTypeInfo() is very disappointing. It
// doesn't create a full ITypeInfo object, so calling ITypeInfo::GetTypeAttr()
// claims that there are NO methods and properties in the list (?).
// This basically renders the idea of creating a CComTypeInfoHolder clone
// useless. I might as well have done a better IDispatch impl instead.
if( SUCCEEDED(Hr) ) {
LoadNameCache(m_pInfo);
_Module.AddTermFunc(Cleanup, (DWORD)this);
}
return Hr;
};
#endif // !defined(AFX_ATLDISPA_H__20010608_7B20_BD08_5EED_0080AD509054__INCLUDED_)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -