/* * An implementation of IUnknown. * * hidenori@a2.ctktv.ne.jp */ #include "config.h" #include "windef.h" #include "winerror.h" #include "winbase.h" #include "wine/obj_base.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(quartz); #include "quartz_private.h" #include "iunk.h" static HRESULT WINAPI IUnknown_fnQueryInterface(IUnknown* iface,REFIID riid,LPVOID *ppobj) { ICOM_THIS(QUARTZ_IUnkImpl,iface); size_t ofs; DWORD dwIndex; QUARTZ_IFDelegation* pDelegation; HRESULT hr; TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); if ( ppobj == NULL ) return E_POINTER; *ppobj = NULL; ofs = 0; if ( IsEqualGUID( &IID_IUnknown, riid ) ) { TRACE("IID_IUnknown - returns inner object.\n"); } else { for ( dwIndex = 0; dwIndex < This->dwEntries; dwIndex++ ) { if ( IsEqualGUID( This->pEntries[dwIndex].piid, riid ) ) { ofs = This->pEntries[dwIndex].ofsVTPtr; break; } } if ( dwIndex == This->dwEntries ) { hr = E_NOINTERFACE; /* delegation */ pDelegation = This->pDelegationFirst; while ( pDelegation != NULL ) { hr = (*pDelegation->pOnQueryInterface)( iface, riid, ppobj ); if ( hr != E_NOINTERFACE ) break; pDelegation = pDelegation->pNext; } if ( hr == E_NOINTERFACE ) { FIXME("(%p) unknown interface: %s\n",This,debugstr_guid(riid)); } return hr; } } *ppobj = (LPVOID)(((char*)This) + ofs); IUnknown_AddRef((IUnknown*)(*ppobj)); return S_OK; } static ULONG WINAPI IUnknown_fnAddRef(IUnknown* iface) { ICOM_THIS(QUARTZ_IUnkImpl,iface); TRACE("(%p)->()\n",This); return InterlockedExchangeAdd(&(This->ref),1) + 1; } static ULONG WINAPI IUnknown_fnRelease(IUnknown* iface) { ICOM_THIS(QUARTZ_IUnkImpl,iface); LONG ref; TRACE("(%p)->()\n",This); ref = InterlockedExchangeAdd(&(This->ref),-1) - 1; if ( ref > 0 ) return (ULONG)ref; This->ref ++; if ( This->pOnFinalRelease != NULL ) (*(This->pOnFinalRelease))(iface); This->ref --; QUARTZ_FreeObj(This); return 0; } static ICOM_VTABLE(IUnknown) iunknown = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE /* IUnknown fields */ IUnknown_fnQueryInterface, IUnknown_fnAddRef, IUnknown_fnRelease, }; void QUARTZ_IUnkInit( QUARTZ_IUnkImpl* pImpl, IUnknown* punkOuter ) { TRACE("(%p)\n",pImpl); ICOM_VTBL(pImpl) = &iunknown; pImpl->pEntries = NULL; pImpl->dwEntries = 0; pImpl->pDelegationFirst = NULL; pImpl->pOnFinalRelease = NULL; pImpl->ref = 1; pImpl->punkControl = (IUnknown*)pImpl; /* for implementing aggregation. */ if ( punkOuter != NULL ) pImpl->punkControl = punkOuter; } void QUARTZ_IUnkAddDelegation( QUARTZ_IUnkImpl* pImpl, QUARTZ_IFDelegation* pDelegation ) { pDelegation->pNext = pImpl->pDelegationFirst; pImpl->pDelegationFirst = pDelegation; }