|  | /* | 
|  | *	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 | 
|  |  | 
|  | #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 | 
|  |  | 
|  | /************************************************************************** | 
|  | *  OleAdviseHolderImpl Implementation | 
|  | */ | 
|  | typedef struct OleAdviseHolderImpl | 
|  | { | 
|  | const IOleAdviseHolderVtbl *lpVtbl; | 
|  |  | 
|  | LONG ref; | 
|  |  | 
|  | DWORD         maxSinks; | 
|  | IAdviseSink** arrayOfSinks; | 
|  |  | 
|  | } OleAdviseHolderImpl; | 
|  |  | 
|  | static HRESULT EnumOleSTATDATA_Construct(OleAdviseHolderImpl *pOleAdviseHolder, ULONG index, IEnumSTATDATA **ppenum); | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | const IEnumSTATDATAVtbl *lpvtbl; | 
|  | LONG ref; | 
|  |  | 
|  | ULONG index; | 
|  | OleAdviseHolderImpl *pOleAdviseHolder; | 
|  | } EnumOleSTATDATA; | 
|  |  | 
|  | static HRESULT WINAPI EnumOleSTATDATA_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 EnumOleSTATDATA_AddRef( | 
|  | IEnumSTATDATA *iface) | 
|  | { | 
|  | EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface; | 
|  | TRACE("()\n"); | 
|  | return InterlockedIncrement(&This->ref); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI EnumOleSTATDATA_Release( | 
|  | IEnumSTATDATA *iface) | 
|  | { | 
|  | EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface; | 
|  | LONG refs = InterlockedDecrement(&This->ref); | 
|  | TRACE("()\n"); | 
|  | if (!refs) | 
|  | { | 
|  | IOleAdviseHolder_Release((IOleAdviseHolder *)This->pOleAdviseHolder); | 
|  | HeapFree(GetProcessHeap(), 0, This); | 
|  | } | 
|  | return refs; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI EnumOleSTATDATA_Next( | 
|  | IEnumSTATDATA *iface, ULONG celt, LPSTATDATA rgelt, | 
|  | ULONG *pceltFetched) | 
|  | { | 
|  | EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface; | 
|  | HRESULT hr = S_OK; | 
|  |  | 
|  | TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); | 
|  |  | 
|  | if (pceltFetched) | 
|  | *pceltFetched = 0; | 
|  |  | 
|  | for (; celt; celt--, rgelt++) | 
|  | { | 
|  | while ((This->index < This->pOleAdviseHolder->maxSinks) && | 
|  | !This->pOleAdviseHolder->arrayOfSinks[This->index]) | 
|  | { | 
|  | This->index++; | 
|  | } | 
|  | if (This->index >= This->pOleAdviseHolder->maxSinks) | 
|  | { | 
|  | hr = S_FALSE; | 
|  | break; | 
|  | } | 
|  |  | 
|  | memset(&rgelt->formatetc, 0, sizeof(rgelt->formatetc)); | 
|  | rgelt->advf = 0; | 
|  | rgelt->pAdvSink = This->pOleAdviseHolder->arrayOfSinks[This->index]; | 
|  | IAdviseSink_AddRef(rgelt->pAdvSink); | 
|  | rgelt->dwConnection = This->index; | 
|  |  | 
|  | if (pceltFetched) | 
|  | (*pceltFetched)++; | 
|  | This->index++; | 
|  | } | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI EnumOleSTATDATA_Skip( | 
|  | IEnumSTATDATA *iface, ULONG celt) | 
|  | { | 
|  | EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface; | 
|  |  | 
|  | TRACE("(%d)\n", celt); | 
|  |  | 
|  | for (; celt; celt--) | 
|  | { | 
|  | while ((This->index < This->pOleAdviseHolder->maxSinks) && | 
|  | !This->pOleAdviseHolder->arrayOfSinks[This->index]) | 
|  | { | 
|  | This->index++; | 
|  | } | 
|  | if (This->index >= This->pOleAdviseHolder->maxSinks) | 
|  | return S_FALSE; | 
|  | This->index++; | 
|  | } | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI EnumOleSTATDATA_Reset( | 
|  | IEnumSTATDATA *iface) | 
|  | { | 
|  | EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface; | 
|  |  | 
|  | TRACE("()\n"); | 
|  |  | 
|  | This->index = 0; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI EnumOleSTATDATA_Clone( | 
|  | IEnumSTATDATA *iface, | 
|  | IEnumSTATDATA **ppenum) | 
|  | { | 
|  | EnumOleSTATDATA *This = (EnumOleSTATDATA *)iface; | 
|  | return EnumOleSTATDATA_Construct(This->pOleAdviseHolder, This->index, ppenum); | 
|  | } | 
|  |  | 
|  | static const IEnumSTATDATAVtbl EnumOleSTATDATA_VTable = | 
|  | { | 
|  | EnumOleSTATDATA_QueryInterface, | 
|  | EnumOleSTATDATA_AddRef, | 
|  | EnumOleSTATDATA_Release, | 
|  | EnumOleSTATDATA_Next, | 
|  | EnumOleSTATDATA_Skip, | 
|  | EnumOleSTATDATA_Reset, | 
|  | EnumOleSTATDATA_Clone | 
|  | }; | 
|  |  | 
|  | static HRESULT EnumOleSTATDATA_Construct(OleAdviseHolderImpl *pOleAdviseHolder, ULONG index, IEnumSTATDATA **ppenum) | 
|  | { | 
|  | EnumOleSTATDATA *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); | 
|  | if (!This) | 
|  | return E_OUTOFMEMORY; | 
|  | This->lpvtbl = &EnumOleSTATDATA_VTable; | 
|  | This->ref = 1; | 
|  | This->index = index; | 
|  | This->pOleAdviseHolder = pOleAdviseHolder; | 
|  | IOleAdviseHolder_AddRef((IOleAdviseHolder *)pOleAdviseHolder); | 
|  | *ppenum = (IEnumSTATDATA *)&This->lpvtbl; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  OleAdviseHolderImpl_Destructor | 
|  | */ | 
|  | static void OleAdviseHolderImpl_Destructor( | 
|  | OleAdviseHolderImpl* ptrToDestroy) | 
|  | { | 
|  | DWORD index; | 
|  | TRACE("%p\n", ptrToDestroy); | 
|  |  | 
|  | for (index = 0; index < ptrToDestroy->maxSinks; index++) | 
|  | { | 
|  | if (ptrToDestroy->arrayOfSinks[index]!=0) | 
|  | { | 
|  | IAdviseSink_Release(ptrToDestroy->arrayOfSinks[index]); | 
|  | ptrToDestroy->arrayOfSinks[index] = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | HeapFree(GetProcessHeap(), | 
|  | 0, | 
|  | ptrToDestroy->arrayOfSinks); | 
|  |  | 
|  |  | 
|  | HeapFree(GetProcessHeap(), | 
|  | 0, | 
|  | ptrToDestroy); | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  OleAdviseHolderImpl_QueryInterface | 
|  | */ | 
|  | static HRESULT WINAPI OleAdviseHolderImpl_QueryInterface( | 
|  | LPOLEADVISEHOLDER iface, | 
|  | REFIID            riid, | 
|  | LPVOID*           ppvObj) | 
|  | { | 
|  | OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; | 
|  | TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObj); | 
|  | /* | 
|  | * Sanity check | 
|  | */ | 
|  | if (ppvObj==NULL) | 
|  | return E_POINTER; | 
|  |  | 
|  | *ppvObj = NULL; | 
|  |  | 
|  | if (IsEqualIID(riid, &IID_IUnknown)) | 
|  | { | 
|  | /* IUnknown */ | 
|  | *ppvObj = This; | 
|  | } | 
|  | else if(IsEqualIID(riid, &IID_IOleAdviseHolder)) | 
|  | { | 
|  | /* IOleAdviseHolder */ | 
|  | *ppvObj = This; | 
|  | } | 
|  |  | 
|  | if(*ppvObj == NULL) | 
|  | return E_NOINTERFACE; | 
|  |  | 
|  | /* | 
|  | * A successful QI always increments the reference count. | 
|  | */ | 
|  | IUnknown_AddRef((IUnknown*)*ppvObj); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * OleAdviseHolderImpl_AddRef | 
|  | */ | 
|  | static ULONG WINAPI OleAdviseHolderImpl_AddRef( | 
|  | LPOLEADVISEHOLDER iface) | 
|  | { | 
|  | OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; | 
|  | ULONG ref = InterlockedIncrement(&This->ref); | 
|  |  | 
|  | TRACE("(%p)->(ref=%d)\n", This, ref - 1); | 
|  |  | 
|  | return ref; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * OleAdviseHolderImpl_Release | 
|  | */ | 
|  | static ULONG WINAPI OleAdviseHolderImpl_Release( | 
|  | LPOLEADVISEHOLDER iface) | 
|  | { | 
|  | OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)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( | 
|  | LPOLEADVISEHOLDER iface, | 
|  | IAdviseSink*      pAdvise, | 
|  | DWORD*            pdwConnection) | 
|  | { | 
|  | DWORD index; | 
|  |  | 
|  | OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p, %p)\n", This, pAdvise, pdwConnection); | 
|  |  | 
|  | /* | 
|  | * Sanity check | 
|  | */ | 
|  | if (pdwConnection==NULL) | 
|  | return E_POINTER; | 
|  |  | 
|  | *pdwConnection = 0; | 
|  |  | 
|  | /* | 
|  | * Find a free spot in the array. | 
|  | */ | 
|  | for (index = 0; index < This->maxSinks; index++) | 
|  | { | 
|  | if (This->arrayOfSinks[index]==NULL) | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * If the array is full, we need to grow it. | 
|  | */ | 
|  | if (index == This->maxSinks) | 
|  | { | 
|  | DWORD i; | 
|  |  | 
|  | This->maxSinks+=INITIAL_SINKS; | 
|  |  | 
|  | This->arrayOfSinks = HeapReAlloc(GetProcessHeap(), | 
|  | 0, | 
|  | This->arrayOfSinks, | 
|  | This->maxSinks*sizeof(IAdviseSink*)); | 
|  |  | 
|  | for (i=index;i < This->maxSinks; i++) | 
|  | This->arrayOfSinks[i]=0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Store the new sink | 
|  | */ | 
|  | This->arrayOfSinks[index] = pAdvise; | 
|  |  | 
|  | if (This->arrayOfSinks[index]!=NULL) | 
|  | IAdviseSink_AddRef(This->arrayOfSinks[index]); | 
|  |  | 
|  | /* | 
|  | * Return the index as the cookie. | 
|  | * Since 0 is not a valid cookie, we will increment by | 
|  | * 1 the index in the table. | 
|  | */ | 
|  | *pdwConnection = index+1; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * OleAdviseHolderImpl_Unadvise | 
|  | */ | 
|  | static HRESULT WINAPI OleAdviseHolderImpl_Unadvise( | 
|  | LPOLEADVISEHOLDER iface, | 
|  | DWORD             dwConnection) | 
|  | { | 
|  | OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%u)\n", This, dwConnection); | 
|  |  | 
|  | /* | 
|  | * So we don't return 0 as a cookie, the index was | 
|  | * incremented by 1 in OleAdviseHolderImpl_Advise | 
|  | * we have to compensate. | 
|  | */ | 
|  | dwConnection--; | 
|  |  | 
|  | /* | 
|  | * Check for invalid cookies. | 
|  | */ | 
|  | if (dwConnection >= This->maxSinks) | 
|  | return OLE_E_NOCONNECTION; | 
|  |  | 
|  | if (This->arrayOfSinks[dwConnection] == NULL) | 
|  | return OLE_E_NOCONNECTION; | 
|  |  | 
|  | /* | 
|  | * Release the sink and mark the spot in the list as free. | 
|  | */ | 
|  | IAdviseSink_Release(This->arrayOfSinks[dwConnection]); | 
|  | This->arrayOfSinks[dwConnection] = NULL; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * OleAdviseHolderImpl_EnumAdvise | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | OleAdviseHolderImpl_EnumAdvise (LPOLEADVISEHOLDER iface, IEnumSTATDATA **ppenumAdvise) | 
|  | { | 
|  | OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n", This, ppenumAdvise); | 
|  |  | 
|  | *ppenumAdvise = NULL; | 
|  |  | 
|  | return EnumOleSTATDATA_Construct(This, 0, ppenumAdvise); | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * OleAdviseHolderImpl_SendOnRename | 
|  | */ | 
|  | static HRESULT WINAPI | 
|  | OleAdviseHolderImpl_SendOnRename (LPOLEADVISEHOLDER 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 (LPOLEADVISEHOLDER 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 (LPOLEADVISEHOLDER 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 LPOLEADVISEHOLDER OleAdviseHolderImpl_Constructor(void) | 
|  | { | 
|  | OleAdviseHolderImpl* lpoah; | 
|  | DWORD                index; | 
|  |  | 
|  | lpoah = HeapAlloc(GetProcessHeap(), 0, sizeof(OleAdviseHolderImpl)); | 
|  |  | 
|  | lpoah->lpVtbl = &oahvt; | 
|  | lpoah->ref = 1; | 
|  | lpoah->maxSinks = INITIAL_SINKS; | 
|  | lpoah->arrayOfSinks = HeapAlloc(GetProcessHeap(), | 
|  | 0, | 
|  | lpoah->maxSinks * sizeof(IAdviseSink*)); | 
|  |  | 
|  | for (index = 0; index < lpoah->maxSinks; index++) | 
|  | lpoah->arrayOfSinks[index]=0; | 
|  |  | 
|  | TRACE("returning %p\n", lpoah); | 
|  | return (LPOLEADVISEHOLDER)lpoah; | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | *  DataAdviseHolder Implementation | 
|  | */ | 
|  | typedef struct DataAdviseConnection { | 
|  | IAdviseSink *sink; | 
|  | FORMATETC fmat; | 
|  | DWORD advf; | 
|  | DWORD remote_connection; | 
|  | } DataAdviseConnection; | 
|  |  | 
|  | typedef struct DataAdviseHolder | 
|  | { | 
|  | const IDataAdviseHolderVtbl *lpVtbl; | 
|  |  | 
|  | LONG                  ref; | 
|  | DWORD                 maxCons; | 
|  | DataAdviseConnection* Connections; | 
|  | IDataObject*          delegate; | 
|  | } DataAdviseHolder; | 
|  |  | 
|  | /* this connection has also has been advised to the delegate data object */ | 
|  | #define WINE_ADVF_REMOTE 0x80000000 | 
|  |  | 
|  | /****************************************************************************** | 
|  | * 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].sink != NULL) | 
|  | { | 
|  | if (ptrToDestroy->delegate && | 
|  | (ptrToDestroy->Connections[index].advf & WINE_ADVF_REMOTE)) | 
|  | IDataObject_DUnadvise(ptrToDestroy->delegate, | 
|  | ptrToDestroy->Connections[index].remote_connection); | 
|  |  | 
|  | IAdviseSink_Release(ptrToDestroy->Connections[index].sink); | 
|  | ptrToDestroy->Connections[index].sink = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, ptrToDestroy->Connections); | 
|  | HeapFree(GetProcessHeap(), 0, ptrToDestroy); | 
|  | } | 
|  |  | 
|  | /************************************************************************ | 
|  | * DataAdviseHolder_QueryInterface (IUnknown) | 
|  | * | 
|  | * See Windows documentation for more details on IUnknown methods. | 
|  | */ | 
|  | static HRESULT WINAPI DataAdviseHolder_QueryInterface( | 
|  | IDataAdviseHolder*      iface, | 
|  | REFIID                  riid, | 
|  | void**                  ppvObject) | 
|  | { | 
|  | DataAdviseHolder *This = (DataAdviseHolder *)iface; | 
|  | TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject); | 
|  | /* | 
|  | * Perform a sanity check on the parameters. | 
|  | */ | 
|  | if ( (This==0) || (ppvObject==0) ) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | /* | 
|  | * Initialize the return parameter. | 
|  | */ | 
|  | *ppvObject = 0; | 
|  |  | 
|  | /* | 
|  | * Compare the riid with the interface IDs implemented by this object. | 
|  | */ | 
|  | if ( (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) || | 
|  | (memcmp(&IID_IDataAdviseHolder, riid, sizeof(IID_IDataAdviseHolder)) == 0)  ) | 
|  | { | 
|  | *ppvObject = iface; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Check that we obtained an interface. | 
|  | */ | 
|  | if ((*ppvObject)==0) | 
|  | { | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Query Interface always increases the reference count by one when it is | 
|  | * successful. | 
|  | */ | 
|  | IUnknown_AddRef((IUnknown*)*ppvObject); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /************************************************************************ | 
|  | * DataAdviseHolder_AddRef (IUnknown) | 
|  | * | 
|  | * See Windows documentation for more details on IUnknown methods. | 
|  | */ | 
|  | static ULONG WINAPI       DataAdviseHolder_AddRef( | 
|  | IDataAdviseHolder*      iface) | 
|  | { | 
|  | DataAdviseHolder *This = (DataAdviseHolder *)iface; | 
|  | TRACE("(%p) (ref=%d)\n", This, This->ref); | 
|  | return InterlockedIncrement(&This->ref); | 
|  | } | 
|  |  | 
|  | /************************************************************************ | 
|  | * DataAdviseHolder_Release (IUnknown) | 
|  | * | 
|  | * See Windows documentation for more details on IUnknown methods. | 
|  | */ | 
|  | static ULONG WINAPI DataAdviseHolder_Release( | 
|  | IDataAdviseHolder*      iface) | 
|  | { | 
|  | DataAdviseHolder *This = (DataAdviseHolder *)iface; | 
|  | ULONG ref; | 
|  | TRACE("(%p) (ref=%d)\n", This, This->ref); | 
|  |  | 
|  | /* | 
|  | * Decrease the reference count on this object. | 
|  | */ | 
|  | ref = InterlockedDecrement(&This->ref); | 
|  |  | 
|  | /* | 
|  | * If the reference count goes down to 0, perform suicide. | 
|  | */ | 
|  | 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; | 
|  |  | 
|  | DataAdviseHolder *This = (DataAdviseHolder *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%p, %p, %08x, %p, %p)\n", This, pDataObject, pFetc, advf, | 
|  | pAdvise, pdwConnection); | 
|  | /* | 
|  | * Sanity check | 
|  | */ | 
|  | if (pdwConnection==NULL) | 
|  | return E_POINTER; | 
|  |  | 
|  | *pdwConnection = 0; | 
|  |  | 
|  | /* | 
|  | * Find a free spot in the array. | 
|  | */ | 
|  | for (index = 0; index < This->maxCons; index++) | 
|  | { | 
|  | if (This->Connections[index].sink == NULL) | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * If the array is full, we need to grow it. | 
|  | */ | 
|  | if (index == This->maxCons) | 
|  | { | 
|  | This->maxCons+=INITIAL_SINKS; | 
|  | This->Connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, | 
|  | This->Connections, | 
|  | This->maxCons*sizeof(DataAdviseConnection)); | 
|  | } | 
|  | /* | 
|  | * Store the new sink | 
|  | */ | 
|  | This->Connections[index].sink = pAdvise; | 
|  | This->Connections[index].advf = advf & ~WINE_ADVF_REMOTE; | 
|  | This->Connections[index].fmat = *pFetc; | 
|  | if (pFetc->ptd) | 
|  | { | 
|  | This->Connections[index].fmat.ptd = CoTaskMemAlloc(pFetc->ptd->tdSize); | 
|  | if (!This->Connections[index].fmat.ptd) | 
|  | { | 
|  | IDataAdviseHolder_Unadvise(iface, index + 1); | 
|  | return E_OUTOFMEMORY; | 
|  | } | 
|  | memcpy(This->Connections[index].fmat.ptd, pFetc->ptd, pFetc->ptd->tdSize); | 
|  | } | 
|  |  | 
|  | if (This->Connections[index].sink != NULL) { | 
|  | IAdviseSink_AddRef(This->Connections[index].sink); | 
|  |  | 
|  | /* if we are already connected advise the remote object */ | 
|  | if (This->delegate) | 
|  | { | 
|  | HRESULT hr; | 
|  |  | 
|  | hr = IDataObject_DAdvise(This->delegate, &This->Connections[index].fmat, | 
|  | This->Connections[index].advf, | 
|  | This->Connections[index].sink, | 
|  | &This->Connections[index].remote_connection); | 
|  | if (FAILED(hr)) | 
|  | { | 
|  | IDataAdviseHolder_Unadvise(iface, index + 1); | 
|  | 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); | 
|  | } | 
|  | /* | 
|  | * Return the index as the cookie. | 
|  | * Since 0 is not a valid cookie, we will increment by | 
|  | * 1 the index in the table. | 
|  | */ | 
|  | *pdwConnection = index+1; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * DataAdviseHolder_Unadvise | 
|  | */ | 
|  | static HRESULT WINAPI     DataAdviseHolder_Unadvise( | 
|  | IDataAdviseHolder*      iface, | 
|  | DWORD                   dwConnection) | 
|  | { | 
|  | DataAdviseHolder *This = (DataAdviseHolder *)iface; | 
|  |  | 
|  | TRACE("(%p)->(%u)\n", This, dwConnection); | 
|  |  | 
|  | /* | 
|  | * So we don't return 0 as a cookie, the index was | 
|  | * incremented by 1 in OleAdviseHolderImpl_Advise | 
|  | * we have to compensate. | 
|  | */ | 
|  | dwConnection--; | 
|  |  | 
|  | /* | 
|  | * Check for invalid cookies. | 
|  | */ | 
|  | if (dwConnection >= This->maxCons) | 
|  | return OLE_E_NOCONNECTION; | 
|  |  | 
|  | if (This->Connections[dwConnection].sink == NULL) | 
|  | return OLE_E_NOCONNECTION; | 
|  |  | 
|  | if (This->delegate && This->Connections[dwConnection].advf & WINE_ADVF_REMOTE) | 
|  | IDataObject_DUnadvise(This->delegate, | 
|  | This->Connections[dwConnection].remote_connection); | 
|  |  | 
|  | /* | 
|  | * Release the sink and mark the spot in the list as free. | 
|  | */ | 
|  | IAdviseSink_Release(This->Connections[dwConnection].sink); | 
|  | memset(&(This->Connections[dwConnection]), 0, sizeof(DataAdviseConnection)); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI     DataAdviseHolder_EnumAdvise( | 
|  | IDataAdviseHolder*      iface, | 
|  | IEnumSTATDATA**         ppenumAdvise) | 
|  | { | 
|  | DataAdviseHolder *This = (DataAdviseHolder *)iface; | 
|  |  | 
|  | FIXME("(%p)->(%p)\n", This, ppenumAdvise); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * DataAdviseHolder_SendOnDataChange | 
|  | */ | 
|  | static HRESULT WINAPI     DataAdviseHolder_SendOnDataChange( | 
|  | IDataAdviseHolder*      iface, | 
|  | IDataObject*            pDataObject, | 
|  | DWORD                   dwReserved, | 
|  | DWORD                   advf) | 
|  | { | 
|  | DataAdviseHolder *This = (DataAdviseHolder *)iface; | 
|  | DWORD index; | 
|  | STGMEDIUM stg; | 
|  | HRESULT res; | 
|  |  | 
|  | TRACE("(%p)->(%p,%08x,%08x)\n", This, pDataObject, dwReserved, advf); | 
|  |  | 
|  | for(index = 0; index < This->maxCons; index++) { | 
|  | if(This->Connections[index].sink != NULL) { | 
|  | memset(&stg, 0, sizeof(stg)); | 
|  | if(!(This->Connections[index].advf & ADVF_NODATA)) { | 
|  | TRACE("Calling IDataObject_GetData\n"); | 
|  | res = IDataObject_GetData(pDataObject, | 
|  | &(This->Connections[index].fmat), | 
|  | &stg); | 
|  | TRACE("returns %08x\n", res); | 
|  | } | 
|  | TRACE("Calling IAdviseSink_OnDataChange\n"); | 
|  | IAdviseSink_OnDataChange(This->Connections[index].sink, | 
|  | &(This->Connections[index].fmat), | 
|  | &stg); | 
|  | TRACE("Done IAdviseSink_OnDataChange\n"); | 
|  | if(This->Connections[index].advf & ADVF_ONLYONCE) { | 
|  | TRACE("Removing connection\n"); | 
|  | DataAdviseHolder_Unadvise(iface, index+1); | 
|  | } | 
|  | } | 
|  | } | 
|  | 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 = (DataAdviseHolder *)iface; | 
|  | DWORD index; | 
|  | HRESULT hr = S_OK; | 
|  |  | 
|  | for(index = 0; index < This->maxCons; index++) | 
|  | { | 
|  | if(This->Connections[index].sink != NULL) | 
|  | { | 
|  | hr = IDataObject_DAdvise(pDelegate, &This->Connections[index].fmat, | 
|  | This->Connections[index].advf, | 
|  | This->Connections[index].sink, | 
|  | &This->Connections[index].remote_connection); | 
|  | if (FAILED(hr)) break; | 
|  | This->Connections[index].advf |= WINE_ADVF_REMOTE; | 
|  | } | 
|  | } | 
|  | This->delegate = pDelegate; | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | void DataAdviseHolder_OnDisconnect(IDataAdviseHolder *iface) | 
|  | { | 
|  | DataAdviseHolder *This = (DataAdviseHolder *)iface; | 
|  | DWORD index; | 
|  |  | 
|  | for(index = 0; index < This->maxCons; index++) | 
|  | { | 
|  | if((This->Connections[index].sink != NULL) && | 
|  | (This->Connections[index].advf & WINE_ADVF_REMOTE)) | 
|  | { | 
|  | IDataObject_DUnadvise(This->delegate, | 
|  | This->Connections[index].remote_connection); | 
|  | 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->lpVtbl = &DataAdviseHolderImpl_VTable; | 
|  | newHolder->ref = 1; | 
|  | newHolder->maxCons = INITIAL_SINKS; | 
|  | newHolder->Connections = HeapAlloc(GetProcessHeap(), | 
|  | HEAP_ZERO_MEMORY, | 
|  | newHolder->maxCons * | 
|  | sizeof(DataAdviseConnection)); | 
|  | newHolder->delegate = NULL; | 
|  |  | 
|  | TRACE("returning %p\n", newHolder); | 
|  | return (IDataAdviseHolder*)newHolder; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | * API functions | 
|  | */ | 
|  |  | 
|  | /*********************************************************************** | 
|  | * CreateOleAdviseHolder [OLE32.@] | 
|  | */ | 
|  | HRESULT WINAPI CreateOleAdviseHolder( | 
|  | LPOLEADVISEHOLDER *ppOAHolder) | 
|  | { | 
|  | TRACE("(%p)\n", ppOAHolder); | 
|  |  | 
|  | /* | 
|  | * Sanity check, | 
|  | */ | 
|  | if (ppOAHolder==NULL) | 
|  | return E_POINTER; | 
|  |  | 
|  | *ppOAHolder = OleAdviseHolderImpl_Constructor (); | 
|  |  | 
|  | if (*ppOAHolder != NULL) | 
|  | return S_OK; | 
|  |  | 
|  | return E_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *              CreateDataAdviseHolder        [OLE32.@] | 
|  | */ | 
|  | HRESULT WINAPI CreateDataAdviseHolder( | 
|  | LPDATAADVISEHOLDER* ppDAHolder) | 
|  | { | 
|  | TRACE("(%p)\n", ppDAHolder); | 
|  |  | 
|  | /* | 
|  | * Sanity check, | 
|  | */ | 
|  | if (ppDAHolder==NULL) | 
|  | return E_POINTER; | 
|  |  | 
|  | *ppDAHolder = DataAdviseHolder_Constructor(); | 
|  |  | 
|  | if (*ppDAHolder != NULL) | 
|  | return S_OK; | 
|  |  | 
|  | return E_OUTOFMEMORY; | 
|  | } |