📄 defaulthandler.c
字号:
/*
* 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 "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
/****************************************************************************
* DefaultHandler
*
*/
struct DefaultHandler
{
const IOleObjectVtbl* lpVtbl;
const IUnknownVtbl* lpvtblIUnknown;
const IDataObjectVtbl* lpvtblIDataObject;
const IRunnableObjectVtbl* lpvtblIRunnableObject;
const IAdviseSinkVtbl *lpvtblIAdviseSink;
/* 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;
/* 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;
/* connection cookie for the advise on the delegate OLE object */
DWORD dwAdvConn;
};
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));
}
static inline DefaultHandler *impl_from_NDIUnknown( IUnknown *iface )
{
return (DefaultHandler *)((char*)iface - FIELD_OFFSET(DefaultHandler, lpvtblIUnknown));
}
static inline DefaultHandler *impl_from_IDataObject( IDataObject *iface )
{
return (DefaultHandler *)((char*)iface - FIELD_OFFSET(DefaultHandler, lpvtblIDataObject));
}
static inline DefaultHandler *impl_from_IRunnableObject( IRunnableObject *iface )
{
return (DefaultHandler *)((char*)iface - FIELD_OFFSET(DefaultHandler, lpvtblIRunnableObject));
}
static inline DefaultHandler *impl_from_IAdviseSink( IAdviseSink *iface )
{
return (DefaultHandler *)((char*)iface - FIELD_OFFSET(DefaultHandler, lpvtblIAdviseSink));
}
static void DefaultHandler_Destroy(DefaultHandler* 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 it's implementation
* to the outer unknown.
*/
static HRESULT WINAPI DefaultHandler_NDIUnknown_QueryInterface(
IUnknown* iface,
REFIID riid,
void** ppvObject)
{
DefaultHandler *This = impl_from_NDIUnknown(iface);
/* Perform a sanity check on the parameters. */
if (!ppvObject)
return E_INVALIDARG;
*ppvObject = NULL;
if (IsEqualIID(&IID_IUnknown, riid))
*ppvObject = iface;
else if (IsEqualIID(&IID_IOleObject, riid))
*ppvObject = (IOleObject*)&This->lpVtbl;
else if (IsEqualIID(&IID_IDataObject, riid))
*ppvObject = (IDataObject*)&This->lpvtblIDataObject;
else if (IsEqualIID(&IID_IRunnableObject, riid))
*ppvObject = (IRunnableObject*)&This->lpvtblIRunnableObject;
else if (IsEqualIID(&IID_IPersist, riid) ||
IsEqualIID(&IID_IPersistStorage, riid) ||
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;
}
/* Check that we obtained an interface. */
if (*ppvObject == NULL)
{
WARN( "() : asking for un supported 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 it's implementation
* to the outer unknown.
*/
static ULONG WINAPI DefaultHandler_NDIUnknown_AddRef(
IUnknown* iface)
{
DefaultHandler *This = impl_from_NDIUnknown(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 it's implementation
* to the outer unknown.
*/
static ULONG WINAPI DefaultHandler_NDIUnknown_Release(
IUnknown* iface)
{
DefaultHandler *This = impl_from_NDIUnknown(iface);
ULONG ref;
/* Decrease the reference count on this object. */
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 (This->pOleDelegate)
hr = IOleObject_SetClientSite(This->pOleDelegate, pClientSite);
/*
* 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 S_OK;
}
/************************************************************************
* 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);
/* Sanity check. */
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 (This->pOleDelegate)
IOleObject_SetHostNames(This->pOleDelegate, szContainerApp, szContainerObj);
/* Be sure to cleanup before re-assinging 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,
(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;
}
/* undos the work done by DefaultHandler_Run */
static void WINAPI DefaultHandler_Stop(DefaultHandler *This)
{
if (!This->pOleDelegate)
return;
IOleObject_Unadvise(This->pOleDelegate, This->dwAdvConn);
/* FIXME: call IOleCache_OnStop */
if (This->dataAdviseHolder)
DataAdviseHolder_OnDisconnect(This->dataAdviseHolder);
if (This->pDataDelegate)
{
IDataObject_Release(This->pDataDelegate);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -