아래는 소스코드인데, 이것을 컴포넌트화 시켜서 컴파일 하셔야 할 것 같습니다. 조금 된 자료라서 확실히 동작이 증명된것은 아니구요.. 만약 이것이 애로사항이 많다면.. 제가 안내해드린 그 컴포넌트에서 OLE 부분만 참고하셔도 될것 같습니다.
[header file]
//===========================================================================
// Copyright ?1998 Thin Air Enterprises and Robert Dunn
//===========================================================================
//---------------------------------------------------------------------------
// class TIRichEditOle - adds basic OLE functionality to TRichEdit.
// Based on code found at
http://www.dystopia.fi/~janij/techinfo/richedit.htm
// and presumably written by Jani J꼛vinen. Thanks, Jani.
//
// Additional code developed through examination of Borland's VCL
library,
// Microsoft's MFC source code, and sample code available on Microsoft's
// developer web site.
//
// Note that this code is very experimental -- the author admits to only
a
// vague familiarity with OLE and accepts no criticism of the code.
Many,
// if not most, of the interfaces return failure codes arbitrarily
chosen by
// the author with no particular reason to think that the values are
correct.
// In particular, no great effort has been expended looking for "memory
// leaks," and these are considered quite probable. You have been
warned.
//---------------------------------------------------------------------------
#ifndef RichEditOLEH
#define RichEditOLEH
#include <ole2.h>
#include <oledlg.h>
#include <richole.h>
//#include <vcl\clipbrd.hpp>
#include "richeditolecallback.h"
//#include "richeditole.h"
//---------------------------------------------------------------------------
class TIRichEditOle
{
protected:
TRichEdit* FRichEdit;
IRichEditOle* FIRichEditOle;
TIRichEditOleCallback* FIRichEditCallback;
LONG GetObjectCount(void);
LONG GetLinkCount(void);
UINT CFObjectDescriptor;
UINT CFEmbeddedObject;
UINT CFLinkSource;
UINT CFRtf;
UINT CFRtfNoObjs;
UINT CFReTextObjs;
public:
TIRichEditOle(TRichEdit* richedit);
~TIRichEditOle(void);
void SetHostNames(AnsiString hostApp, AnsiString hostDoc);
bool InsertObject(void);
bool PasteSpecial(void);
bool CloseActiveObjects(bool savePrompt);
LPOLECLIENTSITE GetClientSite(void);
__property LONG ObjectCount = { read = GetObjectCount };
__property LONG LinkCount = { read = GetLinkCount };
};
#endif
//===========================================================================
// Copyright ?1998 Thin Air Enterprises and Robert Dunn
//===========================================================================
[cpp file]
//===========================================================================
// Copyright ?1998 Thin Air Enterprises and Robert Dunn
//===========================================================================
//---------------------------------------------------------------------------
// class TIRichEditOle - adds basic OLE functionality to TRichEdit.
// Based on code found at
http://www.dystopia.fi/~janij/techinfo/richedit.htm
// and presumably written by Jani J꼛vinen. Thanks, Jani.
//
// Additional code developed through examination of Borland's VCL
library,
// Microsoft's MFC source code, and sample code available on Microsoft's
// developer web site.
//
// Note that this code is very experimental -- the author admits to only
a
// vague familiarity with OLE and accepts no criticism of the code.
Many,
// if not most, of the interfaces return failure codes arbitrarily
chosen by
// the author with no particular reason to think that the values are
correct.
// In particular, no great effort has been expended looking for "memory
// leaks," and these are considered quite probable. You have been
warned.
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#define DEBUG 0
#include <taeassert.h>
#include "RichEditOLE.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
// utiltiy functions
//---------------------------------------------------------------------------
//
static void OleUIMetafilePictIconFree(HGLOBAL hMetaPict)
{
if (!hMetaPict) return;
LPMETAFILEPICT pMF = (LPMETAFILEPICT) GlobalLock(hMetaPict);
if (pMF && pMF->hMF) DeleteMetaFile(pMF->hMF);
GlobalUnlock(hMetaPict);
GlobalFree(hMetaPict);
return;
}
static HRESULT OleStdSwitchDisplayAspect(LPOLEOBJECT lpOleObj,
LPDWORD lpdwCurAspect, DWORD dwNewAspect, HGLOBAL hMetaPict,
BOOL fDeleteOldAspect, BOOL fSetupViewAdvise, LPADVISESINK
lpAdviseSink,
LPBOOL lpfMustUpdate)
{
LPOLECACHE lpOleCache = NULL;
LPVIEWOBJECT lpViewObj = NULL;
LPENUMSTATDATA lpEnumStatData = NULL;
STATDATA StatData;
FORMATETC FmtEtc;
STGMEDIUM Medium;
DWORD dwAdvf;
DWORD dwNewConnection;
DWORD dwOldAspect = *lpdwCurAspect;
HRESULT hrErr;
if (lpfMustUpdate) *lpfMustUpdate = FALSE;
lpOleObj->QueryInterface(IID_IOleCache, (LPVOID*)&lpOleCache);
// if IOleCache* is NOT available, do nothing
if (!lpOleCache) return E_INVALIDARG;
// Setup new cache with the new aspect
FmtEtc.cfFormat = 0; // whatever is needed to draw
FmtEtc.ptd = NULL;
FmtEtc.dwAspect = dwNewAspect;
FmtEtc.lindex = -1;
FmtEtc.tymed = TYMED_NULL;
/* OLE2NOTE: if we are setting up Icon aspect with a custom icon
** then we do not want DataAdvise notifications to ever change
** the contents of the data cache. thus we set up a NODATA
** advise connection. otherwise we set up a standard DataAdvise
** connection.
*/
if (dwNewAspect == DVASPECT_ICON && hMetaPict) dwAdvf = ADVF_NODATA;
else dwAdvf = ADVF_PRIMEFIRST;
hrErr = lpOleCache->Cache(&FmtEtc, dwAdvf, &dwNewConnection);
if (!SUCCEEDED(hrErr)) {
lpOleCache->Release();
return hrErr;
}
*lpdwCurAspect = dwNewAspect;
/* OLE2NOTE: if we are setting up Icon aspect with a custom icon,
** then stuff the icon into the cache. otherwise the cache must
** be forced to be updated. set the *lpfMustUpdate flag to tell
** caller to force the object to Run so that the cache will be
** updated.
*/
if (dwNewAspect == DVASPECT_ICON && hMetaPict) {
FmtEtc.cfFormat = CF_METAFILEPICT;
FmtEtc.ptd = NULL;
FmtEtc.dwAspect = DVASPECT_ICON;
FmtEtc.lindex = -1;
FmtEtc.tymed = TYMED_MFPICT;
Medium.tymed = TYMED_MFPICT;
Medium.hGlobal = hMetaPict;
Medium.pUnkForRelease = NULL;
hrErr = lpOleCache->SetData(&FmtEtc, &Medium, FALSE /* fRelease */);
}
else if (lpfMustUpdate) *lpfMustUpdate = TRUE;
if (fSetupViewAdvise && lpAdviseSink) {
/* OLE2NOTE: re-establish the ViewAdvise connection */
lpOleObj->QueryInterface(IID_IViewObject, (LPVOID*)&lpViewObj);
if (lpViewObj) {
lpViewObj->SetAdvise(dwNewAspect, 0, lpAdviseSink);
lpViewObj->Release();
}
}
/* OLE2NOTE: remove any existing caches that are set up for the old
** display aspect. It WOULD be possible to retain the caches set
** up for the old aspect, but this would increase the storage
** space required for the object and possibly require additional
** overhead to maintain the unused cachaes. For these reasons the
** strategy to delete the previous caches is prefered. If it is a
** requirement to quickly switch between Icon and Content
** display, then it would be better to keep both aspect caches.
*/
if (fDeleteOldAspect) {
hrErr = lpOleCache->EnumCache(&lpEnumStatData);
while (hrErr == NOERROR) {
hrErr = lpEnumStatData->Next(1, &StatData, NULL);
if (hrErr != NOERROR) break; // DONE! no more caches.
if (StatData.formatetc.dwAspect == dwOldAspect)
// Remove previous cache with old aspect
lpOleCache->Uncache(StatData. dwConnection);
}
if (lpEnumStatData)
if (lpEnumStatData->Release())
throw EOleError("OleStdSwitchDisplayAspect: Cache enumerator NOT
released");
}
if (lpOleCache) lpOleCache->Release();
return NOERROR;
}
//---------------------------------------------------------------------------
// TIRichEditOle
//
TIRichEditOle::TIRichEditOle(TRichEdit* richedit) : FIRichEditOle(0)
{
TAEASSERT(richedit /* invalid richedit handle */);
// do we need to call OleInitialize(NULL)? seems to work without it...
::OleInitialize(0);
FIRichEditCallback = new TIRichEditOleCallback(richedit);
// FIRichEditCallback->AddRef();
FRichEdit = richedit;
::SendMessage(richedit->Handle, EM_SETOLECALLBACK, 0, (LPARAM)
(LPRICHEDITOLECALLBACK) FIRichEditCallback);
if (!::SendMessage(richedit->Handle, EM_GETOLEINTERFACE, 0, (LPARAM)
&FIRichEditOle))
FIRichEditOle = 0;
// register clipboard formats used in ole (so we'll have the clipboard
// format IDs for ole clipboard operations (like OleUIPasteSpecial)
CFObjectDescriptor = RegisterClipboardFormat("Object Descriptor");
CFEmbeddedObject = RegisterClipboardFormat("Embedded Object");
CFLinkSource = RegisterClipboardFormat("Link Source");
CFRtf = RegisterClipboardFormat(CF_RTF);
CFRtfNoObjs = RegisterClipboardFormat(CF_RTFNOOBJS);
CFReTextObjs = RegisterClipboardFormat(CF_RETEXTOBJ);
}
//---------------------------------------------------------------------------
TIRichEditOle::~TIRichEditOle(void)
{
// close any active objects unconditionally
if (FIRichEditOle) CloseActiveObjects(false);
// set the callback to null
::SendMessage(FRichEdit->Handle, EM_SETOLECALLBACK, 0, (LPARAM) 0);
// release the interface
if (FIRichEditOle) {
// FIRichEditOle->Release();
FIRichEditOle = 0;
}
if (FIRichEditCallback) {
delete FIRichEditCallback;
FIRichEditCallback = 0;
}
// balance calls to OleInitialize()
OleUninitialize();
}
//---------------------------------------------------------------------------
void TIRichEditOle::SetHostNames(AnsiString hostApp, AnsiString hostDoc)
{
if (!FIRichEditOle) return;
FIRichEditOle->SetHostNames(hostApp.c_str(), hostDoc.c_str());
}
//---------------------------------------------------------------------------
LPOLECLIENTSITE TIRichEditOle::GetClientSite(void)
{
LPOLECLIENTSITE clientSite;
if (FIRichEditOle->GetClientSite(&clientSite) != S_OK) clientSite = 0;
return clientSite;
}
//---------------------------------------------------------------------------
LONG TIRichEditOle::GetObjectCount(void)
{
if (!FIRichEditOle) throw EOleError("IRichEditOle interface is not
valid.");
return FIRichEditOle->GetObjectCount();
}
//---------------------------------------------------------------------------
LONG TIRichEditOle::GetLinkCount(void)
{
if (!FIRichEditOle) throw EOleError("IRichEditOle interface is not
valid.");
return FIRichEditOle->GetLinkCount();
}
//---------------------------------------------------------------------------
bool TIRichEditOle::InsertObject(void)
{
LPOLEOBJECT pOleObject = 0;
// better be a valid richedit
if (!FRichEdit) return false;
// make sure client site is valid
LPOLECLIENTSITE pClientSite = GetClientSite();
if (!pClientSite) throw EOleError("IOleClientSite interface is not
valid.");
// get substorage
LPSTORAGE pStg;
if (FIRichEditCallback->GetNewStorage(&pStg) != S_OK) {
pClientSite->Release();
throw EOleError("GetNewStorage failed.");
}
// display the InsertObject dialog
TCHAR buf[MAX_PATH];
buf[0] = 0;
OLEUIINSERTOBJECT io;
::memset(&io, 0, sizeof(io));
io.cbStruct = sizeof(io);
io.dwFlags = IOF_SHOWHELP | IOF_CREATENEWOBJECT | IOF_CREATEFILEOBJECT
|
IOF_SELECTCREATENEW | IOF_CREATELINKOBJECT;
io.hWndOwner = Application->MainForm->Handle;
io.lpszFile = buf;
io.cchFile = sizeof(buf);
io.iid = IID_IOleObject;
io.oleRender = OLERENDER_DRAW;
io.lpIOleClientSite = pClientSite;
io.lpIStorage = pStg;
io.ppvObj = (void**) &pOleObject;
io.clsid = CLSID_NULL;
DWORD retVal = ::OleUIInsertObject(&io);
if (retVal != OLEUI_SUCCESS) {
pClientSite->Release();
pStg->Release();
if (io.hMetaPict) ::OleUIMetafilePictIconFree(io.hMetaPict);
if (pOleObject) pOleObject->Release();
if (retVal == OLEUI_CANCEL) return false;
throw EOleError("Insert Object dialog returned failure.");
}
// got the object
pOleObject = (LPOLEOBJECT) *io.ppvObj;
REOBJECT reObj;
::memset(&reObj, 0, sizeof(reObj));
reObj.cbStruct = sizeof(reObj);
reObj.cp = REO_CP_SELECTION;
reObj.clsid = io.clsid;
reObj.poleobj = pOleObject;
reObj.pstg = pStg;
reObj.polesite = pClientSite;
reObj.dvaspect = DVASPECT_CONTENT;
reObj.dwFlags = REO_RESIZABLE;
if (io.dwFlags & IOF_SELECTCREATENEW) reObj.dwFlags |= REO_BLANK;
// try to get a valid clsid
if (::IsEqualCLSID(reObj.clsid, CLSID_NULL)) {
#ifdef UNICODE
::GetClassFile(buf, &reObj.clsid);
#else
WCHAR bufFile[MAX_PATH];
::MultiByteToWideChar(CP_ACP, 0, buf, -1, bufFile, sizeof(bufFile));
::GetClassFile(bufFile, &reObj.clsid);
#endif
}
// display as icon?
if (io.dwFlags & IOF_CHECKDISPLAYASICON) {
int fUpdate;
if (::OleStdSwitchDisplayAspect(pOleObject, &reObj.dvaspect,
DVASPECT_ICON, io.hMetaPict, true, false, 0, &fUpdate))
Application->MessageBox("Cannot display object as icon.",
"Insert Object", MB_OK | MB_ICONWARNING);
}
// insert the object into the richedit
if (FIRichEditOle->InsertObject(&reObj) != S_OK) {
pClientSite->Release();
pStg->Release();
if (io.hMetaPict) OleUIMetafilePictIconFree(io.hMetaPict);
if (pOleObject) pOleObject->Release();
throw EOleError("RichEdit refused to insert object.");
}
// if new object, do the show verb
if (io.dwFlags & IOF_SELECTCREATENEW) {
// get object position
POINT pt;
// hey! where is REO_IOB_SELECTION documented!
::SendMessage(FRichEdit->Handle, EM_POSFROMCHAR, (WPARAM) &pt,
REO_IOB_SELECTION);
RECT rect = { 0, 0, 100, 100 };
::OffsetRect(&rect, pt.x, pt.y);
pOleObject->DoVerb(OLEIVERB_SHOW, 0, pClientSite, 0,
FRichEdit->Handle, &rect);
}
pClientSite->Release();
pStg->Release();
if (io.hMetaPict) OleUIMetafilePictIconFree(io.hMetaPict);
if (pOleObject) pOleObject->Release();
return true;
}
//---------------------------------------------------------------------------
bool TIRichEditOle::PasteSpecial(void)
{
TOleUIPasteSpecial data;
TOleUIPasteEntry formats[8];
::memset(&data, 0, sizeof(data));
::memset(&formats, 0, sizeof(formats));
data.cbStruct = sizeof(data);
data.hWndOwner = Application->MainForm->Handle;
data.arrPasteEntries = formats;
data.cPasteEntries = sizeof(formats) / sizeof(formats[0]);
data.arrLinkTypes = &CFLinkSource;
data.cLinkTypes = 1;
// the following entries were devined from MS MFC code and appear to
// be fairly standard for rich edit controls; this is basically a
static
// table and could be moved, but the overhead here is small...
formats[0].fmtetc.cfFormat = (CLIPFORMAT) CFEmbeddedObject;
formats[0].fmtetc.dwAspect = DVASPECT_CONTENT;
formats[0].fmtetc.lindex = -1;
formats[0].fmtetc.tymed = TYMED_ISTORAGE;
formats[0].lpstrFormatName = "%s";
formats[0].lpstrResultText = "%s";
formats[0].dwFlags = OLEUIPASTE_PASTE | OLEUIPASTE_ENABLEICON;
formats[1].fmtetc.cfFormat = (CLIPFORMAT) CFLinkSource;
formats[1].fmtetc.dwAspect = DVASPECT_CONTENT;
formats[1].fmtetc.lindex = -1;
formats[1].fmtetc.tymed = TYMED_ISTREAM;
formats[1].lpstrFormatName = "%s";
formats[1].lpstrResultText = "%s";
formats[1].dwFlags = OLEUIPASTE_LINKTYPE1 | OLEUIPASTE_ENABLEICON;
formats[2].fmtetc.cfFormat = CF_TEXT;
formats[2].fmtetc.dwAspect = DVASPECT_CONTENT;
formats[2].fmtetc.lindex = -1;
formats[2].fmtetc.tymed = TYMED_HGLOBAL;
formats[2].lpstrFormatName = "Unformatted Text";
formats[2].lpstrResultText = "text without any formatting";
formats[2].dwFlags = OLEUIPASTE_PASTEONLY;
formats[3].fmtetc.cfFormat = (CLIPFORMAT) CFRtf;
formats[3].fmtetc.dwAspect = DVASPECT_CONTENT;
formats[3].fmtetc.lindex = -1;
formats[3].fmtetc.tymed = TYMED_HGLOBAL;
formats[3].lpstrFormatName = "Formatted Text (RTF)";
formats[3].lpstrResultText = "text with font and paragraph formatting";
formats[3].dwFlags = OLEUIPASTE_PASTEONLY;
formats[4].fmtetc.cfFormat = CF_ENHMETAFILE;
formats[4].fmtetc.dwAspect = DVASPECT_CONTENT;
formats[4].fmtetc.lindex = -1;
formats[4].fmtetc.tymed = TYMED_ENHMF;
formats[4].lpstrFormatName = "Picture (Enhanced Metafile)";
formats[4].lpstrResultText = "a picture";
formats[4].dwFlags = OLEUIPASTE_PASTEONLY;
formats[5].fmtetc.cfFormat = CF_METAFILEPICT;
formats[5].fmtetc.dwAspect = DVASPECT_CONTENT;
formats[5].fmtetc.lindex = -1;
formats[5].fmtetc.tymed = TYMED_MFPICT;
formats[5].lpstrFormatName = "Picture (Metafile)";
formats[5].lpstrResultText = "a picture";
formats[5].dwFlags = OLEUIPASTE_PASTEONLY;
formats[6].fmtetc.cfFormat = CF_DIB;
formats[6].fmtetc.dwAspect = DVASPECT_CONTENT;
formats[6].fmtetc.lindex = -1;
formats[6].fmtetc.tymed = TYMED_MFPICT;
formats[6].lpstrFormatName = "Device Independent Bitmap";
formats[6].lpstrResultText = "a device independent bitmap";
formats[6].dwFlags = OLEUIPASTE_PASTEONLY;
formats[7].fmtetc.cfFormat = CF_BITMAP;
formats[7].fmtetc.dwAspect = DVASPECT_CONTENT;
formats[7].fmtetc.lindex = -1;
formats[7].fmtetc.tymed = TYMED_GDI;
formats[7].lpstrFormatName = "Bitmap";
formats[7].lpstrResultText = "a bitmap";
formats[7].dwFlags = OLEUIPASTE_PASTEONLY;
DWORD retVal = OleUIPasteSpecial(&data);
if (retVal == OLEUI_OK) {
// apparently, richedit handles linking for us; unfortunately, some
// objects do not embed (MS Word/Office 97 simply fails to embed,
// although linking works...
if (FIRichEditOle->ImportDataObject(data.lpSrcDataObj,
formats[data.nSelectedIndex].fmtetc.cfFormat,
(data.dwFlags & PSF_CHECKDISPLAYASICON) ? data.hMetaPict : 0) !=
S_OK)
throw EOleError("RichEdit refused to paste object.");
}
if (data.hMetaPict) OleUIMetafilePictIconFree(data.hMetaPict);
if (data.lpSrcDataObj) data.lpSrcDataObj->Release();
return retVal == OLEUI_OK;
}
//---------------------------------------------------------------------------
// close any active ole objects (else servers left hanging); return
false on
// cancel unconditionally if savePrompt != true (changes are lost)
//
bool TIRichEditOle::CloseActiveObjects(bool savePrompt)
{
// if no interface, yell
if (!FIRichEditOle) throw EOleError("RichEdit OLE interface is not
valid.");
// get the total number of objects
int objCnt = FIRichEditOle->GetObjectCount();
// check each object and, if active, deactivate and, if open, close
for (int i = 0; i < objCnt; i++) {
REOBJECT reObj;
::memset(&reObj, 0, sizeof(reObj));
reObj.cbStruct = sizeof(reObj);
// get object data
if (FIRichEditOle->GetObject(i, &reObj, REO_GETOBJ_POLEOBJ) == S_OK) {
// if active, kill it
if (reObj.dwFlags & REO_INPLACEACTIVE)
FIRichEditOle->InPlaceDeactivate();
// if open, close it (prompting if requested)
HRESULT hr = S_OK;
if (reObj.dwFlags & REO_OPEN)
hr = reObj.poleobj->Close(savePrompt ?
OLECLOSE_PROMPTSAVE : OLECLOSE_NOSAVE);
// release the interface
reObj.poleobj->Release();
// if cancelled, return false
if (hr == OLE_E_PROMPTSAVECANCELLED) return false;
}
}
return true;
}
//===========================================================================
// Copyright ?1998 Thin Air Enterprises and Robert Dunn
//===========================================================================
송득보 님이 쓰신 글 :
: 답변 감사합니다. 다른 기능은 필요없구요. 그림만 같이 추가될 수 있으면 합니다. ole 부분만 수정하는 소스코드 좀 올려주세요. 번거로우시더라도 부탁드립니다.
:
: -locke
:
: 유영인 [Chris] 님이 쓰신 글 :
: : RichEdit에 수정을 해서, OLE 를 지원하도록 수정을 하면 사용하실 수 있습니다. 수정을 직접 하시는 방법도 있지만, 이미 수정을 된 컴포넌트를 사용하시는 것도 편하실 것 같네요.
: :
: :
http://home.att.net/~robertdunn/Yacs.html
: :
: : 위 사이트에 가시면, 수정된 RichEdit를 (몇몇 기능이 더 들어있습니다) 받으실 수 있습니다. 만약, OLE 부분만 수정을 하는 소스코드를 원하시면 리플 주세요.
: :
: :
: : 송득보 님이 쓰신 글 :
: : : richedit에 그림삽입이 안되나요?
: : : rtf인 노트패드에서 그림이 삽입된 문서를 저장하고
: : : c++빌더의 richedit에서 load하면 다른건 다 로드가 되는데
: : : 해당 위치에 있어야 할 그림만 없네요.
: : : 그림이나 개체 삽입 기능같은게 trichedit에 빠져있는가요?
: : : 방법을 아시는 분..도와주세요.
: : :
: : : -locke
: : :