// Copyright 1995-1997 Microsoft Corporation. All Rights Reserved. #if _MSC_VER > 1000 #pragma once #endif #ifndef _CTRLOBJ_H_ #define _CTRLOBJ_H_ // we need the automation object and ctlole.h #include "AutoObj.H" #include // forward declaration class COleControl; //=--------------------------------------------------------------------------= // Misc Helper Functions //=--------------------------------------------------------------------------= // // given an Unknown pointer, get the COleControl * for it. used typically // in property page code. COleControl *ControlFromUnknown(IUnknown *); //=--------------------------------------------------------------------------= // Misc Constants //=--------------------------------------------------------------------------= // maximum number of arguments that can be sent to FireEvent() #define MAX_ARGS 32 // for the types of sinks that the COleControl class has. you shouldn't ever // need to use these #define SINK_TYPE_EVENT 0 #define SINK_TYPE_PROPNOTIFY 1 // superclass window support. you can pass this in to DoSuperClassPaint #define DRAW_SENDERASEBACKGROUND 1 //=--------------------------------------------------------------------------= // Various Hosts don't handle OLEIVERB_PROPERTIES correctly, so we can't use // that as our Properties verb number. Instead, we're going to define // CTLIVERB_PROPERTIES as 1, and return that one in IOleObject::EnumVerbs, // but we'll still handle OLEIVERB_PROPERTIES correctly in DoVerb. #define CTLIVERB_PROPERTIES 1 //=--------------------------------------------------------------------------= // this structure is like the OLEVERB structure, except that it has a resource ID // instead of a string for the verb's name. better support for localization. typedef struct tagVERBINFO { LONG lVerb; // verb id ULONG idVerbName; // resource ID of verb name DWORD fuFlags; // verb flags DWORD grfAttribs; // Specifies some combination of the verb attributes in the OLEVERBATTRIB enumeration. } VERBINFO; // describes an event typedef struct tagEVENTINFO { DISPID dispid; // dispid of the event int cParameters; // number of arguments to the event VARTYPE *rgTypes; // type of each argument } EVENTINFO; //=--------------------------------------------------------------------------= // CONTROLOBJECTINFO //=--------------------------------------------------------------------------= // for each control you wish to expose to the programmer/user, you need to // declare and define one of the following structures. the first part should // follow the rules of the AUTOMATIONOBJECTINFO structure. it's pretty hard, // however, to imagine a scenario where the control isn't CoCreatable ... // once this structre is declared/defined, an entry should be put in the // global g_ObjectInfo table. // typedef struct { AUTOMATIONOBJECTINFO AutomationInfo; // automation and creation information const IID *piidEvents; // IID of primary event interface DWORD dwOleMiscFlags; // control flags DWORD dwActivationPolicy; // IPointerInactive support VARIANT_BOOL fOpaque; // is your control 100% opaque? VARIANT_BOOL fWindowless; // do we do windowless if we can? WORD wToolboxId; // resource ID of Toolbox Bitmap LPCSTR szWndClass; // name of window control class VARIANT_BOOL fWindowClassRegistered; // has the window class been registered yet? WORD cPropPages; // number of property pages const GUID **rgPropPageGuids; // array of the property page GUIDs WORD cCustomVerbs; // number of custom verbs const VERBINFO *rgCustomVerbs; // description of custom verbs WNDPROC pfnSubClass; // for subclassed controls. } CONTROLOBJECTINFO; #ifndef INITOBJECTS #define DEFINE_CONTROLOBJECT(name, clsid, progid, fn, ver, riid, pszh, piide, dwcf, dwap, w, szwc, cpp, rgppg, ccv, rgcv) \ extern CONTROLOBJECTINFO name##Control \ #define DEFINE_WINDOWLESSCONTROLOBJECT(name, clsid, progid, fn, ver, riid, pszh, piide, dwcf, dwap, fo, w, szwc, cpp, rgppg, ccv, rgcv) \ extern CONTROLOBJECTINFO name##Control \ #else #define DEFINE_CONTROLOBJECT(name, clsid, progid, fn, ver, riid, pszh, piide, dwcf, dwap, w, szwc, cpp, rgppg, ccv, rgcv) \ CONTROLOBJECTINFO name##Control = { { {clsid, progid, fn}, ver, riid, pszh, NULL, 0}, piide, dwcf, dwap, TRUE, FALSE, w, szwc, FALSE, cpp, rgppg, ccv, rgcv, NULL } \ #define DEFINE_WINDOWLESSCONTROLOBJECT(name, clsid, progid, fn, ver, riid, pszh, piide, dwcf, dwap, fo, w, szwc, cpp, rgppg, ccv, rgcv) \ CONTROLOBJECTINFO name##Control = { { {clsid, progid, fn}, ver, riid, pszh, NULL, 0}, piide, dwcf, dwap, fo, TRUE, w, szwc, FALSE, cpp, rgppg, ccv, rgcv, NULL } \ #endif // !INITOBJECTS #define OLEMISCFLAGSOFCONTROL(index) ((CONTROLOBJECTINFO *)(g_ObjectInfo[index].pInfo))->dwOleMiscFlags #define FCONTROLISWINDOWLESS(index) ((CONTROLOBJECTINFO *)(g_ObjectInfo[index].pInfo))->fWindowless #define FCONTROLISOPAQUE(index) ((CONTROLOBJECTINFO *)(g_ObjectInfo[index].pInfo))->fOpaque #define ACTIVATIONPOLICYOFCONTROL(index) ((CONTROLOBJECTINFO *)(g_ObjectInfo[index].pInfo))->dwActivationPolicy #define EVENTIIDOFCONTROL(index) (*(((CONTROLOBJECTINFO *)(g_ObjectInfo[index].pInfo))->piidEvents)) #define WNDCLASSNAMEOFCONTROL(index) ((CONTROLOBJECTINFO *)(g_ObjectInfo[index].pInfo))->szWndClass #define CPROPPAGESOFCONTROL(index) ((CONTROLOBJECTINFO *)(g_ObjectInfo[index].pInfo))->cPropPages #define PPROPPAGESOFCONTROL(index) ((CONTROLOBJECTINFO *)(g_ObjectInfo[index].pInfo))->rgPropPageGuids #define CCUSTOMVERBSOFCONTROL(index) ((CONTROLOBJECTINFO *)(g_ObjectInfo[index].pInfo))->cCustomVerbs #define CUSTOMVERBSOFCONTROL(index) ((CONTROLOBJECTINFO *)(g_ObjectInfo[index].pInfo))->rgCustomVerbs #define BITMAPIDOFCONTROL(index) ((CONTROLOBJECTINFO *)(g_ObjectInfo[index].pInfo))->wToolboxId #define CTLWNDCLASSREGISTERED(index) ((CONTROLOBJECTINFO *)(g_ObjectInfo[index].pInfo))->fWindowClassRegistered #define SUBCLASSWNDPROCOFCONTROL(index) ((CONTROLOBJECTINFO *)(g_ObjectInfo[index].pInfo))->pfnSubClass // These need to match what is in COleControl::InternalQueryInterface class COleControl : public CAutomationObject, public IOleObject, public IOleControl, public IOleInPlaceObjectWindowless, public IOleInPlaceActiveObject, public IViewObjectEx, public IPersistPropertyBag, public IPersistStreamInit, public IPersistStorage, public IConnectionPointContainer, public IProvideClassInfo, public IPointerInactive, public IQuickActivate { public: // IUnknown methods -- there are required since we inherit from variuos // people who themselves inherit from IUnknown. just delegate to controlling // unknown DECLARE_STANDARD_UNKNOWN(); //=--------------------------------------------------------------------------= // IPersist methods. used by IPersistStream and IPersistStorage STDMETHOD(GetClassID)(THIS_ LPCLSID lpClassID); // IPersistStreamInit methods STDMETHOD(IsDirty)(THIS); STDMETHOD(Load)(LPSTREAM pStm); STDMETHOD(Save)(LPSTREAM pStm, BOOL fClearDirty); STDMETHOD(GetSizeMax)(ULARGE_INTEGER FAR* pcbSize); STDMETHOD(InitNew)(); // IPersistStorage STDMETHOD(InitNew)(IStorage *pStg); STDMETHOD(Load)(IStorage *pStg); STDMETHOD(Save)(IStorage *pStgSave, BOOL fSameAsLoad); STDMETHOD(SaveCompleted)(IStorage *pStgNew); STDMETHOD(HandsOffStorage)(void); // IPersistPropertyBag STDMETHOD(Load)(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog); STDMETHOD(Save)(LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties); // IOleControl methods STDMETHOD(GetControlInfo)(LPCONTROLINFO pCI); STDMETHOD(OnMnemonic)(LPMSG pMsg); STDMETHOD(OnAmbientPropertyChange)(DISPID dispid); STDMETHOD(FreezeEvents)(BOOL bFreeze); // IOleObject methods STDMETHOD(SetClientSite)(IOleClientSite *pClientSite); STDMETHOD(GetClientSite)(IOleClientSite * *ppClientSite); STDMETHOD(SetHostNames)(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj); STDMETHOD(Close)(DWORD dwSaveOption); STDMETHOD(SetMoniker)(DWORD dwWhichMoniker, IMoniker *pmk); STDMETHOD(GetMoniker)(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker * *ppmk); STDMETHOD(InitFromData)(IDataObject *pDataObject, BOOL fCreation, DWORD dwReserved); STDMETHOD(GetClipboardData)(DWORD dwReserved, IDataObject * *ppDataObject); STDMETHOD(DoVerb)(LONG iVerb, LPMSG lpmsg, IOleClientSite *pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect); STDMETHOD(EnumVerbs)(IEnumOLEVERB * *ppEnumOleVerb); STDMETHOD(Update)(void); STDMETHOD(IsUpToDate)(void); STDMETHOD(GetUserClassID)(CLSID *pClsid); STDMETHOD(GetUserType)(DWORD dwFormOfType, LPOLESTR *pszUserType); STDMETHOD(SetExtent)(DWORD dwDrawAspect,SIZEL *psizel); STDMETHOD(GetExtent)(DWORD dwDrawAspect, SIZEL *psizel); STDMETHOD(Advise)(IAdviseSink *pAdvSink, DWORD *pdwConnection); STDMETHOD(Unadvise)(DWORD dwConnection); STDMETHOD(EnumAdvise)(IEnumSTATDATA * *ppenumAdvise); STDMETHOD(GetMiscStatus)(DWORD dwAspect, DWORD *pdwStatus); STDMETHOD(SetColorScheme)(LOGPALETTE *pLogpal); // IOleWindow. required for IOleInPlaceObject and IOleInPlaceActiveObject STDMETHOD(GetWindow)(HWND *phwnd); STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode); // IOleInPlaceObject/IOleInPlaceObjectWindowless STDMETHOD(InPlaceDeactivate)(void); STDMETHOD(UIDeactivate)(void); // STDMETHOD(SetObjectRects)(LPCRECT lprcPosRect,LPCRECT lprcClipRect) ; STDMETHOD(ReactivateAndUndo)(void); STDMETHOD(OnWindowMessage)(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *plResult); STDMETHOD(GetDropTarget)(IDropTarget **ppDropTarget); // IOleInPlaceActiveObject STDMETHOD(TranslateAccelerator)(LPMSG lpmsg); STDMETHOD(OnFrameWindowActivate)(BOOL fActivate); STDMETHOD(OnDocWindowActivate)(BOOL fActivate); STDMETHOD(ResizeBorder)(LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fFrameWindow); STDMETHOD(EnableModeless)(BOOL fEnable); // IViewObject2/IViewObjectEx STDMETHOD(Draw)(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds, BOOL ( __stdcall *pfnContinue )(ULONG_PTR dwContinue), ULONG_PTR dwContinue); STDMETHOD(GetColorSet)(DWORD dwDrawAspect,LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDev, LOGPALETTE * *ppColorSet); STDMETHOD(Freeze)(DWORD dwDrawAspect, LONG lindex, void *pvAspect,DWORD *pdwFreeze); STDMETHOD(Unfreeze)(DWORD dwFreeze); STDMETHOD(SetAdvise)(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink); STDMETHOD(GetAdvise)(DWORD *pAspects, DWORD *pAdvf, IAdviseSink * *ppAdvSink); STDMETHOD(GetExtent)(DWORD dwDrawAspect, LONG lindex, DVTARGETDEVICE __RPC_FAR *ptd, LPSIZEL lpsizel); STDMETHOD(GetRect)(DWORD dwAspect, LPRECTL pRect); STDMETHOD(GetViewStatus)(DWORD *pdwStatus); STDMETHOD(QueryHitPoint)(DWORD dwAspect, LPCRECT pRectBounds, POINT ptlLoc, LONG lCloseHint, DWORD *pHitResult); STDMETHOD(QueryHitRect)(DWORD dwAspect, LPCRECT pRectBounds, LPCRECT prcLoc, LONG lCloseHint, DWORD *pHitResult); STDMETHOD(GetNaturalExtent)(DWORD dwAspect, LONG lindex, DVTARGETDEVICE *ptd, HDC hicTargetDev, DVEXTENTINFO *pExtentInfo, LPSIZEL psizel); // IConnectionPointContainer methods STDMETHOD(EnumConnectionPoints)(LPENUMCONNECTIONPOINTS FAR* ppEnum); STDMETHOD(FindConnectionPoint)(REFIID iid, LPCONNECTIONPOINT FAR* ppCP); // ISpecifyPropertyPages // STDMETHOD(GetPages)(CAUUID * pPages); // IProvideClassInfo methods STDMETHOD(GetClassInfo)(LPTYPEINFO * ppTI); // IPointerInactive methods STDMETHOD(GetActivationPolicy)(DWORD *pdwPolicy); STDMETHOD(OnInactiveMouseMove)(LPCRECT pRectBounds, long x, long y, DWORD dwMouseMsg); STDMETHOD(OnInactiveSetCursor)(LPCRECT pRectBounds, long x, long y, DWORD dwMouseMsg, BOOL fSetAlways); // IQuickActivate methods STDMETHOD(QuickActivate)(QACONTAINER *pqacontainer, QACONTROL *pqacontrol); STDMETHOD(SetContentExtent)(LPSIZEL); STDMETHOD(GetContentExtent)(LPSIZEL); // constructor and destructor COleControl(IUnknown *pUnkOuter, int iPrimaryDispatch, void *pMainInterface); virtual ~COleControl(); //=--------------------------------------------------------------------------= // callable by anybody static LRESULT CALLBACK ControlWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); // static LRESULT CALLBACK ReflectWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); static COleControl * ControlFromHwnd(HWND hwnd) { return (COleControl *) GetWindowLongPtr(hwnd, GWLP_USERDATA); } void __cdecl FireEvent(EVENTINFO * pEventInfo, ...); /* * ole controls that want to support both windowed and windowless * operations should use these wrappers instead of the appropriate win32 * api routine. controls that don't care and just want to be windowed * all the time can just go ahead and use the api routines. */ BOOL SetFocus(BOOL fGrab); // SetFocus API BOOL OcxGetFocus(void); // GetFocus() == m_hwnd BOOL OcxGetWindowRect(LPRECT); // gets your current window rect LRESULT OcxDefWindowProc(UINT, WPARAM, LPARAM); // DefWindowProc HDC OcxGetDC(void); // GetDC(m_hwnd); void OcxReleaseDC(HDC hdc); // ReleaseDC(m_hwnd, hdc); BOOL OcxSetCapture(BOOL fGrab); // SetCapture(fGrab ? m_hwnd : NULL); BOOL OcxGetCapture(void); // GetCapture() == m_hwnd BOOL OcxInvalidateRect(LPCRECT, BOOL); // InvalidateRect(m_hwnd, prc, f); BOOL OcxScrollRect(LPCRECT, LPCRECT, int, int); // ScrollWindowEx(...); protected: //=--------------------------------------------------------------------------= // member variables that derived controls can get at. // // derived controls Should NOT modify the following. IOleClientSite *m_pClientSite; // client site IOleControlSite *m_pControlSite; // IOleControlSite ptr on client site IOleInPlaceSite *m_pInPlaceSite; // IOleInPlaceSite for managing activation IOleInPlaceFrame *m_pInPlaceFrame; // IOleInPlaceFrame ptr on client site IOleInPlaceUIWindow *m_pInPlaceUIWindow; // for negotiating border space with client ISimpleFrameSite *m_pSimpleFrameSite; // simple frame site IDispatch *m_pDispAmbient; // ambient dispatch pointer SIZEL m_Size; // the size of this control RECT m_rcLocation; // where we at public: HWND m_hwnd; // our window HWND m_hwndParent; // our parent window protected: // Windowless OLE controls support IOleInPlaceSiteWindowless *m_pInPlaceSiteWndless; // IOleInPlaceSiteWindowless pointer // flags indicating internal state. do not modify. unsigned m_fDirty:1; // does the control need to be resaved? unsigned m_fInPlaceActive:1; // are we in place active or not? unsigned m_fInPlaceVisible:1; // we are in place visible or not? unsigned m_fUIActive:1; // are we UI active or not. unsigned m_fCreatingWindow:1; // indicates if we're in CreateWindowEx or not //=--------------------------------------------------------------------------= // methods that derived controls can override, but may need to be called // from their versions. virtual void ViewChanged(void); virtual HRESULT InternalQueryInterface(REFIID riid, void **ppvObjOut); //=--------------------------------------------------------------------------= // member functions that provide for derived controls, or that we use, but // derived controls might still find useful. HRESULT DoSuperClassPaint(HDC, LPCRECTL); // HRESULT RecreateControlWindow(void); BOOL DesignMode(void); BOOL GetAmbientProperty(DISPID, VARTYPE, void *); BOOL GetAmbientFont(IFont **ppFontOut); public: void ModalDialog(BOOL fShow) { // notify the container of our intention to show a modal dialog... if (m_pInPlaceFrame) m_pInPlaceFrame->EnableModeless(!fShow); } HRESULT InPlaceActivate(LONG lVerb); void InvalidateControl(LPCRECT prc); protected: BOOL SetControlSize(SIZEL *pSizel); HWND CreateInPlaceWindow(int x, int y, BOOL fNoRedraw); void SetInPlaceVisible(BOOL); void SetInPlaceParent(HWND); // IPropertyNotifySink stuff. inline void PropertyChanged(DISPID dispid) { m_cpPropNotify.DoOnChanged(dispid); } inline BOOL RequestPropertyEdit(DISPID dispid) { return m_cpPropNotify.DoOnRequestEdit(dispid); } // subclassed windows controls support ... // little routine for people to tell if they are windowless or not // inline BOOL Windowless(void) { return !m_fInPlaceActive || m_pInPlaceSiteWndless; } // some people don't care if they're windowed or not -- they just need // a site pointer. this makes it a little easier. // inline IOleInPlaceSite *GetInPlaceSite(void) { return (IOleInPlaceSite *)(m_pInPlaceSiteWndless ? m_pInPlaceSiteWndless : m_pInPlaceSite); } protected: //=--------------------------------------------------------------------------= // the following are methods that ALL control writers must override and implement STDMETHOD(LoadBinaryState)(IStream *pStream) PURE; // STDMETHOD(SaveBinaryState)(IStream *pStream) PURE; STDMETHOD(LoadTextState)(IPropertyBag *pPropertyBag, IErrorLog *pErrorLog) PURE; STDMETHOD(SaveTextState)(IPropertyBag *pPropertyBag, BOOL fWriteDefault) PURE; STDMETHOD(OnDraw)(DWORD dvAspect, HDC hdcDraw, LPCRECTL prcBounds, LPCRECTL prcWBounds, HDC hicTargetDev, BOOL fOptimize) PURE; virtual LRESULT WindowProc(UINT msg, WPARAM wParam, LPARAM lParam) PURE; virtual BOOL RegisterClassData(void) PURE; //=--------------------------------------------------------------------------= // OVERRIDABLES -- methods controls can implement for customized functionality virtual void AmbientPropertyChanged(DISPID dispid) { }; virtual BOOL ShouldCreateWindow() { return TRUE; } virtual BOOL BeforeCreateWindow(DWORD *, DWORD *, LPSTR) { return TRUE; } virtual void BeforeDestroyWindow(void) { } virtual HRESULT DoCustomVerb(LONG lVerb) { return OLEOBJ_S_INVALIDVERB; } virtual BOOL OnSetExtent(const SIZE* pSize) { return TRUE; } virtual BOOL OnSpecialKey(LPMSG) { return FALSE; } virtual BOOL OnGetPalette(HDC, LOGPALETTE **); virtual HRESULT OnQuickActivate(QACONTAINER *, DWORD *); virtual BOOL InitializeNewState(); virtual BOOL AfterCreateWindow(void) { return TRUE; } virtual BOOL OnGetRect(DWORD dvAspect, LPRECTL prcRect); //=--------------------------------------------------------------------------= // methods that various people internally will share. not needed, however, by // any inherting classes. HRESULT m_SaveToStream(IStream *pStream); HRESULT LoadStandardState(IPropertyBag *pPropertyBag, IErrorLog *pErrorLog); HRESULT LoadStandardState(IStream *pStream); HRESULT SaveStandardState(IPropertyBag *pPropertyBag); HRESULT SaveStandardState(IStream *pStream); //=--------------------------------------------------------------------------= // member variables we don't want anybody to get their hands on, including // inheriting classes IOleAdviseHolder *m_pOleAdviseHolder; // IOleObject::Advise holder object IAdviseSink *m_pViewAdviseSink; // IViewAdvise sink for IViewObject2 unsigned short m_nFreezeEvents; // count of freezes versus thaws // internal flags. various other flags are visible to the end control class. unsigned m_fModeFlagValid:1; // we stash the mode as much as possible unsigned m_fSaveSucceeded:1; // did an IStorage save work correctly? unsigned m_fViewAdvisePrimeFirst: 1; // for IViewobject2::setadvise unsigned m_fViewAdviseOnlyOnce: 1; // for iviewobject2::setadvise unsigned m_fUsingWindowRgn:1; // for SetObjectRects and clipping unsigned m_fRunMode:1; // are we in run mode or not? class CConnectionPoint : public IConnectionPoint { public: #ifdef _WIN64 CONNECTDATA * m_rgSinks64; #else IUnknown **m_rgSinks; #endif // IUnknown methods // STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) ; STDMETHOD_(ULONG,AddRef)(THIS) ; STDMETHOD_(ULONG,Release)(THIS) ; // IConnectionPoint methods // STDMETHOD(GetConnectionInterface)(IID FAR* pIID); STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer FAR* FAR* ppCPC); STDMETHOD(Advise)(LPUNKNOWN pUnkSink, DWORD FAR* pdwCookie); STDMETHOD(Unadvise)(DWORD dwCookie); STDMETHOD(EnumConnections)(LPENUMCONNECTIONS FAR* ppEnum); void DoInvoke(DISPID dispid, DISPPARAMS * pdispparam); void DoOnChanged(DISPID dispid); BOOL DoOnRequestEdit(DISPID dispid); HRESULT AddSink(void *, DWORD *); COleControl *m_pOleControl(); CConnectionPoint(BYTE b){ m_bType = b; m_cSinks = 0; #ifdef _WIN64 m_rgSinks64 = NULL; m_dwNextCookie = 1; #else m_rgSinks = NULL; #endif } ~CConnectionPoint(); private: BYTE m_bType; short m_cSinks; #ifdef _WIN64 DWORD m_dwNextCookie; DWORD NextCookie(); IUnknown* CookieToSink( DWORD dwCookie ); #endif } m_cpEvents, m_cpPropNotify; // so they can get at some of our protected things, like AddRef, QI, etc. friend CConnectionPoint; }; #endif // _CTRLOBJ_H_