Solved

Rich Edit and Bitmaps

Posted on 2000-04-26
12
1,089 Views
Last Modified: 2013-12-03
How can I insert a bitmap in to a rich edit without using the clipboard or the bmp file?
0
Comment
Question by:Tony_Sebastian
  • 7
  • 5
12 Comments
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2753773
Where is you bitmap then?
0
 

Author Comment

by:Tony_Sebastian
ID: 2753797
in a hbitmap.

Thanks,
Tony.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2753881
Here is what the MS KB has to say ...
>>>>
HOWTO: Insert a Bitmap Into an RTF Document Using the RichEdit Control
ID: Q220844

--------------------------------------------------------------------------------
The information in this article applies to:

The Microsoft Foundation Classes (MFC), included with:
Microsoft Visual C++, 32-bit Editions, version 6.0

--------------------------------------------------------------------------------


SUMMARY
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.

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.

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.

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

      ASSERT_VALID(this);
      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)
            AfxThrowOleException(sc);
      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;
            AfxThrowOleException(sc);
      }
      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
      m_pRichEditOle->GetClientSite(&m_lpClientSite);

      sc = ::OleCreateFromFile(clsid, T2COLE(lpszFileName),
            IID_IUnknown, OLERENDER_DRAW, lpFormatEtc, m_lpClientSite, m_lpStorage,
            (void**)&m_lpObject);
      if (sc != S_OK)
            AfxThrowOleException(sc);

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

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

      ASSERT_VALID(this);
      return TRUE;
}

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.

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)
            AfxThrowOleException(sc);

      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;
      sizel.cx = sizel.cy = 0;
      reobject.sizel = sizel;

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

Call InsertObject but add a carriage return first as in the following sample:

      CString strCr = "\r\n";
      m_ctlRichText.SetSelText((LPCTSTR)strCr);

Finally!

      m_pRichEditOle->InsertObject(&reobject);

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

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->Release();
            m_lpObject = NULL;
      }
      if (m_lpStorage)
      {
            m_lpStorage->Release();
            m_lpStorage = NULL;
      }
      if (m_lpClientSite)
      {
            m_lpClientSite->Release();
            m_lpClientSite = NULL;
      }

Finally, release m_pRichEditOle.

Additional query words:

Keywords          : kbole kbBitmap kbCtrl kbMFC kbRichEdit kbVC600 kbDSupport
Version           : winnt:6.0
Platform          : winnt
Issue type        : kbhowto

Last Reviewed: October 8, 1999
) 1999 Microsoft Corporation. All rights reserved. Terms of Use.

--------------------------------------------------------------------------------
Send feedback to MSDN.Look here for MSDN Online resources.
>>>>
0
Active Directory Webinar

We all know we need to protect and secure our privileges, but where to start? Join Experts Exchange and ManageEngine on Tuesday, April 11, 2017 10:00 AM PDT to learn how to track and secure privileged users in Active Directory.

 

Author Comment

by:Tony_Sebastian
ID: 2756073
Adjusted points from 100 to 125
0
 

Author Comment

by:Tony_Sebastian
ID: 2756074
Yeah, I know. I don't have a file though and I don't want to create a file and then open it because the bits are already in memory at this point. I need some way to create an IDataObject using the hbitmap then I can call ::OleCreateFromStatic, or something along those lines.

Thanks for the help,
Tony.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2757774
I'd try a COleDataSource. call CacheGlobalData to put the bitmap in it, then use OleCreateFromData (similar to the above)

0
 

Author Comment

by:Tony_Sebastian
ID: 2757816
Cool, how do I get the IDataObject out of the COleDataSource object ?

Thanks,
Tony.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 2757844
NOt sure .. I'm just throwing some thoughts around here.  If I get some time I'll research a little further.
0
 

Author Comment

by:Tony_Sebastian
ID: 2757865
ok, thanks.
0
 

Author Comment

by:Tony_Sebastian
ID: 2757972
got it, COleDataSource has the IDataObject interface.

Tony.
0
 
LVL 10

Accepted Solution

by:
RONSLOW earned 125 total points
ID: 2761872
Thought it might.  Let me know how you get on.
0
 

Author Comment

by:Tony_Sebastian
ID: 2762041
Thanks, it works.
0

Featured Post

Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Set Font and Size on Excel Template 2 120
Window placement 17 87
FizzBuzz challenge 9 82
PowerPoint not providing access to all installed fonts within a family 22 512
Here is how to use MFC's automatic Radio Button handling in your dialog boxes and forms.  Beginner programmers usually start with a OnClick handler for each radio button and that's just not the right way to go.  MFC has a very cool system for handli…
Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

828 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question