blob: e6c52cd0933bf8745a3564bd17b2c1c99de9c6f2 [file] [log] [blame]
/*
* 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 <assert.h>
#include <stdarg.h>
#include <string.h>
#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/unicode.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) )))
strcpyW( This->containerApp, szContainerApp );
}
if (szContainerObj)
{
if ((This->containerObj = HeapAlloc( GetProcessHeap(), 0,
(lstrlenW(szContainerObj) + 1) * sizeof(WCHAR) )))
strcpyW( 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;
}