Home > other >  RichEdit doesn't show pictures
RichEdit doesn't show pictures

Time:11-03

I created a simple RTF-document in WordPad, here is the screenshot:

enter image description here

It seems, that all format things of RTF work properly except pictures, which replaced by empty string. Here is RichEdit screenshot:

enter image description here

I tried both .bmp and .png. I also tried different version of RichEdit libraries: Riched20.dll and Msftedit.dll. Inside my .rtf file there is a string {\*\generator Riched20 10.0.19041}, I suppose it's a library and SDK version and in Visual Studio I use the same.

The code I use for loading RTF is popular and is taken from internet:

    static DWORD CALLBACK FileStreamCallback(DWORD dwCookie, LPBYTE pbBuff,    LONG cb, LONG* pcb)
    {
        std::ifstream* pFile = (std::ifstream*)dwCookie;
        pFile->read((char*)pbBuff, cb);
        return 0;
    }

    // ...
    std::fstream file{ filePath };
    EDITSTREAM   editStream = { 0 };
    editStream.dwCookie = (DWORD)&file;
    editStream.pfnCallback = FileStreamCallback;
    SendMessage(hwndEdit, EM_STREAMIN, SF_RTF, (LPARAM)&editStream);

And here is the RTF with cut image data for brevity:

{\rtf1\ansi\ansicpg1251\deff0\nouicompat\deflang1049\deflangfe1049{\fonttbl{\f0\fswiss\fprq2\fcharset204 Calibri;}{\f1\fswiss\fprq2\fcharset0 Calibri;}}
{\colortbl ;\red0\green0\blue255;}
{\*\generator Riched20 10.0.19041}{\*\mmathPr\mdispDef1\mwrapIndent1440 }\viewkind4\uc1 
\pard\nowidctlpar\sa200\sl240\slmult1\f0\fs22{\pict{\*\picprop}\wmetafile8\picw1323\pich1323\picwgoal750\pichgoal750 
010009000003260300000000fd02000000000400000003010800050000000b0200000000050000
// intermediate data
0000002701ffff030000000000
}\par
\strike Hello\strike0 .\par

\pard 
{\pntext\f0 a.\tab}{\*\pn\pnlvlbody\pnf0\pnindent0\pnstart1\pnlcltr{\pntxta.}}
\nowidctlpar\fi-360\li720\sa200\sl240\slmult1\f1\lang1033 34\f0\lang1049\par
{\pntext\f0 b.\tab}\f1\lang1033 28\f0\lang1049\par

\pard\nowidctlpar\sa200\sl240\slmult1 {\f1\lang1033{\field{\*\fldinst{HYPERLINK www.google.com }}{\fldrslt{www.google.com\ul0\cf0}}}}\f0\fs22\par
}

Also I've found few allegations, that RichEdit is actually can't process images using the method described above. I don't know how to treat them.

CodePudding user response:

To insert a bitmap in to richedit, see this example (InsertObject(HWND hRichEdit, LPCTSTR pszFileName))

Otherwise, the bitmap in WordPad's rtf files is save as numbers in decimal format. To read that, IRichEditOleCallback interface is needed.

Create a new file called "cole_callback.h" as follows:

#include <richole.h>

interface cole_callback : public IRichEditOleCallback
{
public:
    IStorage* pstorage;
    DWORD m_ref;
    int grfmode;
    cole_callback() : grfmode(STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE)
    {
        pstorage = nullptr;
        m_ref = 0;
        (void)StgCreateDocfile(NULL, grfmode, 0, &pstorage);
    }

    HRESULT STDMETHODCALLTYPE GetNewStorage(LPSTORAGE* lplpstg)
    {
        wchar_t name[256] = { 0 };
        return pstorage->CreateStorage(name, grfmode, 0, 0, lplpstg);
    }

    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** lplpObj)
    {
        *lplpObj = NULL;
        if (iid == IID_IUnknown || iid == IID_IRichEditOleCallback)
        {
            *lplpObj = this;
            AddRef();
            return NOERROR;
        }
        return E_NOINTERFACE;
    }

    ULONG STDMETHODCALLTYPE AddRef()
    {
        return   m_ref;
    }

    ULONG STDMETHODCALLTYPE Release()
    {
        if (--m_ref == 0) { delete this; return 0; }
        return m_ref;
    }

    STDMETHOD(GetInPlaceContext) (LPOLEINPLACEFRAME FAR*, LPOLEINPLACEUIWINDOW FAR*, LPOLEINPLACEFRAMEINFO) { return S_OK; }
    STDMETHOD(ShowContainerUI) (BOOL) { return S_OK; }
    STDMETHOD(QueryInsertObject) (LPCLSID, LPSTORAGE, LONG) { return S_OK; }
    STDMETHOD(DeleteObject) (LPOLEOBJECT) { return S_OK; }
    STDMETHOD(QueryAcceptData) (LPDATAOBJECT, CLIPFORMAT FAR*, DWORD, BOOL, HGLOBAL) { return S_OK; }
    STDMETHOD(ContextSensitiveHelp) (BOOL) { return S_OK; }
    STDMETHOD(GetClipboardData) (CHARRANGE FAR*, DWORD, LPDATAOBJECT FAR*) { return S_OK; }
    STDMETHOD(GetDragDropEffect) (BOOL, DWORD, LPDWORD) { return S_OK; }
    STDMETHOD(GetContextMenu) (WORD, LPOLEOBJECT, CHARRANGE FAR*, HMENU FAR*) { return S_OK; }
};

Next step, create a new instance of cole_callback, and send it using EM_SETOLECALLBACK message. Follow by reading the rtf file using EM_STREAMIN

#include <"cole_callback.h">
...
LoadLibrary(L"Riched20.dll");
...
cole_callback* ole_callback = new cole_callback;
...
richedit = CreateWindowEx(0, RICHEDIT_CLASS, ...

SendMessage(richedit, EM_SETOLECALLBACK, 0, (LPARAM)ole_callback);

auto callback = [](DWORD ptr, LPBYTE buf, LONG count, LONG* red)
{
    auto fp = (std::ifstream*)ptr;
    fp->read((char*)buf, count);
    *red = (LONG)fp->gcount();
    return DWORD(0);
};
std::ifstream fin(L"c:/test/document.rtf", std::ios::binary);
EDITSTREAM es{ (DWORD_PTR)&fin, 0, callback };
SendMessage(richedit, EM_STREAMIN, WPARAM(SF_RTF), (LPARAM)&es);
  • Related