windows-nt/Source/XPSP1/NT/multimedia/media/sndrec32/o2base/sctrl.cxx

1526 lines
44 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------
//
// File: sctrl.cxx
//
//------------------------------------------------------------------------
//[ srvr_overview
/*
Srvr Library Overview
The Srvr library is a set of C++ base classes intended to greatly simplify
the process of implementing an OLE Compound Document object DLL in C++.
This library requires the O2UTIL library and and understanding of elements
in that library is prerequisite to a complete understanding of these base
classes. Consult documentation for the O2UTIL library.
The library consists of three C++ base classes: SrvrCtrl, SrvrDV, and
SrvrInPlace. An OLE Compound Document object implemented using the Srvr
library is an aggregate of three subobjects -- the control, data/view
and in-place subobjects. The implementations of these subobjects are C++
classes that inherit from SrvrCtrl, SrvrDV, and SrvrInPlace respectively.
Behaviour specific to the C.D. object type is implemented
by overriding virtual methods on the base classes. The base classes are
designed so that a simple but functional server can be implemented by overriding
only a small number of virtual methods. Progressively more advanced servers
can be implemented by deriving more virtual methods and adding support for
new interfaces in the derived classes.
In the following discussion, the unqualified term "object" refers to an OLE
Compound Document (C.D.) object. The term "subobject" refers to a C++ object
whose class inherits from one of the Srvr base classes.
The data/view subobject encapsulates the persistent data of an object and the
rendering of that data. This subobject supports the IDataObject, IViewObject,
and the IPersist family of interfaces. These subobjects can also function
independently as a data transfer object for clipboard and drag-drop operations.
The control subobject manages the dynamic control of the object. This subobject
supports the IOleObject interface and directs all state transitions of the object.
The in-place subobject is responsible for the child window and user interface
of an object while it is in-place active. The subobject supports the
IOleInPlaceObject and IOleInPlaceActiveObject interfaces. This subobject is
not required for objects that don't support in-place editing.
The control subobject controls the aggregate and holds pointers to the data/view
and inplace subobjects. It maintains the reference count for the object as a
whole and delegates QueryInterfaces to the other subobjects for interfaces
that it does not handle. The data/view and in-place subobjects each hold a
pointer to the control subobject. They each forward their IUnknown methods
to the control. When a data/view subobject is being used independently as
a data-transfer object then its control pointer is NULL.
For more information consult the overview sections for each of the base
classes and the documentation for the base class methods.
*/
//]
//[ srvrctrl_overview
/*
SrvrCtrl Overview
The SrvrCtrl base class implements the control aspects common to most
OLE Compound Document objects. It records the state of the object and
directs the state transitions. It implements the IOleObject interface.
An object is in one of five possible states: passive, loaded, in-place,
U.I. active, or opened. An object is passive when it is holding no
resources. This is true for objects that are newly created or have
been released. An object becomes loaded when it gets
an IPersistXXX::Load or IPersistStorage::InitNew call and has loaded
or initialized the necessary part of its persistent state. An object in
the in-place state has a child window in its containers window and
can receive window messages. The object (nor any of its embeddings)
does not have its U.I. visible (e.g. shared menu or toolbars).
A U.I. active object does have its (or one of its embeddings) U.I. visible.
An open object is one that is being open-edited in a separate, top-level
window.
Part of implementing the control subobject of an OLE Compound Document object
is implementing verbs. There are a number of standard, OLE-defined verbs
and an object can add its own. Since the set of verbs is very object
dependent SrvrCtrl requires a derived class to supply tables indicating
the verbs that are supported. One is table of OLEVERB structures giving
standard information about the verb including the verb number and name.
A parallel table contains a pointer for each verb pointing to a function
that implements that verb. SrvrCtrl has a set of static methods that
implement the standard OLE verbs. The derived class can include these methods
in its verb table. SrvrCtrl implements all the IOleObject verb-related
methods using these two verb tables. The verb tables must be in order
of verb number and must be contiguous (i.e. no missing verb numbers).
*/
//]
#include "headers.hxx"
#pragma hdrstop
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::SrvrCtrl, protected
//
// Synopsis: Constructor for SrvrCtrl object
//
// Notes: To create a properly initialized object you must
// call the Init method immediately after construction.
//
//---------------------------------------------------------------
SrvrCtrl::SrvrCtrl(void)
{
DOUT(TEXT("SrvrCtrl: Constructing\r\n"));
_pDV = NULL;
_pInPlace = NULL;
_pPrivUnkDV = NULL;
_pPrivUnkIP = NULL;
// site-related information
_pClientSite = NULL;
_pOleAdviseHolder = NULL;
_pClass = NULL;
_dwRegROT = 0;
_lpstrCntrApp = NULL;
_lpstrCntrObj = NULL;
#if !defined(UNICODE) && !defined(OLE2ANSI)
_lpstrCntrAppA = NULL;
_lpstrCntrObjA = NULL;
#endif
_state = OS_PASSIVE;
EnableIPB(TRUE);
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::Init, protected
//
// Synopsis: Fully initializes a SrvrCtrl object
//
// Arguments: [pClass] -- The initialized class descriptor for the server
// [pUnkOuter] -- The controlling unknown if this server is being
// created as part of an aggregate; NULL otherwise
//
// Returns: NOERROR if successful
//
// Notes: The class descriptor pointer is saved in the protected _pClass
// member variable where it is accessible during the lifetime
// of the object.
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::Init(LPCLASSDESCRIPTOR pClass)
{
_pClass = pClass;
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::~SrvrCtrl, protected
//
// Synopsis: Destructor for the SrvrCtrl object
//
// Notes: The destructor is called as a result of the servers
// reference count going to 0. It ensure the object
// is in a passive state and releases the data/view and inplace
// subobjects objects.
//
//---------------------------------------------------------------
SrvrCtrl::~SrvrCtrl(void)
{
DOUT(TEXT("~~~~~SrvrCtrl::~OPCtrl\r\n"));
// note: we don't have to release _pDV and _pInPlace because
// we should have released them right away (standard aggregation policy)
// We must release the private unknowns of those two subobjects, though.
if (_pPrivUnkIP)
_pPrivUnkIP->Release();
if (_pPrivUnkDV)
_pPrivUnkDV->Release();
// free our advise holder
if(_pOleAdviseHolder != NULL)
_pOleAdviseHolder->Release();
// release our client site
TaskFreeString(_lpstrCntrApp);
TaskFreeString(_lpstrCntrObj);
#if !defined(UNICODE) && !defined(OLE2ANSI)
TaskFreeMem(_lpstrCntrAppA);
TaskFreeMem(_lpstrCntrObjA);
#endif
if (_pClientSite != NULL)
_pClientSite->Release();
DOUT(TEXT("SrvrCtrl: Destructed\r\n"));
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::TransitionTo, public
//
// Synopsis: Drives the transition of the object from one state to another
//
// Arguments: [state] -- the desired resulting state of the object
//
// Returns: Success iff the transition completed successfully. On failure
// the object will be in the original or some intermediate,
// but consistent, state.
//
// Notes: There are eight direct state transitions. These are:
// between the passive and loaded states, between the
// loaded and inplace states, between the inplace and U.I. active
// states, and between the loaded and opened states.
// Each of these direct transitions has an overridable method
// that effects it. The TransitionTo function implements
// transitions between any two arbitrary states by calling
// these direct transition methods in the proper order.
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::TransitionTo(OLE_SERVER_STATE state)
{
#if DBG
TCHAR achTemp[256];
wsprintf(achTemp,TEXT("[%d] --> [%d] SrvrCtrl::TransitionTo\n\r"),(int)_state,(int)state);
DOUT(achTemp);
#endif //DBG
Assert(state >= OS_PASSIVE && state <= OS_OPEN);
Assert(_state >= OS_PASSIVE && _state <= OS_OPEN);
//
// at each iteration we transition one state closer to
// our destination state...
//
HRESULT hr = NOERROR;
while (state != _state && OK(hr))
{
switch(_state)
{
case OS_PASSIVE:
// from passive we can only go to loaded!
if (OK(hr = PassiveToLoaded()))
_state = OS_LOADED;
break;
case OS_LOADED:
switch(state)
{
default:
if (OK(hr = LoadedToRunning()))
_state = OS_RUNNING;
break;
case OS_PASSIVE:
if (OK(hr = LoadedToPassive()))
_state = OS_PASSIVE;
break;
}
break;
case OS_RUNNING:
switch(state)
{
default:
case OS_LOADED:
if (OK(hr = RunningToLoaded()))
_state = OS_LOADED;
break;
case OS_INPLACE:
case OS_UIACTIVE:
if (OK(hr = RunningToInPlace()))
_state = OS_INPLACE;
break;
case OS_OPEN:
if (OK(hr = RunningToOpened()))
_state = OS_OPEN;
break;
}
break;
case OS_INPLACE:
switch(state)
{
default:
if (OK(hr = InPlaceToRunning()))
{
//
// The following handles re-entrancy cases in which
// processing of this state transition caused us to
// reach a state below our current target state...
if(_state < OS_RUNNING)
goto LExit;
_state = OS_RUNNING;
}
break;
case OS_UIACTIVE:
if (OK(hr = InPlaceToUIActive()))
_state = OS_UIACTIVE;
break;
}
break;
case OS_UIACTIVE:
// from UIActive we can only go to inplace
if (OK(hr = UIActiveToInPlace()))
{
//
// In the course of notifying the container that we
// are no longer UIActive, it is possible that we
// got InPlace deactivated (or worse, Closed).
// If this happened we abort our currently targeted
// transition...
if(_state < OS_INPLACE)
goto LExit;
_state = OS_INPLACE;
}
break;
case OS_OPEN:
// from Open we can only go to running
if (OK(hr = OpenedToRunning()))
_state = OS_RUNNING;
break;
}
}
LExit:
#if DBG
wsprintf(achTemp,TEXT("SrvrCtrl::TransitionTo [%d] hr = %lx\n\r"),(int)_state, hr);
DOUT(achTemp);
#endif //DBG
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::PassiveToLoaded, protected
//
// Synopsis: Effects the direct passive to loaded state transition
//
// Returns: Success iff the object is in the loaded state. On failure
// the object will be in a consistent passive state.
//
// Notes: The base class does not do any processing on this transition.
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::PassiveToLoaded(void)
{
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::LoadedToRunning, protected
//
// Synopsis: Effects the direct loaded to running state transition
//
// Returns: Success if the object is running.
//
// Notes: This transition occurs as a result of an
// IRunnableObject::Run call (TBD) and is implicit in any
// DoVerb call.
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::LoadedToRunning(void)
{
DOUT(TEXT("SrvrCtrl::LoadedToRunning\r\n"));
//
// enter ourself in the Running Object Table
//
LPMONIKER pmk;
if (OK(_pDV->GetMoniker(OLEGETMONIKER_ONLYIFTHERE, &pmk)))
{
RegisterAsRunning((LPUNKNOWN)this, pmk, &_dwRegROT);
pmk->Release();
}
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::LoadedToPassive, protected
//
// Synopsis: Effects the direct loaded to passive state transition
//
// Returns: Success if the object is loaded.
//
// Notes: This transition occurs as a result of an IOleObject::Close()
// call.
// This method sends an OnClose notification to all of our
// advises.
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::LoadedToPassive(void)
{
DOUT(TEXT("SrvrCtrl::LoadedToPassive\r\n"));
// notify our data advise holders of 'stop'
_pDV->OnDataChange(ADVF_DATAONSTOP);
// notify our advise holders that we have closed
if (_pOleAdviseHolder != NULL)
{
DOUT(TEXT("SrvrCtrl::LoadedToPassive calling _pOleAdviseHolder->SendOnClose()\r\n"));
_pOleAdviseHolder->SendOnClose();
}
// forcibly cut off remoting clients???
//CoDisconnectObject((LPUNKNOWN)this, 0);
//
// revoke our entry in the running object table
//
if (_dwRegROT != 0)
{
DOUT(TEXT(".-.-.SrvrCtrl::RunningToLoaded calling RevokeAsRunning\r\n"));
RevokeAsRunning(&_dwRegROT);
_dwRegROT = 0;
}
DOUT(TEXT("SrvrCtrl::LoadedToPassive (returning)\r\n"));
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::RunningToLoaded, protected
//
// Synopsis: Effects the direct running to loaded state transition
//
// Returns: Success if the object is loaded.
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::RunningToLoaded(void)
{
DOUT(TEXT("SrvrCtrl::RunningToLoaded\r\n"));
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::RunningToOpened, protected
//
// Synopsis: Effects the direct running to opened state transition
//
// Returns: Success if the object is open-edited.
//
// Notes: Open-editing is not yet supported. This returns E_FAIL.
//
// The derived class MUST completely override this
// transition to implement an open-ediing server!
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::RunningToOpened(void)
{
DOUT(TEXT("SrvrCtrl::RunningToOpened E_FAIL\r\n"));
return E_FAIL;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::OpenedToRunning, protected
//
// Synopsis: Effects the direct opened to running state transition
//
// Returns: Success if the open-editing session was shut down
//
// Notes: This occurs as the result of a DoVerb(HIDE...)
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::OpenedToRunning(void)
{
// notify our container so it can un-hatch
if (_pClientSite != NULL)
_pClientSite->OnShowWindow(FALSE);
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::RunningToInPlace, protected
//
// Synopsis: Effects the direct Running to inplace state transition
//
// Returns: Success iff the object is in the inplace state. On failure
// the object will be in a consistent Running state.
//
// Notes: This transition invokes the ActivateInPlace method on the
// inplace subobject of the server, if there is one. Containers
// will typically override this method in order to additionally
// inplace activate any inside-out embeddings that are visible.
// If the server does not support in-place
// activation then this method will return E_UNEXPECTED.
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::RunningToInPlace(void)
{
if (_pInPlace == NULL)
{
DOUT(TEXT("SrvrCtrl::RunningToInPlace E_FAIL\r\n"));
return E_FAIL;
}
return _pInPlace->ActivateInPlace(_pClientSite);
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::InPlaceToRunning, protected
//
// Synopsis: Effects the direct inplace to Running state transition
//
// Returns: Success under all but catastrophic circumstances.
//
// Notes: This transition invokes the DeactivateInPlace method on the
// inplace subobject of the server, if there is one. Containers
// will typically override this method in order to additionally
// inplace deactivate any inplace-active embeddings.
// If the server does not support in-place activation then
// this method will never be called.
// This method is called as the result of a DoVerb(HIDE...)
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::InPlaceToRunning(void)
{
Assert(_pInPlace != NULL);
return _pInPlace->DeactivateInPlace();
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::InPlaceToUIActive, protected
//
// Synopsis: Effects the direct inplace to U.I. active state transition
//
// Returns: Success iff the object is in the U.I. active state. On failure
// the object will be in a consistent inplace state.
//
// Notes: This transition invokes the ActivateUI methods on the inplace
// subobject of the server.
// If the server does not support in-place activation then
// this method will never be called.
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::InPlaceToUIActive(void)
{
Assert(_pInPlace != NULL);
return _pInPlace->ActivateUI();
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::UIActiveToInPlace, protected
//
// Synopsis: Effects the direct U.I. Active to inplace state transition
//
// Returns: Success under all but catastrophic circumstances.
//
// Notes: This transition invokes the DeactivateUI methods
// on the inplace subobject of the server. Containers
// will typically override this method in order to possibly
// U.I. deactivate a U.I. active embedding.
// If the server does not support in-place activation then
// this method will never be called.
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::UIActiveToInPlace(void)
{
Assert(_pInPlace != NULL);
return _pInPlace->DeactivateUI();
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::OnSave, public
//
// Synopsis: Raises the OnSave advise to any registered advises
//
// Notes: This method is called by the data/view subobject upon
// successful completion of a save operation.
//
//---------------------------------------------------------------
void
SrvrCtrl::OnSave(void)
{
if (_pOleAdviseHolder != NULL)
_pOleAdviseHolder->SendOnSave();
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::DoShow, public
//
// Synopsis: Implementation of the standard verb OLEIVERB_SHOW
//
// Arguments: [pv] -- pointer to a SrvrCntrl object.
// All other parameters are the same as the IOleObject::DoVerb
// method.
//
// Returns: Success if the verb was successfully executed
//
// Notes: This and the other static Do functions are provided for
// use in the server's verb table. This verb results in
// a ShowObject call on our container and a transition
// to the U.I. active state
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::DoShow(LPVOID pv,
LONG iVerb,
LPMSG lpmsg,
LPOLECLIENTSITE pActiveSite,
LONG lindex,
HWND hwndParent,
LPCRECT lprcPosRect)
{
LPSRVRCTRL pCtrl = (LPSRVRCTRL)pv;
HRESULT hr = NOERROR;
#if DBG
TCHAR achTemp[256];
wsprintf(achTemp,TEXT("SrvrCtrl::DoShow [%d]\n\r"),(int)pCtrl->State());
DOUT(achTemp);
#endif
if (pCtrl->_pClientSite != NULL)
{
pCtrl->_pClientSite->ShowObject();
if(pCtrl->State() == OS_OPEN)
{
HWND hwnd = NULL;
if(pCtrl->_pInPlace)
pCtrl->_pInPlace->GetWindow(&hwnd);
if(hwnd != NULL)
SetForegroundWindow(hwnd);
}
else
{
hr = pCtrl->TransitionTo(OS_UIACTIVE);
}
}
if (!OK(hr))
{
// the default action is OPEN...
hr = pCtrl->TransitionTo(OS_OPEN);
}
// if the verb was unknown then return Unknown Verb error.
if (OK(hr) && iVerb != OLEIVERB_PRIMARY && iVerb != OLEIVERB_SHOW)
{
DOUT(TEXT("SrvrCtrl::DoShow returning OLEOBJ_S_INVALIDVERB\r\n"));
hr = OLEOBJ_S_INVALIDVERB;
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::DoOpen, public
//
// Synopsis: Implementation of the standard verb OLEIVERB_OPEN.
// This verb results in a transition to the open state.
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::DoOpen(LPVOID pv,
LONG iVerb,
LPMSG lpmsg,
LPOLECLIENTSITE pActiveSite,
LONG lindex,
HWND hwndParent,
LPCRECT lprcPosRect)
{
DOUT(TEXT("SrvrCtrl::DoOpen\r\n"));
LPSRVRCTRL pCtrl = (LPSRVRCTRL)pv;
if(pCtrl->State() == OS_OPEN)
{
HWND hwnd = NULL;
if(pCtrl->_pInPlace)
pCtrl->_pInPlace->GetWindow(&hwnd);
if(hwnd != NULL)
SetForegroundWindow(hwnd);
}
return pCtrl->TransitionTo(OS_OPEN);
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::DoHide, public
//
// Synopsis: Implementation of the standard verb OLEIVERB_HIDE
// This verb results in a transition to the Running state.
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::DoHide(LPVOID pv,
LONG iVerb,
LPMSG lpmsg,
LPOLECLIENTSITE pActiveSite,
LONG lindex,
HWND hwndParent,
LPCRECT lprcPosRect)
{
DOUT(TEXT("SrvrCtrl::DoHide\r\n"));
LPSRVRCTRL pCtrl = (LPSRVRCTRL)pv;
if(pCtrl != NULL)
{
//jyg: ntbug 17327
// if(pCtrl->_state == OS_LOADED || pCtrl->_state == OS_PASSIVE)
// return pCtrl->TransitionTo(OS_PASSIVE);
// else
return pCtrl->TransitionTo(OS_RUNNING);
}
else
{
DOUT(TEXT("SrvrCtrl::DoHide E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::DoUIActivate, public
//
// Synopsis: Implementation of the standard verb OLEIVERB_UIACTIVATE
// This verb results in a transition to the U.I. active state.
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::DoUIActivate(LPVOID pv,
LONG iVerb,
LPMSG lpmsg,
LPOLECLIENTSITE pActiveSite,
LONG lindex,
HWND hwndParent,
LPCRECT lprcPosRect)
{
LPSRVRCTRL pCtrl = (LPSRVRCTRL)pv;
HRESULT hr = pCtrl->TransitionTo(OS_UIACTIVE);
if(OK(hr) && (lpmsg != NULL))
{
PostMessage(pCtrl->_pInPlace->WindowHandle(),
lpmsg->message,
lpmsg->wParam,
lpmsg->lParam);
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::DoInPlaceActivate, public
//
// Synopsis: Implementation of the standard verb OLEIVERB_INPLACEACTIVATE
// This verb results in a transition to the inplace state.
//
//---------------------------------------------------------------
HRESULT
SrvrCtrl::DoInPlaceActivate(LPVOID pv,
LONG iVerb,
LPMSG lpmsg,
LPOLECLIENTSITE pActiveSite,
LONG lindex,
HWND hwndParent,
LPCRECT lprcPosRect)
{
LPSRVRCTRL pCtrl = (LPSRVRCTRL)pv;
HRESULT hr = pCtrl->TransitionTo(OS_INPLACE);
if(OK(hr) && (lpmsg != NULL))
{
PostMessage(pCtrl->_pInPlace->WindowHandle(),
lpmsg->message,
lpmsg->wParam,
lpmsg->lParam);
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::SetClientSite, public
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method saves the client site pointer in the
// _pClientSite member variable.
//
// We never fail!
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::SetClientSite(LPOLECLIENTSITE pClientSite)
{
//
// if we already have a client site then release it
//
if (_pClientSite != NULL)
_pClientSite->Release();
//
// if there is a new client site then hold on to it
//
_pClientSite = pClientSite;
if (_pClientSite != NULL)
_pClientSite->AddRef();
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::GetClientSite
//
// Synopsis: Method of IOleObject interface
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::GetClientSite(LPOLECLIENTSITE FAR* ppClientSite)
{
if (ppClientSite == NULL)
{
DOUT(TEXT("SrvrCtrl::GetClientSite E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*ppClientSite = NULL; // set out params to NULL
//
// if we have a client site then return it, but addref it first.
//
if (_pClientSite != NULL)
(*ppClientSite = _pClientSite)->AddRef();
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::SetHostNames
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method saves copies of the container-related strings
// in the _lpstrCntrApp and _lpstrCntrObj member variables.
//
// We never fail!
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::SetHostNames(LPCOLESTR lpstrCntrApp, LPCOLESTR lpstrCntrObj)
{
// free any strings we are holding on to
if (_lpstrCntrApp != NULL)
{
TaskFreeString(_lpstrCntrApp);
_lpstrCntrApp = NULL;
#if !defined(UNICODE) && !defined(OLE2ANSI)
TaskFreeMem(_lpstrCntrAppA);
_lpstrCntrAppA = NULL;
#endif
}
if (_lpstrCntrObj != NULL)
{
TaskFreeString(_lpstrCntrObj);
_lpstrCntrObj = NULL;
#if !defined(UNICODE) && !defined(OLE2ANSI)
TaskFreeMem(_lpstrCntrObjA);
_lpstrCntrObjA = NULL;
#endif
}
// make copies of the new strings and hold on
TaskAllocString(lpstrCntrApp, &_lpstrCntrApp);
TaskAllocString(lpstrCntrObj, &_lpstrCntrObj);
#if !defined(UNICODE) && !defined(OLE2ANSI)
_lpstrCntrAppA = ConvertOLESTRToMB(_lpstrCntrApp, -1);
_lpstrCntrObjA = ConvertOLESTRToMB(_lpstrCntrObj, -1);
#endif
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::Close
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method ensures the object is in the loaded
// (not passive!) state.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::Close(DWORD dwSaveOption)
{
HRESULT hr = NOERROR;
// if our object is dirty then we should save it, depending on the
// save options
if (_pClientSite != NULL && NOERROR == _pDV->IsDirty())
{
BOOL fSave;
switch(dwSaveOption)
{
case OLECLOSE_SAVEIFDIRTY:
fSave = TRUE;
break;
case OLECLOSE_NOSAVE:
fSave = FALSE;
break;
case OLECLOSE_PROMPTSAVE:
{
// put up a message box asking the user if they want to update
// the container
LPOLESTR lpstrObj =
_pDV->GetMonikerDisplayName(OLEGETMONIKER_ONLYIFTHERE);
if (lpstrObj == NULL)
{
lpstrObj = _pClass->_szUserClassType[USERCLASSTYPE_FULL];
}
int i = IDYES;
#if 0
#pragma message("Localizable string here!")
int i = MessageBox(NULL,
TEXT("Object has changed. Update?"),
lpstrObj,
MB_YESNOCANCEL | MB_ICONQUESTION);
#endif
if (IDCANCEL == i)
{
return OLE_E_PROMPTSAVECANCELLED;
}
fSave = (IDYES == i);
}
break;
default:
DOUT(TEXT("SrvrCtrl::Close E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
if (fSave)
hr = _pClientSite->SaveObject();
}
// Ensure that we do not loose any SaveObject() failure.
if (SUCCEEDED (hr))
hr = TransitionTo(OS_PASSIVE);
else
(void) TransitionTo(OS_PASSIVE);
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::SetMoniker
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method notifies our data/view subobject of our new
// moniker. It also registers us in the running object
// table and sends an OnRename notification to all registered
// advises.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::SetMoniker(DWORD dwWhichMoniker, LPMONIKER pmk)
{
// our moniker has changed so revoke our entry in the running object table
if (_dwRegROT != 0)
{
RevokeAsRunning(&_dwRegROT);
}
//
// insure that we have a full moniker to register in the ROT
// if we have a full moniker, then go with it
// otherwise ask our client site for a full moniker
//
HRESULT hr = NOERROR;
LPMONIKER pmkFull = NULL;
if (dwWhichMoniker == OLEWHICHMK_OBJFULL)
{
if((pmkFull = pmk) != NULL)
pmkFull->AddRef();
}
else
{
if (_pClientSite == NULL)
{
DOUT(TEXT("SrvrCtrl::SetMoniker E_FAIL\r\n"));
hr = E_FAIL;
}
else
{
hr = _pClientSite->GetMoniker(OLEGETMONIKER_ONLYIFTHERE,
OLEWHICHMK_OBJFULL,
&pmkFull);
}
}
if (OK(hr))
{
// stow the moniker away in our data object
_pDV->SetMoniker(pmkFull);
if(pmkFull != NULL)
{
// register ourself in the running object table
// NOTE: if we had native data items that weren't embeddings
// but could be pseudo-objects then we would also register a
// wildcard moniker
//
RegisterAsRunning((LPUNKNOWN)this, pmkFull, &_dwRegROT);
// notify our advise holders that we have been renamed!
if (_pOleAdviseHolder != NULL)
{
_pOleAdviseHolder->SendOnRename(pmkFull);
}
pmkFull->Release();
}
else
{
RevokeAsRunning(&_dwRegROT);
}
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::GetMoniker
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method forwards the request to our client site
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk)
{
if (ppmk == NULL)
{
DOUT(TEXT("SrvrCtrl::GetMoniker E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*ppmk = NULL; // set out parameters to NULL
// get the requested moniker from our client site
HRESULT hr;
if (_pClientSite == NULL)
{
DOUT(TEXT("SrvrCtrl::GetMoniker MK_E_UNAVAILABLE\r\n"));
hr = MK_E_UNAVAILABLE;
}
else
hr = _pClientSite->GetMoniker(dwAssign, dwWhichMoniker, ppmk);
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::InitFromData
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method returns S_FALSE indicating InitFromData
// is not supported. Servers that wish to support initialization
// from a selection should override this function.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::InitFromData(LPDATAOBJECT pDataObject,
BOOL fCreation,
DWORD dwReserved)
{
return S_FALSE;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::GetClipboardData
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method uses the GetClipboardCopy method on our
// data/view subobject to obtain a data transfer object
// representing a snapshot of our compound document object.
//
// This is considered an exotic, and OPTIONAL method to
// implement. It was intended for programatic access
// (bypassing the clipboard), and will probably never
// be used...
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::GetClipboardData(DWORD dwReserved, LPDATAOBJECT FAR* ppDataObject)
{
if (ppDataObject == NULL)
{
DOUT(TEXT("SrvrCtrl::GetClipboardData E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*ppDataObject = NULL; // set out params to NULL
// create a new data object initialized from our own data object
LPSRVRDV pDV = NULL;
HRESULT hr;
if (OK(hr = _pDV->GetClipboardCopy(&pDV)))
{
*ppDataObject = (LPDATAOBJECT)pDV;
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::DoVerb
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method locates the requested verb in the servers
// verb table and calls the associated verb function.
// If the verb is not found then the first (at index 0) verb in
// the verb table is called. This should be the primary verb
// with verb number 0.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::DoVerb(LONG iVerb,
LPMSG lpmsg,
LPOLECLIENTSITE pActiveSite,
LONG lindex,
HWND hwndParent,
LPCRECT lprcPosRect)
{
//
// All DoVerbs make an implicit transition to the running state if
// the object is not already running...
//
HRESULT hr = NOERROR;
if (_state < OS_RUNNING)
hr = TransitionTo(OS_RUNNING);
if (OK(hr))
{
//
// find the verb in the verb table. if it is not there then default
// to the 0th entry in the table (should be primary verb)
//
for (int i = 0; i < _pClass->_cVerbTable; i++)
{
if (iVerb == _pClass->_pVerbTable[i].lVerb)
{
break;
}
}
if (i >= _pClass->_cVerbTable)
{
i = 0;
}
// dispatch the verb
hr = (*_pVerbFuncs[i])(this,
iVerb,
lpmsg,
pActiveSite,
lindex,
hwndParent,
lprcPosRect);
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::EnumVerbs
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method produces an enumerator over the server's
// verb table.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::EnumVerbs(LPENUMOLEVERB FAR* ppenum)
{
if (ppenum == NULL)
{
DOUT(TEXT("SrvrCtrl::EnumVerbs E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*ppenum = NULL;
//return OLE_S_USEREG;
return CreateOLEVERBEnum(_pClass->_pVerbTable, _pClass->_cVerbTable, ppenum);
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::Update
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method returns NOERROR indicating that the update was
// successful. Containers will wish to override this function
// in order to recursively pass the function on to all embeddings.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::Update(void)
{
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::IsUpToDate
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method returns NOERROR indicating that the object is
// up to date. Containers will wish to override this function
// in order to recursively pass the function on to all embeddings.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::IsUpToDate(void)
{
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::GetUserClassID
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method supplies the class id from the server's
// CLASSDESCRIPTOR structure
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::GetUserClassID(CLSID FAR* pClsid)
{
if (pClsid == NULL)
{
DOUT(TEXT("SrvrCtrl::GetUserClassID E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*pClsid = _pClass->_clsid;
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::GetUserType
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method supplies the user type string from the server's
// CLASSDESCRIPTOR structure
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::GetUserType(DWORD dwFormOfType, LPOLESTR FAR* plpstr)
{
if (plpstr == NULL || dwFormOfType < 1 || dwFormOfType > 3)
{
DOUT(TEXT("SrvrCtrl::GetUserType E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
return TaskAllocString(_pClass->_szUserClassType[dwFormOfType], plpstr);
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::SetExtent
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method is forwarded to the SetExtent method on
// the data/view subobject.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::SetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
{
if (lpsizel == NULL)
{
DOUT(TEXT("SrvrCtrl::SetExtent E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
return _pDV->SetExtent(dwDrawAspect, *lpsizel);
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::GetExtent
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method is forwarded to the SetExtent method on
// the data/view subobject.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::GetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)
{
if (lpsizel == NULL)
{
DOUT(TEXT("SrvrCtrl::GetExtent E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
return _pDV->GetExtent(dwDrawAspect, lpsizel);
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::Advise
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method is implemented using the standard
// OLE advise holder.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::Advise(IAdviseSink FAR* pAdvSink, DWORD FAR* pdwConnection)
{
if (pdwConnection == NULL)
{
DOUT(TEXT("SrvrCtrl::Advise E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*pdwConnection = NULL; // set out params to NULL
HRESULT hr = NOERROR;
if (_pOleAdviseHolder == NULL)
hr = CreateOleAdviseHolder(&_pOleAdviseHolder);
if (OK(hr))
hr = _pOleAdviseHolder->Advise(pAdvSink, pdwConnection);
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::Unadvise
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method is implemented using the standard
// OLE advise holder.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::Unadvise(DWORD dwConnection)
{
if (_pOleAdviseHolder == NULL)
return NOERROR;
return _pOleAdviseHolder->Unadvise(dwConnection);
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::EnumAdvise
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method is implemented using the standard
// OLE advise holder.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::EnumAdvise(LPENUMSTATDATA FAR* ppenumAdvise)
{
if (ppenumAdvise == NULL)
{
DOUT(TEXT("SrvrCtrl::EnumAdvise E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
HRESULT hr;
if (_pOleAdviseHolder == NULL)
{
*ppenumAdvise = NULL;
hr = NOERROR;
}
else
{
hr = _pOleAdviseHolder->EnumAdvise(ppenumAdvise);
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::GetMiscStatus
//
// Synopsis: Method of IOleObject interface
//
// Notes: This method supplies the misc status flags from the server's
// CLASSDESCRIPTOR structure
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::GetMiscStatus(DWORD dwAspect, DWORD FAR* pdwStatus)
{
if (pdwStatus == NULL)
{
DOUT(TEXT("SrvrCtrl::GetMiscStatus E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*pdwStatus = _pClass->_dwMiscStatus;
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrCtrl::SetColorScheme
//
// Synopsis: Method of IOleObject interface
//
// Notes: Servers should override this method if they are
// interested in the palette.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrCtrl::SetColorScheme(LPLOGPALETTE lpLogpal)
{
DOUT(TEXT("SrvrCtrl::SetColorScheme E_NOTIMPL\r\n"));
return E_NOTIMPL; //will we ever?
}