博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
RichEdit对ole 对象的相关支持总结
阅读量:2392 次
发布时间:2019-05-10

本文共 11116 字,大约阅读时间需要 37 分钟。

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);

 

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

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

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

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

   对象,将自己处理过的数据,存入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
vec_xml_objs=xmlParser.GetDecodeString(); //遍历vec_xml_objs ,插入元素 vector
::iterator iter_begin=vec_xml_objs.begin(); vector
::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
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://yzeab.baihongyu.com/

你可能感兴趣的文章
java中的多态
查看>>
JAVA中的Object类和System类
查看>>
面试常问——java中的“==”和equals的区别
查看>>
java中输入的日期打印出星期几,Date互相转换String
查看>>
java小案例:计算你现在到出生的天数
查看>>
JAVA中的集合类接口——Collection
查看>>
java中的迭代器
查看>>
java中的增强for 和 泛型
查看>>
JAVA集合中常见的两种去重的两种方式
查看>>
JAVA中Set接口
查看>>
java中的集合工具类Collections中的常用方法
查看>>
java用ArrayList集合来实现斗地主发牌案例
查看>>
JAVA中Map集合常用的方法
查看>>
java中Map的两种遍历方式
查看>>
java中的异常
查看>>
java中的异常处理
查看>>
java 中Throwable常用方法
查看>>
java中自定义异常& 编译时异常&运行时异常
查看>>
java中throws和throw的区别
查看>>
常见面试题——斐波纳挈数列
查看>>