单击"确定"有如下代码:
HBITMAP hBitmap = HBITMAP(::LoadImage(NULL, "C:\\pic813.bmp", IMAGE_BITMAP,64,64, LR_LOADFROMFILE) );
void CMyRich20Dlg::OnBnClickedOk()
{ m_wndRich.InsertBitmap(hBitmap); IRichEditOle *pOle = m_wndRich.GetIRichEditOle();
REOBJECT reo;
reo.cbStruct = sizeof(REOBJECT);
pOle->GetObject(0, & reo, REO_GETOBJ_NO_INTERFACES);
int iSize = reo.cp; 
}运行时:reo.cp表示图片在控件中的索引
向控件里输入"ABC"和一幅图片,此时reo.cp=3是正确的,向控件里
输入"中国人"和一幅图片,此时reo.cp=3?我就不懂了,中文应该是6才对啊
请高手们看看?

解决方案 »

  1.   

    类似 MSN 信息发送框的制作(上)
    作者:北方工业大学 阙荣文 (querw)
    下载源代码 一、引言
      用 MSN 和 QQ 等聊天的时候,当用户输入特定意义的字符串时,系统回自动用一张小图片替代.比如输入" : ) "系统
    会用一个小笑脸代替。我要实现的就是这样一个信息输入框 。这个信息输入框由两部分组成:图案选择器和多功能文本框。本篇介绍多功能文本框。 二、原理简介1、主要功能用CRichEditCtrl实现,像设置字体,设置字体颜色,字号等等CRichEditCtrl都提供了很完善的支持,我就不一一赘述了。CRichEditCtrl 主要的不足在于以下几个方面:(1).没有右键菜单 
    (2).不能插入图片(这是实现转义字符显示的关键) 
    (3).RTF格式输入输出不够方便(涉及到回调函数的递归调用) 
      我扩展了CRichEditCtrl类CRichEditCtrlEx实现了上述功能.参考了很多网上的文章,对所有公开源码的开发人员表示崇高的敬意!!2、实现右键菜单:///生成右键菜单
    void CRichEditCtrlEx::OnRButtonUp(UINT nFlags, CPoint point) 
    {
    // TODO: Add your message handler code here and/or call default
    //设置为焦点
    SetFocus();
    //创建一个弹出式菜单
    CMenu popmenu;
    popmenu.CreatePopupMenu();
    //添加菜单项目
    popmenu.AppendMenu(0, ID_RICH_UNDO, "&Undo");
    popmenu.AppendMenu(0, MF_SEPARATOR);
    popmenu.AppendMenu(0, ID_RICH_CUT, "&Cut");
    popmenu.AppendMenu(0, ID_RICH_COPY, "C&opy");
    popmenu.AppendMenu(0, ID_RICH_PASTE, "&Paste");
    popmenu.AppendMenu(0, ID_RICH_CLEAR, "C&lear");
    popmenu.AppendMenu(0, MF_SEPARATOR);
    popmenu.AppendMenu(0, ID_RICH_SELECTALL, "Select &All");
    popmenu.AppendMenu(0, MF_SEPARATOR);
    popmenu.AppendMenu(0, ID_RICH_SETFONT, "Select &Font");

    //初始化菜单项
    UINT nUndo=(CanUndo() ? 0 : MF_GRAYED );
    popmenu.EnableMenuItem(ID_RICH_UNDO, MF_BYCOMMAND|nUndo);

    UINT nSel=((GetSelectionType()!=SEL_EMPTY) ? 0 : MF_GRAYED) ;
    popmenu.EnableMenuItem(ID_RICH_CUT, MF_BYCOMMAND|nSel);
    popmenu.EnableMenuItem(ID_RICH_COPY, MF_BYCOMMAND|nSel);
    popmenu.EnableMenuItem(ID_RICH_CLEAR, MF_BYCOMMAND|nSel);

    UINT nPaste=(CanPaste() ? 0 : MF_GRAYED) ;
    popmenu.EnableMenuItem(ID_RICH_PASTE, MF_BYCOMMAND|nPaste);

    //显示菜单
    CPoint pt;
    GetCursorPos(&pt);
    popmenu.TrackPopupMenu(TPM_RIGHTBUTTON, pt.x, pt.y, this);
    popmenu.DestroyMenu();
    CRichEditCtrl::OnRButtonDown(nFlags, point);
    CRichEditCtrl::OnRButtonUp(nFlags, point);
    }
    3、关于如何把图片插入到RichEdit中,国外由很多文章介绍,都是(我看到的都是)通过插入OLE对象来实现.主要用两个函数,还涉及到了和多接口的调用。(1)从文件创建OLE对象OleCreateFromFile();
    void CRichEditCtrlEx::InsertBitmap(CString szFileName)
    {
    USES_CONVERSION;
    SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &m_lpLockBytes);
    if (sc != S_OK)
    AfxThrowOleException(sc);
    ASSERT(m_lpLockBytes != NULL);

    sc = ::StgCreateDocfileOnILockBytes(m_lpLockBytes,
    STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &m_lpStorage);
    if (sc != S_OK)
    {
    VERIFY(m_lpLockBytes->Release() == 0);
    m_lpLockBytes = NULL;
    AfxThrowOleException(sc);
    }

    // attempt to create the object
    sc = ::OleCreateFromFile(CLSID_NULL, T2COLE(szFileName),
            IID_IUnknown, OLERENDER_DRAW, NULL, NULL, 
            m_lpStorage, (void **)&m_lpObject);
    if ( sc != S_OK )
    {
    TCHAR * lpMsgBuf;
    ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM, NULL, 
    ::GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR) &lpMsgBuf, 0, NULL );
    CString msg( lpMsgBuf );
    msg += _T("\n\n\nThe following file, created in\n"
    "Simulation->Plot, may be missing due\n"
    "to not doing a File->Save Workspace:\n\n" );
    msg += szFileName;
    AfxMessageBox( msg, MB_OK );
    ::LocalFree( lpMsgBuf );
    return;
    }

    // m_lpObject is currently an IUnknown, convert to IOleObject
    if (m_lpObject != NULL)
    {
    LPUNKNOWN lpUnk = m_lpObject;
    m_lpObject = QUERYINTERFACE(lpUnk, IOleObject);
    lpUnk->Release();
    if (m_lpObject == NULL)
    AfxThrowOleException(E_OUTOFMEMORY);
    }

    // cache the IViewObject interface
    m_lpViewObject = QUERYINTERFACE(m_lpObject, IViewObject2);
    if (m_lpViewObject == NULL)
    return;

    // setup for advises; we assume that OLE cleans them up properly
    LPADVISESINK lpAdviseSink =
    (LPADVISESINK)GetInterface(&IID_IAdviseSink);

    // set up view advise
    VERIFY(m_lpViewObject->SetAdvise(DVASPECT_CONTENT, 0, lpAdviseSink)
    == S_OK);

    // the server shows these in its user-interface
    //  (as document title and in File Exit menu)
    m_lpObject->SetHostNames(T2COLE(AfxGetAppName()),
    T2COLE(_T("Test")));

    // all items are "contained" -- this makes our reference to this object
    //  weak -- which is needed for links to embedding silent update.
    OleSetContainedObject(m_lpObject, TRUE);

    CHARRANGE cr;
    this->GetSel( cr );
    cr.cpMin = cr.cpMax -1;
    this->SetSel( cr );

    REOBJECT reo;
    memset( &reo, 0, sizeof( reo ) );
    reo.cbStruct = sizeof( reo );
    CLSID classID;
    if ( m_lpObject->GetUserClassID( &classID ) != S_OK)
    classID = CLSID_NULL;
    reo.clsid = classID;
    reo.cp = REO_CP_SELECTION;
    reo.poleobj = m_lpObject;
    reo.pstg = m_lpStorage;
    LPOLECLIENTSITE lpClientSite;
    this->GetIRichEditOle()->GetClientSite( &lpClientSite );
    reo.polesite = lpClientSite;
    SIZEL sizel;
    sizel.cx = sizel.cy = 0; // let richedit determine initial size
    reo.sizel = sizel;
    reo.dvaspect = DVASPECT_CONTENT;
    reo.dwFlags = REO_RESIZABLE;
    reo.dwUser = 0;
    HRESULT hr = this->GetIRichEditOle()->InsertObject( &reo );

    }(2)根据位图句柄创建OleCreateStaticFromData();用这个函数可以把资源中的图片插入到文本框中
    void CRichEditCtrlEx::InsertBitmap(HBITMAP hBitmap)
    {
    STGMEDIUM stgm;
    stgm.tymed = TYMED_GDI;    // Storage medium = HBITMAP handle
    stgm.hBitmap = hBitmap;
    stgm.pUnkForRelease = NULL; // Use ReleaseStgMedium

    FORMATETC fm;
    fm.cfFormat = CF_BITMAP;    // Clipboard format = CF_BITMAP
    fm.ptd = NULL;       // Target Device = Screen
    fm.dwAspect = DVASPECT_CONTENT;   // Level of detail = Full content
    fm.lindex = -1;       // Index = Not applicaple
    fm.tymed = TYMED_GDI;  

    ////创建输入数据源
    IStorage *pStorage; 

    ///分配内存
    LPLOCKBYTES lpLockBytes = NULL;
    SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
    if (sc != S_OK)
    AfxThrowOleException(sc);
    ASSERT(lpLockBytes != NULL);

    sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
    STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &pStorage);
    if (sc != S_OK)
    {
    VERIFY(lpLockBytes->Release() == 0);
    lpLockBytes = NULL;
    AfxThrowOleException(sc);
    }
    ASSERT(pStorage != NULL);

    COleDataSource *pDataSource = new COleDataSource;
    pDataSource->CacheData(CF_BITMAP, &stgm);
    LPDATAOBJECT lpDataObject = 
    (LPDATAOBJECT)pDataSource->GetInterface(&IID_IDataObject);

    ///获取RichEdit的OLEClientSite
    LPOLECLIENTSITE lpClientSite;
    this->GetIRichEditOle()->GetClientSite( &lpClientSite );


    ///创建OLE对象
    IOleObject *pOleObject;
    sc = OleCreateStaticFromData(lpDataObject,IID_IOleObject,OLERENDER_FORMAT,
    &fm,lpClientSite,pStorage,(void **)&pOleObject);
    if(sc!=S_OK)
    AfxThrowOleException(sc);

    ///插入OLE对象

    REOBJECT reobject;
    ZeroMemory(&reobject, sizeof(REOBJECT));
    reobject.cbStruct = sizeof(REOBJECT);

    CLSID clsid;
    sc = pOleObject->GetUserClassID(&clsid);
    if (sc != S_OK)
    AfxThrowOleException(sc);

    reobject.clsid = clsid;
    reobject.cp = REO_CP_SELECTION;
    reobject.dvaspect = DVASPECT_CONTENT;
    reobject.poleobj = pOleObject;
    reobject.polesite = lpClientSite;
    reobject.pstg = pStorage;

    HRESULT hr = this->GetIRichEditOle()->InsertObject( &reobject );

    }4、读取/写入RTF格式字符串
      CRichEditCtrl 提供了两个函数StreamIn()和StreamOut()来实现这个功能,输出的内容包含文本信息和字体信息。我把这两个函数重新包装了一下 ,用GetRTF()把格式文本返回到一个CString变量中SetRTF(CString )实现逆过程。具体代码参看本文附带的工程文件。 三、到此,这个多功能文本框就已经基本能满足我的要求了。但是如何选择表情符号? 如何自动替换? 还是个问题。(待续)
      

  2.   

    unicode里面中文就是一个字算一格长度的,正常