The RichTextEdit control in .NET does 99% of what I need to do for my application, except for a few little things:

  1. I want to disallow pasting/dragging images into the control
  2. When text is pasted/dragged into the control, I want to reset its style to the control's default

As far as I can work out, Microsoft hasn't provided any type of "no images" property on this control that you can use, which would be ideal.

My thought was that I could respond to the "textChanged" event then remove the image and/or reset the text style before it gets rendered to the screen. Of course this would be a total hack. For one thing, the user's drag&drop mouse icon would indicate that images are droppable and they really aren't.

To make a long question short, is there a way to set a filter on what type of data types a RichTextEdit control can import via Copy&Paste and Drag&Drop?

No correct solution


This is possible; however, you'll have to leave the confines of the .NET RichTextBox interface to do it, as the callback needed lives in the IRichEditOleCallback COM interface.

To give you an idea of what's involved, in ATL C++ (no guarantees that this will work though, and you'll have to adapt it to however you create a Plain Ol' COM Object in whatever language you're working in):

#include <windows.h>
#include <Richole.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlcomcli.h>
#include <string>

struct RattyRichEditOleCallbackImpl: public CComObjectRoot, public IRichEditOleCallback
  HWND* hRichEdit;
  RattyRichEditOleCallbackImpl(): hRichEdit(NULL) {}
  HRESULT SetRichEditCtl(HWND *hCtl)
    hRichEdit = hCtl;
    return S_OK;
  HRESULT QueryAcceptData(LPDATAOBJECT lpdataobj, CLIPFORMAT* lpcfFormat, DWORD reco, BOOL fReally, HGLOBAL hMetaPict)
    // This list of image formats covers all the standard ones listed in
    // the [MSDN docs](
    // if there are more CF_blahs that correspond to images, add them here
    if (*lpcfFormat == CF_DIB || *lpcfFormat == CF_DIBV5
      || *lpcfFormat == CF_BITMAP || *lpcfFormat == CF_TIFF
      || *lpcfFormat == CF_ENHMETAFILE || *lpcfFormat == CF_METAFILEPICT
      || *lpcfFormat == CF_PALETTE || *lpcfFormat == CF_DSPBITMAP
      || *lpcfFormat == CF_DSPMETAFILEPICT || *lpcfFormat == CF_DSPENHMETAFILE
      || *lpcfFormat >= CF_GDIOBJECTFIRST || *lpcfFormat <= CF_GDIOBJECTLAST)
      // Bail out with an error HRESULT because we don't want some stinkin' image in our rich edit control!
      return E_NOTIMPL;
    // Try to convert anything else to plain ol' Unicode text
      *lpcfFormat = CF_UNICODETEXT;
      // Are we being asked to paste this?
      if (fReally)
        // Insert the data as text with the default style
        STGMEDIUM stg;
        if (hRichEdit && (res = lpdataobj->GetData(fmt, stg)) == S_OK)
          // Lock the HGLOBAL as it might not be ordinary heap mem
          WCHAR* pText = GlobalLock(stg.hGlobal);
          if (!pText)
            return res;
          std::wstring text(pText);

          // Do a bit of selection trickiness to ensure we have the default text style -- we can't just EM_PASTESPECIAL due to recursion issues
          DWORD cursorPos, selPos;
          SendMessageW(hRichEdit, EM_GETSEL, &cursorPos, &selPos);
          if (cursorPos == selPos)
            // No selection, so select the character after the cursor, fetch it, and append it to the text
            SendMessageW(hRichEdit, EM_SETSEL, cursorPos, cursorPos + 1);
            WCHAR buffer[2];
            TEXTRANGEW tr = {{cursorPos, cursorPos + 1}, buffer};
            SendMessageW(hRichEdit, EM_GETTEXTRANGE, 0, &tr);
          // Now that we have ourselves a selection -- we can unformat it then replace it
          CHARFORMAT2 cf;
          cf.cbSize = sizeof(CHARFORMAT2);
          SendMessageW(hRichEdit, EM_GETCHARFORMAT, SCF_DEFAULT, &cf);
          SendMessageW(hRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, &cf);
          SendMessageW(hRichEdit, EM_REPLACESEL, TRUE, text.c_str());

          // We did the work ourselves, so don't ask the control to do anything for us, unless something broke that is
          res = S_FALSE;
        return res;
        // Have the control check for us to see if it can coerce what's on the clipboard to CF_UNICODETEXT
        return S_OK;

typedef CComObject<RattyRichEditOleCallbackImpl> RattyRichEditOleCallback;

inline void AttachRattyCallbackToRichEdit(HWND *hRichEdit)
  RattyRichEditOleCallback* pCb;
  if (RattyRichEditOleCallback::CreateInstance(&pCb) == S_OK)
    CComPtr cb(pCb);
    SendMessage(hRichEdit, EM_SETOLECALLBACK, 0, cb);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow