904 lines
25 KiB
C
904 lines
25 KiB
C
/*
|
|
* OLE2 COM objects
|
|
*
|
|
* Copyright 1998 Eric Kohl
|
|
* Copyright 1999 Francis Beaudet
|
|
*
|
|
* 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
|
|
*/
|
|
|
|
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#define COBJMACROS
|
|
#define NONAMELESSUNION
|
|
#define NONAMELESSSTRUCT
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winuser.h"
|
|
#include "winerror.h"
|
|
#include "wine/debug.h"
|
|
#include "ole2.h"
|
|
|
|
#include "compobj_private.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
|
|
|
#define INITIAL_SINKS 10
|
|
|
|
static void release_statdata(STATDATA *data)
|
|
{
|
|
if(data->formatetc.ptd)
|
|
{
|
|
CoTaskMemFree(data->formatetc.ptd);
|
|
data->formatetc.ptd = NULL;
|
|
}
|
|
|
|
if(data->pAdvSink)
|
|
{
|
|
IAdviseSink_Release(data->pAdvSink);
|
|
data->pAdvSink = NULL;
|
|
}
|
|
}
|
|
|
|
static HRESULT copy_statdata(STATDATA *dst, const STATDATA *src)
|
|
{
|
|
*dst = *src;
|
|
if(src->formatetc.ptd)
|
|
{
|
|
dst->formatetc.ptd = CoTaskMemAlloc(src->formatetc.ptd->tdSize);
|
|
if(!dst->formatetc.ptd) return E_OUTOFMEMORY;
|
|
memcpy(dst->formatetc.ptd, src->formatetc.ptd, src->formatetc.ptd->tdSize);
|
|
}
|
|
if(dst->pAdvSink) IAdviseSink_AddRef(dst->pAdvSink);
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* EnumSTATDATA Implementation
|
|
*/
|
|
|
|
static HRESULT EnumSTATDATA_Construct(IUnknown *holder, ULONG index, DWORD array_len, STATDATA *data, IEnumSTATDATA **ppenum);
|
|
|
|
typedef struct
|
|
{
|
|
IEnumSTATDATA IEnumSTATDATA_iface;
|
|
LONG ref;
|
|
|
|
ULONG index;
|
|
DWORD num_of_elems;
|
|
STATDATA *statdata;
|
|
IUnknown *holder;
|
|
} EnumSTATDATA;
|
|
|
|
static inline EnumSTATDATA *impl_from_IEnumSTATDATA(IEnumSTATDATA *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, EnumSTATDATA, IEnumSTATDATA_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI EnumSTATDATA_QueryInterface(IEnumSTATDATA *iface, REFIID riid, void **ppv)
|
|
{
|
|
TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
|
|
if (IsEqualIID(riid, &IID_IUnknown) ||
|
|
IsEqualIID(riid, &IID_IEnumSTATDATA))
|
|
{
|
|
IUnknown_AddRef(iface);
|
|
*ppv = iface;
|
|
return S_OK;
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI EnumSTATDATA_AddRef(IEnumSTATDATA *iface)
|
|
{
|
|
EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
|
|
TRACE("()\n");
|
|
return InterlockedIncrement(&This->ref);
|
|
}
|
|
|
|
static ULONG WINAPI EnumSTATDATA_Release(IEnumSTATDATA *iface)
|
|
{
|
|
EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
|
|
LONG refs = InterlockedDecrement(&This->ref);
|
|
TRACE("()\n");
|
|
if (!refs)
|
|
{
|
|
DWORD i;
|
|
for(i = 0; i < This->num_of_elems; i++)
|
|
release_statdata(This->statdata + i);
|
|
HeapFree(GetProcessHeap(), 0, This->statdata);
|
|
IUnknown_Release(This->holder);
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
}
|
|
return refs;
|
|
}
|
|
|
|
static HRESULT WINAPI EnumSTATDATA_Next(IEnumSTATDATA *iface, ULONG num, LPSTATDATA data,
|
|
ULONG *fetched)
|
|
{
|
|
EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
|
|
DWORD count = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
TRACE("(%d, %p, %p)\n", num, data, fetched);
|
|
|
|
while(num--)
|
|
{
|
|
if (This->index >= This->num_of_elems)
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
copy_statdata(data + count, This->statdata + This->index);
|
|
|
|
count++;
|
|
This->index++;
|
|
}
|
|
|
|
if (fetched) *fetched = count;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI EnumSTATDATA_Skip(IEnumSTATDATA *iface, ULONG num)
|
|
{
|
|
EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
|
|
|
|
TRACE("(%d)\n", num);
|
|
|
|
if(This->index + num >= This->num_of_elems)
|
|
{
|
|
This->index = This->num_of_elems;
|
|
return S_FALSE;
|
|
}
|
|
|
|
This->index += num;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI EnumSTATDATA_Reset(IEnumSTATDATA *iface)
|
|
{
|
|
EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
|
|
|
|
TRACE("()\n");
|
|
|
|
This->index = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI EnumSTATDATA_Clone(IEnumSTATDATA *iface, IEnumSTATDATA **ppenum)
|
|
{
|
|
EnumSTATDATA *This = impl_from_IEnumSTATDATA(iface);
|
|
|
|
return EnumSTATDATA_Construct(This->holder, This->index, This->num_of_elems, This->statdata, ppenum);
|
|
}
|
|
|
|
static const IEnumSTATDATAVtbl EnumSTATDATA_VTable =
|
|
{
|
|
EnumSTATDATA_QueryInterface,
|
|
EnumSTATDATA_AddRef,
|
|
EnumSTATDATA_Release,
|
|
EnumSTATDATA_Next,
|
|
EnumSTATDATA_Skip,
|
|
EnumSTATDATA_Reset,
|
|
EnumSTATDATA_Clone
|
|
};
|
|
|
|
static HRESULT EnumSTATDATA_Construct(IUnknown *holder, ULONG index, DWORD array_len, STATDATA *data,
|
|
IEnumSTATDATA **ppenum)
|
|
{
|
|
EnumSTATDATA *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
|
|
DWORD i, count;
|
|
|
|
if (!This) return E_OUTOFMEMORY;
|
|
|
|
This->IEnumSTATDATA_iface.lpVtbl = &EnumSTATDATA_VTable;
|
|
This->ref = 1;
|
|
This->index = index;
|
|
|
|
This->statdata = HeapAlloc(GetProcessHeap(), 0, array_len * sizeof(*This->statdata));
|
|
if(!This->statdata)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
for(i = 0, count = 0; i < array_len; i++)
|
|
{
|
|
if(data[i].pAdvSink)
|
|
{
|
|
copy_statdata(This->statdata + count, data + i);
|
|
count++;
|
|
}
|
|
}
|
|
|
|
This->num_of_elems = count;
|
|
This->holder = holder;
|
|
IUnknown_AddRef(holder);
|
|
*ppenum = &This->IEnumSTATDATA_iface;
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* OleAdviseHolder Implementation
|
|
*/
|
|
typedef struct
|
|
{
|
|
IOleAdviseHolder IOleAdviseHolder_iface;
|
|
|
|
LONG ref;
|
|
|
|
DWORD max_cons;
|
|
STATDATA *connections;
|
|
} OleAdviseHolderImpl;
|
|
|
|
static inline OleAdviseHolderImpl *impl_from_IOleAdviseHolder(IOleAdviseHolder *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, OleAdviseHolderImpl, IOleAdviseHolder_iface);
|
|
}
|
|
|
|
/**************************************************************************
|
|
* OleAdviseHolderImpl_Destructor
|
|
*/
|
|
static void OleAdviseHolderImpl_Destructor(OleAdviseHolderImpl *This)
|
|
{
|
|
DWORD index;
|
|
TRACE("%p\n", This);
|
|
|
|
for (index = 0; index < This->max_cons; index++)
|
|
{
|
|
if (This->connections[index].pAdvSink != NULL)
|
|
release_statdata(This->connections + index);
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, This->connections);
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
}
|
|
|
|
/**************************************************************************
|
|
* OleAdviseHolderImpl_QueryInterface
|
|
*/
|
|
static HRESULT WINAPI OleAdviseHolderImpl_QueryInterface(IOleAdviseHolder *iface,
|
|
REFIID iid, void **obj)
|
|
{
|
|
OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
|
|
TRACE("(%p)->(%s,%p)\n",This, debugstr_guid(iid), obj);
|
|
|
|
if (obj == NULL)
|
|
return E_POINTER;
|
|
|
|
*obj = NULL;
|
|
|
|
if (IsEqualIID(iid, &IID_IUnknown) ||
|
|
IsEqualIID(iid, &IID_IOleAdviseHolder))
|
|
{
|
|
*obj = &This->IOleAdviseHolder_iface;
|
|
}
|
|
|
|
if(*obj == NULL)
|
|
return E_NOINTERFACE;
|
|
|
|
IUnknown_AddRef((IUnknown*)*obj);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* OleAdviseHolderImpl_AddRef
|
|
*/
|
|
static ULONG WINAPI OleAdviseHolderImpl_AddRef(IOleAdviseHolder *iface)
|
|
{
|
|
OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
|
|
ULONG ref = InterlockedIncrement(&This->ref);
|
|
|
|
TRACE("(%p)->(ref=%d)\n", This, ref - 1);
|
|
|
|
return ref;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* OleAdviseHolderImpl_Release
|
|
*/
|
|
static ULONG WINAPI OleAdviseHolderImpl_Release(IOleAdviseHolder *iface)
|
|
{
|
|
OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
|
|
ULONG ref;
|
|
TRACE("(%p)->(ref=%d)\n", This, This->ref);
|
|
ref = InterlockedDecrement(&This->ref);
|
|
|
|
if (ref == 0) OleAdviseHolderImpl_Destructor(This);
|
|
|
|
return ref;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* OleAdviseHolderImpl_Advise
|
|
*/
|
|
static HRESULT WINAPI OleAdviseHolderImpl_Advise(IOleAdviseHolder *iface,
|
|
IAdviseSink *pAdvise,
|
|
DWORD *pdwConnection)
|
|
{
|
|
DWORD index;
|
|
OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
|
|
STATDATA new_conn;
|
|
static const FORMATETC empty_fmtetc = {0, NULL, 0, -1, 0};
|
|
|
|
TRACE("(%p)->(%p, %p)\n", This, pAdvise, pdwConnection);
|
|
|
|
if (pdwConnection==NULL)
|
|
return E_POINTER;
|
|
|
|
*pdwConnection = 0;
|
|
|
|
for (index = 0; index < This->max_cons; index++)
|
|
{
|
|
if (This->connections[index].pAdvSink == NULL)
|
|
break;
|
|
}
|
|
|
|
if (index == This->max_cons)
|
|
{
|
|
This->max_cons += INITIAL_SINKS;
|
|
This->connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->connections,
|
|
This->max_cons * sizeof(*This->connections));
|
|
}
|
|
|
|
new_conn.pAdvSink = pAdvise;
|
|
new_conn.advf = 0;
|
|
new_conn.formatetc = empty_fmtetc;
|
|
new_conn.dwConnection = index + 1; /* 0 is not a valid cookie, so increment the index */
|
|
|
|
copy_statdata(This->connections + index, &new_conn);
|
|
|
|
*pdwConnection = new_conn.dwConnection;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* OleAdviseHolderImpl_Unadvise
|
|
*/
|
|
static HRESULT WINAPI OleAdviseHolderImpl_Unadvise(IOleAdviseHolder *iface,
|
|
DWORD dwConnection)
|
|
{
|
|
OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
|
|
DWORD index;
|
|
|
|
TRACE("(%p)->(%u)\n", This, dwConnection);
|
|
|
|
/* The connection number is 1 more than the index, see OleAdviseHolder_Advise */
|
|
index = dwConnection - 1;
|
|
|
|
if (index >= This->max_cons || This->connections[index].pAdvSink == NULL)
|
|
return OLE_E_NOCONNECTION;
|
|
|
|
release_statdata(This->connections + index);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* OleAdviseHolderImpl_EnumAdvise
|
|
*/
|
|
static HRESULT WINAPI OleAdviseHolderImpl_EnumAdvise(IOleAdviseHolder *iface, IEnumSTATDATA **enum_advise)
|
|
{
|
|
OleAdviseHolderImpl *This = impl_from_IOleAdviseHolder(iface);
|
|
IUnknown *unk;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)->(%p)\n", This, enum_advise);
|
|
|
|
IOleAdviseHolder_QueryInterface(iface, &IID_IUnknown, (void**)&unk);
|
|
hr = EnumSTATDATA_Construct(unk, 0, This->max_cons, This->connections, enum_advise);
|
|
IUnknown_Release(unk);
|
|
return hr;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* OleAdviseHolderImpl_SendOnRename
|
|
*/
|
|
static HRESULT WINAPI OleAdviseHolderImpl_SendOnRename(IOleAdviseHolder *iface, IMoniker *pmk)
|
|
{
|
|
IEnumSTATDATA *pEnum;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)->(%p)\n", iface, pmk);
|
|
|
|
hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
STATDATA statdata;
|
|
while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
|
|
{
|
|
IAdviseSink_OnRename(statdata.pAdvSink, pmk);
|
|
|
|
IAdviseSink_Release(statdata.pAdvSink);
|
|
}
|
|
IEnumSTATDATA_Release(pEnum);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* OleAdviseHolderImpl_SendOnSave
|
|
*/
|
|
static HRESULT WINAPI OleAdviseHolderImpl_SendOnSave(IOleAdviseHolder *iface)
|
|
{
|
|
IEnumSTATDATA *pEnum;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)->()\n", iface);
|
|
|
|
hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
STATDATA statdata;
|
|
while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
|
|
{
|
|
IAdviseSink_OnSave(statdata.pAdvSink);
|
|
|
|
IAdviseSink_Release(statdata.pAdvSink);
|
|
}
|
|
IEnumSTATDATA_Release(pEnum);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* OleAdviseHolderImpl_SendOnClose
|
|
*/
|
|
static HRESULT WINAPI OleAdviseHolderImpl_SendOnClose(IOleAdviseHolder *iface)
|
|
{
|
|
IEnumSTATDATA *pEnum;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)->()\n", iface);
|
|
|
|
hr = IOleAdviseHolder_EnumAdvise(iface, &pEnum);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
STATDATA statdata;
|
|
while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
|
|
{
|
|
IAdviseSink_OnClose(statdata.pAdvSink);
|
|
|
|
IAdviseSink_Release(statdata.pAdvSink);
|
|
}
|
|
IEnumSTATDATA_Release(pEnum);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* OleAdviseHolderImpl_VTable
|
|
*/
|
|
static const IOleAdviseHolderVtbl oahvt =
|
|
{
|
|
OleAdviseHolderImpl_QueryInterface,
|
|
OleAdviseHolderImpl_AddRef,
|
|
OleAdviseHolderImpl_Release,
|
|
OleAdviseHolderImpl_Advise,
|
|
OleAdviseHolderImpl_Unadvise,
|
|
OleAdviseHolderImpl_EnumAdvise,
|
|
OleAdviseHolderImpl_SendOnRename,
|
|
OleAdviseHolderImpl_SendOnSave,
|
|
OleAdviseHolderImpl_SendOnClose
|
|
};
|
|
|
|
/**************************************************************************
|
|
* OleAdviseHolderImpl_Constructor
|
|
*/
|
|
|
|
static IOleAdviseHolder *OleAdviseHolderImpl_Constructor(void)
|
|
{
|
|
OleAdviseHolderImpl* lpoah;
|
|
|
|
lpoah = HeapAlloc(GetProcessHeap(), 0, sizeof(OleAdviseHolderImpl));
|
|
|
|
lpoah->IOleAdviseHolder_iface.lpVtbl = &oahvt;
|
|
lpoah->ref = 1;
|
|
lpoah->max_cons = INITIAL_SINKS;
|
|
lpoah->connections = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
lpoah->max_cons * sizeof(*lpoah->connections));
|
|
|
|
TRACE("returning %p\n", &lpoah->IOleAdviseHolder_iface);
|
|
return &lpoah->IOleAdviseHolder_iface;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* DataAdviseHolder Implementation
|
|
*/
|
|
typedef struct
|
|
{
|
|
IDataAdviseHolder IDataAdviseHolder_iface;
|
|
|
|
LONG ref;
|
|
DWORD maxCons;
|
|
STATDATA* connections;
|
|
DWORD* remote_connections;
|
|
IDataObject* delegate;
|
|
} DataAdviseHolder;
|
|
|
|
/* this connection has also has been advised to the delegate data object */
|
|
#define WINE_ADVF_REMOTE 0x80000000
|
|
|
|
static inline DataAdviseHolder *impl_from_IDataAdviseHolder(IDataAdviseHolder *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, DataAdviseHolder, IDataAdviseHolder_iface);
|
|
}
|
|
|
|
/******************************************************************************
|
|
* DataAdviseHolder_Destructor
|
|
*/
|
|
static void DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy)
|
|
{
|
|
DWORD index;
|
|
TRACE("%p\n", ptrToDestroy);
|
|
|
|
for (index = 0; index < ptrToDestroy->maxCons; index++)
|
|
{
|
|
if (ptrToDestroy->connections[index].pAdvSink != NULL)
|
|
{
|
|
if (ptrToDestroy->delegate &&
|
|
(ptrToDestroy->connections[index].advf & WINE_ADVF_REMOTE))
|
|
IDataObject_DUnadvise(ptrToDestroy->delegate,
|
|
ptrToDestroy->remote_connections[index]);
|
|
|
|
release_statdata(ptrToDestroy->connections + index);
|
|
}
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, ptrToDestroy->remote_connections);
|
|
HeapFree(GetProcessHeap(), 0, ptrToDestroy->connections);
|
|
HeapFree(GetProcessHeap(), 0, ptrToDestroy);
|
|
}
|
|
|
|
/************************************************************************
|
|
* DataAdviseHolder_QueryInterface (IUnknown)
|
|
*/
|
|
static HRESULT WINAPI DataAdviseHolder_QueryInterface(IDataAdviseHolder *iface,
|
|
REFIID riid, void **ppvObject)
|
|
{
|
|
DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
|
|
TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject);
|
|
|
|
if ( (This==0) || (ppvObject==0) )
|
|
return E_INVALIDARG;
|
|
|
|
*ppvObject = 0;
|
|
|
|
if ( IsEqualIID(&IID_IUnknown, riid) ||
|
|
IsEqualIID(&IID_IDataAdviseHolder, riid) )
|
|
{
|
|
*ppvObject = iface;
|
|
}
|
|
|
|
if ((*ppvObject)==0)
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
IUnknown_AddRef((IUnknown*)*ppvObject);
|
|
return S_OK;
|
|
}
|
|
|
|
/************************************************************************
|
|
* DataAdviseHolder_AddRef (IUnknown)
|
|
*/
|
|
static ULONG WINAPI DataAdviseHolder_AddRef(IDataAdviseHolder *iface)
|
|
{
|
|
DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
|
|
TRACE("(%p) (ref=%d)\n", This, This->ref);
|
|
return InterlockedIncrement(&This->ref);
|
|
}
|
|
|
|
/************************************************************************
|
|
* DataAdviseHolder_Release (IUnknown)
|
|
*/
|
|
static ULONG WINAPI DataAdviseHolder_Release(IDataAdviseHolder *iface)
|
|
{
|
|
DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
|
|
ULONG ref;
|
|
TRACE("(%p) (ref=%d)\n", This, This->ref);
|
|
|
|
ref = InterlockedDecrement(&This->ref);
|
|
if (ref==0) DataAdviseHolder_Destructor(This);
|
|
|
|
return ref;
|
|
}
|
|
|
|
/************************************************************************
|
|
* DataAdviseHolder_Advise
|
|
*
|
|
*/
|
|
static HRESULT WINAPI DataAdviseHolder_Advise(IDataAdviseHolder *iface,
|
|
IDataObject *pDataObject, FORMATETC *pFetc,
|
|
DWORD advf, IAdviseSink *pAdvise,
|
|
DWORD *pdwConnection)
|
|
{
|
|
DWORD index;
|
|
STATDATA new_conn;
|
|
DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
|
|
|
|
TRACE("(%p)->(%p, %p, %08x, %p, %p)\n", This, pDataObject, pFetc, advf,
|
|
pAdvise, pdwConnection);
|
|
|
|
if (pdwConnection==NULL)
|
|
return E_POINTER;
|
|
|
|
*pdwConnection = 0;
|
|
|
|
for (index = 0; index < This->maxCons; index++)
|
|
{
|
|
if (This->connections[index].pAdvSink == NULL)
|
|
break;
|
|
}
|
|
|
|
if (index == This->maxCons)
|
|
{
|
|
This->maxCons+=INITIAL_SINKS;
|
|
This->connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
This->connections,
|
|
This->maxCons * sizeof(*This->connections));
|
|
This->remote_connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
This->remote_connections,
|
|
This->maxCons * sizeof(*This->remote_connections));
|
|
}
|
|
|
|
new_conn.pAdvSink = pAdvise;
|
|
new_conn.advf = advf & ~WINE_ADVF_REMOTE;
|
|
new_conn.formatetc = *pFetc;
|
|
new_conn.dwConnection = index + 1; /* 0 is not a valid cookie, so increment the index */
|
|
|
|
copy_statdata(This->connections + index, &new_conn);
|
|
|
|
if (This->connections[index].pAdvSink != NULL)
|
|
{
|
|
/* if we are already connected advise the remote object */
|
|
if (This->delegate)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = IDataObject_DAdvise(This->delegate, &new_conn.formatetc,
|
|
new_conn.advf, new_conn.pAdvSink,
|
|
&This->remote_connections[index]);
|
|
if (FAILED(hr))
|
|
{
|
|
IDataAdviseHolder_Unadvise(iface, new_conn.dwConnection);
|
|
return hr;
|
|
}
|
|
This->connections[index].advf |= WINE_ADVF_REMOTE;
|
|
}
|
|
else if(advf & ADVF_PRIMEFIRST)
|
|
/* only do this if we have no delegate, since in the above case the
|
|
* delegate will do the priming for us */
|
|
IDataAdviseHolder_SendOnDataChange(iface, pDataObject, 0, advf);
|
|
}
|
|
|
|
*pdwConnection = new_conn.dwConnection;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* DataAdviseHolder_Unadvise
|
|
*/
|
|
static HRESULT WINAPI DataAdviseHolder_Unadvise(IDataAdviseHolder *iface,
|
|
DWORD dwConnection)
|
|
{
|
|
DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
|
|
DWORD index;
|
|
TRACE("(%p)->(%u)\n", This, dwConnection);
|
|
|
|
/* The connection number is 1 more than the index, see DataAdviseHolder_Advise */
|
|
index = dwConnection - 1;
|
|
|
|
if (index >= This->maxCons || This->connections[index].pAdvSink == NULL)
|
|
return OLE_E_NOCONNECTION;
|
|
|
|
if (This->delegate && This->connections[index].advf & WINE_ADVF_REMOTE)
|
|
{
|
|
IDataObject_DUnadvise(This->delegate, This->remote_connections[index]);
|
|
This->remote_connections[index] = 0;
|
|
}
|
|
|
|
release_statdata(This->connections + index);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* DataAdviseHolder_EnumAdvise
|
|
*/
|
|
static HRESULT WINAPI DataAdviseHolder_EnumAdvise(IDataAdviseHolder *iface,
|
|
IEnumSTATDATA **enum_advise)
|
|
{
|
|
DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
|
|
IUnknown *unk;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)->(%p)\n", This, enum_advise);
|
|
|
|
IDataAdviseHolder_QueryInterface(iface, &IID_IUnknown, (void**)&unk);
|
|
hr = EnumSTATDATA_Construct(unk, 0, This->maxCons, This->connections, enum_advise);
|
|
IUnknown_Release(unk);
|
|
return hr;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* DataAdviseHolder_SendOnDataChange
|
|
*/
|
|
static HRESULT WINAPI DataAdviseHolder_SendOnDataChange(IDataAdviseHolder *iface,
|
|
IDataObject *data_obj,
|
|
DWORD dwReserved, DWORD advf)
|
|
{
|
|
IEnumSTATDATA *pEnum;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)->(%p, %08x, %08x)\n", iface, data_obj, dwReserved, advf);
|
|
|
|
hr = IDataAdviseHolder_EnumAdvise(iface, &pEnum);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
STATDATA statdata;
|
|
while (IEnumSTATDATA_Next(pEnum, 1, &statdata, NULL) == S_OK)
|
|
{
|
|
STGMEDIUM stg;
|
|
stg.tymed = TYMED_NULL;
|
|
stg.u.pstg = NULL;
|
|
stg.pUnkForRelease = NULL;
|
|
|
|
if(!(statdata.advf & ADVF_NODATA))
|
|
{
|
|
hr = IDataObject_GetData(data_obj, &statdata.formatetc, &stg);
|
|
}
|
|
|
|
IAdviseSink_OnDataChange(statdata.pAdvSink, &statdata.formatetc, &stg);
|
|
|
|
if(statdata.advf & ADVF_ONLYONCE)
|
|
{
|
|
IDataAdviseHolder_Unadvise(iface, statdata.dwConnection);
|
|
}
|
|
|
|
release_statdata(&statdata);
|
|
}
|
|
IEnumSTATDATA_Release(pEnum);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* DataAdviseHolderImpl_VTable
|
|
*/
|
|
static const IDataAdviseHolderVtbl DataAdviseHolderImpl_VTable =
|
|
{
|
|
DataAdviseHolder_QueryInterface,
|
|
DataAdviseHolder_AddRef,
|
|
DataAdviseHolder_Release,
|
|
DataAdviseHolder_Advise,
|
|
DataAdviseHolder_Unadvise,
|
|
DataAdviseHolder_EnumAdvise,
|
|
DataAdviseHolder_SendOnDataChange
|
|
};
|
|
|
|
HRESULT DataAdviseHolder_OnConnect(IDataAdviseHolder *iface, IDataObject *pDelegate)
|
|
{
|
|
DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
|
|
DWORD index;
|
|
HRESULT hr = S_OK;
|
|
|
|
for(index = 0; index < This->maxCons; index++)
|
|
{
|
|
if(This->connections[index].pAdvSink != NULL)
|
|
{
|
|
hr = IDataObject_DAdvise(pDelegate, &This->connections[index].formatetc,
|
|
This->connections[index].advf,
|
|
This->connections[index].pAdvSink,
|
|
&This->remote_connections[index]);
|
|
if (FAILED(hr)) break;
|
|
This->connections[index].advf |= WINE_ADVF_REMOTE;
|
|
}
|
|
}
|
|
This->delegate = pDelegate;
|
|
return hr;
|
|
}
|
|
|
|
void DataAdviseHolder_OnDisconnect(IDataAdviseHolder *iface)
|
|
{
|
|
DataAdviseHolder *This = impl_from_IDataAdviseHolder(iface);
|
|
DWORD index;
|
|
|
|
for(index = 0; index < This->maxCons; index++)
|
|
{
|
|
if((This->connections[index].pAdvSink != NULL) &&
|
|
(This->connections[index].advf & WINE_ADVF_REMOTE))
|
|
{
|
|
IDataObject_DUnadvise(This->delegate, This->remote_connections[index]);
|
|
This->remote_connections[index] = 0;
|
|
This->connections[index].advf &= ~WINE_ADVF_REMOTE;
|
|
}
|
|
}
|
|
This->delegate = NULL;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* DataAdviseHolder_Constructor
|
|
*/
|
|
static IDataAdviseHolder *DataAdviseHolder_Constructor(void)
|
|
{
|
|
DataAdviseHolder* newHolder;
|
|
|
|
newHolder = HeapAlloc(GetProcessHeap(), 0, sizeof(DataAdviseHolder));
|
|
|
|
newHolder->IDataAdviseHolder_iface.lpVtbl = &DataAdviseHolderImpl_VTable;
|
|
newHolder->ref = 1;
|
|
newHolder->maxCons = INITIAL_SINKS;
|
|
newHolder->connections = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
newHolder->maxCons * sizeof(*newHolder->connections));
|
|
newHolder->remote_connections = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
newHolder->maxCons * sizeof(*newHolder->remote_connections));
|
|
newHolder->delegate = NULL;
|
|
|
|
TRACE("returning %p\n", &newHolder->IDataAdviseHolder_iface);
|
|
return &newHolder->IDataAdviseHolder_iface;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* API functions
|
|
*/
|
|
|
|
/***********************************************************************
|
|
* CreateOleAdviseHolder [OLE32.@]
|
|
*/
|
|
HRESULT WINAPI CreateOleAdviseHolder(IOleAdviseHolder **ppOAHolder)
|
|
{
|
|
TRACE("(%p)\n", ppOAHolder);
|
|
|
|
if (ppOAHolder==NULL)
|
|
return E_POINTER;
|
|
|
|
*ppOAHolder = OleAdviseHolderImpl_Constructor ();
|
|
|
|
if (*ppOAHolder != NULL)
|
|
return S_OK;
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* CreateDataAdviseHolder [OLE32.@]
|
|
*/
|
|
HRESULT WINAPI CreateDataAdviseHolder(IDataAdviseHolder **ppDAHolder)
|
|
{
|
|
TRACE("(%p)\n", ppDAHolder);
|
|
|
|
if (ppDAHolder==NULL)
|
|
return E_POINTER;
|
|
|
|
*ppDAHolder = DataAdviseHolder_Constructor();
|
|
|
|
if (*ppDAHolder != NULL)
|
|
return S_OK;
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|