// リッチエディットにビットマップOle オブジェクトを貼り付けるためのコード
// http://www.codeguru.com/Cpp/controls/richedit/article.php/c5383/
// ビットマップは勝手に開放しないよう注意する。(まぁ、あたりまえか。)
// アーカイブ所在 C:\ProgramFolder\Practice\Comm
class CImageDataObject : IDataObject
{
public:
// This static function accepts a pointer to IRochEditOle
// and the bitmap handle.
// After that the function insert the image in the current
// position of the RichEdit
//
static void InsertBitmap(IRichEditOle* pRichEditOle,
HBITMAP hBitmap);
private:
ULONG m_ulRefCnt;
BOOL m_bRelease;
// The data being bassed to the richedit
//
STGMEDIUM m_stgmed;
FORMATETC m_fromat;
public:
CImageDataObject() : m_ulRefCnt(0) {
m_bRelease = FALSE;
}
~CImageDataObject() {
if (m_bRelease)
::ReleaseStgMedium(&m_stgmed);
}
// Methods of the IUnknown interface
//
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{
if (iid == IID_IUnknown || iid == IID_IDataObject)
{
*ppvObject = this;
AddRef();
return S_OK;
}
else
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)(void)
{
m_ulRefCnt++;
return m_ulRefCnt;
}
STDMETHOD_(ULONG, Release)(void)
{
if (--m_ulRefCnt == 0)
{
delete this;
}
return m_ulRefCnt;
}
// Methods of the IDataObject Interface
//
STDMETHOD(GetData)(FORMATETC *pformatetcIn,
STGMEDIUM *pmedium) {
HANDLE hDst;
hDst = ::OleDuplicateData(m_stgmed.hBitmap,
CF_BITMAP, NULL);
if (hDst == NULL)
{
return E_HANDLE;
}
pmedium->tymed = TYMED_GDI;
pmedium->hBitmap = (HBITMAP)hDst;
pmedium->pUnkForRelease = NULL;
return S_OK;
}
STDMETHOD(GetDataHere)(FORMATETC* pformatetc,
STGMEDIUM* pmedium ) {
return E_NOTIMPL;
}
STDMETHOD(QueryGetData)(FORMATETC* pformatetc ) {
return E_NOTIMPL;
}
STDMETHOD(GetCanonicalFormatEtc)(FORMATETC* pformatectIn ,
FORMATETC* pformatetcOut ) {
return E_NOTIMPL;
}
STDMETHOD(SetData)(FORMATETC* pformatetc ,
STGMEDIUM* pmedium ,
BOOL fRelease ) {
m_fromat = *pformatetc;
m_stgmed = *pmedium;
return S_OK;
}
STDMETHOD(EnumFormatEtc)(DWORD dwDirection ,
IEnumFORMATETC** ppenumFormatEtc ) {
return E_NOTIMPL;
}
STDMETHOD(DAdvise)(FORMATETC *pformatetc,
DWORD advf,
IAdviseSink *pAdvSink,
DWORD *pdwConnection) {
return E_NOTIMPL;
}
STDMETHOD(DUnadvise)(DWORD dwConnection) {
return E_NOTIMPL;
}
STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise) {
return E_NOTIMPL;
}
// Some Other helper functions
//
void SetBitmap(HBITMAP hBitmap);
IOleObject *GetOleObject(IOleClientSite *pOleClientSite,
IStorage *pStorage);
};
// ImageDataObject.h: Impementation for IDataObject Interface to be used
// in inserting bitmap to the RichEdit Control.
//
// Author : Hani Atassi (atassi@arabteam2000.com)
//
// How to use : Just call the static member InsertBitmap with
// the appropriate parrameters.
//
// Known bugs :
//
//
//////////////////////////////////////////////////////////////////////
#define NO_STDAFX_H
#ifndef NO_STDAFX_H
#include "stdafx.h"
#else
#define ASSERT assert
#endif
//////////////////////////////////////////////////////////////////////
// Static member functions
//////////////////////////////////////////////////////////////////////
void CImageDataObject::InsertBitmap(IRichEditOle* pRichEditOle, HBITMAP hBitmap)
{
SCODE sc;
// Get the image data object
//
CImageDataObject *pods = new CImageDataObject;
LPDATAOBJECT lpDataObject;
pods->QueryInterface(IID_IDataObject, (void **)&lpDataObject);
pods->SetBitmap(hBitmap);
// Get the RichEdit container site
//
IOleClientSite *pOleClientSite;
pRichEditOle->GetClientSite(&pOleClientSite);
// Initialize a Storage Object
//
IStorage *pStorage;
LPLOCKBYTES lpLockBytes = NULL;
sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
#ifndef NO_STDAFX_H
if (sc != S_OK)
AfxThrowOleException(sc);
#endif
ASSERT(lpLockBytes != NULL);
sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &pStorage);
if (sc != S_OK)
{
#ifndef NO_STDAFX_H
VERIFY(lpLockBytes->Release() == 0);
lpLockBytes = NULL;
AfxThrowOleException(sc);
#else
lpLockBytes->Release() ;
lpLockBytes = NULL;
#endif
}
ASSERT(pStorage != NULL);
// The final ole object which will be inserted in the richedit control
//
IOleObject *pOleObject;
pOleObject = pods->GetOleObject(pOleClientSite, pStorage);
// all items are "contained" -- this makes our reference to this object
// weak -- which is needed for links to embedding silent update.
OleSetContainedObject(pOleObject, TRUE);
// Now Add the object to the RichEdit
//
REOBJECT reobject;
ZeroMemory(&reobject, sizeof(REOBJECT));
reobject.cbStruct = sizeof(REOBJECT);
CLSID clsid;
sc = pOleObject->GetUserClassID(&clsid);
#ifndef NO_STDAFX_H
if (sc != S_OK)
AfxThrowOleException(sc);
#endif
reobject.clsid = clsid;
reobject.cp = REO_CP_SELECTION;
reobject.dvaspect = DVASPECT_CONTENT;
reobject.poleobj = pOleObject;
reobject.polesite = pOleClientSite;
reobject.pstg = pStorage;
// Insert the bitmap at the current location in the richedit control
//
pRichEditOle->InsertObject(&reobject);
// Release all unnecessary interfaces
//
pOleObject->Release();
pOleClientSite->Release();
pStorage->Release();
lpDataObject->Release();
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
void CImageDataObject::SetBitmap(HBITMAP hBitmap)
{
ASSERT(hBitmap);
STGMEDIUM stgm;
stgm.tymed = TYMED_GDI; // Storage medium = HBITMAP handle
stgm.hBitmap = hBitmap;
stgm.pUnkForRelease = NULL; // Use ReleaseStgMedium
FORMATETC fm;
fm.cfFormat = CF_BITMAP; // Clipboard format = CF_BITMAP
fm.ptd = NULL; // Target Device = Screen
fm.dwAspect = DVASPECT_CONTENT; // Level of detail = Full content
fm.lindex = -1; // Index = Not applicaple
fm.tymed = TYMED_GDI; // Storage medium = HBITMAP handle
this->SetData(&fm, &stgm, TRUE);
}
IOleObject *CImageDataObject::GetOleObject(IOleClientSite *pOleClientSite, IStorage *pStorage)
{
ASSERT(m_stgmed.hBitmap);
SCODE sc;
IOleObject *pOleObject;
sc = ::OleCreateStaticFromData(this, IID_IOleObject, OLERENDER_FORMAT,
&m_fromat, pOleClientSite, pStorage, (void **)&pOleObject);
#ifndef NO_STDAFX_H
if (sc != S_OK)
AfxThrowOleException(sc);
#endif
return pOleObject;
}
#undef ASSERT
/************************************************************************
If you want object insertion operations to work in your RichEdit Control,
you have to supply an IRichEditOleCallback interface
and implement the GetNewStorage method.
*************************************************************************/
// Set-up the OLE Callback
/*******************************************************************
IRichEditOleCallback* mREOLECallback = new IExtRichEditOleCallback ;
&&&&
::SendMessage( mHWnd, EM_SETOLECALLBACK, 0, (LPARAM) mREOLECallback);
********************************************************************/
// and also, had better set "ES_NOOLEDRAGDROP" ?
// Class definition
extern HWND hStatus , hMainEdit ;
int iCall ;
class IExtRichEditOleCallback : IRichEditOleCallback
{
public:
// Constructor / Destructor
IExtRichEditOleCallback () { mRefCounter = 0; }
~IExtRichEditOleCallback () {}
// Methods of the IUnknown interface
STDMETHOD_(ULONG, AddRef) (void) { mRefCounter++; return mRefCounter; }
STDMETHOD_(ULONG, Release) (void) { if ( --mRefCounter == 0 ) delete this; return mRefCounter; }
STDMETHOD(QueryInterface) (REFIID iid, void** ppvObject)
{
if (iid == IID_IUnknown || iid == IID_IRichEditOleCallback) { *ppvObject = this; AddRef(); return S_OK; }
else { return E_NOINTERFACE ;}
}
// Methods of the IRichEditOleCallback interface
STDMETHOD(ContextSensitiveHelp) (BOOL fEnterMode) { return E_NOTIMPL; }
STDMETHOD(DeleteObject) (LPOLEOBJECT lpoleobj)
{ // my implementation.
// by my experiment ..not called .
return E_NOTIMPL; }
STDMETHOD(GetClipboardData) (CHARRANGE FAR *lpchrg, DWORD reco, LPDATAOBJECT FAR *lplpdataobj) { return E_NOTIMPL; }
STDMETHOD(GetContextMenu) (WORD seltype, LPOLEOBJECT lpoleobj, CHARRANGE FAR *lpchrg, HMENU FAR *lphmenu) { return E_NOTIMPL; }
STDMETHOD(GetDragDropEffect) (BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect) { return E_NOTIMPL; }
STDMETHOD(GetInPlaceContext) (LPOLEINPLACEFRAME FAR *lplpFrame, LPOLEINPLACEUIWINDOW FAR *lplpDoc, LPOLEINPLACEFRAMEINFO lpFrameInfo)
{ // my implementation.
// by my experiment ..not called .
return E_NOTIMPL; }
STDMETHOD(GetNewStorage) (LPSTORAGE FAR *lplpstg);
//エラー E2352 ezfax.cpp 774: 抽象クラス 'IExtRichEditOleCallback ' の変数は作成できない(関数
// __stdcall WndProc(HWND__ *,unsigned int,unsigned int,long) )
//エラー E2353 ezfax.cpp 774: クラス 'IExtRichEditOleCallback ' は抽象クラス('__stdcall IRic
//hEditOleCallback::GetNewStorage(IStorage * *) = 0' のため)(関数 __stdcall WndPr
//oc(HWND__ *,unsigned int,unsigned int,long) )
STDMETHOD(QueryAcceptData) (LPDATAOBJECT lpdataobj, CLIPFORMAT FAR *lpcfFormat, DWORD reco, BOOL fReally, HGLOBAL hMetaPict)
{ // my implementation.
// by my experiment ..not called .
return E_NOTIMPL; }
STDMETHOD(QueryInsertObject) (LPCLSID lpclsid, LPSTORAGE lpstg, LONG cp)
{ // my implementation.
// by my experiment ..called TWICE.
char sztext[256] ;
wsprintf( sztext , "oyobare %d" , ++ iCall ) ;
StatusBar_SetText( hStatus , 0 , sztext ) ;
return S_OK; }
STDMETHOD(ShowContainerUI) (BOOL fShow)
{ // my implementation.
// by my experiment ..not called .
return E_NOTIMPL; }
// Data
private:
DWORD mRefCounter; // udword ?
};
// Class implementation
//Error: 外部シンボル '__stdcall IExtRichEditOleCallback ::GetNewStorage(IStorage * *)' が未
//解決(C:\PROGRAMFOLDER\PRACTICE\COMM\EZFAX.OBJ が参照)
STDMETHODIMP IExtRichEditOleCallback ::GetNewStorage(LPSTORAGE FAR *lplpstg)
{
// Initialize a Storage Object from a DocFile in memory
LPLOCKBYTES lpLockBytes = NULL;
SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
if (sc != S_OK) return sc;
sc = ::StgCreateDocfileOnILockBytes(lpLockBytes, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, lplpstg);
if (sc != S_OK) lpLockBytes->Release();
return sc;
}