600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > MFC富文本编辑框richedit插入图片ole对象问题

MFC富文本编辑框richedit插入图片ole对象问题

时间:2020-04-21 04:15:21

相关推荐

MFC富文本编辑框richedit插入图片ole对象问题

MFC富文本编辑框richedit插入图片ole对象问题

学习了三四天的一点成果,如果有不对的地方还请指出。

目前发现有两种方法来向richedit中插入ole对象:

1.直接粘贴,然后使用回调函数来控制即将插入的ole对象。

2.自己构造一个ole对象然后调用richedit的方法来插入。

MFC应该对richedit插入ole对象做了封装,只留了一个接口设置回调函数,然后在回调函数中对即将插入的ole对象进行处理。这种方法的广度还是很大的,可以直接获得ole对象中的所有数据,然后想怎么改就怎么改。但是问题是,这方面的文档实在是有点少,找来找去只找到了一个能用的例子,而且是简单的返回,没有做更多的操作。回调函数中的很多方法和结构体完全不知道怎么使用,于是尝试第二种方法。

大致思路是:先截图,然后从剪切板中读取位图数据,转换成CImage类型的图片,然后对图片进行缩放,构造ole对象,将其中的hBitmap替换成缩放图的hBitmap,最后插入richedit。我的做法只是能实现功能而已,很多地方并不规范,实现功能简单。如果有做过截图和ole的大佬,也希望能够指点一下。

大致源码如下:

CChatRichEditCtrl.h

class CChatRichEditCtrl : public CRichEditCtrl

{

CDisplayPicture* m_pDisplayPic = nullptr;//图片显示器类

bool m_bPastePic = false;//粘贴的是位图则屏蔽系统的ctrl+v

DWORD m_oleCnt = 0;

map<DWORD, CString> m_olePathMap;//粘贴到聊天框中的ole与原图的映射

public:

CChatRichEditCtrl() {/* AfxInitRichEdit(); AfxInitRichEdit2(); AfxOleInit();/}

~CChatRichEditCtrl(){}

DECLARE_MESSAGE_MAP()

afx_msg void OnPaste();

afx_msg void OnPasteUpdateUI(CCmdUIpCmdUI);

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

virtual BOOL PreTranslateMessage(MSG* pMsg);

protected:

static DWORD CALLBACK readFunction(DWORD dwCookie,

LPBYTE lpBuf, // the buffer to fill

LONG nCount, // number of bytes to read

LONG* nRead); // number of bytes actually read

interface IExRichEditOleCallback; // forward declaration (see below in this header file)

IExRichEditOleCallback* m_pIRichEditOleCallback;

BOOL m_bCallbackSet;

interface IExRichEditOleCallback : public IRichEditOleCallback

{

public:

IExRichEditOleCallback();

virtual ~IExRichEditOleCallback();

int m_iNumStorages;

IStorage* pStorage;

DWORD m_dwRef;

virtual HRESULT STDMETHODCALLTYPE GetNewStorage(LPSTORAGE* lplpstg);

virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);

virtual ULONG STDMETHODCALLTYPE AddRef();

virtual ULONG STDMETHODCALLTYPE Release();

virtual HRESULT STDMETHODCALLTYPE GetInPlaceContext(LPOLEINPLACEFRAME FAR* lplpFrame,

LPOLEINPLACEUIWINDOW FAR* lplpDoc, LPOLEINPLACEFRAMEINFO lpFrameInfo);

virtual HRESULT STDMETHODCALLTYPE ShowContainerUI(BOOL fShow);

virtual HRESULT STDMETHODCALLTYPE QueryInsertObject(LPCLSID lpclsid, LPSTORAGE lpstg, LONG cp);

virtual HRESULT STDMETHODCALLTYPE DeleteObject(LPOLEOBJECT lpoleobj);

virtual HRESULT STDMETHODCALLTYPE QueryAcceptData(LPDATAOBJECT lpdataobj, CLIPFORMAT FAR* lpcfFormat,

DWORD reco, BOOL fReally, HGLOBAL hMetaPict);

virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);

virtual HRESULT STDMETHODCALLTYPE GetClipboardData(CHARRANGE FAR* lpchrg, DWORD reco, LPDATAOBJECT FAR* lplpdataobj);

virtual HRESULT STDMETHODCALLTYPE GetDragDropEffect(BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect);

virtual HRESULT STDMETHODCALLTYPE GetContextMenu(WORD seltyp, LPOLEOBJECT lpoleobj, CHARRANGE FAR* lpchrg,

HMENU FAR* lphmenu);

};

IRichEditOle* m_pRichEditOle;

virtual void PreSubclassWindow();

public:

afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);

};

CChatRichEditCtrl.cpp

#define ID_RICH_PASTE 104

BEGIN_MESSAGE_MAP(CChatRichEditCtrl, CRichEditCtrl)

ON_COMMAND(ID_RICH_PASTE, OnPaste)

ON_UPDATE_COMMAND_UI(ID_RICH_PASTE, OnPasteUpdateUI)

ON_WM_CREATE()

ON_WM_LBUTTONDBLCLK()

END_MESSAGE_MAP()

int CChatRichEditCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CRichEditCtrl::OnCreate(lpCreateStruct) == -1)

return -1;

ASSERT(m_pIRichEditOleCallback != NULL);if (!m_bCallbackSet)SetOLECallback(m_pIRichEditOleCallback);AFX_MANAGE_STATE(AfxGetStaticModuleState());m_pDisplayPic = new CDisplayPicture;m_pDisplayPic->Create(IDD_DIALOG_DISPLAYPIC, this/*AfxGetMainWnd()*/);m_pDisplayPic->ShowWindow(SW_HIDE);return 0;

}

BOOL CChatRichEditCtrl::PreTranslateMessage(MSG* pMsg)

{

// TODO: 在此添加专用代码和/或调用基类

if (pMsg->message == WM_KEYDOWN)

{

if(pMsg->wParam == 0x56 && GetAsyncKeyState(VK_CONTROL))

//0x56是’v’键,但是不知道为什么,直接写pMsg->wParam == 'v’不好使

{

m_bPastePic = false;

OnPaste();

if (m_bPastePic)

return TRUE;//屏蔽ctrl+v

}

}

return CRichEditCtrl::PreTranslateMessage(pMsg);

}

void CChatRichEditCtrl::OnPaste()

{

//对于图片,粘贴前需要进行处理

if (IsClipboardFormatAvailable(CF_DIB))

{

GLOBALHANDLE hGMem;

LPBITMAPINFO lpBI;

void* pDIBBits;

if (OpenClipboard())

{

hGMem = GetClipboardData(CF_DIB);

lpBI = (LPBITMAPINFO)GlobalLock(hGMem);

// point to DIB bits after BITMAPINFO object

pDIBBits = (void*)(lpBI + 1);

int width = 100 * lpBI->bmiHeader.biWidth / lpBI->bmiHeader.biHeight;

//缩略图高固定100,按比例计算缩略图宽,最大200

if (width > 200)

width = 200;

CRect abbpic(0,0, width,100);

CImage image, image1, image2;

if (m_pTeamWorkOpr)

{

CString path = L"C:\Users\Administrator\Desktop\新建文件夹";

image1.Load(path + L"system\\screenshot.bmp");//样图,提供格式,否则下面的GetBPP()函数错误,无法生成图片image.Create(abbpic.Width(), abbpic.Height(), image1.GetBPP());image2.Create(lpBI->bmiHeader.biWidth, lpBI->bmiHeader.biHeight, image1.GetBPP());::StretchDIBits(image2.GetDC(), 0, 0,lpBI->bmiHeader.biWidth,lpBI->bmiHeader.biHeight,0, 0, lpBI->bmiHeader.biWidth,lpBI->bmiHeader.biHeight,pDIBBits, lpBI, DIB_RGB_COLORS, SRCCOPY);//保存原图image2.Save(path + L"system\\oriscreenshot.png");string pathStr = StringWideToAnsi((path + L"system\\oriscreenshot.png").GetBuffer());//生成md5作为文件名另存文件,用于之后ole对象和图片的关联//生成md5用的第三方库,可以生成GUID代替md5做文件名string md5 = CalcFileMd5(pathStr);CString md5Name;md5Name = StringAnsiToWide(md5).c_str();CString md5Path;md5Path = path + L"system\\OriScreenShot\\" + md5Name + L".png";image2.Save(md5Path);HBITMAP bitmap2 = image2.Detach();image2.ReleaseDC();::StretchDIBits(image.GetDC(),abbpic.left, abbpic.top,abbpic.Width(), abbpic.Height(),0, 0, lpBI->bmiHeader.biWidth,lpBI->bmiHeader.biHeight,pDIBBits, lpBI, DIB_RGB_COLORS, SRCCOPY);//保存缩略图GlobalUnlock(hGMem);image.Save(path + L"system\\abbscreenshot.png");HBITMAP bitmap = image.Detach();image.ReleaseDC();CloseClipboard();STGMEDIUM stgm;stgm.tymed = TYMED_GDI;stgm.hBitmap = bitmap;//在这里将图片hBitmap换成缩略图的stgm.pUnkForRelease = NULL;FORMATETC fm;fm.cfFormat = CF_BITMAP;fm.ptd = NULL;fm.dwAspect = DVASPECT_CONTENT;fm.lindex = -1;fm.tymed = TYMED_GDI;IStorage* pStorage;LPLOCKBYTES lpLockBytes = NULL;SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);if (sc != S_OK) AfxThrowOleException(sc);ASSERT(lpLockBytes != NULL);sc = ::StgCreateDocfileOnILockBytes(lpLockBytes, STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE, 0, &pStorage);if (sc != S_OK){VERIFY(lpLockBytes->Release() == 0);lpLockBytes = NULL;AfxThrowOleException(sc);}ASSERT(pStorage != NULL);COleDataSource* pDataSource = new COleDataSource;pDataSource->CacheData(CF_BITMAP, &stgm);LPDATAOBJECT lpDataObject = (LPDATAOBJECT)pDataSource->GetInterface(&IID_IDataObject);LPOLECLIENTSITE lpClientSite;GetIRichEditOle()->GetClientSite(&lpClientSite);//创建OLE对象IOleObject* pOleObject;sc = OleCreateStaticFromData(lpDataObject, IID_IOleObject, OLERENDER_FORMAT,&fm, lpClientSite, pStorage, (void**)&pOleObject);if (sc != S_OK) AfxThrowOleException(sc);//插入OLE对象REOBJECT reobject;ZeroMemory(&reobject, sizeof(REOBJECT));reobject.cbStruct = sizeof(REOBJECT);CLSID clsid;sc = pOleObject->GetUserClassID(&clsid);if (sc != S_OK)AfxThrowOleException(sc);reobject.clsid = clsid;reobject.cp = REO_CP_SELECTION;reobject.dvaspect = DVASPECT_CONTENT;reobject.poleobj = pOleObject;reobject.polesite = lpClientSite;reobject.pstg = pStorage;reobject.dwUser = m_oleCnt++;//每次插入ole对象的索引,删除不做处理//REOBJECT obj;//obj.cbStruct = sizeof(obj);// if (GetPic(&obj))// {// long lStart, lEnd;// pTextIn1->GetSel(lStart, lEnd);// pTextIn1->SetSel(obj.cp, obj.cp + 1);// pTextIn1->Clear();// // pTextIn1->GetIRichEditOle()->InsertObject(&reobject);// // pTextIn1->SetSel(lStart, lEnd);// // }//else//{GetIRichEditOle()->InsertObject(&reobject);//}delete pDataSource;SendMessage(EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);SetFocus();m_olePathMap.insert(make_pair(reobject.dwUser, md5Path));//关联ole和原图m_bPastePic = true;}}}

}

void CChatRichEditCtrl::OnPasteUpdateUI(CCmdUI* pCmdUI)

{

pCmdUI->Enable(CanPaste());

}

DWORD CALLBACK CChatRichEditCtrl::readFunction(DWORD dwCookie,

LPBYTE lpBuf, // the buffer to fill

LONG nCount, // number of bytes to read

LONG* nRead) // number of bytes actually read

{

CFile* fp = (CFile*)dwCookie;

*nRead = fp->Read(lpBuf, nCount);

return 0;

}

CChatRichEditCtrl::IExRichEditOleCallback::IExRichEditOleCallback()

{

pStorage = NULL;

m_iNumStorages = 0;

m_dwRef = 0;

// set up OLE storageHRESULT hResult = ::StgCreateDocfile(NULL,STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE /*| STGM_DELETEONRELEASE */ | STGM_CREATE,0, &pStorage);if (pStorage == NULL ||hResult != S_OK){AfxThrowOleException(hResult);}

}

CChatRichEditCtrl::IExRichEditOleCallback::~IExRichEditOleCallback()

{

}

HRESULT STDMETHODCALLTYPE

CChatRichEditCtrl::IExRichEditOleCallback::GetNewStorage(LPSTORAGE* lplpstg)

{

m_iNumStorages++;

WCHAR tName[50];

swprintf_s(tName, L"REOLEStorage%d", m_iNumStorages);

HRESULT hResult = pStorage->CreateStorage(tName,STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,0, 0, lplpstg);if (hResult != S_OK){::AfxThrowOleException(hResult);}return hResult;

}

HRESULT STDMETHODCALLTYPE

CChatRichEditCtrl::IExRichEditOleCallback::QueryInterface(REFIID iid, void** ppvObject)

{

HRESULT hr = S_OK;*ppvObject = NULL;if (iid == IID_IUnknown ||iid == IID_IRichEditOleCallback){*ppvObject = this;AddRef();hr = NOERROR;}else{hr = E_NOINTERFACE;}return hr;

}

ULONG STDMETHODCALLTYPE

CChatRichEditCtrl::IExRichEditOleCallback::AddRef()

{

return ++m_dwRef;

}

ULONG STDMETHODCALLTYPE

CChatRichEditCtrl::IExRichEditOleCallback::Release()

{

if (–m_dwRef == 0)

{

delete this;

return 0;

}

return m_dwRef;

}

HRESULT STDMETHODCALLTYPE

CChatRichEditCtrl::IExRichEditOleCallback::GetInPlaceContext(LPOLEINPLACEFRAME FAR* lplpFrame,

LPOLEINPLACEUIWINDOW FAR* lplpDoc, LPOLEINPLACEFRAMEINFO lpFrameInfo)

{

return S_OK;

}

HRESULT STDMETHODCALLTYPE

CChatRichEditCtrl::IExRichEditOleCallback::ShowContainerUI(BOOL fShow)

{

return S_OK;

}

HRESULT STDMETHODCALLTYPE

CChatRichEditCtrl::IExRichEditOleCallback::QueryInsertObject(LPCLSID lpclsid, LPSTORAGE lpstg, LONG cp)

{

//return E_NOTIMPL;

return S_OK;

}

HRESULT STDMETHODCALLTYPE

CChatRichEditCtrl::IExRichEditOleCallback::DeleteObject(LPOLEOBJECT lpoleobj)

{

return S_OK;

}

HRESULT STDMETHODCALLTYPE

CChatRichEditCtrl::IExRichEditOleCallback::QueryAcceptData(LPDATAOBJECT lpdataobj, CLIPFORMAT FAR* lpcfFormat,

DWORD reco, BOOL fReally, HGLOBAL hMetaPict)

{

return S_OK;

}

HRESULT STDMETHODCALLTYPE

CChatRichEditCtrl::IExRichEditOleCallback::ContextSensitiveHelp(BOOL fEnterMode)

{

return S_OK;

}

HRESULT STDMETHODCALLTYPE

CChatRichEditCtrl::IExRichEditOleCallback::GetClipboardData(CHARRANGE FAR* lpchrg, DWORD reco, LPDATAOBJECT FAR* lplpdataobj)

{

return E_NOTIMPL;//这里如果返回S_OK,则剪切板数据被拦截

}

HRESULT STDMETHODCALLTYPE

CChatRichEditCtrl::IExRichEditOleCallback::GetDragDropEffect(BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect)

{

return S_OK;

}

HRESULT STDMETHODCALLTYPE

CChatRichEditCtrl::IExRichEditOleCallback::GetContextMenu(WORD seltyp, LPOLEOBJECT lpoleobj, CHARRANGE FAR* lpchrg,

HMENU FAR* lphmenu)

{

return S_OK;

}

void CChatRichEditCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)

{

// TODO: 在此添加消息处理程序代码和/或调用默认值

LONG cnt = GetIRichEditOle()->GetObjectCount();

for (LONG i=0;i<cnt;i++)//判断双击中哪个ole对象

{

REOBJECT reobject;

ZeroMemory(&reobject, sizeof(REOBJECT));

reobject.cbStruct = sizeof(REOBJECT);

GetIRichEditOle()->GetObjectW(i, &reobject, REO_GETOBJ_NO_INTERFACES);

if (reobject.dwFlags &= REO_SELECTED)

//这里我只知道如果选中ole对象则会有REO_SELECTED标志,但我感觉选中ole对象和对ole对象的操作不是这么做的

{

if (m_pDisplayPic)

{

if (m_olePathMap.count(reobject.dwUser))

{

CString path = m_olePathMap[reobject.dwUser];

m_pDisplayPic->DisplayPic(path);

}

}

}

}

CRichEditCtrl::OnLButtonDblClk(nFlags, point);

}

CDisplayPicture.h

class CDisplayPicture : public CDialogEx

{

DECLARE_DYNAMIC(CDisplayPicture)

public:

CDisplayPicture(CWnd* pParent = nullptr); // 标准构造函数

virtual ~CDisplayPicture();

// 对话框数据

enum { IDD = IDD_DIALOG_DISPLAYPIC };

void DisplayPic(CString path);bool m_bInit = false;bool m_bDealCut = false;int m_delX;int m_delY;CRect m_initStaticPicRect;int m_initDlgWidth;int m_initDlgHeight;

protected:

virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持

DECLARE_MESSAGE_MAP()

public:

CStatic m_picDisplayPic;

virtual BOOL OnInitDialog();

afx_msg void OnSize(UINT nType, int cx, int cy);

};

CDisplayPiture.cpp

IMPLEMENT_DYNAMIC(CDisplayPicture, CDialogEx)

CDisplayPicture::CDisplayPicture(CWnd* pParent /=nullptr/)CDialogEx(IDD_DIALOG_DISPLAYPIC, pParent)

{

}

CDisplayPicture::~CDisplayPicture()

{

}

void CDisplayPicture::DoDataExchange(CDataExchange* pDX)

{

CDialogEx::DoDataExchange(pDX);

DDX_Control(pDX, IDC_STATIC_DISPLAYPIC, m_picDisplayPic);

}

BEGIN_MESSAGE_MAP(CDisplayPicture, CDialogEx)

ON_WM_SIZE()

END_MESSAGE_MAP()

// CDisplayPicture 消息处理程序

void CDisplayPicture::DisplayPic(CString path)

{

CRect rect;

m_picDisplayPic.GetClientRect(&rect);

CImage image;

image.Load(path);

HBITMAP hbitmap = image.Detach();

if (image.GetWidth()>rect.Width()||image.GetHeight()>rect.Height())

{

CImage image1;

image1.Create(rect.Width(), rect.Height(), image.GetBPP());

SetStretchBltMode(image1.GetDC(), COLORONCOLOR);

StretchBlt(image1.GetDC(), 0, 0, rect.Width(), rect.Height(), image.GetDC(), 0, 0, image.GetWidth(), image.GetHeight(), SRCCOPY);

hbitmap = image1.Detach();

image1.ReleaseDC();

image1.Destroy();

}

m_picDisplayPic.SetBitmap(hbitmap);

image.ReleaseDC();

image.Destroy();

ShowWindow(SW_SHOW);

}

BOOL CDisplayPicture::OnInitDialog()

{

CDialogEx::OnInitDialog();

// TODO: 在此添加额外的初始化m_bInit = true;CRect rect, crect;m_picDisplayPic.GetClientRect(rect);GetClientRect(crect);m_initStaticPicRect = rect;m_initDlgHeight = crect.Height();m_initDlgWidth = crect.Width();SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE, 0);return TRUE; // return TRUE unless you set the focus to a control// 异常: OCX 属性页应返回 FALSE

}

void CDisplayPicture::OnSize(UINT nType, int cx, int cy)

{

CDialogEx::OnSize(nType, cx, cy);

// TODO: 在此处添加消息处理程序代码if (m_bInit){CRect currect;GetClientRect(currect);int curheight = currect.Height();int curwidth = currect.Width();CRect rect;rect.top = m_initStaticPicRect.top;rect.bottom = m_initStaticPicRect.bottom * curheight / m_initDlgHeight;rect.left = m_initStaticPicRect.left * curwidth / m_initDlgWidth;rect.right = m_initStaticPicRect.right * curwidth / m_initDlgWidth;m_picDisplayPic.MoveWindow(rect);RedrawWindow();}

}

希望能对第一次做richedit的人有帮助

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。