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