RichEdit对ole 对象的相关支持总结

RichEdit对ole 的相关支持总结

1.       RichEdit要嵌入ole  objects必须要继承 IRichEditOleCallback 接口,这个接口让richEdit能够增加RichEdit对Ole的嵌入支持。

 

  

首先在RichEdit的OnCreate中调用SetOLECallback函数,这样就设置了IRichEditOleCallback的接口实现者。

    //设置OLECallBack接口,让richEdit能够插入显示ole控件  
        BOOL bSuccess=SetOLECallback(this);  

 

在OnCreate中,还要记得注册 ole剪贴板格式,这个格式是我们自己定的,在处理复制和粘贴的时候,需要用到它。

//注册自己的ole 剪贴板格式  
#define   STR_OWN_OLE_CLIPBOARD_FORMAT   _T("STR_OWN_OLE_CLIPBOARD_FORMAT")  
    m_uOwnOleClipboardFormat = RegisterClipboardFormat(STR_OWN_OLE_CLIPBOARD_FORMAT); 

 

这个接口的几个必须实现的接口函数:

(1) GetNewStorage

它为一个来自剪贴板粘贴的对象提供新的存储。

    STDMETHODIMP CRichEditCtrlEx::GetNewStorage(THIS_ LPSTORAGE FAR * lplpstg)  
    {  
        //Create a flat storage and steal it from the client item  
        //the client item is only used for creating the storage  
        COleClientItem item;  
        item.GetItemStorageFlat();  
        *lplpstg = item.m_lpStorage;  
        HRESULT hRes = E_OUTOFMEMORY;  
        if (item.m_lpStorage != NULL)  
        {  
            item.m_lpStorage = NULL;  
            hRes = S_OK;  
        }  
        return hRes;  
    }  


(2)QueryInsertObject

     它处理来自ole object的插入请求,如果同意插入,就返回S_OK,否则返回E_NOTIMPL

     在这个里面可以判断是否是自己需要的类型,如果不是,就可以拒绝插入。

 

     STDMETHODIMP CRichEditCtrlEx::QueryInsertObject(THIS_ LPCLSID lpclsid, LPSTORAGE lpstg,LONG cp)  
    {  
            if(CLSID_DynamicGif == *lpclsid)  
            {  
                //如果是CLSID_DynamicGif类型的嵌入对象,则支持,否则不支持  
                return S_OK; //此语句用来显示一个嵌入对象  
            }  
            else  
    {  
                 //否则  
                 return  E_NOTIMPL;  
    }  
    }  

 

(3) DeleteObject

它处理删除ole  obj的请求,直接返回E_NOTIMPL即可。

 

    STDMETHODIMP CRichEditCtrlEx::DeleteObject(THIS_ LPOLEOBJECT lpoleobj)  
    {  
            //return S_OK;  
            return E_NOTIMPL;     
    }  

(4) GetClipboardData

   在这个地方处理复制或拖拽

   创建一个 DataSource对象,将自己处理过的数据,存入ole 剪贴板,最好获得DataSource对象的 IDataObject接口,将它赋值给lpchrg参数。

 

         STDMETHODIMP CRichEditCtrlEx::GetClipboardData(THIS_ CHARRANGE FAR * lpchrg, DWORD reco,LPDATAOBJECT FAR * lplpdataobj)  
      
    //在这里处理复制,剪切  
    if (reco==RECO_COPY || reco==RECO_CUT)  
    {    
        //获得lpchrg对应的richedit的内容  
        CString  strText;  
        GetTextRange(lpchrg->cpMin,lpchrg->cpMax,strText);  
      
        //code  text,存入剪贴板的为string ,通过XML编码string  
        string   strCodedText=ToCodedString(* lpchrg,strText);  
      
      
      
        //创建一个 DataSource  
        COleDataSource *pDataSource = new COleDataSource;  
      
        int  strBytes=  strCodedText.length();  
        HGLOBAL hG = GlobalAlloc(GMEM_DDESHARE, strBytes);  
        void* pBuffer = GlobalLock(hG);  
        {  
            memcpy(pBuffer, strCodedText.c_str(), strBytes);  
            GlobalUnlock(hG);  
        }  
      
        FORMATETC fmt;  
        fmt.cfFormat = m_uOwnOleClipboardFormat;  
        fmt.dwAspect = DVASPECT_CONTENT;  
        fmt.lindex = -1;  
        fmt.ptd = NULL;  
        fmt.tymed = TYMED_HGLOBAL;  
      
        STGMEDIUM stg;  
        stg.tymed = TYMED_HGLOBAL;  
        stg.hGlobal = hG;  
        stg.pUnkForRelease = NULL;  
      
      
        pDataSource->CacheData(m_uOwnOleClipboardFormat,&stg, &fmt);  
        //将 pDataSource的 IDataObject接口赋值给 lplpdataobj  
        *lplpdataobj= (IDataObject *)pDataSource->GetInterface(&IID_IDataObject);  
      
        return  S_OK;  
    }  
      
       return E_NOTIMPL;  

(5) QueryAcceptData

      当有粘贴操作或者拖放操作的时候,询问是否应该接受这些操作。

      可以在这里处理粘贴和拖放,然后解析来自ole 剪贴板的数据,然后把他输出到richedit中。这些ole 剪贴板中的数据,是在GetClipboardData中写入的。

 

        STDMETHODIMP CRichEditCtrlEx::QueryAcceptData(THIS_ LPDATAOBJECT lpdataobj, CLIPFORMAT FAR * lpcfFormat, DWORD reco,BOOL bReally, HGLOBAL hMetaPict)  
    {  
        USES_CONVERSION;  
      
        if (!bReally)   // just query  
        {  
            //return E_NOTIMPL;  
      
            return  S_OK;  
        }  
          
        //只处理粘贴  
        switch(reco)  
        {  
        case RECO_PASTE:  
        case RECO_DROP:  
            {  
                COleDataObject odo;  
                odo.Attach(lpdataobj);  
      
                //如果 m_uOwnOleClipboardFormat 剪贴板格式可用  
                if (odo.IsDataAvailable(m_uOwnOleClipboardFormat))  
                {  
                    STGMEDIUM stg;  
                    VERIFY(odo.GetData(m_uOwnOleClipboardFormat, &stg));  
      
                    int nSize = GlobalSize(stg.hGlobal);  
                    void* pBuffer = GlobalLock(stg.hGlobal);  
                    {  
                        //在这个地方复制插入进去......  
                        string   strText=    string((char *)pBuffer);  
      
                        //解码 XML 元素  
                        CXmlParser   xmlParser;  
                        xmlParser.BeginDecodeString(strText);  
                        xmlParser.EndDecodeString();  
      
                        vector<XML_OBJ_STRUCT>  vec_xml_objs=xmlParser.GetDecodeString();  
      
      
                        //遍历vec_xml_objs  ,插入元素  
                        vector<XML_OBJ_STRUCT>::iterator  iter_begin=vec_xml_objs.begin();  
                        vector<XML_OBJ_STRUCT>::iterator  iter_end=vec_xml_objs.end();  
                        for (;iter_begin!=iter_end;++iter_begin)  
                        {  
                            if (iter_begin->obj_type== STR_OBJ_TYPE)  
                            {  
                                CString   strToInsert=A2CT(iter_begin->str_obj_struct.strText.c_str())  ;  
                                InsertText(theApp.g_edit_font_,strToInsert,FALSE,TRUE,TRUE,FALSE);  
                            }  
      
                            else if (iter_begin->obj_type==OLE_OBJ_TYPE)  
                            {  
                                 CString  strPathToInsert=A2CT(iter_begin->ole_obj_struct.strOleFilePath.c_str());  
                                 int      index= iter_begin->ole_obj_struct.iIndex;  
                                 //插入 ole obj   
                                 if (index>=MAX_EMOTION_INDEX_NUMBER + BMP_INDEX_OFFSET_GAP)  
                                 {   //如果是复制的 BMP,那么就重新计算index  
                                     InsertPicImpl(strPathToInsert,0,true,true);  
                                 }  
                                 else  
                                 {  
                                     InsertPicImpl(strPathToInsert,index,false,true);  
                                 }  
                            }  
      
                        }  
      
                        GlobalUnlock(stg.hGlobal);  
                    }  
                    odo.Detach();  
                    return S_OK;  
                }  
                else if (odo.IsDataAvailable(CF_TEXT))  
                {  
                    odo.Detach();  
                    return S_OK;  
                }  
      
                odo.Detach();  
                return E_FAIL;  
            }  
            break;  
      
        case RECO_COPY:  
            break;  
      
        case RECO_CUT:  
            break;  
      
        case RECO_DRAG:  
            break;  
      
      
        default:  
            break;  
        }  
      
        return E_NOTIMPL;  
    }  

 

(6) GetContextMenu

      这个函数处理右键菜单。

 

         HMENU CRichEditCtrlEx::GetContextMenuInner(WORD seltype, LPOLEOBJECT lpoleobj, CHARRANGE* lpchrg)  
    {  
        //创建一个弹出式菜单  
        CMenu popmenu;  
        popmenu.CreatePopupMenu();  
        UINT nSel = ((GetSelectionType() != SEL_EMPTY) ? 0 : MF_GRAYED);  
        UINT nPaste = ((CanPaste()||IsClipboardFormatAvailable(CF_BITMAP)|| IsClipboardFormatAvailable(m_uOwnOleClipboardFormat)) ? 0 : MF_GRAYED);  
      
        //添加菜单项目  
        if(read_only_)  
        {  
            popmenu.AppendMenu(0, ID_RICH_COPY, TEXT("复制(&C)"));  
            popmenu.EnableMenuItem(ID_RICH_COPY, MF_BYCOMMAND|nSel);      
        }  
        else  
        {  
            popmenu.AppendMenu(0, ID_RICH_CUT, TEXT("剪切(&X)"));  
            popmenu.AppendMenu(0, ID_RICH_COPY, TEXT("复制(&C)"));  
            popmenu.AppendMenu(0, ID_RICH_PASTE, TEXT("粘贴(&V)"));  
            //popmenu.AppendMenu(MF_SEPARATOR);  
            //popmenu.AppendMenu(0, ID_RICH_SETFONT, TEXT("选择字体"));  
      
            popmenu.EnableMenuItem(ID_RICH_CUT, MF_BYCOMMAND|nSel);  
            popmenu.EnableMenuItem(ID_RICH_COPY, MF_BYCOMMAND|nSel);      
            popmenu.EnableMenuItem(ID_RICH_PASTE, MF_BYCOMMAND|nPaste);  
        }  
      
        if(seltype == SEL_OBJECT)  
        {  
            popmenu.AppendMenu(MF_SEPARATOR);  
            popmenu.AppendMenu(MF_STRING, IDM_CHAT_DLG_SAVE_OLE_IMG, TEXT("另存为..."));  
        }  
      
        //显示菜单  
        POINT pt;  
        GetCursorPos(&pt);  
        DWORD dwCmd = popmenu.TrackPopupMenu(TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RETURNCMD, pt.x, pt.y, this);  
        popmenu.DestroyMenu();  
        switch(dwCmd)  
        {  
        case ID_RICH_COPY:  
            {  
                Copy();  
                break;  
            }  
        case ID_RICH_CUT:  
            {  
                Cut();  
                break;  
            }  
        case ID_RICH_PASTE:  
            {  
                Paste();  
                break;  
            }  
        case IDM_CHAT_DLG_SAVE_OLE_IMG:  
            {  
                CComPtr<IGGGifCtrl>  pGifCtrl;  
                HRESULT hr = lpoleobj->QueryInterface(&pGifCtrl);  
                if(SUCCEEDED(hr))  
                {  
                    if(pGifCtrl)  
                    {  
                        BSTR bstrFile;  
                        pGifCtrl->GetFilePath(&bstrFile);  
                     // 保存文件到另外一个文件,这里控件根据控件中文件类型的不同设置  
                     // 不同的扩展名,如果采用对话框的形式保存文件时注意分析文件的扩展名,来正确的保存文件类型。  
                        if(_bstr_t(bstrFile).length())  
                        {  
                            CString strSrcFilePath = bstrFile;  
                            SaveOleImgToFile(strSrcFilePath);  
                        }  
                    }  
                }  
                break;  
            }  
        default:  
            break;  
        }  
      
        return NULL;  
    }  

 

 

 

1.   RichEdit中,怎么实现对复制的内容中,什么是普通文本,什么是ole对象的识别。

(1)  首先,创建一个Manager类,类里面有个vector,用来管理richedit中的 ole对象对应的结构体列表。

另外一个结构体OleStruct用来存储ole对象的相关的信息。

这些信息包括:ole对象在richedit中的位置nPos,这个很重要,因为在处理复制的时候,需要通过这个来判断,复制的是否是文字还是ole对象。

              Ole对象的Index,如果有的话

              Ole对象的 path,也就是插入到richedit的 图像的路径,这个是最重要的。

其他的一些信息。

 

Manager类 提供一个方法,这个方法传入一个位置nPos,如果这个位置是一个ole obj ,那么返回这个ole object对应的vector中的OleStruct对象,否则返回NULL.

在处理复制的时候,就调用这个方法,来将所有的ole obj的数据,替换为编码过的OleStruct对象的数据。然后在处理粘贴的时候,又解码,将对应的Ole object对象插入到

RichEdit中。

 

(2)  然后,响应richedit的 EN_CHANGE消息

注意在richEdit的OnCreate函数中启用EN_CHANGE消息,否则收不到这个消息:

           //设置让 EN_CHANGE  生效

  SetEventMask(GetEventMask() | ENM_CHANGE);

 

在EN_CHANGE消息响应函数中:

首先获得整个richedit的内容,然后遍历内容,将所有的Ole objects 的信息都收集到 ole对象管理器中,这样就可以随时查询ole objects的相关信息了。

 

 

(3)  在处理复制和拖拽的时候,首先获得复制的内容,通过查询ole 对象管理器,可以知道对应的内容是否是ole obj对象。

将文本和ole 对象的数据分别用XML文档编码,编码为下面的两种类型:

 typedef   struct   _STR_OBJ_STRUCT

{

           string   strText; //文本内容

}STR_OBJ_STRUCT;

 

typedef   struct   _OLE_OBJ_STRUCT

{

          string   strOleFilePath; //路径

          int      iIndex;         //index

}OLE_OBJ_STRUCT;

 

然后再用XML插入这两种类型的结点,最终获得XML 的字符串。

通过ole剪贴板,将这个编码过的字符串保存起来。

 

(4)在处理粘贴或拖放的时候:

        获得编码过的XML文本,然后解析XML文本,获得

        STR_OBJ_STRUCT结构体和OLE_OBJ_STRUCT结构体的对象。

 

        依次遍历这些对象,将他们插入到richedit中。这样就让richedit增加了对ole对象的复制粘贴和拖拽的支持。


原文地址:http://blog.csdn.net/tangaowen/article/details/6198238

你可能感兴趣的:(xml,String,object,struct,null,iterator)