/* * OLE 2 default object handler * * Copyright 1999 Francis Beaudet * Copyright 2000 Abey George * * 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 * * NOTES: * The OLE2 default object handler supports a whole whack of * interfaces including: * IOleObject, IDataObject, IPersistStorage, IViewObject2, * IRunnableObject, IOleCache2, IOleCacheControl and much more. * * All the implementation details are taken from: Inside OLE * second edition by Kraig Brockschmidt, * * TODO * - This implementation of the default handler does not launch the * server in the DoVerb, Update, GetData, GetDataHere and Run * methods. When it is fixed to do so, all the methods will have * to be revisited to allow delegating to the running object * * - All methods in the class that use the class ID should be * aware that it is possible for a class to be treated as * another one and go into emulation mode. Nothing has been * done in this area. * * - Some functions still return E_NOTIMPL they have to be * implemented. Most of those are related to the running of the * actual server. * * - All the methods related to notification and advise sinks are * in place but no notifications are sent to the sinks yet. */ #include #include #include #define COBJMACROS #include "windef.h" #include "winbase.h" #include "winuser.h" #include "winerror.h" #include "ole2.h" #include "compobj_private.h" #include "storage32.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); enum storage_state { storage_state_uninitialised, storage_state_initialised, storage_state_loaded }; enum object_state { object_state_not_running, object_state_running, object_state_deferred_close }; /**************************************************************************** * DefaultHandler * */ struct DefaultHandler { IOleObject IOleObject_iface; IUnknown IUnknown_iface; IDataObject IDataObject_iface; IRunnableObject IRunnableObject_iface; IAdviseSink IAdviseSink_iface; IPersistStorage IPersistStorage_iface; /* Reference count of this object */ LONG ref; /* IUnknown implementation of the outer object. */ IUnknown* outerUnknown; /* Class Id that this handler object represents. */ CLSID clsid; /* IUnknown implementation of the datacache. */ IUnknown* dataCache; /* IPersistStorage implementation of the datacache. */ IPersistStorage* dataCache_PersistStg; /* Client site for the embedded object. */ IOleClientSite* clientSite; /* * The IOleAdviseHolder maintains the connections * on behalf of the default handler. */ IOleAdviseHolder* oleAdviseHolder; /* * The IDataAdviseHolder maintains the data * connections on behalf of the default handler. */ IDataAdviseHolder* dataAdviseHolder; /* Name of the container and object contained */ LPWSTR containerApp; LPWSTR containerObj; /* IOleObject delegate */ IOleObject *pOleDelegate; /* IPersistStorage delegate */ IPersistStorage *pPSDelegate; /* IDataObject delegate */ IDataObject *pDataDelegate; enum object_state object_state; ULONG in_call; /* connection cookie for the advise on the delegate OLE object */ DWORD dwAdvConn; /* storage passed to Load or InitNew */ IStorage *storage; enum storage_state storage_state; /* optional class factory for object */ IClassFactory *pCFObject; /* TRUE if acting as an inproc server instead of an inproc handler */ BOOL inproc_server; }; typedef struct DefaultHandler DefaultHandler; static inline DefaultHandler *impl_from_IOleObject( IOleObject *iface ) { return CONTAINING_RECORD(iface, DefaultHandler, IOleObject_iface); } static inline DefaultHandler *impl_from_IUnknown( IUnknown *iface ) { return CONTAINING_RECORD(iface, DefaultHandler, IUnknown_iface); } static inline DefaultHandler *impl_from_IDataObject( IDataObject *iface ) { return CONTAINING_RECORD(iface, DefaultHandler, IDataObject_iface); } static inline DefaultHandler *impl_from_IRunnableObject( IRunnableObject *iface ) { return CONTAINING_RECORD(iface, DefaultHandler, IRunnableObject_iface); } static inline DefaultHandler *impl_from_IAdviseSink( IAdviseSink *iface ) { return CONTAINING_RECORD(iface, DefaultHandler, IAdviseSink_iface); } static inline DefaultHandler *impl_from_IPersistStorage( IPersistStorage *iface ) { return CONTAINING_RECORD(iface, DefaultHandler, IPersistStorage_iface); } static void DefaultHandler_Destroy(DefaultHandler* This); static inline BOOL object_is_running(DefaultHandler *This) { return IRunnableObject_IsRunning(&This->IRunnableObject_iface); } static void DefaultHandler_Stop(DefaultHandler *This); static inline void start_object_call(DefaultHandler *This) { This->in_call++; } static inline void end_object_call(DefaultHandler *This) { This->in_call--; if (This->in_call == 0 && This->object_state == object_state_deferred_close) DefaultHandler_Stop( This ); } /********************************************************* * Method implementation for the non delegating IUnknown * part of the DefaultHandler class. */ /************************************************************************ * DefaultHandler_NDIUnknown_QueryInterface (IUnknown) * * See Windows documentation for more details on IUnknown methods. * * This version of QueryInterface will not delegate its implementation * to the outer unknown. */ static HRESULT WINAPI DefaultHandler_NDIUnknown_QueryInterface( IUnknown* iface, REFIID riid, void** ppvObject) { DefaultHandler *This = impl_from_IUnknown(iface); if (!ppvObject) return E_INVALIDARG; *ppvObject = NULL; if (IsEqualIID(&IID_IUnknown, riid)) *ppvObject = iface; else if (IsEqualIID(&IID_IOleObject, riid)) *ppvObject = &This->IOleObject_iface; else if (IsEqualIID(&IID_IDataObject, riid)) *ppvObject = &This->IDataObject_iface; else if (IsEqualIID(&IID_IRunnableObject, riid)) *ppvObject = &This->IRunnableObject_iface; else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStorage, riid)) *ppvObject = &This->IPersistStorage_iface; else if (IsEqualIID(&IID_IViewObject, riid) || IsEqualIID(&IID_IViewObject2, riid) || IsEqualIID(&IID_IOleCache, riid) || IsEqualIID(&IID_IOleCache2, riid)) { HRESULT hr = IUnknown_QueryInterface(This->dataCache, riid, ppvObject); if (FAILED(hr)) FIXME("interface %s not implemented by data cache\n", debugstr_guid(riid)); return hr; } else if (This->inproc_server && This->pOleDelegate) { return IOleObject_QueryInterface(This->pOleDelegate, riid, ppvObject); } /* Check that we obtained an interface. */ if (*ppvObject == NULL) { WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } /* * Query Interface always increases the reference count by one when it is * successful. */ IUnknown_AddRef((IUnknown*)*ppvObject); return S_OK; } /************************************************************************ * DefaultHandler_NDIUnknown_AddRef (IUnknown) * * See Windows documentation for more details on IUnknown methods. * * This version of QueryInterface will not delegate its implementation * to the outer unknown. */ static ULONG WINAPI DefaultHandler_NDIUnknown_AddRef( IUnknown* iface) { DefaultHandler *This = impl_from_IUnknown(iface); return InterlockedIncrement(&This->ref); } /************************************************************************ * DefaultHandler_NDIUnknown_Release (IUnknown) * * See Windows documentation for more details on IUnknown methods. * * This version of QueryInterface will not delegate its implementation * to the outer unknown. */ static ULONG WINAPI DefaultHandler_NDIUnknown_Release( IUnknown* iface) { DefaultHandler *This = impl_from_IUnknown(iface); ULONG ref; ref = InterlockedDecrement(&This->ref); if (!ref) DefaultHandler_Destroy(This); return ref; } /********************************************************* * Methods implementation for the IOleObject part of * the DefaultHandler class. */ /************************************************************************ * DefaultHandler_QueryInterface (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static HRESULT WINAPI DefaultHandler_QueryInterface( IOleObject* iface, REFIID riid, void** ppvObject) { DefaultHandler *This = impl_from_IOleObject(iface); return IUnknown_QueryInterface(This->outerUnknown, riid, ppvObject); } /************************************************************************ * DefaultHandler_AddRef (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static ULONG WINAPI DefaultHandler_AddRef( IOleObject* iface) { DefaultHandler *This = impl_from_IOleObject(iface); return IUnknown_AddRef(This->outerUnknown); } /************************************************************************ * DefaultHandler_Release (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static ULONG WINAPI DefaultHandler_Release( IOleObject* iface) { DefaultHandler *This = impl_from_IOleObject(iface); return IUnknown_Release(This->outerUnknown); } /************************************************************************ * DefaultHandler_SetClientSite (IOleObject) * * The default handler's implementation of this method only keeps the * client site pointer for future reference. * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_SetClientSite( IOleObject* iface, IOleClientSite* pClientSite) { DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr = S_OK; TRACE("(%p, %p)\n", iface, pClientSite); if (object_is_running(This)) { start_object_call( This ); hr = IOleObject_SetClientSite(This->pOleDelegate, pClientSite); end_object_call( This ); } /* * Make sure we release the previous client site if there * was one. */ if (This->clientSite) IOleClientSite_Release(This->clientSite); This->clientSite = pClientSite; if (This->clientSite) IOleClientSite_AddRef(This->clientSite); return hr; } /************************************************************************ * DefaultHandler_GetClientSite (IOleObject) * * The default handler's implementation of this method returns the * last pointer set in IOleObject_SetClientSite. * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_GetClientSite( IOleObject* iface, IOleClientSite** ppClientSite) { DefaultHandler *This = impl_from_IOleObject(iface); if (!ppClientSite) return E_POINTER; *ppClientSite = This->clientSite; if (This->clientSite) IOleClientSite_AddRef(This->clientSite); return S_OK; } /************************************************************************ * DefaultHandler_SetHostNames (IOleObject) * * The default handler's implementation of this method just stores * the strings and returns S_OK. * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_SetHostNames( IOleObject* iface, LPCOLESTR szContainerApp, LPCOLESTR szContainerObj) { DefaultHandler *This = impl_from_IOleObject(iface); TRACE("(%p, %s, %s)\n", iface, debugstr_w(szContainerApp), debugstr_w(szContainerObj)); if (object_is_running(This)) { start_object_call( This ); IOleObject_SetHostNames(This->pOleDelegate, szContainerApp, szContainerObj); end_object_call( This ); } /* Be sure to cleanup before re-assigning the strings. */ HeapFree( GetProcessHeap(), 0, This->containerApp ); This->containerApp = NULL; HeapFree( GetProcessHeap(), 0, This->containerObj ); This->containerObj = NULL; if (szContainerApp) { if ((This->containerApp = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(szContainerApp) + 1) * sizeof(WCHAR) ))) lstrcpyW( This->containerApp, szContainerApp ); } if (szContainerObj) { if ((This->containerObj = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(szContainerObj) + 1) * sizeof(WCHAR) ))) lstrcpyW( This->containerObj, szContainerObj ); } return S_OK; } static void release_delegates(DefaultHandler *This) { if (This->pDataDelegate) { IDataObject_Release(This->pDataDelegate); This->pDataDelegate = NULL; } if (This->pPSDelegate) { IPersistStorage_Release(This->pPSDelegate); This->pPSDelegate = NULL; } if (This->pOleDelegate) { IOleObject_Release(This->pOleDelegate); This->pOleDelegate = NULL; } } /* undoes the work done by DefaultHandler_Run */ static void DefaultHandler_Stop(DefaultHandler *This) { IOleCacheControl *cache_ctrl; HRESULT hr; if (This->object_state == object_state_not_running) return; hr = IUnknown_QueryInterface( This->dataCache, &IID_IOleCacheControl, (void **)&cache_ctrl ); if (SUCCEEDED(hr)) { hr = IOleCacheControl_OnStop( cache_ctrl ); IOleCacheControl_Release( cache_ctrl ); } IOleObject_Unadvise(This->pOleDelegate, This->dwAdvConn); if (This->dataAdviseHolder) DataAdviseHolder_OnDisconnect(This->dataAdviseHolder); This->object_state = object_state_not_running; release_delegates( This ); } /************************************************************************ * DefaultHandler_Close (IOleObject) * * The default handler's implementation of this method is meaningless * without a running server so it does nothing. * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_Close( IOleObject* iface, DWORD dwSaveOption) { DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr; TRACE("(%d)\n", dwSaveOption); if (!object_is_running(This)) return S_OK; start_object_call( This ); hr = IOleObject_Close(This->pOleDelegate, dwSaveOption); end_object_call( This ); DefaultHandler_Stop(This); return hr; } /************************************************************************ * DefaultHandler_SetMoniker (IOleObject) * * The default handler's implementation of this method does nothing. * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_SetMoniker( IOleObject* iface, DWORD dwWhichMoniker, IMoniker* pmk) { DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr = S_OK; TRACE("(%p, %d, %p)\n", iface, dwWhichMoniker, pmk); if (object_is_running(This)) { start_object_call( This ); hr = IOleObject_SetMoniker(This->pOleDelegate, dwWhichMoniker, pmk); end_object_call( This ); } return hr; } /************************************************************************ * DefaultHandler_GetMoniker (IOleObject) * * Delegate this request to the client site if we have one. * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_GetMoniker( IOleObject* iface, DWORD dwAssign, DWORD dwWhichMoniker, IMoniker** ppmk) { DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr; TRACE("(%p, %d, %d, %p)\n", iface, dwAssign, dwWhichMoniker, ppmk); if (object_is_running(This)) { start_object_call( This ); hr = IOleObject_GetMoniker(This->pOleDelegate, dwAssign, dwWhichMoniker, ppmk); end_object_call( This ); return hr; } /* FIXME: dwWhichMoniker == OLEWHICHMK_CONTAINER only? */ if (This->clientSite) { return IOleClientSite_GetMoniker(This->clientSite, dwAssign, dwWhichMoniker, ppmk); } return E_FAIL; } /************************************************************************ * DefaultHandler_InitFromData (IOleObject) * * This method is meaningless if the server is not running * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_InitFromData( IOleObject* iface, IDataObject* pDataObject, BOOL fCreation, DWORD dwReserved) { DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr = OLE_E_NOTRUNNING; TRACE("(%p, %p, %d, %d)\n", iface, pDataObject, fCreation, dwReserved); if (object_is_running(This)) { start_object_call( This ); hr = IOleObject_InitFromData(This->pOleDelegate, pDataObject, fCreation, dwReserved); end_object_call( This ); } return hr; } /************************************************************************ * DefaultHandler_GetClipboardData (IOleObject) * * This method is meaningless if the server is not running * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_GetClipboardData( IOleObject* iface, DWORD dwReserved, IDataObject** ppDataObject) { DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr = OLE_E_NOTRUNNING; TRACE("(%p, %d, %p)\n", iface, dwReserved, ppDataObject); if (object_is_running(This)) { start_object_call( This ); hr = IOleObject_GetClipboardData(This->pOleDelegate, dwReserved, ppDataObject); end_object_call( This ); } return hr; } static HRESULT WINAPI DefaultHandler_DoVerb( IOleObject* iface, LONG iVerb, struct tagMSG* lpmsg, IOleClientSite* pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect) { DefaultHandler *This = impl_from_IOleObject(iface); IRunnableObject *pRunnableObj = &This->IRunnableObject_iface; HRESULT hr; TRACE("(%d, %p, %p, %d, %p, %s)\n", iVerb, lpmsg, pActiveSite, lindex, hwndParent, wine_dbgstr_rect(lprcPosRect)); hr = IRunnableObject_Run(pRunnableObj, NULL); if (FAILED(hr)) return hr; start_object_call( This ); hr = IOleObject_DoVerb(This->pOleDelegate, iVerb, lpmsg, pActiveSite, lindex, hwndParent, lprcPosRect); end_object_call( This ); return hr; } /************************************************************************ * DefaultHandler_EnumVerbs (IOleObject) * * The default handler implementation of this method simply delegates * to OleRegEnumVerbs * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_EnumVerbs( IOleObject* iface, IEnumOLEVERB** ppEnumOleVerb) { DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr = OLE_S_USEREG; TRACE("(%p, %p)\n", iface, ppEnumOleVerb); if (object_is_running(This)) { start_object_call( This ); hr = IOleObject_EnumVerbs(This->pOleDelegate, ppEnumOleVerb); end_object_call( This ); } if (hr == OLE_S_USEREG) return OleRegEnumVerbs(&This->clsid, ppEnumOleVerb); else return hr; } static HRESULT WINAPI DefaultHandler_Update( IOleObject* iface) { DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr; TRACE("(%p)\n", iface); if (!object_is_running(This)) { FIXME("Should run object\n"); return E_NOTIMPL; } start_object_call( This ); hr = IOleObject_Update(This->pOleDelegate); end_object_call( This ); return hr; } /************************************************************************ * DefaultHandler_IsUpToDate (IOleObject) * * This method is meaningless if the server is not running * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_IsUpToDate( IOleObject* iface) { DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr = OLE_E_NOTRUNNING; TRACE("(%p)\n", iface); if (object_is_running(This)) { start_object_call( This ); hr = IOleObject_IsUpToDate(This->pOleDelegate); end_object_call( This ); } return hr; } /************************************************************************ * DefaultHandler_GetUserClassID (IOleObject) * * TODO: Map to a new class ID if emulation is active. * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_GetUserClassID( IOleObject* iface, CLSID* pClsid) { DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr; TRACE("(%p, %p)\n", iface, pClsid); if (object_is_running(This)) { start_object_call( This ); hr = IOleObject_GetUserClassID(This->pOleDelegate, pClsid); end_object_call( This ); return hr; } if (!pClsid) return E_POINTER; *pClsid = This->clsid; return S_OK; } /************************************************************************ * DefaultHandler_GetUserType (IOleObject) * * The default handler implementation of this method simply delegates * to OleRegGetUserType * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_GetUserType( IOleObject* iface, DWORD dwFormOfType, LPOLESTR* pszUserType) { DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr; TRACE("(%p, %d, %p)\n", iface, dwFormOfType, pszUserType); if (object_is_running(This)) { start_object_call( This ); hr = IOleObject_GetUserType(This->pOleDelegate, dwFormOfType, pszUserType); end_object_call( This ); return hr; } return OleRegGetUserType(&This->clsid, dwFormOfType, pszUserType); } /************************************************************************ * DefaultHandler_SetExtent (IOleObject) * * This method is meaningless if the server is not running * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_SetExtent( IOleObject* iface, DWORD dwDrawAspect, SIZEL* psizel) { DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr = OLE_E_NOTRUNNING; TRACE("(%p, %x, (%d x %d))\n", iface, dwDrawAspect, psizel->cx, psizel->cy); if (object_is_running(This)) { start_object_call( This ); hr = IOleObject_SetExtent(This->pOleDelegate, dwDrawAspect, psizel); end_object_call( This ); } return hr; } /************************************************************************ * DefaultHandler_GetExtent (IOleObject) * * The default handler's implementation of this method returns uses * the cache to locate the aspect and extract the extent from it. * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_GetExtent( IOleObject* iface, DWORD dwDrawAspect, SIZEL* psizel) { DVTARGETDEVICE* targetDevice; IViewObject2* cacheView = NULL; HRESULT hres; DefaultHandler *This = impl_from_IOleObject(iface); TRACE("(%p, %x, %p)\n", iface, dwDrawAspect, psizel); if (object_is_running(This)) { start_object_call( This ); hres = IOleObject_GetExtent(This->pOleDelegate, dwDrawAspect, psizel); end_object_call( This ); return hres; } hres = IUnknown_QueryInterface(This->dataCache, &IID_IViewObject2, (void**)&cacheView); if (FAILED(hres)) return E_UNEXPECTED; /* * Prepare the call to the cache's GetExtent method. * * Here we would build a valid DVTARGETDEVICE structure * but, since we are calling into the data cache, we * know its implementation and we'll skip this * extra work until later. */ targetDevice = NULL; hres = IViewObject2_GetExtent(cacheView, dwDrawAspect, -1, targetDevice, psizel); IViewObject2_Release(cacheView); return hres; } /************************************************************************ * DefaultHandler_Advise (IOleObject) * * The default handler's implementation of this method simply * delegates to the OleAdviseHolder. * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_Advise( IOleObject* iface, IAdviseSink* pAdvSink, DWORD* pdwConnection) { HRESULT hres = S_OK; DefaultHandler *This = impl_from_IOleObject(iface); TRACE("(%p, %p, %p)\n", iface, pAdvSink, pdwConnection); /* Make sure we have an advise holder before we start. */ if (!This->oleAdviseHolder) hres = CreateOleAdviseHolder(&This->oleAdviseHolder); if (SUCCEEDED(hres)) hres = IOleAdviseHolder_Advise(This->oleAdviseHolder, pAdvSink, pdwConnection); return hres; } /************************************************************************ * DefaultHandler_Unadvise (IOleObject) * * The default handler's implementation of this method simply * delegates to the OleAdviseHolder. * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_Unadvise( IOleObject* iface, DWORD dwConnection) { DefaultHandler *This = impl_from_IOleObject(iface); TRACE("(%p, %d)\n", iface, dwConnection); /* * If we don't have an advise holder yet, it means we don't have * a connection. */ if (!This->oleAdviseHolder) return OLE_E_NOCONNECTION; return IOleAdviseHolder_Unadvise(This->oleAdviseHolder, dwConnection); } /************************************************************************ * DefaultHandler_EnumAdvise (IOleObject) * * The default handler's implementation of this method simply * delegates to the OleAdviseHolder. * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_EnumAdvise( IOleObject* iface, IEnumSTATDATA** ppenumAdvise) { DefaultHandler *This = impl_from_IOleObject(iface); TRACE("(%p, %p)\n", iface, ppenumAdvise); if (!ppenumAdvise) return E_POINTER; *ppenumAdvise = NULL; if (!This->oleAdviseHolder) return S_OK; return IOleAdviseHolder_EnumAdvise(This->oleAdviseHolder, ppenumAdvise); } /************************************************************************ * DefaultHandler_GetMiscStatus (IOleObject) * * The default handler's implementation of this method simply delegates * to OleRegGetMiscStatus. * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_GetMiscStatus( IOleObject* iface, DWORD dwAspect, DWORD* pdwStatus) { HRESULT hres; DefaultHandler *This = impl_from_IOleObject(iface); TRACE("(%p, %x, %p)\n", iface, dwAspect, pdwStatus); if (object_is_running(This)) { start_object_call( This ); hres = IOleObject_GetMiscStatus(This->pOleDelegate, dwAspect, pdwStatus); end_object_call( This ); return hres; } hres = OleRegGetMiscStatus(&This->clsid, dwAspect, pdwStatus); if (FAILED(hres)) *pdwStatus = 0; return hres; } /************************************************************************ * DefaultHandler_SetColorScheme (IOleObject) * * This method is meaningless if the server is not running * * See Windows documentation for more details on IOleObject methods. */ static HRESULT WINAPI DefaultHandler_SetColorScheme( IOleObject* iface, struct tagLOGPALETTE* pLogpal) { DefaultHandler *This = impl_from_IOleObject(iface); HRESULT hr = OLE_E_NOTRUNNING; TRACE("(%p, %p))\n", iface, pLogpal); if (object_is_running(This)) { start_object_call( This ); hr = IOleObject_SetColorScheme(This->pOleDelegate, pLogpal); end_object_call( This ); } return hr; } /********************************************************* * Methods implementation for the IDataObject part of * the DefaultHandler class. */ /************************************************************************ * DefaultHandler_IDataObject_QueryInterface (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static HRESULT WINAPI DefaultHandler_IDataObject_QueryInterface( IDataObject* iface, REFIID riid, void** ppvObject) { DefaultHandler *This = impl_from_IDataObject(iface); return IUnknown_QueryInterface(This->outerUnknown, riid, ppvObject); } /************************************************************************ * DefaultHandler_IDataObject_AddRef (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static ULONG WINAPI DefaultHandler_IDataObject_AddRef( IDataObject* iface) { DefaultHandler *This = impl_from_IDataObject(iface); return IUnknown_AddRef(This->outerUnknown); } /************************************************************************ * DefaultHandler_IDataObject_Release (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static ULONG WINAPI DefaultHandler_IDataObject_Release( IDataObject* iface) { DefaultHandler *This = impl_from_IDataObject(iface); return IUnknown_Release(This->outerUnknown); } /************************************************************************ * DefaultHandler_GetData * * Get Data from a source dataobject using format pformatetcIn->cfFormat * See Windows documentation for more details on GetData. * Default handler's implementation of this method delegates to the cache. */ static HRESULT WINAPI DefaultHandler_GetData( IDataObject* iface, LPFORMATETC pformatetcIn, STGMEDIUM* pmedium) { IDataObject* cacheDataObject = NULL; HRESULT hres; DefaultHandler *This = impl_from_IDataObject(iface); TRACE("(%p, %p, %p)\n", iface, pformatetcIn, pmedium); hres = IUnknown_QueryInterface(This->dataCache, &IID_IDataObject, (void**)&cacheDataObject); if (FAILED(hres)) return E_UNEXPECTED; hres = IDataObject_GetData(cacheDataObject, pformatetcIn, pmedium); IDataObject_Release(cacheDataObject); if (hres == S_OK) return hres; if (object_is_running( This )) { start_object_call(This); hres = IDataObject_GetData(This->pDataDelegate, pformatetcIn, pmedium); end_object_call(This); if (hres == S_OK) return hres; } /* Query running state again, as the object may have closed during _GetData call */ if (!object_is_running( This )) hres = OLE_E_NOTRUNNING; return hres; } static HRESULT WINAPI DefaultHandler_GetDataHere( IDataObject* iface, LPFORMATETC pformatetc, STGMEDIUM* pmedium) { FIXME(": Stub\n"); return E_NOTIMPL; } /************************************************************************ * DefaultHandler_QueryGetData (IDataObject) * * The default handler's implementation of this method delegates to * the cache. * * See Windows documentation for more details on IDataObject methods. */ static HRESULT WINAPI DefaultHandler_QueryGetData( IDataObject* iface, LPFORMATETC pformatetc) { IDataObject* cacheDataObject = NULL; HRESULT hres; DefaultHandler *This = impl_from_IDataObject(iface); TRACE("(%p, %p)\n", iface, pformatetc); hres = IUnknown_QueryInterface(This->dataCache, &IID_IDataObject, (void**)&cacheDataObject); if (FAILED(hres)) return E_UNEXPECTED; hres = IDataObject_QueryGetData(cacheDataObject, pformatetc); IDataObject_Release(cacheDataObject); if (hres == S_OK) return hres; if (object_is_running( This )) { start_object_call( This ); hres = IDataObject_QueryGetData(This->pDataDelegate, pformatetc); end_object_call( This ); if (hres == S_OK) return hres; } /* Query running state again, as the object may have closed during _QueryGetData call */ if (!object_is_running( This )) hres = OLE_E_NOTRUNNING; return hres; } /************************************************************************ * DefaultHandler_GetCanonicalFormatEtc (IDataObject) * * This method is meaningless if the server is not running * * See Windows documentation for more details on IDataObject methods. */ static HRESULT WINAPI DefaultHandler_GetCanonicalFormatEtc( IDataObject* iface, LPFORMATETC pformatetcIn, LPFORMATETC pformatetcOut) { DefaultHandler *This = impl_from_IDataObject(iface); HRESULT hr; TRACE("(%p, %p, %p)\n", iface, pformatetcIn, pformatetcOut); if (!object_is_running( This )) return OLE_E_NOTRUNNING; start_object_call( This ); hr = IDataObject_GetCanonicalFormatEtc(This->pDataDelegate, pformatetcIn, pformatetcOut); end_object_call( This ); return hr; } /************************************************************************ * DefaultHandler_SetData (IDataObject) * * The default handler's implementation of this method delegates to * the cache. * * See Windows documentation for more details on IDataObject methods. */ static HRESULT WINAPI DefaultHandler_SetData( IDataObject* iface, LPFORMATETC pformatetc, STGMEDIUM* pmedium, BOOL fRelease) { DefaultHandler *This = impl_from_IDataObject(iface); IDataObject* cacheDataObject = NULL; HRESULT hres; TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease); hres = IUnknown_QueryInterface(This->dataCache, &IID_IDataObject, (void**)&cacheDataObject); if (FAILED(hres)) return E_UNEXPECTED; hres = IDataObject_SetData(cacheDataObject, pformatetc, pmedium, fRelease); IDataObject_Release(cacheDataObject); return hres; } /************************************************************************ * DefaultHandler_EnumFormatEtc (IDataObject) * * The default handler's implementation of This method simply delegates * to OleRegEnumFormatEtc. * * See Windows documentation for more details on IDataObject methods. */ static HRESULT WINAPI DefaultHandler_EnumFormatEtc( IDataObject* iface, DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc) { DefaultHandler *This = impl_from_IDataObject(iface); TRACE("(%p, %x, %p)\n", iface, dwDirection, ppenumFormatEtc); return OleRegEnumFormatEtc(&This->clsid, dwDirection, ppenumFormatEtc); } /************************************************************************ * DefaultHandler_DAdvise (IDataObject) * * The default handler's implementation of this method simply * delegates to the DataAdviseHolder. * * See Windows documentation for more details on IDataObject methods. */ static HRESULT WINAPI DefaultHandler_DAdvise( IDataObject* iface, FORMATETC* pformatetc, DWORD advf, IAdviseSink* pAdvSink, DWORD* pdwConnection) { HRESULT hres = S_OK; DefaultHandler *This = impl_from_IDataObject(iface); TRACE("(%p, %p, %d, %p, %p)\n", iface, pformatetc, advf, pAdvSink, pdwConnection); /* Make sure we have a data advise holder before we start. */ if (!This->dataAdviseHolder) { hres = CreateDataAdviseHolder(&This->dataAdviseHolder); if (SUCCEEDED(hres) && object_is_running( This )) { start_object_call( This ); DataAdviseHolder_OnConnect(This->dataAdviseHolder, This->pDataDelegate); end_object_call( This ); } } if (SUCCEEDED(hres)) hres = IDataAdviseHolder_Advise(This->dataAdviseHolder, iface, pformatetc, advf, pAdvSink, pdwConnection); return hres; } /************************************************************************ * DefaultHandler_DUnadvise (IDataObject) * * The default handler's implementation of this method simply * delegates to the DataAdviseHolder. * * See Windows documentation for more details on IDataObject methods. */ static HRESULT WINAPI DefaultHandler_DUnadvise( IDataObject* iface, DWORD dwConnection) { DefaultHandler *This = impl_from_IDataObject(iface); TRACE("(%p, %d)\n", iface, dwConnection); /* * If we don't have a data advise holder yet, it means that * we don't have any connections.. */ if (!This->dataAdviseHolder) return OLE_E_NOCONNECTION; return IDataAdviseHolder_Unadvise(This->dataAdviseHolder, dwConnection); } /************************************************************************ * DefaultHandler_EnumDAdvise (IDataObject) * * The default handler's implementation of this method simply * delegates to the DataAdviseHolder. * * See Windows documentation for more details on IDataObject methods. */ static HRESULT WINAPI DefaultHandler_EnumDAdvise( IDataObject* iface, IEnumSTATDATA** ppenumAdvise) { DefaultHandler *This = impl_from_IDataObject(iface); TRACE("(%p, %p)\n", iface, ppenumAdvise); if (!ppenumAdvise) return E_POINTER; *ppenumAdvise = NULL; /* If we have a data advise holder object, delegate. */ if (This->dataAdviseHolder) return IDataAdviseHolder_EnumAdvise(This->dataAdviseHolder, ppenumAdvise); return S_OK; } /********************************************************* * Methods implementation for the IRunnableObject part * of the DefaultHandler class. */ /************************************************************************ * DefaultHandler_IRunnableObject_QueryInterface (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static HRESULT WINAPI DefaultHandler_IRunnableObject_QueryInterface( IRunnableObject* iface, REFIID riid, void** ppvObject) { DefaultHandler *This = impl_from_IRunnableObject(iface); return IUnknown_QueryInterface(This->outerUnknown, riid, ppvObject); } /************************************************************************ * DefaultHandler_IRunnableObject_AddRef (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static ULONG WINAPI DefaultHandler_IRunnableObject_AddRef( IRunnableObject* iface) { DefaultHandler *This = impl_from_IRunnableObject(iface); return IUnknown_AddRef(This->outerUnknown); } /************************************************************************ * DefaultHandler_IRunnableObject_Release (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static ULONG WINAPI DefaultHandler_IRunnableObject_Release( IRunnableObject* iface) { DefaultHandler *This = impl_from_IRunnableObject(iface); return IUnknown_Release(This->outerUnknown); } /************************************************************************ * DefaultHandler_GetRunningClass (IRunnableObject) * * See Windows documentation for more details on IRunnableObject methods. */ static HRESULT WINAPI DefaultHandler_GetRunningClass( IRunnableObject* iface, LPCLSID lpClsid) { FIXME("()\n"); return S_OK; } static HRESULT WINAPI DefaultHandler_Run( IRunnableObject* iface, IBindCtx* pbc) { DefaultHandler *This = impl_from_IRunnableObject(iface); HRESULT hr; IOleCacheControl *cache_ctrl; FIXME("(%p): semi-stub\n", pbc); /* already running? if so nothing to do */ if (object_is_running(This)) return S_OK; release_delegates(This); hr = CoCreateInstance(&This->clsid, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, &IID_IOleObject, (void **)&This->pOleDelegate); if (FAILED(hr)) return hr; hr = IOleObject_Advise(This->pOleDelegate, &This->IAdviseSink_iface, &This->dwAdvConn); if (FAILED(hr)) goto fail; if (This->clientSite) { hr = IOleObject_SetClientSite(This->pOleDelegate, This->clientSite); if (FAILED(hr)) goto fail; } hr = IOleObject_QueryInterface(This->pOleDelegate, &IID_IPersistStorage, (void **)&This->pPSDelegate); if (FAILED(hr)) goto fail; if (This->storage_state == storage_state_initialised) hr = IPersistStorage_InitNew(This->pPSDelegate, This->storage); else if (This->storage_state == storage_state_loaded) hr = IPersistStorage_Load(This->pPSDelegate, This->storage); if (FAILED(hr)) goto fail; if (This->containerApp) { hr = IOleObject_SetHostNames(This->pOleDelegate, This->containerApp, This->containerObj); if (FAILED(hr)) goto fail; } /* FIXME: do more stuff here: * - IOleObject_GetMiscStatus * - IOleObject_GetMoniker */ hr = IOleObject_QueryInterface(This->pOleDelegate, &IID_IDataObject, (void **)&This->pDataDelegate); if (FAILED(hr)) goto fail; This->object_state = object_state_running; if (This->dataAdviseHolder) { hr = DataAdviseHolder_OnConnect(This->dataAdviseHolder, This->pDataDelegate); if (FAILED(hr)) goto fail; } hr = IUnknown_QueryInterface( This->dataCache, &IID_IOleCacheControl, (void **)&cache_ctrl ); if (FAILED(hr)) goto fail; hr = IOleCacheControl_OnRun( cache_ctrl, This->pDataDelegate ); IOleCacheControl_Release( cache_ctrl ); if (FAILED(hr)) goto fail; return hr; fail: DefaultHandler_Stop(This); return hr; } /************************************************************************ * DefaultHandler_IsRunning (IRunnableObject) * * See Windows documentation for more details on IRunnableObject methods. */ static BOOL WINAPI DefaultHandler_IsRunning( IRunnableObject* iface) { DefaultHandler *This = impl_from_IRunnableObject(iface); TRACE("()\n"); if (This->object_state == object_state_running) return TRUE; else return FALSE; } /************************************************************************ * DefaultHandler_LockRunning (IRunnableObject) * * See Windows documentation for more details on IRunnableObject methods. */ static HRESULT WINAPI DefaultHandler_LockRunning( IRunnableObject* iface, BOOL fLock, BOOL fLastUnlockCloses) { FIXME("()\n"); return S_OK; } /************************************************************************ * DefaultHandler_SetContainedObject (IRunnableObject) * * See Windows documentation for more details on IRunnableObject methods. */ static HRESULT WINAPI DefaultHandler_SetContainedObject( IRunnableObject* iface, BOOL fContained) { FIXME("()\n"); return S_OK; } static HRESULT WINAPI DefaultHandler_IAdviseSink_QueryInterface( IAdviseSink *iface, REFIID riid, void **ppvObject) { if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAdviseSink)) { *ppvObject = iface; IAdviseSink_AddRef(iface); return S_OK; } return E_NOINTERFACE; } static ULONG WINAPI DefaultHandler_IAdviseSink_AddRef( IAdviseSink *iface) { DefaultHandler *This = impl_from_IAdviseSink(iface); return IUnknown_AddRef(&This->IUnknown_iface); } static ULONG WINAPI DefaultHandler_IAdviseSink_Release( IAdviseSink *iface) { DefaultHandler *This = impl_from_IAdviseSink(iface); return IUnknown_Release(&This->IUnknown_iface); } static void WINAPI DefaultHandler_IAdviseSink_OnDataChange( IAdviseSink *iface, FORMATETC *pFormatetc, STGMEDIUM *pStgmed) { FIXME(": stub\n"); } static void WINAPI DefaultHandler_IAdviseSink_OnViewChange( IAdviseSink *iface, DWORD dwAspect, LONG lindex) { FIXME(": stub\n"); } static void WINAPI DefaultHandler_IAdviseSink_OnRename( IAdviseSink *iface, IMoniker *pmk) { DefaultHandler *This = impl_from_IAdviseSink(iface); TRACE("(%p)\n", pmk); if (This->oleAdviseHolder) IOleAdviseHolder_SendOnRename(This->oleAdviseHolder, pmk); } static void WINAPI DefaultHandler_IAdviseSink_OnSave( IAdviseSink *iface) { DefaultHandler *This = impl_from_IAdviseSink(iface); TRACE("()\n"); if (This->oleAdviseHolder) IOleAdviseHolder_SendOnSave(This->oleAdviseHolder); } static void WINAPI DefaultHandler_IAdviseSink_OnClose( IAdviseSink *iface) { DefaultHandler *This = impl_from_IAdviseSink(iface); TRACE("()\n"); if (This->oleAdviseHolder) IOleAdviseHolder_SendOnClose(This->oleAdviseHolder); if(!This->in_call) DefaultHandler_Stop(This); else { TRACE("OnClose during call. Deferring shutdown\n"); This->object_state = object_state_deferred_close; } } /************************************************************************ * DefaultHandler_IPersistStorage_QueryInterface * */ static HRESULT WINAPI DefaultHandler_IPersistStorage_QueryInterface( IPersistStorage* iface, REFIID riid, void** ppvObject) { DefaultHandler *This = impl_from_IPersistStorage(iface); return IUnknown_QueryInterface(This->outerUnknown, riid, ppvObject); } /************************************************************************ * DefaultHandler_IPersistStorage_AddRef * */ static ULONG WINAPI DefaultHandler_IPersistStorage_AddRef( IPersistStorage* iface) { DefaultHandler *This = impl_from_IPersistStorage(iface); return IUnknown_AddRef(This->outerUnknown); } /************************************************************************ * DefaultHandler_IPersistStorage_Release * */ static ULONG WINAPI DefaultHandler_IPersistStorage_Release( IPersistStorage* iface) { DefaultHandler *This = impl_from_IPersistStorage(iface); return IUnknown_Release(This->outerUnknown); } /************************************************************************ * DefaultHandler_IPersistStorage_GetClassID * */ static HRESULT WINAPI DefaultHandler_IPersistStorage_GetClassID( IPersistStorage* iface, CLSID* clsid) { DefaultHandler *This = impl_from_IPersistStorage(iface); HRESULT hr; TRACE("(%p)->(%p)\n", iface, clsid); if(object_is_running(This)) { start_object_call( This ); hr = IPersistStorage_GetClassID(This->pPSDelegate, clsid); end_object_call( This ); } else hr = IPersistStorage_GetClassID(This->dataCache_PersistStg, clsid); return hr; } /************************************************************************ * DefaultHandler_IPersistStorage_IsDirty * */ static HRESULT WINAPI DefaultHandler_IPersistStorage_IsDirty( IPersistStorage* iface) { DefaultHandler *This = impl_from_IPersistStorage(iface); HRESULT hr; TRACE("(%p)\n", iface); hr = IPersistStorage_IsDirty(This->dataCache_PersistStg); if(hr != S_FALSE) return hr; if(object_is_running(This)) { start_object_call( This ); hr = IPersistStorage_IsDirty(This->pPSDelegate); end_object_call( This ); } return hr; } /*********************************************************************** * * The format of '\1Ole' stream is as follows: * * DWORD Version == 0x02000001 * DWORD Flags - low bit set indicates the object is a link otherwise it's embedded. * DWORD LinkupdateOption - [MS-OLEDS describes this as an implementation specific hint * supplied by the app that creates the data structure. May be * ignored on processing]. * * DWORD Reserved == 0 * DWORD MonikerStreamSize - size of the rest of the data (ie CLSID + moniker stream data). * CLSID clsid - class id of object capable of processing the moniker * BYTE data[] - moniker data for a link */ static const WCHAR OleStream[] = {1,'O','l','e',0}; typedef struct { DWORD version; DWORD flags; DWORD link_update_opt; DWORD res; DWORD moniker_size; } ole_stream_header_t; static const DWORD ole_stream_version = 0x02000001; static HRESULT load_ole_stream(DefaultHandler *This, IStorage *storage) { IStream *stream; HRESULT hr; hr = IStorage_OpenStream(storage, OleStream, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream); if(SUCCEEDED(hr)) { DWORD read; ole_stream_header_t header; hr = IStream_Read(stream, &header, sizeof(header), &read); if(hr == S_OK && read == sizeof(header) && header.version == ole_stream_version) { if(header.flags & 1) { /* FIXME: Read the moniker and deal with the link */ FIXME("Linked objects are not supported yet\n"); } } else { WARN("Incorrect OleStream header\n"); hr = DV_E_CLIPFORMAT; } IStream_Release(stream); } else hr = STORAGE_CreateOleStream(storage, 0); return hr; } /************************************************************************ * DefaultHandler_IPersistStorage_InitNew * */ static HRESULT WINAPI DefaultHandler_IPersistStorage_InitNew( IPersistStorage* iface, IStorage* pStg) { DefaultHandler *This = impl_from_IPersistStorage(iface); HRESULT hr; TRACE("(%p)->(%p)\n", iface, pStg); hr = STORAGE_CreateOleStream(pStg, 0); if (hr != S_OK) return hr; hr = IPersistStorage_InitNew(This->dataCache_PersistStg, pStg); if(SUCCEEDED(hr) && object_is_running(This)) { start_object_call( This ); hr = IPersistStorage_InitNew(This->pPSDelegate, pStg); end_object_call( This ); } if(SUCCEEDED(hr)) { IStorage_AddRef(pStg); This->storage = pStg; This->storage_state = storage_state_initialised; } return hr; } /************************************************************************ * DefaultHandler_IPersistStorage_Load * */ static HRESULT WINAPI DefaultHandler_IPersistStorage_Load( IPersistStorage* iface, IStorage* pStg) { DefaultHandler *This = impl_from_IPersistStorage(iface); HRESULT hr; TRACE("(%p)->(%p)\n", iface, pStg); hr = load_ole_stream(This, pStg); if(SUCCEEDED(hr)) hr = IPersistStorage_Load(This->dataCache_PersistStg, pStg); if(SUCCEEDED(hr) && object_is_running(This)) { start_object_call( This ); hr = IPersistStorage_Load(This->pPSDelegate, pStg); end_object_call( This ); } if(SUCCEEDED(hr)) { IStorage_AddRef(pStg); This->storage = pStg; This->storage_state = storage_state_loaded; } return hr; } /************************************************************************ * DefaultHandler_IPersistStorage_Save * */ static HRESULT WINAPI DefaultHandler_IPersistStorage_Save( IPersistStorage* iface, IStorage* pStgSave, BOOL fSameAsLoad) { DefaultHandler *This = impl_from_IPersistStorage(iface); HRESULT hr; TRACE("(%p)->(%p, %d)\n", iface, pStgSave, fSameAsLoad); hr = IPersistStorage_Save(This->dataCache_PersistStg, pStgSave, fSameAsLoad); if(SUCCEEDED(hr) && object_is_running(This)) { start_object_call( This ); hr = IPersistStorage_Save(This->pPSDelegate, pStgSave, fSameAsLoad); end_object_call( This ); } return hr; } /************************************************************************ * DefaultHandler_IPersistStorage_SaveCompleted * */ static HRESULT WINAPI DefaultHandler_IPersistStorage_SaveCompleted( IPersistStorage* iface, IStorage* pStgNew) { DefaultHandler *This = impl_from_IPersistStorage(iface); HRESULT hr; TRACE("(%p)->(%p)\n", iface, pStgNew); hr = IPersistStorage_SaveCompleted(This->dataCache_PersistStg, pStgNew); if(SUCCEEDED(hr) && object_is_running(This)) { start_object_call( This ); hr = IPersistStorage_SaveCompleted(This->pPSDelegate, pStgNew); end_object_call( This ); } if(pStgNew) { IStorage_AddRef(pStgNew); if(This->storage) IStorage_Release(This->storage); This->storage = pStgNew; This->storage_state = storage_state_loaded; } return hr; } /************************************************************************ * DefaultHandler_IPersistStorage_HandsOffStorage * */ static HRESULT WINAPI DefaultHandler_IPersistStorage_HandsOffStorage( IPersistStorage* iface) { DefaultHandler *This = impl_from_IPersistStorage(iface); HRESULT hr; TRACE("(%p)\n", iface); hr = IPersistStorage_HandsOffStorage(This->dataCache_PersistStg); if(SUCCEEDED(hr) && object_is_running(This)) { start_object_call( This ); hr = IPersistStorage_HandsOffStorage(This->pPSDelegate); end_object_call( This ); } if(This->storage) IStorage_Release(This->storage); This->storage = NULL; This->storage_state = storage_state_uninitialised; return hr; } /* * Virtual function tables for the DefaultHandler class. */ static const IOleObjectVtbl DefaultHandler_IOleObject_VTable = { DefaultHandler_QueryInterface, DefaultHandler_AddRef, DefaultHandler_Release, DefaultHandler_SetClientSite, DefaultHandler_GetClientSite, DefaultHandler_SetHostNames, DefaultHandler_Close, DefaultHandler_SetMoniker, DefaultHandler_GetMoniker, DefaultHandler_InitFromData, DefaultHandler_GetClipboardData, DefaultHandler_DoVerb, DefaultHandler_EnumVerbs, DefaultHandler_Update, DefaultHandler_IsUpToDate, DefaultHandler_GetUserClassID, DefaultHandler_GetUserType, DefaultHandler_SetExtent, DefaultHandler_GetExtent, DefaultHandler_Advise, DefaultHandler_Unadvise, DefaultHandler_EnumAdvise, DefaultHandler_GetMiscStatus, DefaultHandler_SetColorScheme }; static const IUnknownVtbl DefaultHandler_NDIUnknown_VTable = { DefaultHandler_NDIUnknown_QueryInterface, DefaultHandler_NDIUnknown_AddRef, DefaultHandler_NDIUnknown_Release, }; static const IDataObjectVtbl DefaultHandler_IDataObject_VTable = { DefaultHandler_IDataObject_QueryInterface, DefaultHandler_IDataObject_AddRef, DefaultHandler_IDataObject_Release, DefaultHandler_GetData, DefaultHandler_GetDataHere, DefaultHandler_QueryGetData, DefaultHandler_GetCanonicalFormatEtc, DefaultHandler_SetData, DefaultHandler_EnumFormatEtc, DefaultHandler_DAdvise, DefaultHandler_DUnadvise, DefaultHandler_EnumDAdvise }; static const IRunnableObjectVtbl DefaultHandler_IRunnableObject_VTable = { DefaultHandler_IRunnableObject_QueryInterface, DefaultHandler_IRunnableObject_AddRef, DefaultHandler_IRunnableObject_Release, DefaultHandler_GetRunningClass, DefaultHandler_Run, DefaultHandler_IsRunning, DefaultHandler_LockRunning, DefaultHandler_SetContainedObject }; static const IAdviseSinkVtbl DefaultHandler_IAdviseSink_VTable = { DefaultHandler_IAdviseSink_QueryInterface, DefaultHandler_IAdviseSink_AddRef, DefaultHandler_IAdviseSink_Release, DefaultHandler_IAdviseSink_OnDataChange, DefaultHandler_IAdviseSink_OnViewChange, DefaultHandler_IAdviseSink_OnRename, DefaultHandler_IAdviseSink_OnSave, DefaultHandler_IAdviseSink_OnClose }; static const IPersistStorageVtbl DefaultHandler_IPersistStorage_VTable = { DefaultHandler_IPersistStorage_QueryInterface, DefaultHandler_IPersistStorage_AddRef, DefaultHandler_IPersistStorage_Release, DefaultHandler_IPersistStorage_GetClassID, DefaultHandler_IPersistStorage_IsDirty, DefaultHandler_IPersistStorage_InitNew, DefaultHandler_IPersistStorage_Load, DefaultHandler_IPersistStorage_Save, DefaultHandler_IPersistStorage_SaveCompleted, DefaultHandler_IPersistStorage_HandsOffStorage }; /********************************************************* * Methods implementation for the DefaultHandler class. */ static DefaultHandler* DefaultHandler_Construct( REFCLSID clsid, LPUNKNOWN pUnkOuter, DWORD flags, IClassFactory *pCF) { DefaultHandler* This = NULL; HRESULT hr; This = HeapAlloc(GetProcessHeap(), 0, sizeof(DefaultHandler)); if (!This) return This; This->IOleObject_iface.lpVtbl = &DefaultHandler_IOleObject_VTable; This->IUnknown_iface.lpVtbl = &DefaultHandler_NDIUnknown_VTable; This->IDataObject_iface.lpVtbl = &DefaultHandler_IDataObject_VTable; This->IRunnableObject_iface.lpVtbl = &DefaultHandler_IRunnableObject_VTable; This->IAdviseSink_iface.lpVtbl = &DefaultHandler_IAdviseSink_VTable; This->IPersistStorage_iface.lpVtbl = &DefaultHandler_IPersistStorage_VTable; This->inproc_server = (flags & EMBDHLP_INPROC_SERVER) != 0; /* * Start with one reference count. The caller of this function * must release the interface pointer when it is done. */ This->ref = 1; /* * Initialize the outer unknown * We don't keep a reference on the outer unknown since, the way * aggregation works, our lifetime is at least as large as its * lifetime. */ if (!pUnkOuter) pUnkOuter = &This->IUnknown_iface; This->outerUnknown = pUnkOuter; /* * Create a datacache object. * We aggregate with the datacache. Make sure we pass our outer * unknown as the datacache's outer unknown. */ hr = CreateDataCache(This->outerUnknown, clsid, &IID_IUnknown, (void**)&This->dataCache); if(SUCCEEDED(hr)) { hr = IUnknown_QueryInterface(This->dataCache, &IID_IPersistStorage, (void**)&This->dataCache_PersistStg); /* keeping a reference to This->dataCache_PersistStg causes us to keep a * reference on the outer object */ if (SUCCEEDED(hr)) IUnknown_Release(This->outerUnknown); else IUnknown_Release(This->dataCache); } if(FAILED(hr)) { ERR("Unexpected error creating data cache\n"); HeapFree(GetProcessHeap(), 0, This); return NULL; } This->clsid = *clsid; This->clientSite = NULL; This->oleAdviseHolder = NULL; This->dataAdviseHolder = NULL; This->containerApp = NULL; This->containerObj = NULL; This->pOleDelegate = NULL; This->pPSDelegate = NULL; This->pDataDelegate = NULL; This->object_state = object_state_not_running; This->in_call = 0; This->dwAdvConn = 0; This->storage = NULL; This->storage_state = storage_state_uninitialised; if (This->inproc_server && !(flags & EMBDHLP_DELAYCREATE)) { HRESULT hr; This->pCFObject = NULL; if (pCF) hr = IClassFactory_CreateInstance(pCF, NULL, &IID_IOleObject, (void **)&This->pOleDelegate); else hr = CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IOleObject, (void **)&This->pOleDelegate); if (SUCCEEDED(hr)) hr = IOleObject_QueryInterface(This->pOleDelegate, &IID_IPersistStorage, (void **)&This->pPSDelegate); if (SUCCEEDED(hr)) hr = IOleObject_QueryInterface(This->pOleDelegate, &IID_IDataObject, (void **)&This->pDataDelegate); if (SUCCEEDED(hr)) This->object_state = object_state_running; if (FAILED(hr)) WARN("object creation failed with error %08x\n", hr); } else { This->pCFObject = pCF; if (pCF) IClassFactory_AddRef(pCF); } return This; } static void DefaultHandler_Destroy( DefaultHandler* This) { TRACE("(%p)\n", This); /* AddRef/Release may be called on this object during destruction. * Prevent the object being destroyed recursively by artificially raising * the reference count. */ This->ref = 10000; /* release delegates */ DefaultHandler_Stop(This); HeapFree( GetProcessHeap(), 0, This->containerApp ); This->containerApp = NULL; HeapFree( GetProcessHeap(), 0, This->containerObj ); This->containerObj = NULL; if (This->dataCache) { /* to balance out the release of dataCache_PersistStg which will result * in a reference being released from the outer unknown */ IUnknown_AddRef(This->outerUnknown); IPersistStorage_Release(This->dataCache_PersistStg); IUnknown_Release(This->dataCache); This->dataCache_PersistStg = NULL; This->dataCache = NULL; } if (This->clientSite) { IOleClientSite_Release(This->clientSite); This->clientSite = NULL; } if (This->oleAdviseHolder) { IOleAdviseHolder_Release(This->oleAdviseHolder); This->oleAdviseHolder = NULL; } if (This->dataAdviseHolder) { IDataAdviseHolder_Release(This->dataAdviseHolder); This->dataAdviseHolder = NULL; } if (This->storage) { IStorage_Release(This->storage); This->storage = NULL; } if (This->pCFObject) { IClassFactory_Release(This->pCFObject); This->pCFObject = NULL; } HeapFree(GetProcessHeap(), 0, This); } /****************************************************************************** * OleCreateEmbeddingHelper [OLE32.@] */ HRESULT WINAPI OleCreateEmbeddingHelper( REFCLSID clsid, LPUNKNOWN pUnkOuter, DWORD flags, IClassFactory *pCF, REFIID riid, LPVOID* ppvObj) { DefaultHandler* newHandler = NULL; HRESULT hr = S_OK; TRACE("(%s, %p, %08x, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter, flags, pCF, debugstr_guid(riid), ppvObj); if (!ppvObj) return E_POINTER; *ppvObj = NULL; /* * If This handler is constructed for aggregation, make sure * the caller is requesting the IUnknown interface. * This is necessary because it's the only time the non-delegating * IUnknown pointer can be returned to the outside. */ if (pUnkOuter && !IsEqualIID(&IID_IUnknown, riid)) return CLASS_E_NOAGGREGATION; /* * Try to construct a new instance of the class. */ newHandler = DefaultHandler_Construct(clsid, pUnkOuter, flags, pCF); if (!newHandler) return E_OUTOFMEMORY; /* * Make sure it supports the interface required by the caller. */ hr = IUnknown_QueryInterface(&newHandler->IUnknown_iface, riid, ppvObj); /* * Release the reference obtained in the constructor. If * the QueryInterface was unsuccessful, it will free the class. */ IUnknown_Release(&newHandler->IUnknown_iface); return hr; } /****************************************************************************** * OleCreateDefaultHandler [OLE32.@] */ HRESULT WINAPI OleCreateDefaultHandler(REFCLSID clsid, LPUNKNOWN pUnkOuter, REFIID riid, LPVOID* ppvObj) { TRACE("(%s, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter,debugstr_guid(riid), ppvObj); return OleCreateEmbeddingHelper(clsid, pUnkOuter, EMBDHLP_INPROC_HANDLER | EMBDHLP_CREATENOW, NULL, riid, ppvObj); } typedef struct HandlerCF { IClassFactory IClassFactory_iface; LONG refs; CLSID clsid; } HandlerCF; static inline HandlerCF *impl_from_IClassFactory(IClassFactory *iface) { return CONTAINING_RECORD(iface, HandlerCF, IClassFactory_iface); } static HRESULT WINAPI HandlerCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) { *ppv = NULL; if (IsEqualIID(riid,&IID_IUnknown) || IsEqualIID(riid,&IID_IClassFactory)) { *ppv = iface; IClassFactory_AddRef(iface); return S_OK; } return E_NOINTERFACE; } static ULONG WINAPI HandlerCF_AddRef(LPCLASSFACTORY iface) { HandlerCF *This = impl_from_IClassFactory(iface); return InterlockedIncrement(&This->refs); } static ULONG WINAPI HandlerCF_Release(LPCLASSFACTORY iface) { HandlerCF *This = impl_from_IClassFactory(iface); ULONG refs = InterlockedDecrement(&This->refs); if (!refs) HeapFree(GetProcessHeap(), 0, This); return refs; } static HRESULT WINAPI HandlerCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) { HandlerCF *This = impl_from_IClassFactory(iface); return OleCreateDefaultHandler(&This->clsid, pUnk, riid, ppv); } static HRESULT WINAPI HandlerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) { FIXME("(%d), stub!\n",fLock); return S_OK; } static const IClassFactoryVtbl HandlerClassFactoryVtbl = { HandlerCF_QueryInterface, HandlerCF_AddRef, HandlerCF_Release, HandlerCF_CreateInstance, HandlerCF_LockServer }; HRESULT HandlerCF_Create(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { HRESULT hr; HandlerCF *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); if (!This) return E_OUTOFMEMORY; This->IClassFactory_iface.lpVtbl = &HandlerClassFactoryVtbl; This->refs = 0; This->clsid = *rclsid; hr = IClassFactory_QueryInterface(&This->IClassFactory_iface, riid, ppv); if (FAILED(hr)) HeapFree(GetProcessHeap(), 0, This); return hr; }