No announcement yet.

Richedit, picture(again) and caret.

  • Filter
  • Time
  • Show
Clear All
new posts

  • Richedit, picture(again) and caret.


    I'm still looking for a way to read an RTF file containing a bitmap into the richedit box.
    Wordpad uses this class too.

    I'm also trying to use the box for readonly.
    A simple lock for edit is not sufficient.

    It should more behave like a webbrowser in this case.
    The scrollbar should work, the edit part should no get focus.



  • #2
    Unfortunately, the RichEdit control is not "Microsoft Word in a Box."

    The RichEdit control does not provide a direct method for loading a
    bitmap and inserting it into an RTF document.

    Look into using OLE2 Client support. To insert the bitmap, create an embedded object
    from a file. OLE provides the OleCreateFromFile function call to make this easier.

    Why not convert the RTF file to a string array and extract the images and paint them
    both to a memory DC and then blit them for smooth scrolling and non-editable window.

    Regards, Jules


    • #3
      I'm not sure what you mean about the OLE variant.
      I don't want to INSERT a picture in existing (RTF)data.

      I simply want to load a RTF file containing a WMF and text.

      VB does it OK, Wordpad does. (all using the same RTF-file)
      I don't know why it won't work, i'm searching for hours now.

      I want to use the 1.00 version and i make use of the streamin callback.

      In this case, i'm only going to use it as presentation.
      The RTF data is maintained by somebody else so, nopprogramming tricks.




      • #4

        I don't want to INSERT a picture in existing (RTF)data.

        No, but you do want to put it into the RichEdit control.
        Then you will need to support OLE object to insert it. This is
        probably why the RichEdit control supports OLE2 client.

        I simply want to load a RTF file containing a WMF and text.

        Then you will have to do what VB does, use ActiveX or in the case of WordPad most likely built into a DLL. You just can't do it using just the RichEdit control, it does not support it at this time. You have to do it programmatically i.e. parse the RTF file and re-build its formatting attributes.

        Regards, Jules


        • #5
          To set it to readonly:

          ' SendMessage hEdit, %EM_SETREADONLY, %TRUE, 0

          You can still select and copy text from it, just you can in any
          webbrowser, but you can't change it's contents.

          As for pictures. Like Jules already have answered - you have to
          use OLE. I remember seing a document about this somewhere at the
          MSDN -site, complete with sample code in C++ and all, so if you
          go there and search for "bitmap" and Richedit", I'm sure you will
          be able to find out more about it.



          • #6
            Since i could not find a solution to my picture problem, let me tell what i want.

            I have a richedit box wich should have a logo on the right - up side.
            The document should aut. wrap around this logo (no gaps near the logo).

            The problem is the resolution of the picture, a different logo might be used.
            This makes it hard to align/prepare the text so that it would fit around the logo.

            Maybe i can 'paste' the logo into the RTF text after loading the text?
            It's not a big problem if the logo was left aligned for now.
            I just want to fully implement it in the RTF text.

            So, painting it in the box is not an option i prefer.

            1) The picture is a bitmap.
            2) The picture can be different (different logo's)
            3) The picture is allways aligned to the top of the box.
            4) I need only this picture alone for now.

            Your option might be ok but, i saw this call, it looks pretty hard.

            Did you had some succes to do this?
            I'm using a resource for the RTF data.
            This call might need a file instead..


            BTW the readonly, i was aware of this, i used it for now, it's not that bad but maybe someone had it more working like the webbrowser does.
            Forget it, it's much less important.



            • #7

              I honestly don't know how to do it using OLE. I would attempt to parse the RTF and paint it all only if the RTF contains 1 font, 1 point and 1 color. (You could use the RichEdit control to convert the RTF file to Text first before parsing). To put it all together on the screen and have smooth scrolling, see my post in the Source Code forum, look for "SuperCharge Repaints".

              Also, look at WinLift+Jazzage "Universal Browser" demo. That
              may have something for you.

              Regards, Jules


              • #8
                Thanks Jules for your effort.

                No, it should have it's orginal format.

                Sure, i know about the webbrowser.

                It's to large for an installer-app.
                I use an outlook bar with an RTF box to install the app we distr.
                I made it hypertext-aware, this is very nice, allmost a webbrowser..

                But it should stay independed of IE.

                I like it so far, only the logo is a problem.
                If i would place the logo above the RTF control, there would be a big (unpredictable) gap.

                To bad..




                • #9
                  VB Richtx32.Ocx supports, at least, WMF (window class - RichTextWndClass).
                  But I have no idea, how to use it - LoadLibrary Ocx & Control Add "RichTextWndClass" are not enough.



                  • #10
                    Picked this up at MSDN. Maybe it can be of some help..

                    HOWTO: Insert a Bitmap Into an RTF Document Using the RichEdit Control
                    The information in this article applies to:
                    The Microsoft Foundation Classes (MFC), included with:
                        Microsoft Visual C++, 32-bit Editions, version 6.0
                    The RichEdit control does not provide a direct method for loading a bitmap and inserting it into an RTF document. The ActiveX control (RichTextBox) provides the Add method through the COleObjects class, but this action loads the bitmap for editing in the registered bitmap editor (usually Paintbrush) before inserting it into the document. Both the DLL and the OCX expose the IRichEditOle interface which, however, provides the InsertObject method. This requires a fully-populated RichEdit Object (REOBJECT) structure to be passed. 
                    MORE INFORMATION
                    The following code is based on a project in which the Microsoft RichTextBox control has been inserted. With minor changes, it can apply to the RichEdit DLL as well. 
                    1.First, add four OLE interface pointers as member variables:
                                  LPRICHEDITOLE   m_pRichEditOle;
                                  LPOLEOBJECT     m_lpObject;
                                  LPSTORAGE         m_lpStorage;
                                  LPOLECLIENTSITE m_lpClientSite; 
                          NOTE: Set these variables to NULL in your constructor.
                    2.Get the IRichEditOLE interface early on in your program and keep it available in OnInitDialog or OnInitialUpdate. For the RichTextBox control, use the following method:
                                  ::SendMessage((HWND)m_ctlRichText.GetHwnd(), EM_GETOLEINTERFACE, 0, (LPARAM)&m_pRichEditOle);
                                  ASSERT(m_pRichEditOle != NULL); 
                    NOTE: M_ctlRichText is an instance of the Visual C++ wrapper class MFC generates when inserting a RichTextBox ActiveX control through the component gallery. The MFC CRichEditCtrl class provides the GetRichEditOle() method that wraps code similar to the above and produces the same result.
                    3.To insert the bitmap, create an embedded object from a file. OLE provides the OleCreateFromFile function call to make this easier, but you still need to prepare for the call. The following code is an amalgam of techniques used within the MFC classes to provide similar functionality.
                          BOOL CRichTextDlg::CreateFromFile(LPCTSTR lpszFileName)
                                  ASSERT(m_lpObject == NULL);     // one time only
                                  ASSERT(m_lpStorage == NULL);
                                  ASSERT(m_lpClientSite == NULL);
                                  LPLOCKBYTES lpLockBytes = NULL;
                                  CLSID clsid = CLSID_NULL;
                                  OLERENDER render = OLERENDER_DRAW;
                                  CLIPFORMAT cfFormat = 0;
                                  LPFORMATETC lpFormatEtc = NULL;
                                  SCODE sc;
                                  sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
                                  if (sc != S_OK)
                                  ASSERT(lpLockBytes != NULL);
                                  sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
                                          STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &m_lpStorage);
                                  if (sc != S_OK)
                                          VERIFY(lpLockBytes->Release() == 0);
                                          lpLockBytes = NULL;
                                  ASSERT(m_lpStorage != NULL);
                                  // fill in FORMATETC struct
                                  FORMATETC formatEtc;
                                  lpFormatEtc = &formatEtc;
                                  lpFormatEtc->cfFormat = cfFormat;
                                  lpFormatEtc->ptd = NULL;
                                  lpFormatEtc->dwAspect = DVASPECT_CONTENT;
                                  lpFormatEtc->lindex = -1;
                                  lpFormatEtc->tymed = TYMED_NULL;
                                  // attempt to create the object
                                  sc = ::OleCreateFromFile(clsid, T2COLE(lpszFileName),
                                          IID_IUnknown, OLERENDER_DRAW, lpFormatEtc, m_lpClientSite, m_lpStorage,
                                  if (sc != S_OK)
                                  // m_lpObject is currently an IUnknown, convert to IOleObject
                                  if (m_lpObject != NULL)
                                          LPUNKNOWN lpUnk = m_lpObject;
                                          lpUnk->QueryInterface(IID_IOleObject, (void**)&m_lpObject);
                                          if (m_lpObject == NULL)
                                  // 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);
                                  return TRUE;
                    4.To use the function, simply pass the full path to a bitmap as the file name parameter. The function creates a byte array in global memory and a compound file storage object in that memory. It then populates the FORMATETC structure, gets the client site, and creates the object within the provided storage. The result is an IUnknown pointer to the object that is then converted to a true IOleObject pointer by a call to QueryInterface.
                    5.Populate the RichEdit Object (REOBJECT) structure so it can call InsertObject through the IRichEditOle pointer stored earlier. The following code fills this structure:
                                  REOBJECT reobject;
                                  ZeroMemory(&reobject, sizeof(REOBJECT));
                                  reobject.cbStruct = sizeof(REOBJECT);
                                  CLSID clsid;
                                  SCODE sc = m_lpObject->GetUserClassID(&clsid);
                                  if (sc != S_OK)
                                  reobject.clsid = clsid;
                                  reobject.cp = REO_CP_SELECTION;
                                  reobject.dvaspect = DVASPECT_CONTENT;
                                  reobject.dwFlags = REO_RESIZABLE | REO_BELOWBASELINE;
                                  reobject.dwUser = 0;
                                  reobject.poleobj = m_lpObject;
                                  ASSERT(m_lpClientSite != NULL);
                                  reobject.polesite = m_lpClientSite;
                                  ASSERT(m_lpStorage != NULL);
                                  reobject.pstg = m_lpStorage;
                                  SIZEL sizel;
                         = = 0;
                                  reobject.sizel = sizel; 
                    6.At this point, make the InsertObject call. Insert the bitmap at the bottom of the file. A combination of EM_GETSEL/EM_SETSEL messages selects the document's text and positions the cursor at the end.
                                  HWND hWndRT = (HWND)m_ctlRichText.GetHwnd();
                                  ::SendMessage(hWndRT, EM_SETSEL, 0, -1);
                                  DWORD dwStart, dwEnd;
                                  ::SendMessage(hWndRT, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
                                  ::SendMessage(hWndRT, EM_SETSEL, dwEnd+1, dwEnd+1); 
                    7.Call InsertObject but add a carriage return first as in the following sample:
                                  CString strCr = "\r\n";
                    8.The bitmap is dropped neatly at the bottom of the document with a carriage return separating it from the body of the text as in the following code sample:
                                  ::SendMessage(hWndRT, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0); 
                    9.This message scrolls the document to the caret position and the bitmap rolls into view. To repeat this, release the interface pointers:
                                  if (m_lpObject)
                                          m_lpObject = NULL;
                                  if (m_lpStorage)
                                          m_lpStorage = NULL;
                                  if (m_lpClientSite)
                                          m_lpClientSite = NULL;
                    10.Finally, release m_pRichEditOle.


                    • #11

                      OCX's can be loaded using Jazzage.
                      But these controls require an additional JA dll to run.
                      And then i need to distr./register a lot of stuff!

                      Not in this case i'm affraid.

                      I'm gonna take a c course maybe this year.
                      All those MS examples are in c.
                      I really have a problem reading them.
                      But also the macro's/internal functions differ a lot from basic.

                      It's not easy to convert this c code to pb unless you recode to a way PB fits i guess.
                      (Different from the original)

                      This would lead to inventing the (PB-)weel.