| /* | 
 |  *	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; | 
 | } |