wine-wine/dlls/oleaut32/connpt.c

595 lines
16 KiB
C

/*
* Implementation of a generic ConnectionPoint object.
*
* Copyright 2000 Huw D M Davies for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* NOTES:
* See one exported function here is CreateConnectionPoint, see
* comments just above that function for information.
*/
#include <assert.h>
#include <stdarg.h>
#include <string.h>
#define COBJMACROS
#include "winerror.h"
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "ole2.h"
#include "olectl.h"
#include "connpt.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
#define MAXSINKS 10
/************************************************************************
* Implementation of IConnectionPoint
*/
typedef struct ConnectionPointImpl {
IConnectionPoint IConnectionPoint_iface;
/* IUnknown of our main object*/
IUnknown *Obj;
/* Reference count */
LONG ref;
/* IID of sink interface */
IID iid;
/* Array of sink IUnknowns */
IUnknown **sinks;
DWORD maxSinks;
DWORD nSinks;
} ConnectionPointImpl;
/************************************************************************
* Implementation of IEnumConnections
*/
typedef struct EnumConnectionsImpl {
IEnumConnections IEnumConnections_iface;
LONG ref;
/* IUnknown of ConnectionPoint, used for ref counting */
IUnknown *pUnk;
/* Connection Data */
CONNECTDATA *pCD;
DWORD nConns;
/* Next connection to enumerate from */
DWORD nCur;
} EnumConnectionsImpl;
static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
DWORD nSinks,
CONNECTDATA *pCD);
static inline ConnectionPointImpl *impl_from_IConnectionPoint(IConnectionPoint *iface)
{
return CONTAINING_RECORD(iface, ConnectionPointImpl, IConnectionPoint_iface);
}
static inline EnumConnectionsImpl *impl_from_IEnumConnections(IEnumConnections *iface)
{
return CONTAINING_RECORD(iface, EnumConnectionsImpl, IEnumConnections_iface);
}
/************************************************************************
* ConnectionPointImpl_Destroy
*/
static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj)
{
DWORD i;
for(i = 0; i < Obj->maxSinks; i++) {
if(Obj->sinks[i]) {
IUnknown_Release(Obj->sinks[i]);
Obj->sinks[i] = NULL;
}
}
HeapFree(GetProcessHeap(), 0, Obj->sinks);
HeapFree(GetProcessHeap(), 0, Obj);
return;
}
/************************************************************************
* ConnectionPointImpl_QueryInterface (IUnknown)
*
* See Windows documentation for more details on IUnknown methods.
*/
static HRESULT WINAPI ConnectionPointImpl_QueryInterface(
IConnectionPoint* iface,
REFIID riid,
void** ppvObject)
{
ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
/*
* Perform a sanity check on the parameters.
*/
if (!ppvObject)
return E_INVALIDARG;
/*
* Initialize the return parameter.
*/
*ppvObject = 0;
if (IsEqualIID(&IID_IConnectionPoint, riid) || IsEqualIID(&IID_IUnknown, riid))
*ppvObject = iface;
/*
* Check that we obtained an interface.
*/
if ((*ppvObject)==0)
{
FIXME("() : asking for unsupported interface %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
IUnknown_AddRef((IUnknown*)*ppvObject);
return S_OK;
}
/************************************************************************
* ConnectionPointImpl_AddRef (IUnknown)
*
* See Windows documentation for more details on IUnknown methods.
*/
static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface)
{
ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
ULONG refCount = InterlockedIncrement(&This->ref);
TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
return refCount;
}
/************************************************************************
* ConnectionPointImpl_Release (IUnknown)
*
* See Windows documentation for more details on IUnknown methods.
*/
static ULONG WINAPI ConnectionPointImpl_Release(
IConnectionPoint* iface)
{
ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
ULONG refCount = InterlockedDecrement(&This->ref);
TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
/*
* If the reference count goes down to 0, perform suicide.
*/
if (!refCount) ConnectionPointImpl_Destroy(This);
return refCount;
}
/************************************************************************
* ConnectionPointImpl_GetConnectionInterface (IConnectionPoint)
*
*/
static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface(
IConnectionPoint *iface,
IID *piid)
{
ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid)));
*piid = This->iid;
return S_OK;
}
/************************************************************************
* ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint)
*
*/
static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer(
IConnectionPoint *iface,
IConnectionPointContainer **ppCPC)
{
ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
TRACE("(%p)->(%p)\n", This, ppCPC);
return IUnknown_QueryInterface(This->Obj, &IID_IConnectionPointContainer, (void**)ppCPC);
}
/************************************************************************
* ConnectionPointImpl_Advise (IConnectionPoint)
*
*/
static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface,
IUnknown *lpUnk,
DWORD *pdwCookie)
{
DWORD i;
ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
IUnknown *lpSink;
TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie);
*pdwCookie = 0;
if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (void**)&lpSink)))
return CONNECT_E_CANNOTCONNECT;
for(i = 0; i < This->maxSinks; i++) {
if(This->sinks[i] == NULL)
break;
}
if(i == This->maxSinks) {
This->maxSinks += MAXSINKS;
This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks,
This->maxSinks * sizeof(IUnknown *));
}
This->sinks[i] = lpSink;
This->nSinks++;
*pdwCookie = i + 1;
return S_OK;
}
/************************************************************************
* ConnectionPointImpl_Unadvise (IConnectionPoint)
*
*/
static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface,
DWORD dwCookie)
{
ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
TRACE("(%p)->(%d)\n", This, dwCookie);
if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG;
if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION;
IUnknown_Release(This->sinks[dwCookie-1]);
This->sinks[dwCookie-1] = NULL;
This->nSinks--;
return S_OK;
}
/************************************************************************
* ConnectionPointImpl_EnumConnections (IConnectionPoint)
*
*/
static HRESULT WINAPI ConnectionPointImpl_EnumConnections(
IConnectionPoint *iface,
LPENUMCONNECTIONS *ppEnum)
{
ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
CONNECTDATA *pCD;
DWORD i, nextslot;
EnumConnectionsImpl *EnumObj;
HRESULT hr;
TRACE("(%p)->(%p)\n", This, ppEnum);
*ppEnum = NULL;
if(This->nSinks == 0) return OLE_E_NOCONNECTION;
pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks);
for(i = 0, nextslot = 0; i < This->maxSinks; i++) {
if(This->sinks[i] != NULL) {
pCD[nextslot].pUnk = This->sinks[i];
pCD[nextslot].dwCookie = i + 1;
nextslot++;
}
}
assert(nextslot == This->nSinks);
/* Bump the ref count of this object up by one. It gets Released in
IEnumConnections_Release */
IConnectionPoint_AddRef(iface);
EnumObj = EnumConnectionsImpl_Construct((IUnknown*)iface, This->nSinks, pCD);
hr = IEnumConnections_QueryInterface(&EnumObj->IEnumConnections_iface,
&IID_IEnumConnections, (void**)ppEnum);
IEnumConnections_Release(&EnumObj->IEnumConnections_iface);
HeapFree(GetProcessHeap(), 0, pCD);
return hr;
}
static const IConnectionPointVtbl ConnectionPointImpl_VTable =
{
ConnectionPointImpl_QueryInterface,
ConnectionPointImpl_AddRef,
ConnectionPointImpl_Release,
ConnectionPointImpl_GetConnectionInterface,
ConnectionPointImpl_GetConnectionPointContainer,
ConnectionPointImpl_Advise,
ConnectionPointImpl_Unadvise,
ConnectionPointImpl_EnumConnections
};
static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable;
/************************************************************************
* EnumConnectionsImpl_Construct
*/
static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
DWORD nSinks,
CONNECTDATA *pCD)
{
EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
DWORD i;
Obj->IEnumConnections_iface.lpVtbl = &EnumConnectionsImpl_VTable;
Obj->ref = 1;
Obj->pUnk = pUnk;
Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA));
Obj->nConns = nSinks;
Obj->nCur = 0;
for(i = 0; i < nSinks; i++) {
Obj->pCD[i] = pCD[i];
IUnknown_AddRef(Obj->pCD[i].pUnk);
}
return Obj;
}
/************************************************************************
* EnumConnectionsImpl_Destroy
*/
static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj)
{
DWORD i;
for(i = 0; i < Obj->nConns; i++)
IUnknown_Release(Obj->pCD[i].pUnk);
HeapFree(GetProcessHeap(), 0, Obj->pCD);
HeapFree(GetProcessHeap(), 0, Obj);
return;
}
/************************************************************************
* EnumConnectionsImpl_QueryInterface (IUnknown)
*
* See Windows documentation for more details on IUnknown methods.
*/
static HRESULT WINAPI EnumConnectionsImpl_QueryInterface(
IEnumConnections* iface,
REFIID riid,
void** ppvObject)
{
ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
/*
* Perform a sanity check on the parameters.
*/
if (!ppvObject)
return E_INVALIDARG;
/*
* Initialize the return parameter.
*/
*ppvObject = 0;
if (IsEqualIID(&IID_IEnumConnections, riid) || IsEqualIID(&IID_IUnknown, riid))
*ppvObject = iface;
/*
* Check that we obtained an interface.
*/
if ((*ppvObject)==0)
{
FIXME("() : asking for unsupported interface %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
IUnknown_AddRef((IUnknown*)*ppvObject);
return S_OK;
}
/************************************************************************
* EnumConnectionsImpl_AddRef (IUnknown)
*
* See Windows documentation for more details on IUnknown methods.
*/
static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface)
{
EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
ULONG refCount = InterlockedIncrement(&This->ref);
TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
IUnknown_AddRef(This->pUnk);
return refCount;
}
/************************************************************************
* EnumConnectionsImpl_Release (IUnknown)
*
* See Windows documentation for more details on IUnknown methods.
*/
static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface)
{
EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
ULONG refCount = InterlockedDecrement(&This->ref);
TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
IUnknown_Release(This->pUnk);
/*
* If the reference count goes down to 0, perform suicide.
*/
if (!refCount) EnumConnectionsImpl_Destroy(This);
return refCount;
}
/************************************************************************
* EnumConnectionsImpl_Next (IEnumConnections)
*
*/
static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface,
ULONG cConn, LPCONNECTDATA pCD,
ULONG *pEnum)
{
EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
DWORD nRet = 0;
TRACE("(%p)->(%d, %p, %p)\n", This, cConn, pCD, pEnum);
if(pEnum == NULL) {
if(cConn != 1)
return E_POINTER;
} else
*pEnum = 0;
if(This->nCur >= This->nConns)
return S_FALSE;
while(This->nCur < This->nConns && cConn) {
*pCD++ = This->pCD[This->nCur];
IUnknown_AddRef(This->pCD[This->nCur].pUnk);
This->nCur++;
cConn--;
nRet++;
}
if(pEnum)
*pEnum = nRet;
return S_OK;
}
/************************************************************************
* EnumConnectionsImpl_Skip (IEnumConnections)
*
*/
static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface,
ULONG cSkip)
{
EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
TRACE("(%p)->(%d)\n", This, cSkip);
if(This->nCur + cSkip >= This->nConns)
return S_FALSE;
This->nCur += cSkip;
return S_OK;
}
/************************************************************************
* EnumConnectionsImpl_Reset (IEnumConnections)
*
*/
static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface)
{
EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
TRACE("(%p)\n", This);
This->nCur = 0;
return S_OK;
}
/************************************************************************
* EnumConnectionsImpl_Clone (IEnumConnections)
*
*/
static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface,
LPENUMCONNECTIONS *ppEnum)
{
EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
EnumConnectionsImpl *newObj;
TRACE("(%p)->(%p)\n", This, ppEnum);
newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD);
newObj->nCur = This->nCur;
*ppEnum = &newObj->IEnumConnections_iface;
IUnknown_AddRef(This->pUnk);
return S_OK;
}
static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable =
{
EnumConnectionsImpl_QueryInterface,
EnumConnectionsImpl_AddRef,
EnumConnectionsImpl_Release,
EnumConnectionsImpl_Next,
EnumConnectionsImpl_Skip,
EnumConnectionsImpl_Reset,
EnumConnectionsImpl_Clone
};
/************************************************************************
*
* The exported function to create the connection point.
* NB not a windows API
*
* PARAMS
* pUnk [in] IUnknown of object to which the ConnectionPoint is associated.
* Needed to access IConnectionPointContainer.
*
* riid [in] IID of sink interface that this ConnectionPoint manages
*
* pCP [out] returns IConnectionPoint
*
*/
HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid,
IConnectionPoint **pCP)
{
ConnectionPointImpl *Obj;
TRACE("(%p %s %p)\n", pUnk, debugstr_guid(riid), pCP);
*pCP = NULL;
Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
if (!Obj)
return E_OUTOFMEMORY;
Obj->IConnectionPoint_iface.lpVtbl = &ConnectionPointImpl_VTable;
Obj->Obj = pUnk;
Obj->ref = 1;
Obj->iid = *riid;
Obj->maxSinks = MAXSINKS;
Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IUnknown*) * MAXSINKS);
Obj->nSinks = 0;
*pCP = &Obj->IConnectionPoint_iface;
return S_OK;
}