これは可能です。ただし、必要なコールバックはIRichEditOleCallback COM インターフェイス内に存在するため、.NET RichTextBox インターフェイスの境界を離れる必要があります。
ATL C++ で何が関係しているかを理解するために (ただし、これが機能するという保証はありません。作業している言語に関係なく、Plain Ol' COM オブジェクトを作成する方法に適応させる必要があります)。
#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](https://msdn.microsoft.com/en-us/library/ff729168.aspx)
// 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
else
{
*lpcfFormat = CF_UNICODETEXT;
// Are we being asked to paste this?
if (fReally)
{
// Insert the data as text with the default style
FORMATETC fmt = {*lpcfFormat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM stg;
HRESULT res = E_UNEXPECTED;
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)
{
ReleaseStgMedium(stg);
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);
text.append(buffer[0]);
}
// 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());
GlobalUnlock(stg.hGlobal);
ReleaseStgMedium(stg);
// 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;
}
else
{
// 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);
cb->SetRichEditCtl(hRichEdit);
SendMessage(hRichEdit, EM_SETOLECALLBACK, 0, cb);
}
}