//+--------------------------------------------------------------------- // // 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? }