/* * 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 #include #define COBJMACROS #include "windef.h" #include "winbase.h" #include "winuser.h" #include "winerror.h" #include "wine/debug.h" #include "ole2.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 = (IOleAdviseHolder*) 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; memcpy(&(This->Connections[index].fmat), pFetc, sizeof(FORMATETC)); 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; }