*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* NOTES:
* The OLE2 default object handler supports a whole whack of
#include "winbase.h"
#include "winuser.h"
#include "winerror.h"
-#include "wine/unicode.h"
#include "ole2.h"
+
+#include "compobj_private.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
+};
+
/****************************************************************************
* DefaultHandler
*
*/
struct DefaultHandler
{
- const IOleObjectVtbl* lpVtbl;
- const IUnknownVtbl* lpvtblIUnknown;
- const IDataObjectVtbl* lpvtblIDataObject;
- const IRunnableObjectVtbl* lpvtblIRunnableObject;
+ 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 datacache. */
IUnknown* dataCache;
+ /* IPersistStorage implementation of the datacache. */
+ IPersistStorage* dataCache_PersistStg;
/* Client site for the embedded object. */
IOleClientSite* clientSite;
IOleObject *pOleDelegate;
/* IPersistStorage delegate */
IPersistStorage *pPSDelegate;
+ /* IDataObject delegate */
+ IDataObject *pDataDelegate;
+ enum object_state object_state;
+
+ /* 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;
-/*
- * Here, I define utility functions to help with the casting of the
- * "This" parameter.
- * There is a version to accommodate all of the VTables implemented
- * by this object.
- */
static inline DefaultHandler *impl_from_IOleObject( IOleObject *iface )
{
- return (DefaultHandler *)((char*)iface - FIELD_OFFSET(DefaultHandler, lpVtbl));
+ return CONTAINING_RECORD(iface, DefaultHandler, IOleObject_iface);
}
-static inline DefaultHandler *impl_from_NDIUnknown( IUnknown *iface )
+static inline DefaultHandler *impl_from_IUnknown( IUnknown *iface )
{
- return (DefaultHandler *)((char*)iface - FIELD_OFFSET(DefaultHandler, lpvtblIUnknown));
+ return CONTAINING_RECORD(iface, DefaultHandler, IUnknown_iface);
}
static inline DefaultHandler *impl_from_IDataObject( IDataObject *iface )
{
- return (DefaultHandler *)((char*)iface - FIELD_OFFSET(DefaultHandler, lpvtblIDataObject));
+ return CONTAINING_RECORD(iface, DefaultHandler, IDataObject_iface);
}
static inline DefaultHandler *impl_from_IRunnableObject( IRunnableObject *iface )
{
- return (DefaultHandler *)((char*)iface - FIELD_OFFSET(DefaultHandler, lpvtblIRunnableObject));
+ 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);
+}
/*********************************************************
* Method implementation for the non delegating IUnknown
*
* See Windows documentation for more details on IUnknown methods.
*
- * This version of QueryInterface will not delegate it's implementation
+ * This version of QueryInterface will not delegate its implementation
* to the outer unknown.
*/
static HRESULT WINAPI DefaultHandler_NDIUnknown_QueryInterface(
REFIID riid,
void** ppvObject)
{
- DefaultHandler *This = impl_from_NDIUnknown(iface);
+ DefaultHandler *This = impl_from_IUnknown(iface);
- /* Perform a sanity check on the parameters. */
if (!ppvObject)
return E_INVALIDARG;
if (IsEqualIID(&IID_IUnknown, riid))
*ppvObject = iface;
else if (IsEqualIID(&IID_IOleObject, riid))
- *ppvObject = (IOleObject*)&This->lpVtbl;
+ *ppvObject = &This->IOleObject_iface;
else if (IsEqualIID(&IID_IDataObject, riid))
- *ppvObject = (IDataObject*)&This->lpvtblIDataObject;
+ *ppvObject = &This->IDataObject_iface;
else if (IsEqualIID(&IID_IRunnableObject, riid))
- *ppvObject = (IRunnableObject*)&This->lpvtblIRunnableObject;
- else
+ *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)
{
- /*
- * Blind aggregate the data cache to "inherit" it's interfaces.
- */
- if (IUnknown_QueryInterface(This->dataCache, riid, ppvObject) == S_OK)
- return S_OK;
+ return IUnknown_QueryInterface(This->pOleDelegate, riid, ppvObject);
}
/* Check that we obtained an interface. */
*
* See Windows documentation for more details on IUnknown methods.
*
- * This version of QueryInterface will not delegate it's implementation
+ * 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_NDIUnknown(iface);
+ DefaultHandler *This = impl_from_IUnknown(iface);
return InterlockedIncrement(&This->ref);
}
*
* See Windows documentation for more details on IUnknown methods.
*
- * This version of QueryInterface will not delegate it's implementation
+ * 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_NDIUnknown(iface);
+ DefaultHandler *This = impl_from_IUnknown(iface);
ULONG ref;
- /* Decrease the reference count on this object. */
ref = InterlockedDecrement(&This->ref);
if (!ref) DefaultHandler_Destroy(This);
IOleClientSite* pClientSite)
{
DefaultHandler *This = impl_from_IOleObject(iface);
+ HRESULT hr = S_OK;
TRACE("(%p, %p)\n", iface, pClientSite);
+ if (object_is_running(This))
+ hr = IOleObject_SetClientSite(This->pOleDelegate, pClientSite);
+
/*
* Make sure we release the previous client site if there
* was one.
if (This->clientSite)
IOleClientSite_AddRef(This->clientSite);
- return S_OK;
+ return hr;
}
/************************************************************************
{
DefaultHandler *This = impl_from_IOleObject(iface);
- /* Sanity check. */
if (!ppClientSite)
return E_POINTER;
debugstr_w(szContainerApp),
debugstr_w(szContainerObj));
- /* Be sure to cleanup before re-assinging the strings. */
+ if (object_is_running(This))
+ IOleObject_SetHostNames(This->pOleDelegate, szContainerApp, szContainerObj);
+
+ /* 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;
- /* Copy the string supplied. */
if (szContainerApp)
{
if ((This->containerApp = HeapAlloc( GetProcessHeap(), 0,
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)
+{
+ if (!object_is_running(This))
+ return;
+
+ IOleObject_Unadvise(This->pOleDelegate, This->dwAdvConn);
+
+ /* FIXME: call IOleCache_OnStop */
+
+ if (This->dataAdviseHolder)
+ DataAdviseHolder_OnDisconnect(This->dataAdviseHolder);
+
+ This->object_state = object_state_not_running;
+}
+
/************************************************************************
* DefaultHandler_Close (IOleObject)
*
IOleObject* iface,
DWORD dwSaveOption)
{
- TRACE("()\n");
- return S_OK;
+ DefaultHandler *This = impl_from_IOleObject(iface);
+ HRESULT hr;
+
+ TRACE("(%d)\n", dwSaveOption);
+
+ if (!object_is_running(This))
+ return S_OK;
+
+ hr = IOleObject_Close(This->pOleDelegate, dwSaveOption);
+
+ DefaultHandler_Stop(This);
+ release_delegates(This);
+
+ return hr;
}
/************************************************************************
DWORD dwWhichMoniker,
IMoniker* pmk)
{
- TRACE("(%p, %ld, %p)\n",
+ DefaultHandler *This = impl_from_IOleObject(iface);
+
+ TRACE("(%p, %d, %p)\n",
iface,
dwWhichMoniker,
pmk);
+ if (object_is_running(This))
+ return IOleObject_SetMoniker(This->pOleDelegate, dwWhichMoniker, pmk);
+
return S_OK;
}
{
DefaultHandler *This = impl_from_IOleObject(iface);
- TRACE("(%p, %ld, %ld, %p)\n",
+ TRACE("(%p, %d, %d, %p)\n",
iface, dwAssign, dwWhichMoniker, ppmk);
+ if (object_is_running(This))
+ return IOleObject_GetMoniker(This->pOleDelegate, dwAssign, dwWhichMoniker,
+ ppmk);
+
+ /* FIXME: dwWhichMoniker == OLEWHICHMK_CONTAINER only? */
if (This->clientSite)
{
return IOleClientSite_GetMoniker(This->clientSite,
BOOL fCreation,
DWORD dwReserved)
{
- TRACE("(%p, %p, %d, %ld)\n",
+ DefaultHandler *This = impl_from_IOleObject(iface);
+
+ TRACE("(%p, %p, %d, %d)\n",
iface, pDataObject, fCreation, dwReserved);
+ if (object_is_running(This))
+ return IOleObject_InitFromData(This->pOleDelegate, pDataObject, fCreation,
+ dwReserved);
return OLE_E_NOTRUNNING;
}
DWORD dwReserved,
IDataObject** ppDataObject)
{
- TRACE("(%p, %ld, %p)\n",
+ DefaultHandler *This = impl_from_IOleObject(iface);
+
+ TRACE("(%p, %d, %p)\n",
iface, dwReserved, ppDataObject);
+ if (object_is_running(This))
+ return IOleObject_GetClipboardData(This->pOleDelegate, dwReserved,
+ ppDataObject);
+
return OLE_E_NOTRUNNING;
}
HWND hwndParent,
LPCRECT lprcPosRect)
{
- FIXME(": Stub\n");
- return E_NOTIMPL;
+ 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;
+
+ return IOleObject_DoVerb(This->pOleDelegate, iVerb, lpmsg, pActiveSite,
+ lindex, hwndParent, lprcPosRect);
}
/************************************************************************
IEnumOLEVERB** ppEnumOleVerb)
{
DefaultHandler *This = impl_from_IOleObject(iface);
+ HRESULT hr = OLE_S_USEREG;
TRACE("(%p, %p)\n", iface, ppEnumOleVerb);
- return OleRegEnumVerbs(&This->clsid, ppEnumOleVerb);
+ if (object_is_running(This))
+ hr = IOleObject_EnumVerbs(This->pOleDelegate, ppEnumOleVerb);
+
+ if (hr == OLE_S_USEREG)
+ return OleRegEnumVerbs(&This->clsid, ppEnumOleVerb);
+ else
+ return hr;
}
static HRESULT WINAPI DefaultHandler_Update(
IOleObject* iface)
{
- FIXME(": Stub\n");
- return E_NOTIMPL;
+ DefaultHandler *This = impl_from_IOleObject(iface);
+ TRACE("(%p)\n", iface);
+
+ if (!object_is_running(This))
+ {
+ FIXME("Should run object\n");
+ return E_NOTIMPL;
+ }
+ return IOleObject_Update(This->pOleDelegate);
}
/************************************************************************
static HRESULT WINAPI DefaultHandler_IsUpToDate(
IOleObject* iface)
{
- TRACE("(%p)\n", iface);
+ DefaultHandler *This = impl_from_IOleObject(iface);
+ TRACE("(%p)\n", iface);
- return OLE_E_NOTRUNNING;
+ if (object_is_running(This))
+ return IOleObject_IsUpToDate(This->pOleDelegate);
+
+ return OLE_E_NOTRUNNING;
}
/************************************************************************
TRACE("(%p, %p)\n", iface, pClsid);
- /* Sanity check. */
+ if (object_is_running(This))
+ return IOleObject_GetUserClassID(This->pOleDelegate, pClsid);
+
if (!pClsid)
return E_POINTER;
- memcpy(pClsid, &This->clsid, sizeof(CLSID));
+ *pClsid = This->clsid;
return S_OK;
}
{
DefaultHandler *This = impl_from_IOleObject(iface);
- TRACE("(%p, %ld, %p)\n", iface, dwFormOfType, pszUserType);
+ TRACE("(%p, %d, %p)\n", iface, dwFormOfType, pszUserType);
+ if (object_is_running(This))
+ return IOleObject_GetUserType(This->pOleDelegate, dwFormOfType, pszUserType);
return OleRegGetUserType(&This->clsid, dwFormOfType, pszUserType);
}
DWORD dwDrawAspect,
SIZEL* psizel)
{
- TRACE("(%p, %lx, (%ld x %ld))\n", iface,
+ DefaultHandler *This = impl_from_IOleObject(iface);
+
+ TRACE("(%p, %x, (%d x %d))\n", iface,
dwDrawAspect, psizel->cx, psizel->cy);
+
+ if (object_is_running(This))
+ return IOleObject_SetExtent(This->pOleDelegate, dwDrawAspect, psizel);
+
return OLE_E_NOTRUNNING;
}
DefaultHandler *This = impl_from_IOleObject(iface);
- TRACE("(%p, %lx, %p)\n", iface, dwDrawAspect, psizel);
+ TRACE("(%p, %x, %p)\n", iface, dwDrawAspect, psizel);
- hres = IUnknown_QueryInterface(This->dataCache, &IID_IViewObject2, (void**)&cacheView);
+ if (object_is_running(This))
+ return IOleObject_GetExtent(This->pOleDelegate, dwDrawAspect, psizel);
+ hres = IUnknown_QueryInterface(This->dataCache, &IID_IViewObject2, (void**)&cacheView);
if (FAILED(hres))
return E_UNEXPECTED;
*
* Here we would build a valid DVTARGETDEVICE structure
* but, since we are calling into the data cache, we
- * know it's implementation and we'll skip this
+ * know its implementation and we'll skip this
* extra work until later.
*/
targetDevice = NULL;
targetDevice,
psizel);
- /*
- * Cleanup
- */
IViewObject2_Release(cacheView);
return hres;
{
DefaultHandler *This = impl_from_IOleObject(iface);
- TRACE("(%p, %ld)\n", iface, dwConnection);
+ TRACE("(%p, %d)\n", iface, dwConnection);
/*
* If we don't have an advise holder yet, it means we don't have
TRACE("(%p, %p)\n", iface, ppenumAdvise);
- /* Sanity check */
if (!ppenumAdvise)
return E_POINTER;
*ppenumAdvise = NULL;
if (!This->oleAdviseHolder)
- return IOleAdviseHolder_EnumAdvise(This->oleAdviseHolder,
- ppenumAdvise);
+ return S_OK;
- return S_OK;
+ return IOleAdviseHolder_EnumAdvise(This->oleAdviseHolder, ppenumAdvise);
}
/************************************************************************
HRESULT hres;
DefaultHandler *This = impl_from_IOleObject(iface);
- TRACE("(%p, %lx, %p)\n", iface, dwAspect, pdwStatus);
+ TRACE("(%p, %x, %p)\n", iface, dwAspect, pdwStatus);
+
+ if (object_is_running(This))
+ return IOleObject_GetMiscStatus(This->pOleDelegate, dwAspect, pdwStatus);
hres = OleRegGetMiscStatus(&This->clsid, dwAspect, pdwStatus);
if (FAILED(hres))
*pdwStatus = 0;
- return S_OK;
+ return hres;
}
/************************************************************************
- * DefaultHandler_SetExtent (IOleObject)
+ * DefaultHandler_SetColorScheme (IOleObject)
*
* This method is meaningless if the server is not running
*
IOleObject* iface,
struct tagLOGPALETTE* pLogpal)
{
+ DefaultHandler *This = impl_from_IOleObject(iface);
+
TRACE("(%p, %p))\n", iface, pLogpal);
+
+ if (object_is_running(This))
+ return IOleObject_SetColorScheme(This->pOleDelegate, pLogpal);
+
return OLE_E_NOTRUNNING;
}
IDataObject_Release(cacheDataObject);
+ if (FAILED(hres) && This->pDataDelegate)
+ hres = IDataObject_GetData(This->pDataDelegate, pformatetcIn, pmedium);
+
return hres;
}
IDataObject_Release(cacheDataObject);
+ if (FAILED(hres) && This->pDataDelegate)
+ hres = IDataObject_QueryGetData(This->pDataDelegate, pformatetc);
+
return hres;
}
*/
static HRESULT WINAPI DefaultHandler_GetCanonicalFormatEtc(
IDataObject* iface,
- LPFORMATETC pformatectIn,
+ LPFORMATETC pformatetcIn,
LPFORMATETC pformatetcOut)
{
- FIXME("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut);
+ DefaultHandler *This = impl_from_IDataObject(iface);
- return OLE_E_NOTRUNNING;
+ TRACE("(%p, %p, %p)\n", iface, pformatetcIn, pformatetcOut);
+
+ if (!This->pDataDelegate)
+ return OLE_E_NOTRUNNING;
+
+ return IDataObject_GetCanonicalFormatEtc(This->pDataDelegate, pformatetcIn, pformatetcOut);
}
/************************************************************************
STGMEDIUM* pmedium,
BOOL fRelease)
{
+ DefaultHandler *This = impl_from_IDataObject(iface);
IDataObject* cacheDataObject = NULL;
HRESULT hres;
- DefaultHandler *This = impl_from_IDataObject(iface);
-
TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
hres = IUnknown_QueryInterface(This->dataCache,
DWORD dwDirection,
IEnumFORMATETC** ppenumFormatEtc)
{
- HRESULT hres;
DefaultHandler *This = impl_from_IDataObject(iface);
- TRACE("(%p, %lx, %p)\n", iface, dwDirection, ppenumFormatEtc);
-
- hres = OleRegEnumFormatEtc(&This->clsid, dwDirection, ppenumFormatEtc);
+ TRACE("(%p, %x, %p)\n", iface, dwDirection, ppenumFormatEtc);
- return hres;
+ return OleRegEnumFormatEtc(&This->clsid, dwDirection, ppenumFormatEtc);
}
/************************************************************************
HRESULT hres = S_OK;
DefaultHandler *This = impl_from_IDataObject(iface);
- TRACE("(%p, %p, %ld, %p, %p)\n",
+ 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) && This->pDataDelegate)
+ DataAdviseHolder_OnConnect(This->dataAdviseHolder, This->pDataDelegate);
+ }
if (SUCCEEDED(hres))
hres = IDataAdviseHolder_Advise(This->dataAdviseHolder,
{
DefaultHandler *This = impl_from_IDataObject(iface);
- TRACE("(%p, %ld)\n", iface, dwConnection);
+ TRACE("(%p, %d)\n", iface, dwConnection);
/*
* If we don't have a data advise holder yet, it means that
TRACE("(%p, %p)\n", iface, ppenumAdvise);
- /* Sanity check */
if (!ppenumAdvise)
return E_POINTER;
}
/************************************************************************
- * DefaultHandler_IRunnableObject_QueryInterface (IUnknown)
+ * DefaultHandler_IRunnableObject_AddRef (IUnknown)
*
* See Windows documentation for more details on IUnknown methods.
*/
}
/************************************************************************
- * DefaultHandler_IRunnableObject_QueryInterface (IUnknown)
+ * DefaultHandler_IRunnableObject_Release (IUnknown)
*
* See Windows documentation for more details on IUnknown methods.
*/
FIXME("(%p): semi-stub\n", pbc);
/* already running? if so nothing to do */
- if (This->pOleDelegate)
+ if (object_is_running(This))
return S_OK;
- hr = CoCreateInstance(&This->clsid, NULL, CLSCTX_LOCAL_SERVER, &IID_IOleObject, (void **)&This->pOleDelegate);
+ release_delegates(This);
+
+ hr = CoCreateInstance(&This->clsid, NULL, CLSCTX_LOCAL_SERVER,
+ &IID_IOleObject, (void **)&This->pOleDelegate);
if (FAILED(hr))
return hr;
- if (This->clientSite)
+ This->object_state = object_state_running;
+
+ hr = IOleObject_Advise(This->pOleDelegate, &This->IAdviseSink_iface, &This->dwAdvConn);
+
+ if (SUCCEEDED(hr) && This->clientSite)
hr = IOleObject_SetClientSite(This->pOleDelegate, This->clientSite);
if (SUCCEEDED(hr))
{
- IOleObject_QueryInterface(This->pOleDelegate, &IID_IPersistStorage, (void **)&This->pPSDelegate);
+ IOleObject_QueryInterface(This->pOleDelegate, &IID_IPersistStorage,
+ (void **)&This->pPSDelegate);
if (This->pPSDelegate)
- hr = IPersistStorage_InitNew(This->pPSDelegate, NULL);
+ {
+ 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 (SUCCEEDED(hr) && This->containerApp)
- hr = IOleObject_SetHostNames(This->pOleDelegate, This->containerApp, This->containerObj);
+ hr = IOleObject_SetHostNames(This->pOleDelegate, This->containerApp,
+ This->containerObj);
/* FIXME: do more stuff here:
* - IOleObject_GetMiscStatus
- * - IOleObject_Advise
* - IOleObject_GetMoniker
- * - advise data cache that we've connected somehow?
+ * - IOleCache_OnRun
*/
- /* FIXME: if we failed, Close the object */
+ if (SUCCEEDED(hr))
+ hr = IOleObject_QueryInterface(This->pOleDelegate, &IID_IDataObject,
+ (void **)&This->pDataDelegate);
+
+ if (SUCCEEDED(hr) && This->dataAdviseHolder)
+ hr = DataAdviseHolder_OnConnect(This->dataAdviseHolder, This->pDataDelegate);
+
+ if (FAILED(hr))
+ {
+ DefaultHandler_Stop(This);
+ release_delegates(This);
+ }
return hr;
}
TRACE("()\n");
- if (This->pOleDelegate)
+ if (This->object_state == object_state_running)
return TRUE;
else
return FALSE;
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);
+
+ DefaultHandler_Stop(This);
+}
+
+
+/************************************************************************
+ * 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))
+ hr = IPersistStorage_GetClassID(This->pPSDelegate, clsid);
+ 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))
+ hr = IPersistStorage_IsDirty(This->pPSDelegate);
+
+ return hr;
+}
+
+/***********************************************************************
+ * init_ole_stream
+ *
+ * Creates the '\1Ole' stream.
+ * The format of this 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 void init_ole_stream(IStorage *storage)
+{
+ HRESULT hr;
+ IStream *stream;
+
+ hr = IStorage_CreateStream(storage, OleStream, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stream);
+ if(SUCCEEDED(hr))
+ {
+ DWORD written;
+ ole_stream_header_t header;
+
+ header.version = ole_stream_version;
+ header.flags = 0;
+ header.link_update_opt = 0;
+ header.res = 0;
+ header.moniker_size = 0;
+
+ IStream_Write(stream, &header, sizeof(header), &written);
+ IStream_Release(stream);
+ }
+ return;
+}
+
+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
+ {
+ init_ole_stream(storage);
+ hr = S_OK;
+ }
+ 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);
+ init_ole_stream(pStg);
+
+ hr = IPersistStorage_InitNew(This->dataCache_PersistStg, pStg);
+
+ if(SUCCEEDED(hr) && object_is_running(This))
+ hr = IPersistStorage_InitNew(This->pPSDelegate, pStg);
+
+ 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))
+ hr = IPersistStorage_Load(This->pPSDelegate, pStg);
+
+ 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))
+ hr = IPersistStorage_Save(This->pPSDelegate, pStgSave, fSameAsLoad);
+
+ 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))
+ hr = IPersistStorage_SaveCompleted(This->pPSDelegate, pStgNew);
+
+ 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))
+ hr = IPersistStorage_HandsOffStorage(This->pPSDelegate);
+
+ 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.
*/
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)
+ LPUNKNOWN pUnkOuter,
+ DWORD flags,
+ IClassFactory *pCF)
{
DefaultHandler* This = NULL;
+ HRESULT hr;
- /*
- * Allocate space for the object.
- */
This = HeapAlloc(GetProcessHeap(), 0, sizeof(DefaultHandler));
if (!This)
return This;
- This->lpVtbl = &DefaultHandler_IOleObject_VTable;
- This->lpvtblIUnknown = &DefaultHandler_NDIUnknown_VTable;
- This->lpvtblIDataObject = &DefaultHandler_IDataObject_VTable;
- This->lpvtblIRunnableObject = &DefaultHandler_IRunnableObject_VTable;
+ 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) ? TRUE : FALSE;
/*
* Start with one reference count. The caller of this function
/*
* 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 it's
+ * aggregation works, our lifetime is at least as large as its
* lifetime.
*/
if (!pUnkOuter)
- pUnkOuter = (IUnknown*)&This->lpvtblIUnknown;
+ pUnkOuter = &This->IUnknown_iface;
This->outerUnknown = pUnkOuter;
* We aggregate with the datacache. Make sure we pass our outer
* unknown as the datacache's outer unknown.
*/
- CreateDataCache(This->outerUnknown,
- clsid,
- &IID_IUnknown,
- (void**)&This->dataCache);
+ 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;
+ }
- /*
- * Initialize the other data members of the class.
- */
- memcpy(&This->clsid, clsid, sizeof(CLSID));
+ This->clsid = *clsid;
This->clientSite = NULL;
This->oleAdviseHolder = NULL;
This->dataAdviseHolder = NULL;
This->containerObj = NULL;
This->pOleDelegate = NULL;
This->pPSDelegate = NULL;
+ This->pDataDelegate = NULL;
+ This->object_state = object_state_not_running;
+
+ 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)
{
- if (This->pOleDelegate)
- IOleObject_Release(This->pOleDelegate);
- if (This->pPSDelegate)
- IPersistStorage_Release(This->pPSDelegate);
+ 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);
+ release_delegates(This);
- /* Free the strings idenfitying the object */
HeapFree( GetProcessHeap(), 0, This->containerApp );
This->containerApp = NULL;
HeapFree( GetProcessHeap(), 0, This->containerObj );
This->containerObj = NULL;
- /* Release our reference to the data cache. */
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;
}
- /* Same thing for the client site. */
if (This->clientSite)
{
IOleClientSite_Release(This->clientSite);
This->clientSite = NULL;
}
- /* And the advise holder. */
if (This->oleAdviseHolder)
{
IOleAdviseHolder_Release(This->oleAdviseHolder);
This->oleAdviseHolder = NULL;
}
- /* And the data advise holder. */
if (This->dataAdviseHolder)
{
IDataAdviseHolder_Release(This->dataAdviseHolder);
This->dataAdviseHolder = NULL;
}
- /* Free the actual default handler structure. */
+ if (This->storage)
+ {
+ IStorage_Release(This->storage);
+ This->storage = NULL;
+ }
+
+ if (This->pCFObject)
+ {
+ IClassFactory_Release(This->pCFObject);
+ This->pCFObject = NULL;
+ }
+
HeapFree(GetProcessHeap(), 0, This);
}
/******************************************************************************
- * OleCreateDefaultHandler [OLE32.@]
+ * OleCreateEmbeddingHelper [OLE32.@]
*/
-HRESULT WINAPI OleCreateDefaultHandler(
+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, %s, %p)\n", debugstr_guid(clsid), pUnkOuter, debugstr_guid(riid), ppvObj);
+ TRACE("(%s, %p, %08x, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter, flags, pCF, debugstr_guid(riid), ppvObj);
- /*
- * Sanity check
- */
if (!ppvObj)
return E_POINTER;
/*
* Try to construct a new instance of the class.
*/
- newHandler = DefaultHandler_Construct(clsid, pUnkOuter);
+ 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((IUnknown*)&newHandler->lpvtblIUnknown, riid, ppvObj);
+ 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((IUnknown*)&newHandler->lpvtblIUnknown);
+ 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 = IUnknown_QueryInterface((IUnknown *)&This->IClassFactory_iface, riid, ppv);
+ if (FAILED(hr))
+ HeapFree(GetProcessHeap(), 0, This);
+
+ return hr;
+}