|
|
// Copyright (C) 1996-1997 Microsoft Corporation. All rights reserved.
//=--------------------------------------------------------------------------=
//
// implementation of the interfaces required for inplace activation for
// COleControl
#include "header.h"
#include "CtlHelp.H"
#include "StdEnum.H"
#include "ctrlobj.h"
#ifndef _DEBUG
#undef THIS_FILE
static const char THIS_FILE[] = __FILE__; #endif
// External Functions
BOOL IsBusy() ; // See wwheel.cpp - TRUE if we are merging.
// all controls support the following in-place verbs at an absolute minimum.
#define CINPLACEVERBS 4
const VERBINFO rgInPlaceVerbs [] = { { OLEIVERB_SHOW, 0, 0, 0}, { OLEIVERB_HIDE, 0, 0, 0}, { OLEIVERB_INPLACEACTIVATE, 0, 0, 0}, { OLEIVERB_PRIMARY, 0, 0, 0} };
// NOTE: Resource ID for Properties string must be 1000
const VERBINFO ovProperties = { CTLIVERB_PROPERTIES, 1000, 0, OLEVERBATTRIB_ONCONTAINERMENU };
const VERBINFO ovUIActivate = { OLEIVERB_UIACTIVATE, 0, 0, 0};
//=--------------------------------------------------------------------------=
// COleControl::GetControlInfo (IOleControl)
//=--------------------------------------------------------------------------=
// returns some information on a control, such as an accelerator table, and
// flags. really used for keyboard handling and mnemonics
//
// Parameters:
// CONTROLINFO * - [in] where to put said information
STDMETHODIMP COleControl::GetControlInfo(CONTROLINFO *pControlInfo) { DBWIN("COleControl::GetControlInfo()\n");
CHECK_POINTER(pControlInfo);
// certain hosts have a bug in which it doesn't initialize the cb in the
// CONTROLINFO structure, so we can only assert on that here.
ASSERT_COMMENT(pControlInfo->cb == sizeof(CONTROLINFO), "Host doesn't initialize CONTROLINFO structure");
// NOTE: control writers should override this routine if they want to
// return accelerator information in their control.
pControlInfo->hAccel = NULL; pControlInfo->cAccel = NULL;
return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::OnMnemonic [IOleControl]
//=--------------------------------------------------------------------------=
// the container has decided to pass on a key that the end-user has pressed to
// us. default implementation will be to just activate the control. people
// looking for more functionality should override this method.
//
// Parameters:
// LPMSG - [in] message for this mnemonic
STDMETHODIMP COleControl::OnMnemonic(LPMSG pMsg) { // OVERRIDE: default implementation is to just activate our control.
// user can override if they want more interesting behaviour.
DBWIN("COleControl::OnMnemonic()\n"); return InPlaceActivate(OLEIVERB_UIACTIVATE); }
//=--------------------------------------------------------------------------=
// COleControl:OnAmbientPropertyChange [IOleControl]
//=--------------------------------------------------------------------------=
// a container calls this whenever it changes an ambient property.
//
// Parameters:
// DISPID - [in] dispid of the property that changed.
//
// Output:
// HRESULT - S_OK
STDMETHODIMP COleControl::OnAmbientPropertyChange(DISPID dispid) { // if we're being told about a change in mode [design/run] then
// remember that so our stashing of mode will update itself
// correctly
DBWIN("COleControl::OnAmbientPropertyChange()\n");
if (dispid == DISPID_AMBIENT_USERMODE || dispid == DISPID_UNKNOWN) m_fModeFlagValid = FALSE;
// just pass this on to the derived control and see if they want
// to do anything with it.
//
AmbientPropertyChanged(dispid); return S_OK; }
//=--------------------------------------------------------------------------=
// COleControL::FreezeEvents [IOleControl]
//=--------------------------------------------------------------------------=
// allows a container to freeze all of a controls events. when events are
// frozen, a control will not fire any of them.
//
// Parameters:
// BOOL - [in] TRUE means FREEZE, FALSE means THAW
//
// Output:
// HRESULT - S_OK
//
// Notes:
// - we maintain an internal count of freezes versus thaws.
STDMETHODIMP COleControl::FreezeEvents(BOOL fFreeze) { // OVERRIDE: by default, we don't care. user can override if they want to.
DBWIN("COleControl::FreezeEvents()\n");
return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::SetClientSite [IOleObject]
//=--------------------------------------------------------------------------=
// informs the embedded object [control] of it's client site [display
// location] within it's container
//
// Parameters:
// IOleClientSite * - [in] pointer to client site.
//
// Output:
// HRESULT - S_OK, E_UNEXPECTED
STDMETHODIMP COleControl::SetClientSite(IOleClientSite *pClientSite) { RELEASE_OBJECT(m_pClientSite); RELEASE_OBJECT(m_pControlSite); // RELEASE_OBJECT(m_pSimpleFrameSite);
// store away the new client site
m_pClientSite = pClientSite;
// if we've actually got one, then get some other interfaces we want to keep
// around, and keep a handle on it
if (m_pClientSite) { m_pClientSite->AddRef(); m_pClientSite->QueryInterface(IID_IOleControlSite, (void **)&m_pControlSite);
#ifdef _DEBUG
if (OLEMISCFLAGSOFCONTROL(m_ObjectType) & OLEMISC_SIMPLEFRAME) ASSERT_COMMENT(FALSE, "We took out simple frame support..."); // m_pClientSite->QueryInterface(IID_ISimpleFrameSite, (void **)&m_pSimpleFrameSite);
#endif
}
return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::GetClientSite [IOleObject]
//=--------------------------------------------------------------------------=
// obtains a pointer to the controls client site.
//
// Parameters:
// IOleClientSite ** - [out]
STDMETHODIMP COleControl::GetClientSite(IOleClientSite **ppClientSite) { CHECK_POINTER(ppClientSite);
*ppClientSite = m_pClientSite; ADDREF_OBJECT(*ppClientSite); return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::SetHostNames [IOleObject]
//=--------------------------------------------------------------------------=
// Provides the control with the name of its container application and the
// compound document in which it is embedded
//
// Parameters:
// LPCOLESTR - [in] name of container application
// LPCOLESTR - [in] name of container document
STDMETHODIMP COleControl::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObject) { return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::Close [IOleObject]
//=--------------------------------------------------------------------------=
// Changes the control from the running to the loaded state
//
// Parameters:
// DWORD - [in] indicates whether to save the object before closing
//
// Output:
// HRESULT - S_OK, OLE_E_PROMPTSAVECANCELLED
STDMETHODIMP COleControl::Close(DWORD dwSaveOption) { HRESULT hr;
if (m_fInPlaceActive) { hr = InPlaceDeactivate(); RETURN_ON_FAILURE(hr); }
#if 0
// handle the save flag.
14-Aug-1997 [ralphw] We don't support any form of saving
if ((dwSaveOption == OLECLOSE_SAVEIFDIRTY || dwSaveOption == OLECLOSE_PROMPTSAVE) && m_fDirty) { if (m_pClientSite) m_pClientSite->SaveObject(); if (m_pOleAdviseHolder) m_pOleAdviseHolder->SendOnSave(); } #endif
return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::SetMoniker [IOleObject]
//=--------------------------------------------------------------------------=
// Notifies an object of its container's moniker, the object's own moniker
// relative to the container, or the object's full moniker
//
// Parameters:
// DWORD - [in] which moniker is being set
// IMoniker * - [in] the moniker
//
// Output:
// HRESULT - S_OK, E_FAIL
//
// Notes:
// - we don't support monikers.
STDMETHODIMP COleControl::SetMoniker(DWORD dwWhichMoniker, IMoniker *pMoniker) { return E_NOTIMPL; }
//=--------------------------------------------------------------------------=
// COleControl::GetMoniker [IOleObject]
//=--------------------------------------------------------------------------=
// Returns a embedded object's moniker, which the caller can use to link to
// the object
//
// Parameters:
// DWORD - [in] how it's assigned
// DWORD - [in] which moniker
// IMoniker ** - [out] duh.
//
// Output:
// HRESULT - E_NOTIMPL
//
// Notes:
// - we don't support monikers
STDMETHODIMP COleControl::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppMonikerOut) { return E_NOTIMPL; }
//=--------------------------------------------------------------------------=
// COleControl::InitFromData [IOleObject]
//=--------------------------------------------------------------------------=
// Initializes a newly created object with data from a specified data object,
// which can reside either in the same container or on the Clipboard
//
// Parameters:
// IDataObject* - [in] data object with the data
// BOOL - [in] how object is created
// DWORD - reserved
//
// Output:
// HRESULT - S_OK, S_FALSE, E_NOTIMPL, OLE_E_NOTRUNNING
//
// Notes:
// - we don't have data object support
STDMETHODIMP COleControl::InitFromData(IDataObject *pDataObject, BOOL fCreation, DWORD dwReserved) { return E_NOTIMPL; }
//=--------------------------------------------------------------------------=
// COleControl::GetClipboardData [IOleObject]
//=--------------------------------------------------------------------------=
// Retrieves a data object containing the current contents of the control.
// Using the pointer to this data object, it is possible to create a new control
// with the same data as the original
//
// Parameters:
// DWORD - reserved
// IDataObject ** - [out] data object for this control
//
// Output:
// HREUSLT - S_OK, E_NOTIMPL, OLE_E_NOTRUNNING
//
// Notes:
//
STDMETHODIMP COleControl::GetClipboardData(DWORD dwReserved, IDataObject **ppDataObject) { *ppDataObject = NULL; // be a good neighbour
return E_NOTIMPL; }
//=--------------------------------------------------------------------------=
// COleControl::DoVerb [IOleObject]
//=--------------------------------------------------------------------------=
// Requests an object to perform an action in response to an end-user's
// action.
//
// Parameters:
// LONG - [in] verb to be performed
// LPMSG - [in] event that invoked the verb
// IOleClientSite * - [in] the controls active client site
// LONG - [in] reserved
// HWND - [in] handle of window containing the object.
// LPCRECT - [in] pointer to objects's display rectangle
//
// Output:
// HRESULT - S_OK, OLE_E_NOTINPLACEACTIVE, OLE_E_CANT_BINDTOSOURCE,
// DV_E_LINK, OLEOBJ_S_CANNOT_DOVERB_NOW, OLEOBJ_S_INVALIDHWND,
// OLEOBJ_E_NOVERBS, OLEOBJ_S_INVALIDVERB, MK_E_CONNECT,
// OLE_CLASSDIFF, E_NOTIMPL
STDMETHODIMP COleControl::DoVerb(LONG lVerb, LPMSG pMsg, IOleClientSite *pActiveSite, LONG lIndex, HWND hwndParent, LPCRECT prcPosRect) { HRESULT hr;
switch (lVerb) { case OLEIVERB_SHOW: case OLEIVERB_INPLACEACTIVATE: case OLEIVERB_UIACTIVATE: // Check to see if we are merging?
if (IsBusy()) { // We cannot precess these if we are merging.
return OLEOBJ_S_CANNOT_DOVERB_NOW ; } else { return InPlaceActivate(lVerb); }
case OLEIVERB_HIDE: UIDeactivate(); if (m_fInPlaceVisible) SetInPlaceVisible(FALSE); return S_OK;
// we used to have OLEIVERB_PRIMARY InPlaceActivate Ourselves, but it
// turns out that the CDK and certain hosts expect this to show the
// properties instead. Users can change what this verb does at will.
case OLEIVERB_PRIMARY: case CTLIVERB_PROPERTIES: case OLEIVERB_PROPERTIES: { // show the frame ourselves if the hose can't.
if (m_pControlSite) { hr = m_pControlSite->ShowPropertyFrame(); if (hr != E_NOTIMPL) return hr; } IUnknown *pUnk = (IUnknown *)(IOleObject *)this; MAKE_WIDEPTR_FROMANSI(pwsz, NAMEOFOBJECT(m_ObjectType));
#if 0
ModalDialog(TRUE); hr = OleCreatePropertyFrame(GetActiveWindow(), GetSystemMetrics(SM_CXSCREEN) / 2, GetSystemMetrics(SM_CYSCREEN) / 2, pwsz, 1, &pUnk, CPROPPAGESOFCONTROL(m_ObjectType), (LPCLSID)*(PPROPPAGESOFCONTROL(m_ObjectType)), g_lcidLocale, NULL, NULL); ModalDialog(FALSE); #endif
return hr; }
default: // if it's a derived-control defined verb, pass it on to them
//
if (lVerb > 0) { hr = DoCustomVerb(lVerb);
if (hr == OLEOBJ_S_INVALIDVERB) { // unrecognised verb -- just do the primary verb and
// activate the sucker.
//
hr = InPlaceActivate(OLEIVERB_PRIMARY); return (FAILED(hr)) ? hr : OLEOBJ_S_INVALIDVERB; } else return hr; } else { FAIL("Unrecognized Negative verb in DoVerb()."); return E_NOTIMPL; } break; }
// dead code
FAIL("this should be dead code!"); }
//=--------------------------------------------------------------------------=
// COleControl::EnumVerbs [IOleObject]
//=--------------------------------------------------------------------------=
// create an enumerator object for the verbs this object supports.
//
// Parameters:
// IEnumOleVERB ** - [out] new enumerator.
//
// Output:
// HRESULT - S_OK, E_OUTOFMEMORY
STDMETHODIMP COleControl::EnumVerbs(IEnumOLEVERB **ppEnumVerbs) { int cVerbs; OLEVERB *rgVerbs, *pVerb;
DWORD dw = OLEMISCFLAGSOFCONTROL(m_ObjectType); BOOL fCanInPlace = !(dw & OLEMISC_INVISIBLEATRUNTIME) || (dw & OLEMISC_ACTIVATEWHENVISIBLE); BOOL fCanUIActivate = !(dw & OLEMISC_NOUIACTIVATE); BOOL fHasProperties = (CPROPPAGESOFCONTROL(m_ObjectType) != 0);
int cVerbExtra = CCUSTOMVERBSOFCONTROL(m_ObjectType);
// count up all the verbs
cVerbs = (fCanInPlace ? CINPLACEVERBS : 0) + (fCanUIActivate ? 1 : 0) + (fHasProperties ? 1 : 0) + cVerbExtra;
// if there aren't any, this suddenly gets really easy !
if (cVerbs == 0) return OLEOBJ_E_NOVERBS;
if (! (rgVerbs = (OLEVERB *) lcCalloc(cVerbs * sizeof(OLEVERB)))) return E_OUTOFMEMORY;
// start copying over verbs. first, the in-place guys
pVerb = rgVerbs; if (fCanInPlace) { memcpy(pVerb, rgInPlaceVerbs, CINPLACEVERBS * sizeof(OLEVERB)); pVerb += CINPLACEVERBS; }
if (fCanUIActivate) memcpy(pVerb++, &ovUIActivate, sizeof(OLEVERB));
// if their control has properties, copy that over now.
//
if (fHasProperties) { memcpy(pVerb, &ovProperties, sizeof(OLEVERB)); pVerb++; }
// finally, any custom verbs!
//
if (cVerbExtra) { memcpy(pVerb, CUSTOMVERBSOFCONTROL(m_ObjectType), sizeof(OLEVERB) * cVerbExtra); }
*ppEnumVerbs = (IEnumOLEVERB *) (IEnumGeneric *) new CStandardEnum(IID_IEnumOLEVERB, cVerbs, sizeof(OLEVERB), rgVerbs, CopyOleVerb); if (!*ppEnumVerbs) return E_OUTOFMEMORY;
return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::Update [IOleObject]
//=--------------------------------------------------------------------------=
// Updates an object handler's or link object's data or view caches.
STDMETHODIMP COleControl::Update(void) { return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::IsUpToDate [IOleObject]
//=--------------------------------------------------------------------------=
// Checks recursively whether or not an object is up to date.
STDMETHODIMP COleControl::IsUpToDate(void) { return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::GetUserClassID [IOleObject]
//=--------------------------------------------------------------------------=
// Returns the controls class identifier, the CLSID corresponding to the
// string identifying the object to an end user.
//
// Parameters:
// CLSID * - [in] where to put the CLSID
STDMETHODIMP COleControl::GetUserClassID(CLSID *pclsid) { // this is the same as IPersist::GetClassID
return GetClassID(pclsid); }
//=--------------------------------------------------------------------------=
// COleControl::GetUserType [IOleObject]
//=--------------------------------------------------------------------------=
// Retrieves the user-type name of the control for display in user-interface
// elements such as menus, list boxes, and dialog boxes.
//
// Parameters:
// DWORD - [in] specifies the form of the type name.
// LPOLESTR * - [out] where to put user type
//
// Output:
// HRESULT - S_OK, OLE_S_USEREG, E_OUTOFMEMORY
STDMETHODIMP COleControl::GetUserType(DWORD dwFormOfType, LPOLESTR *ppszUserType) { *ppszUserType = OLESTRFROMANSI(NAMEOFOBJECT(m_ObjectType)); return (*ppszUserType) ? S_OK : E_OUTOFMEMORY; }
//=--------------------------------------------------------------------------=
// COleControl::SetExtent [IOleObject]
//=--------------------------------------------------------------------------=
// Informs the control of how much display space its container has assigned it.
//
// Parameters:
// DWORD - [in] which form or 'aspect' is to be displayed.
// SIZEL * - [in] size limit for the control.
//
// Output:
// HRESULT - S_OK, E_FAIL, OLE_E_NOTRUNNING
STDMETHODIMP COleControl::SetExtent(DWORD dwDrawAspect, SIZEL *psizel) { SIZE sl; RECT rect; BOOL f;
if (dwDrawAspect & DVASPECT_CONTENT) {
// change the units to pixels, and resize the control.
HiMetricToPixel(psizel, &sl);
// first call the user version. if they return FALSE, they want
// to keep their current size
f = OnSetExtent(&sl); if (f) HiMetricToPixel(psizel, &m_Size);
// set things up with our HWND if we've got one.
if (!m_pInPlaceSiteWndless) { if (m_fInPlaceActive) {
// theoretically, one should not need to call OnPosRectChange
// here, but there appear to be a few host related issues that
// will make us keep it here. we won't, however, bother with
// windowless ole controls, since they are all new hosts who
// should know better
GetWindowRect(m_hwnd, &rect); MapWindowPoints(NULL, m_hwndParent, (LPPOINT)&rect, 2); rect.right = rect.left + m_Size.cx; rect.bottom = rect.top + m_Size.cy; m_pInPlaceSite->OnPosRectChange(&rect);
if (m_hwnd) { // just go and resize
SetWindowPos(m_hwnd, 0, 0, 0, m_Size.cx, m_Size.cy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); } } else if (m_hwnd) { SetWindowPos(m_hwnd, NULL, 0, 0, m_Size.cx, m_Size.cy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); } else { ViewChanged(); } } else if (m_pInPlaceSite) m_pInPlaceSite->OnPosRectChange(&rect);
// return code depending on whether or not user accepted given
// size
return (f) ? S_OK : E_FAIL;
} else { // we don't support any other aspects.
return DV_E_DVASPECT; }
// dead code
FAIL("This should be dead code"); }
//=--------------------------------------------------------------------------=
// COleControl::GetExtent [IOleObject]
//=--------------------------------------------------------------------------=
// Retrieves the control's current display size.
//
// Parameters:
// DWORD - [in] aspect
// SIZEL * - [in] where to put results
//
// Output:
// S_OK, E_INVALIDARG
//
// Notes:
//
STDMETHODIMP COleControl::GetExtent(DWORD dwDrawAspect, SIZEL *pSizeLOut) {
if (dwDrawAspect & DVASPECT_CONTENT) { PixelToHiMetric((const SIZEL *)&m_Size, pSizeLOut); return S_OK; } else { return DV_E_DVASPECT; }
// dead code
}
//=--------------------------------------------------------------------------=
// COleControl::Advise [IOleObject]
//=--------------------------------------------------------------------------=
// establishes and advisory connection between the control and the container,
// in which the control will notify the container of certain events.
//
// Parameters:
// IAdviseSink * - [in] advise sink of calling object
// DWORD - [out] cookie
//
// Output:
// HRESULT - S_OK, E_OUTOFMEMORY
STDMETHODIMP COleControl::Advise(IAdviseSink *pAdviseSink, DWORD *pdwConnection) { HRESULT hr;
// if we haven't yet created a standard advise holder object, do so
// now
if (!m_pOleAdviseHolder) { hr = CreateOleAdviseHolder(&m_pOleAdviseHolder); RETURN_ON_FAILURE(hr); }
// just get it to do the work for us!
return m_pOleAdviseHolder->Advise(pAdviseSink, pdwConnection); }
//=--------------------------------------------------------------------------=
// COleControl::Unadvise [IOleObject]
//=--------------------------------------------------------------------------=
// Deletes a previously established advisory connection.
//
// Parameters:
// DWORD - [in] connection cookie
//
// Output:
// HRESULT - S_OK, E_FAIL, OLE_E_NOCONNECTION
STDMETHODIMP COleControl::Unadvise(DWORD dwConnection) { if (!m_pOleAdviseHolder) { FAIL("Somebody called Unadvise on IOleObject without calling Advise!"); CONNECT_E_NOCONNECTION; }
return m_pOleAdviseHolder->Unadvise(dwConnection); }
//=--------------------------------------------------------------------------=
// COleControl::EnumAdvise [IOleObject]
//=--------------------------------------------------------------------------=
// Enumerates the advisory connections registered for an object, so a container
// can know what to release prior to closing down.
//
// Parameters:
// IEnumSTATDATA ** - [out] where to put enumerator
//
// Output:
// HRESULT - S_OK, E_FAIL, E_NOTIMPL
STDMETHODIMP COleControl::EnumAdvise ( IEnumSTATDATA **ppEnumOut ) { if (!m_pOleAdviseHolder) { FAIL("Somebody Called EnumAdvise without setting up any connections"); *ppEnumOut = NULL; return E_FAIL; }
return m_pOleAdviseHolder->EnumAdvise(ppEnumOut); }
//=--------------------------------------------------------------------------=
// COleControl::GetMiscStatus [IOleObject]
//=--------------------------------------------------------------------------=
// Returns a value indicating the status of an object at creation and loading.
//
// Parameters:
// DWORD - [in] aspect desired
// DWORD * - [out] where to put the bits.
//
// Output:
// HRESULT - S_OK, OLE_S_USEREG, CO_E_CLASSNOTREG, CO_E_READREGDB
//
// Notes:
//
STDMETHODIMP COleControl::GetMiscStatus(DWORD dwAspect, DWORD *pdwStatus) { CHECK_POINTER(pdwStatus);
if (dwAspect == DVASPECT_CONTENT) { *pdwStatus = OLEMISCFLAGSOFCONTROL(m_ObjectType); return S_OK; } else return DV_E_DVASPECT; }
//=--------------------------------------------------------------------------=
// COleControl::SetColorScheme [IOleObject]
//=--------------------------------------------------------------------------=
// Specifies the color palette that the object application should use when it
// edits the specified object.
//
// Parameters:
// LOGPALETTE * - [in] new palette
//
// Output:
// HRESULT - S_OK, E_NOTIMPL, OLE_E_PALETTE, OLE_E_NOTRUNNING
//
// Notes:
// - we don't care.
STDMETHODIMP COleControl::SetColorScheme(LOGPALETTE *pLogpal) { return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::GetWindow [IOleWindow/IOleInPlaceObject]
//=--------------------------------------------------------------------------=
// Returns the window handle to one of the windows participating in in-place
// activation (frame, document, parent, or in-place object window).
//
// Parameters:
// HWND * - [out] where to return window handle.
//
// Output:
// HRESULT - S_OK, E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL
//
// Notes:
// - this routine has slightly different semantics for windowless controls
STDMETHODIMP COleControl::GetWindow(HWND *phwnd) { // if we're windowles, then we want to return E_FAIL for this so hosts
// know we're windowless
if (m_pInPlaceSiteWndless) return E_FAIL;
// otherwise, just return our outer window.
//
*phwnd = m_hwnd;
return (*phwnd) ? S_OK : E_UNEXPECTED; }
//=--------------------------------------------------------------------------=
// COleControl::ContextSensitiveHelp [IOleWindow/IOleInPlaceObject]
//=--------------------------------------------------------------------------=
// Determines whether context-sensitive help mode should be entered during an
// in-place activation session.
//
// Parameters:
// BOOL - [in] whether or not to enter help mode.
//
// Output:
// HRESULT - S_OK, E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED
STDMETHODIMP COleControl::ContextSensitiveHelp(BOOL fEnterMode) { return E_NOTIMPL; }
//=--------------------------------------------------------------------------=
// COleControl::InPlaceActivate
//=--------------------------------------------------------------------------=
// activates the control, and depending on the verb, optionally ui activates
// it as well.
//
// Parameters:
// LONG - [in] the verb that caused us to activate
//
// Output:
// HRESULT
//
// Notes:
// - this is spaghetti code at it's worst. effectively, we have to
// be able to handle three types of site pointers -- IOleInPlaceSIte,
// IOleInPlaceSiteEx, and IOleInPlaceSiteWindowless. not terribly
// pretty.
//
HRESULT COleControl::InPlaceActivate(LONG lVerb) { BOOL f; SIZEL sizel; IOleInPlaceSiteEx *pIPSEx = NULL; HRESULT hr; BOOL fNoRedraw = FALSE;
// if we don't have a client site, then there's not much to do.
if (!m_pClientSite) return S_OK; //
// <mc>
// This code attempts to insure that we don't give UI activation to a control that is not
// enabled.
// </mc>
if ( m_hwnd ) { HWND hWndButton; if ( !(hWndButton = ::GetWindow(m_hwnd, GW_CHILD)) || !IsWindowEnabled(hWndButton) ) return OLEOBJ_S_CANNOT_DOVERB_NOW; } //
// <mc>
// This code catches the control creation entry to this function and calls a new virtual to insure that we
// do indeed need a control window. If we don't need a control window we MUST return E_NOTIMPL from the
// doverb() call which is the caller of this function. See ShouldCreateWindow() for more details.
// </mc>
if ( !m_hwnd ) { if (! ShouldCreateWindow() ) return E_NOTIMPL; }
// get an InPlace site pointer.
if (!GetInPlaceSite()) {
// if they want windowless support, then we want IOleInPlaceSiteWindowless
if (FCONTROLISWINDOWLESS(m_ObjectType)) m_pClientSite->QueryInterface(IID_IOleInPlaceSiteWindowless, (void **)&m_pInPlaceSiteWndless);
// if we're not able to do windowless siting, then we'll just get an
// IOleInPlaceSite pointer.
if (!m_pInPlaceSiteWndless) { hr = m_pClientSite->QueryInterface(IID_IOleInPlaceSite, (void **)&m_pInPlaceSite); RETURN_ON_FAILURE(hr); } }
// now, we want an IOleInPlaceSiteEx pointer for windowless and flicker free
// activation. if we're windowless, we've already got it, else we need to
// try and get it
if (m_pInPlaceSiteWndless) { pIPSEx = (IOleInPlaceSiteEx *)m_pInPlaceSiteWndless; pIPSEx->AddRef(); } else m_pClientSite->QueryInterface(IID_IOleInPlaceSiteEx, (void **)&pIPSEx);
// if we're not already active, go and do it.
//
if (!m_fInPlaceActive) { OLEINPLACEFRAMEINFO InPlaceFrameInfo; RECT rcPos, rcClip;
// if we have a windowless site, see if we can go in-place windowless
// active
//
hr = S_FALSE; if (m_pInPlaceSiteWndless) { hr = m_pInPlaceSiteWndless->CanWindowlessActivate(); CLEANUP_ON_FAILURE(hr);
// if they refused windowless, we'll try windowed
//
if (S_OK != hr) { RELEASE_OBJECT(m_pInPlaceSiteWndless); hr = m_pClientSite->QueryInterface(IID_IOleInPlaceSite, (void **)&m_pInPlaceSite); CLEANUP_ON_FAILURE(hr); } }
// just try regular windowed in-place activation
//
if (hr != S_OK) { hr = m_pInPlaceSite->CanInPlaceActivate(); if (hr != S_OK) { hr = (FAILED(hr)) ? E_FAIL : hr; goto CleanUp; } }
// if we are here, then we have permission to go in-place active.
// now, announce our intentions to actually go ahead and do this.
//
hr = (pIPSEx) ? pIPSEx->OnInPlaceActivateEx(&fNoRedraw, (m_pInPlaceSiteWndless) ? ACTIVATE_WINDOWLESS : 0) : m_pInPlaceSite->OnInPlaceActivate(); CLEANUP_ON_FAILURE(hr);
// if we're here, we're ready to go in-place active. we just need
// to set up some flags, and then create the window [if we have
// one]
//
m_fInPlaceActive = TRUE;
// we need to get some information about our location in the parent
// window, as well as some information about the parent
//
InPlaceFrameInfo.cb = sizeof(OLEINPLACEFRAMEINFO); hr = GetInPlaceSite()->GetWindow(&m_hwndParent); if (SUCCEEDED(hr)) hr = GetInPlaceSite()->GetWindowContext(&m_pInPlaceFrame, &m_pInPlaceUIWindow, &rcPos, &rcClip, &InPlaceFrameInfo); CLEANUP_ON_FAILURE(hr);
// make sure we'll display ourselves in the correct location with the correct size
//
sizel.cx = rcPos.right - rcPos.left; sizel.cy = rcPos.bottom - rcPos.top; f = OnSetExtent(&sizel); if (f) m_Size = sizel; SetObjectRects(&rcPos, &rcClip);
// finally, create our window if we have to!
if (!m_pInPlaceSiteWndless) {
SetInPlaceParent(m_hwndParent);
// create the window, and display it. die horribly if we couldnt'
//
if (!CreateInPlaceWindow(rcPos.left, rcPos.top, fNoRedraw)) { hr = E_FAIL; goto CleanUp; } } }
// don't need this any more
//
RELEASE_OBJECT(pIPSEx);
// if we're not inplace visible yet, do so now.
//
if (!m_fInPlaceVisible) SetInPlaceVisible(TRUE);
// if we weren't asked to UIActivate, then we're done.
//
if (lVerb != OLEIVERB_PRIMARY && lVerb != OLEIVERB_UIACTIVATE) return S_OK;
// if we're not already UI active, do sow now.
//
if (!m_fUIActive) { m_fUIActive = TRUE;
// inform the container of our intent
GetInPlaceSite()->OnUIActivate();
// take the focus [which is what UI Activation is all about !]
DBWIN("Activate focus"); SetFocus(TRUE);
// set ourselves up in the host.
m_pInPlaceFrame->SetActiveObject((IOleInPlaceActiveObject *)this, NULL); if (m_pInPlaceUIWindow) m_pInPlaceUIWindow->SetActiveObject((IOleInPlaceActiveObject *)this, NULL);
// we have to explicitly say we don't wany any border space.
//
m_pInPlaceFrame->SetBorderSpace(NULL); if (m_pInPlaceUIWindow) m_pInPlaceUIWindow->SetBorderSpace(NULL); }
// be-de-be-de-be-de that's all folks!
//
return S_OK;
CleanUp: // something catastrophic happened [or, at least something bad].
// die a horrible fiery mangled painful death.
//
QUICK_RELEASE(pIPSEx); m_fInPlaceActive = FALSE; return hr;
}
//=--------------------------------------------------------------------------=
// COleControl::InPlaceDeactivate [IOleInPlaceObject]
//=--------------------------------------------------------------------------=
// Deactivates an active in-place object and discards the object's undo state.
//
// Output:
// HRESULT - S_OK, E_UNEXPECTED
STDMETHODIMP COleControl::InPlaceDeactivate(void) { // if we're not in-place active yet, then this is easy.
if (!m_fInPlaceActive) return S_OK;
// transition from UIActive back to active
//
if (m_fUIActive) UIDeactivate();
m_fInPlaceActive = FALSE; m_fInPlaceVisible = FALSE;
// if we have a window, tell it to go away.
//
if (m_hwnd) { ASSERT_COMMENT(!m_pInPlaceSiteWndless, "internal state really messed up");
// so our window proc doesn't crash.
//
BeforeDestroyWindow(); SetWindowLong(m_hwnd, GWLP_USERDATA, 0xFFFFFFFF); DestroyWindow(m_hwnd); m_hwnd = NULL; }
RELEASE_OBJECT(m_pInPlaceFrame); RELEASE_OBJECT(m_pInPlaceUIWindow); GetInPlaceSite()->OnInPlaceDeactivate(); return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::UIDeactivate [IOleInPlaceObject]
//=--------------------------------------------------------------------------=
// transitions us from UI Active to merely being active [visible] for
// a control, this doesn't mean all that much.
//
// Output:
// HRESULT - S_OK, E_UNEXPECTED
STDMETHODIMP COleControl::UIDeactivate(void) { // if we're not UIActive, not much to do.
//
if (!m_fUIActive) return S_OK;
m_fUIActive = FALSE;
// notify frame windows, if appropriate, that we're no longer ui-active.
//
if (m_pInPlaceUIWindow) m_pInPlaceUIWindow->SetActiveObject(NULL, NULL); m_pInPlaceFrame->SetActiveObject(NULL, NULL);
// we don't need to explicitly release the focus here since somebody
// else grabbing the focus is what is likely to cause us to get lose it
//
GetInPlaceSite()->OnUIDeactivate(FALSE);
return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::SetObjectRects [IOleInPlaceObject]
//=--------------------------------------------------------------------------=
// Indicates how much of the control is visible.
//
// Parameters:
// LPCRECT - [in] position of the control.
// LPCRECT - [in] clipping rectangle for the control.
//
// Output:
// HRESULT - S_OK, E_INVALIDARG, E_OUTOFMEMORY, E_UNEXPECTED
//
// Notes:
//
#if 0
STDMETHODIMP COleControl::SetObjectRects(LPCRECT prcPos, LPCRECT prcClip) { BOOL fRemoveWindowRgn;
// verify our information
// This assertion doesn't seem valid because the container (IE 3) never
// calls SetExtent().
// ASSERT_COMMENT(m_Size.cx == (prcPos->right - prcPos->left) && m_Size.cy == (prcPos->bottom - prcPos->top), "Somebody called SetObjectRects without first setting the extent");
/*
* Move our window to the new location and handle clipping. Not * applicable for windowless controls, since the container will be * responsible for all clipping. */
if (m_hwnd) { fRemoveWindowRgn = m_fUsingWindowRgn; if (prcClip) { // the container wants us to clip, so figure out if we really
// need to
RECT rcIXect; if (IntersectRect(&rcIXect, prcPos, prcClip)) { if (!EqualRect(&rcIXect, prcPos)) { OffsetRect(&rcIXect, -(prcPos->left), -(prcPos->top)); SetWindowRgn(m_hwnd, CreateRectRgnIndirect(&rcIXect), TRUE); m_fUsingWindowRgn = TRUE; fRemoveWindowRgn = FALSE; } } }
if (fRemoveWindowRgn) { SetWindowRgn(m_hwnd, NULL, TRUE); m_fUsingWindowRgn = FALSE; }
// set our control's location and size
// [people for whom zooming is important should set that up here]
if (!EqualRect(prcPos, &m_rcLocation)) { m_Size.cx = (prcPos->right - prcPos->left); m_Size.cy = (prcPos->bottom - prcPos->top); SetWindowPos(m_hwnd, NULL, prcPos->left, prcPos->top, m_Size.cx, m_Size.cy, SWP_NOZORDER | SWP_NOACTIVATE); CopyRect(&m_rcLocation, prcPos); return S_OK; } }
// save out our current location. windowless controls want this more
// then windowed ones do, but everybody can have it just in case
// BUGBUG: 20-Apr-1997 [ralphw] why do we care about this for
// windowless controls
CopyRect(&m_rcLocation, prcPos);
return S_OK; } #endif
//=--------------------------------------------------------------------------=
// COleControl::ReactivateAndUndo [IOleInPlaceObject]
//=--------------------------------------------------------------------------=
// Reactivates a previously deactivated object, undoing the last state of the object.
//
// Output:
// HRESULT - S_OK, E_NOTUNDOABLE
STDMETHODIMP COleControl::ReactivateAndUndo(void) { return E_NOTIMPL; }
//=--------------------------------------------------------------------------=
// COleControl::OnWindowMessage [IOleInPlaceObjectWindowless]
//=--------------------------------------------------------------------------=
// this method lets the container dispatch a message to a windowless OLE
// object.
//
// Parameters:
// UINT - [in] the message
// WPARAM - [in] the messages wparam
// LPARAM - [in] duh.
// LRESULT * - [out] the output value
//
// Output:
// HRESULT - S_OK
//
// Notes:
// - people should call m_pInPlaceSiteWndless->OnDefWindowMessage [control
// writers should just call OcxDefWindowProc(msg, wparam, lparam)];
//
// REVIEW: if we don't have a windowless command, this should get nuked
STDMETHODIMP COleControl::OnWindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *plResult) { // little bit of pre-processing -- we need to handle some cases here
// before passing the messages on
switch (msg) { // make sure our UI Activation correctly matches the focus
//
case WM_KILLFOCUS: case WM_SETFOCUS: // give the control site focus notification
//
DBWIN("windowless focus"); if (m_fInPlaceActive && m_pControlSite) m_pControlSite->OnFocus(msg == WM_SETFOCUS); break; }
// just pass it to the control's window proc.
*plResult = WindowProc(msg, wParam, lParam); return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::GetDropTarget [IOleInPlaceObjectWindowless]
//=--------------------------------------------------------------------------=
// this method returns a pointer to the objects IDropTarget interface. since
// they do not have a window, windowless objects cannot register an IDropTarget
// interface.
//
// Parameters:
// IDropTarget ** - [out]
//
// Output:
// HRESULT - S_OK, E_NOTIMPL
STDMETHODIMP COleControl::GetDropTarget(IDropTarget **ppDropTarget) { // OVERRIDE: if you want to do drag and drop and you're windowless,
// override me.
return E_NOTIMPL; }
//=--------------------------------------------------------------------------=
// COleControl::TranslateAccelerator [IOleInPlaceActiveObject]
//=--------------------------------------------------------------------------=
// Processes menu accelerator-key messages from the container's message queue.
//
// Parameters:
// LPMSG - [in] the message that has the special key in it.
//
// Output:
// HRESULT - S_OK, S_FALSE, E_UNEXPECTED
STDMETHODIMP COleControl::TranslateAccelerator(LPMSG pmsg) { DBWIN("TranslateAccelerator");
// see if we want it or not.
if (OnSpecialKey(pmsg)) return S_OK;
// 30-Jul-1997 [ralphw] The docs don't talk about this, and I can't
// find anyone else who calls into controlsite.
// if not, then we want to forward it back to the site for further processing
if (m_pControlSite) return m_pControlSite->TranslateAccelerator(pmsg, _SpecialKeyState());
// we didn't want it.
return S_FALSE; }
//=--------------------------------------------------------------------------=
// COleControl::OnFrameWindowActivate [IOleInPlaceActiveObject]
//=--------------------------------------------------------------------------=
// Notifies the control when the container's top-level frame window is
// activated or deactivated.
//
// Parameters:
// BOOL - [in] state of containers top level window.
//
// Output:
// HRESULT - S_OK
STDMETHODIMP COleControl::OnFrameWindowActivate(BOOL fActivate) { // we're supposed to go UI active in this case
return InPlaceActivate(OLEIVERB_UIACTIVATE); }
//=--------------------------------------------------------------------------=
// COleControl::OnDocWindowActivate [IOleInPlaceActiveObject]
//=--------------------------------------------------------------------------=
// Notifies the active control when the container's document window is
// activated or deactivated.
//
// Parameters:
// BOOL - state of mdi child window.
STDMETHODIMP COleControl::OnDocWindowActivate(BOOL fActivate) { // we're supposed to go UI active in this case
return InPlaceActivate(OLEIVERB_UIACTIVATE); }
//=--------------------------------------------------------------------------=
// COleControl::ResizeBorder [IOleInPlaceActiveObject]
//=--------------------------------------------------------------------------=
// Alerts the control that it needs to resize its border space.
//
// Parameters:
// LPCRECT - [in] new outer rectangle for border space
// IOleInPlaceUIWindow * - [in] the document or frame who's border has changed
// BOOL - [in] true if it was the fram window taht called.
STDMETHODIMP COleControl::ResizeBorder(LPCRECT prcBorder, IOleInPlaceUIWindow *pInPlaceUIWindow, BOOL fFrame) { return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::EnableModeless [IOleInPlaceActiveObject]
//=--------------------------------------------------------------------------=
// Enables or disables modeless dialog boxes when the container creates or
// destroys a modal dialog box.
//
// Parameters:
// BOOL - [in] enable or disable modeless dialogs.
STDMETHODIMP COleControl::EnableModeless(BOOL fEnable) { return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::GetClassInfo [IProvideClassInfo]
//=--------------------------------------------------------------------------=
// returns the TypeInfo for the control's coclass.
//
// Parameters:
// ITypeInfo ** - [out]
//
STDMETHODIMP COleControl::GetClassInfo(ITypeInfo **ppTypeInfo) { ITypeLib *pTypeLib; HRESULT hr;
CHECK_POINTER(ppTypeInfo); *ppTypeInfo = NULL;
// go and get our type library.
// CONSIDER: - go to the same sorta scheme that we use for TypeInfo caching.
hr = LoadRegTypeLib(*g_pLibid, (USHORT)VERSIONOFOBJECT(m_ObjectType), 0, LANGIDFROMLCID(g_lcidLocale), &pTypeLib); if (FAILED(hr)) { // Load and register our type library.
if (g_fServerHasTypeLibrary) { char szTmp[MAX_PATH]; DWORD dwPathLen = GetModuleFileName(_Module.GetModuleInstance(), szTmp, MAX_PATH); MAKE_WIDEPTR_FROMANSI(pwsz, szTmp);
hr = LoadTypeLib(pwsz, &pTypeLib); RETURN_ON_FAILURE(hr); hr = RegisterTypeLib(pTypeLib, pwsz, NULL); if (FAILED(hr)) { pTypeLib->Release(); return hr; } } }
// got the typelib. get typeinfo for our coclass.
hr = pTypeLib->GetTypeInfoOfGuid((REFIID)CLSIDOFOBJECT(m_ObjectType), ppTypeInfo); pTypeLib->Release(); RETURN_ON_FAILURE(hr);
return S_OK; }
//=--------------------------------------------------------------------------=
// COleControl::ViewChange [callable]
//=--------------------------------------------------------------------------=
// called whenever the view of the object has changed.
void COleControl::ViewChanged(void) { // send the view change notification to anybody listening.
if (m_pViewAdviseSink) { m_pViewAdviseSink->OnViewChange(DVASPECT_CONTENT, -1);
// if they only asked to be advised once, kill the connection
if (m_fViewAdviseOnlyOnce) SetAdvise(DVASPECT_CONTENT, 0, NULL); } }
//=--------------------------------------------------------------------------=
// COleControl::SetInPlaceVisible [helper]
//=--------------------------------------------------------------------------=
// controls the visibility of the control window.
//
// Parameters:
// BOOL - TRUE shows FALSE hides.
void COleControl::SetInPlaceVisible(BOOL fShow) { BOOL fVisible;
m_fInPlaceVisible = fShow;
// don't do anything if we don't have a window. otherwise, set it
if (m_hwnd) { fVisible = ((GetWindowLong(m_hwnd, GWL_STYLE) & WS_VISIBLE) != 0);
if (fVisible && !fShow) ShowWindow(m_hwnd, SW_HIDE); else if (!fVisible && fShow) ShowWindow(m_hwnd, SW_SHOWNA); } }
|