麻煩請教一下:
1.我的richeditctrl獲取IRichEditOle指標是空的,這是為什么?
2.我的richeditctrl插入了圖片,但是圖片的大小是原大小而且尺寸可調整。我想實作像qq中的效果,無論截圖尺寸如何都可以按一定比例縮放顯示在richiedit中,且圖片不能調整大小,該如何實作?
3.如果想發送圖片,該如何獲取插入圖片的相關資料呢?
.h:
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();
.cpp:
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 storage
HRESULT 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;
}
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;
}
uj5u.com熱心網友回復:
實戰經驗:CRichEditCtrl插入圖片(不止是位圖)uj5u.com熱心網友回復:
謝謝,這篇文章看過了,寫的很好,但是效果還是不太理想。請問如何操作插入到richedit中的ole物件呢?應該在哪個函式中設定ole物件的尺寸,禁止在界面上修改尺寸呢?謝謝幫助,我再研究研究。
uj5u.com熱心網友回復:
學習了三四天的一點成果,如果有不對的地方還請指出。目前發現有兩種方法來向richedit中插入ole物件:
1.直接粘貼,然后使用回呼函式來控制即將插入的ole物件。
2.自己構造一個ole物件然后呼叫richedit的方法來插入。
MFC應該對richedit插入ole物件做了封裝,只留了一個介面設定回呼函式,然后在回呼函式中對即將插入的ole物件進行處理。這種方法的廣度還是很大的,可以直接獲得ole物件中的所有資料,然后想怎么改就怎么改。但是問題是,這方面的檔案實在是有點少,找來找去只找到了一個能用的例子,而且是簡單的回傳,沒有做更多的操作。回呼函式中的很多方法和結構體完全不知道怎么使用,于是嘗試第二種方法。
大致思路是:先截圖,然后從剪切板中讀取位圖資料,轉換成CImage型別的圖片,然后對圖片進行縮放,構造ole物件,將其中的hBitmap替換成縮放圖的hBitmap,最后插入richedit。我的做法只是能實作功能而已,很多地方并不規范,實作功能簡單。如果有做過截圖和ole的大佬,也希望能夠指點一下。
大致原始碼如下:
.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(CCmdUI* pCmdUI);
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);
};
.cpp
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;
}
}
}
}
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);
}
uj5u.com熱心網友回復:
CHARFORMAT2 中有說明dwMask CFM_PROTECTED The CFE_PROTECTED value is valid.
dwEffects CFE_PROTECTED Characters are protected; an attempt to modify them will cause an EN_PROTECTED notification message.
To receive EN_PROTECTED notifications, SetEventMask specify ENM_PROTECTED in the mask sent with the EM_SETEVENTMASK message.
EN_PROTECTED Notification
Return Value
This message returns zero to allow the operation.
This message returns a nonzero value to prevent the operation.
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/20124.html
標籤:界面
上一篇:OnCreateClient
