RichEdit嵌入自开发OLE控件技术要点(ATL)
richedit插入gif实例下载:
1、创建ATL复合文档控件。可通过wizard创建。
下面是创建OLE控件的最小头文件
// CSimpleOleObject class ATL_NO_VTABLE CSimpleOleObject : public CComObjectRootEx<CComSingleThreadModel>, public IDispatchImpl<ISimpleOleObject, &IID_ISimpleOleObject, &LIBID_atlsdLib, /*wMajor =*/ 1, /*wMinor =*/ 0>, public IPersistStreamInitImpl<CSimpleOleObject>, public IOleControlImpl<CSimpleOleObject>, public IOleObjectImpl<CSimpleOleObject>, public IOleInPlaceActiveObjectImpl<CSimpleOleObject>, public IViewObjectExImpl<CSimpleOleObject>, public IOleInPlaceObjectWindowlessImpl<CSimpleOleObject>, #ifdef _WIN32_WCE // 要在 Windows CE 上正确加载该控件,要求 IObjectSafety public IObjectSafetyImpl<CSimpleOleObject, INTERFACESAFE_FOR_UNTRUSTED_CALLER>, #endif public CComCoClass<CSimpleOleObject, &CLSID_SimpleOleObject>, public CComCompositeControl<CSimpleOleObject> { public: CSimpleOleObject() { m_bWindowOnly = TRUE; CalcExtent(m_sizeExtent); } DECLARE_OLEMISC_STATUS(OLEMISC_RECOMPOSEONRESIZE | OLEMISC_CANTLINKINSIDE | OLEMISC_INSIDEOUT | OLEMISC_ACTIVATEWHENVISIBLE | OLEMISC_SETCLIENTSITEFIRST ) DECLARE_REGISTRY_RESOURCEID(IDR_SIMPLEOLEOBJECT) BEGIN_COM_MAP(CSimpleOleObject) COM_INTERFACE_ENTRY(ISimpleOleObject) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(IViewObjectEx) COM_INTERFACE_ENTRY(IViewObject2) COM_INTERFACE_ENTRY(IViewObject) COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless) COM_INTERFACE_ENTRY(IOleInPlaceObject) COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless) COM_INTERFACE_ENTRY(IOleInPlaceActiveObject) COM_INTERFACE_ENTRY(IOleControl) COM_INTERFACE_ENTRY(IOleObject) COM_INTERFACE_ENTRY(IPersistStreamInit) COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit) #ifdef _WIN32_WCE // 要在 Windows CE 上正确加载该控件,要求 IObjectSafety COM_INTERFACE_ENTRY_IID(IID_IObjectSafety, IObjectSafety) #endif END_COM_MAP() BEGIN_PROP_MAP(CSimpleOleObject) PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4) PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4) // 示例项 // PROP_ENTRY_TYPE("属性名", dispid, clsid, vtType) // PROP_PAGE(CLSID_StockColorPage) END_PROP_MAP() BEGIN_MSG_MAP(CSimpleOleObject) CHAIN_MSG_MAP(CComCompositeControl<CSimpleOleObject>) END_MSG_MAP() // 处理程序原型: // LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); // LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled); // LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled); BEGIN_SINK_MAP(CSimpleOleObject) //请确保事件处理程序含有 __stdcall 调用约定 END_SINK_MAP() STDMETHOD(OnAmbientPropertyChange)(DISPID dispid) { if (dispid == DISPID_AMBIENT_BACKCOLOR) { SetBackgroundColorFromAmbient(); FireViewChange(); } return IOleControlImpl<CSimpleOleObject>::OnAmbientPropertyChange(dispid); } // IViewObjectEx DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE) // ISimpleOleObject enum { IDD = IDD_SIMPLEOLEOBJECT }; DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() { return S_OK; } void FinalRelease() { } }; OBJECT_ENTRY_AUTO(__uuidof(SimpleOleObject), CSimpleOleObject)
2、设置你需要的属性,这些数据是需要存储的,需要在复制和粘贴时使用:
BEGIN_PROP_MAP(CContactOleObject) PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4) PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4) PROP_ENTRY_TYPE("Caption", DISPID_CAPTION, CLSID_NULL, VT_BSTR) // 示例项 // PROP_ENTRY_TYPE("属性名", dispid, clsid, vtType) // PROP_PAGE(CLSID_StockColorPage) END_PROP_MAP()
3、实现IRichEditOleCallBack接口,并在创建RichEdit实例时设置该接口
class ATL_NO_VTABLE CRichEditOleCallback : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CRichEditOleCallback, &CLSID_NULL>, public IRichEditOleCallback { public: CRichEditOleCallback(); DECLARE_NO_REGISTRY() BEGIN_COM_MAP(CRichEditOleCallback) COM_INTERFACE_ENTRY_IID(IID_IRichEditOleCallback, IRichEditOleCallback) END_COM_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() { return S_OK; } void FinalRelease() { } public: STDMETHOD(Init)(HWND hRich); STDMETHOD(UnInit)(); // IRichEditOleCallback STDMETHOD(GetNewStorage)(LPSTORAGE* lplpstg); STDMETHOD(GetInPlaceContext)(LPOLEINPLACEFRAME FAR *lplpFrame, LPOLEINPLACEUIWINDOW FAR *lplpDoc, LPOLEINPLACEFRAMEINFO lpFrameInfo); STDMETHOD(ShowContainerUI)(BOOL fShow); STDMETHOD(QueryInsertObject)(LPCLSID lpclsid, LPSTORAGE lpstg, LONG cp); STDMETHOD(DeleteObject)(LPOLEOBJECT lpoleobj); STDMETHOD(QueryAcceptData)(LPDATAOBJECT lpdataobj, CLIPFORMAT FAR *lpcfFormat, DWORD reco, BOOL fReally, HGLOBAL hMetaPict); STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode); STDMETHOD(GetClipboardData)(CHARRANGE FAR *lpchrg, DWORD reco, LPDATAOBJECT FAR *lplpdataobj); STDMETHOD(GetDragDropEffect)(BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect); STDMETHOD(GetContextMenu)(WORD seltyp, LPOLEOBJECT lpoleobj, CHARRANGE FAR *lpchrg, HMENU FAR *lphmenu); private: HWND m_hRich; int m_iNumStorages; IStoragePtr m_spStorage; };
4、OLE中增加插入到richedit的接口:
virtual HRESULT STDMETHODCALLTYPE InsertOleObjectToRichEdit(IUnknown* pRichEditOle) { if(pRichEditOle == NULL) return E_FAIL; T* pT = static_cast<T*>(this); if(pT->m_spClientSite) { // 如果当前已经嵌入了某个容器中,就不能再插了 return S_FALSE; } IOleObjectPtr spOleObject = NULL; //OLE对象 IOleClientSitePtr spClientSite = NULL; CComPtr<IRichEditOle> spRichEditOle = NULL; CLSID clsid = CLSID_NULL; HRESULT hr = S_OK; BOOL bRet = TRUE; hr = pRichEditOle->QueryInterface(IID_IRichEditOle, (void**)&spRichEditOle); hr = spRichEditOle->GetClientSite(&spClientSite); hr = pT->QueryInterface(IID_IOleObject, (void**)&spOleObject);//获得数据对象接口 GetUserClassID(&clsid); REOBJECT reobject; ZeroMemory(&reobject, sizeof(REOBJECT)); //初始化一个对象 reobject.cbStruct = sizeof(REOBJECT); reobject.clsid = clsid; reobject.cp = REO_CP_SELECTION; reobject.dvaspect = DVASPECT_CONTENT; reobject.dwFlags = REO_DONTNEEDPALETTE | REO_DYNAMICSIZE; reobject.poleobj = spOleObject; reobject.polesite = spClientSite; reobject.pstg = m_spStorage; spOleObject->SetClientSite(spClientSite); hr = spRichEditOle->InsertObject( &reobject ); ::OleSetContainedObject(spOleObject,TRUE); return S_OK; }
5、使用一下代码插入OLE
CComQIPtr<ISimpleOleObject> spCusOle; HRESULT hr = CoCreateInstance(__uuidof(SimpleOleObject), NULL, CLSCTX_INPROC, __uuidof(ISimpleOleObject), (void**)&spCusOle); if(spCusOle) { spCusOle->SetImageFile(_bstr_t(sFile)); IOleObjectPtr spOleObject; spCusOle->QueryInterface(IID_IOleObject, (void**)&spOleObject); CComPtr<IRichEditOle> spEditOle; spEditOle.Attach(GetIRichEditOle()); IOleClientSitePtr spClientSite; spEditOle->GetClientSite(&spClientSite); spCusOle->InsertOleObjectToRichEdit(spEditOle); }