[戻る]

// リッチエディットにビットマップ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;
}