/* * 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 #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) { HRESULT hr; hr = copy_formatetc( &dst->formatetc, &src->formatetc ); if (FAILED(hr)) return hr; dst->advf = src->advf; dst->pAdvSink = src->pAdvSink; if (dst->pAdvSink) IAdviseSink_AddRef( dst->pAdvSink ); dst->dwConnection = src->dwConnection; return S_OK; } /************************************************************************** * EnumSTATDATA Implementation */ 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)) { IEnumSTATDATA_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); if (This->holder) 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, TRUE, ppenum); } static const IEnumSTATDATAVtbl EnumSTATDATA_VTable = { EnumSTATDATA_QueryInterface, EnumSTATDATA_AddRef, EnumSTATDATA_Release, EnumSTATDATA_Next, EnumSTATDATA_Skip, EnumSTATDATA_Reset, EnumSTATDATA_Clone }; HRESULT EnumSTATDATA_Construct(IUnknown *holder, ULONG index, DWORD array_len, STATDATA *data, BOOL copy, 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; if (copy) { 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++; } } } else { This->statdata = data; count = array_len; } This->num_of_elems = count; This->holder = holder; if (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, TRUE, 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, TRUE, 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; }