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

来源:互联网 发布:淘宝禁售管理规范 编辑:程序博客网 时间:2024/05/22 06:13
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

原创粉丝点击