One of the simple IM implementations based on Richedit: interface part

xiaoxiao2021-03-06  42

There are many types of IM software now, and the use of Richedit is relatively small, and the development of Richedit is relatively easy. In this article, it is mainly discussed Richedit's advanced application and the permanent storage of the DynamicGIF control, saved to files.

The DynamicGIF control has been expanded to support the creation of objects and saved to the file from the stream. Here is how to save the files in the control:

Bool Savetofile (IoleObject * PoleObject, LPCWSTR WSZDSTFILE)

{

// The target file name to be saved

BOOL BRET = FALSE;

CComptr spdyngif;

HRESULT HR = PoleObject-> QueryInterface (& SPDYNGIF);

En (ac))

{

CCOMBSTR BSTRFILE;

// Note that the corresponding file cannot be deleted during the living life of the object.

/ / Otherwise, it will fail when saving to a file or copy

HR = SPDYNGIF-> getFilePath (& bstrfile);

IF (BSTRFILE.LENGTH ()> 0)

{

Bret = CopyFilew ((BSTR) BSTRFILE, WSZDSTFILE, FALSE;

}

}

Retur Bret;

}

Here is some advanced applications of Richedit in IM, mainly OLE, and then give a simple implementation.

First introduce the serialization of the Richedit control and the precautions for the use of the CRICHEDITCTRL control in the dialog.

1, serialization of Richedit controls

When the content in the RicHEDIT control is saved in the file or stream, you can select a variety of ways, such as plain text, RTF, etc., you can complete it by setting parameters. Serialization includes reading and writing, corresponding to two messages: em_streamin and em_streamout, cricheditctrl perform simple packages for these two messages, STREAMIN () and streamout () two functions.

The implementation of the MFC is given below, and scalability is still very strong.

First define a structure for callback functions, RichedItCookie:

Class RicheditCookie

{

PUBLIC:

CARCHIVE & M_AR;

DWORD M_DWERROR;

RicheditCookie (CARCHIVE & A): M_AR (ar) {m_dwerror = 0;}

}

Then define how to serialize the content in the Richedit, and CARCHIVE is used as serialized source or target in the Stream function, which only needs to use different file types when constructing the CARCHIVE object, such as cfile / cmemfile / csharedfile, You can read or write from file / memory / global memory or resources.

Here, the Stream determines based on the type of Ar is read or written. NFORMAT is formatted in the format of the text or in RTF format.

Void CMyrrichEditctrl :: Stream (CARCHIVE & AR, BOOL BSELECTION, INT NFORMAT)

{

EditStream ES = {0, 0, EditStreamCallback};

RicheditCookie Cookie (AR);

Es.dwcookie = (DWORD_PTR) & cookie;

IF (BSeLection)

nformat | = sff_selection; if (ar.isstoring ())

Streamout (NFORMAT, ES);

Else

{

Streamin (NFORMAT, ES);

IF (cookie.m_dwrroor! = 0)

AfXTHROWFILEXCEPTION (Cookie.m_dwerror);

}

Here is the definition of the callback function:

// Return 0 for no error, OtherWise Return Error Code

DWORD Callback EditStreamCallback (DWORD DWCOOKIE, LPBYTE PBBUFF, LONG CB, long * PCB)

{

Richeditcookie * pcookie = (richeditcookie *) dwcookie;

CARCHIVE & Ar = Pcookie-> M_AR;

ar.flush ();

DWORD DW = 0;

* PCB = CB;

Try

{

IF (ar.isstoring ())

ar.getfile () -> Write (PBBUFF, CB);

Else

* PCB = ar.getfile () -> read (PBBUFF, CB);

}

Catch (cfileException, e)

{

* PCB = 0;

Pcookie-> m_dwrror = (dword) E-> m_cause;

DW = 1;

DELETE_EXCEPTION (E);

}

And_catch_all (e)

{

* PCB = 0;

Pcookie-> m_dwrror = (dword) cfileException :: generic

DW = 1;

DELETE_EXCEPTION (E);

}

END_CATCH_ALL

Return DW;

}

2, Richedit Advanced Application in OLE section:

Richedit As a container object, allowing users to set up a callback interface to complete some of the OLE support, including request insertion object / get the iStorage interface / get context menu. For detailed definitions of the IRICHEDITOLECALLBACK interface, refer to MSDN, which discusses only the implementation related to DynamicGIF.

First discuss how to implement the IRICHEDITOLECALLBACK interface, here for convenience, I use the COM interface implemented in MFC, define inline, and implement the complicated interface to entrust the control.

Detailed definition of the controls given below:

Class CmyricHeditctrl: Public Cricheditctrl

{

Declare_Dynamic (CMYRICHEDITCTRL)

PUBLIC:

CMYRICHEDITCTRL ();

Virtual ~ cmyricheditctrl ();

protected:

Declare_message_map ()

PUBLIC:

// Implement the IRICHEDITOLECALLBACK Tune Interface

Begin_Interface_part (Richeditolecallback, IricHeditolecallback)

Init_Interface_part (CricheditView, Richeditolecallback)

STDMETHOD (LPSTORAGE);

STDMETHOD (LPOLEINPLACEFRAME *,

LPOLEINPLACEUIWINDOW *,

LPOLEINPLACEFRAMEINFO; STDMETHOD (ShowContainerui) (BOOL);

STDMETHOD (QueryInsertObject) (LPCLSID, LPSTORAGE, LONG)

STDMETHOD (LPOLETEOBJECT);

STDMETHOD (QueryAcceptdata) (LPDataObject, ClipFormat *, DWORD, BOOL, HGLOBAL);

STDMETHOD (ContextSensitiveHelp) (BOOL);

StdMethod (GetClipboardData) (Charrange *, DWORD, LPDATAOBJECT *);

STDMETHOD (GETDRAGDROPEFFECT) (BOOL, DWORD, LPDWORD);

StdMethod (GetContextMenu) (Word, LPoleObject, Charrange *, HMenu *);

End_Interface_part (Richeditolecallback)

Declare_interface_map ()

protected:

Virtual Void PRESUBCLASSWINDOW ();

PUBLIC:

AFX_MSG void OnoLESAVE2File ();

// Realization of the callback interface, obtain different right-click menu according to different context

Hmenu getContextMenu (Word Seltype, LPoleObject LPoleobj, Charrange * LPCHRG);

}

// implementation in the CPP file

Implement_dynamic (CMyricHeditctrl, cricheditctrl)

CMYRICHEDITCTRL :: CMYRICHEDITCTRL ()

{

EnableActiveAccessibility ();

}

CMYRICHEDITCTRL :: ~ CMYRICHEDITCTRL ()

{

}

Begin_INTERFACE_MAP (CMYRICHEDITCTRL, CRICHEDITCTRL)

// We use IID_IUNKNOWN BECAUSE Richedit Doesn't Define An IID

Interface_part (CMYRICHEDITCTRL, IID_IUNKNOWN, Richeditolecallback)

END_INTERFACE_MAP ()

STDMETHODIMP_ (ULONG) CMYRICHEDITCTRL :: Xricheditolecallback :: addref ()

{

Method_Prologue_ex_ (CMYRICHEDITCTRL, Richeditolecallback)

Return (ulong) pthis-> internaladdref ();

}

STDMETHODIMP_ (ULONG) CMYRICHEDITCTRL :: XricheDitolecallback :: release ()

{

Method_Prologue_ex_ (CMYRICHEDITCTRL, Richeditolecallback)

Return (Ulong) pthis-> infnevelease ();

}

STDMETHODIMP CMYRICHEDITCTRL :: XRicheditolecallback :: queryinterface

REFIID IID, LPVOID * PPVOBJ)

{

Method_Prologue_ex_ (CMYRICHEDITCTRL, Richeditolecallback)

Return (HRESULT) PTHIS-> INTERNALQUERYINTERFACE (& IID, PPVOBJ);

}

StdMethodimp CMYRICHEDITCTRL :: Xricheditolecallback :: getNewStorage (LPSTORAGE * PPSTG) {

Method_Prologue_ex_ (CMYRICHEDITCTRL, Richeditolecallback)

ColeClientItem item;

Item.getItemStorageFlat ();

* ppstg = item.m_lpstorage;

HRESULT HRES = E_OUTOFMEMORY;

IF (item.m_lpStorage! = null)

{

Item.m_lpstorage = null;

HRES = S_OK;

}

Return HRES;

}

StdMethodimp CMYRICHEDITCTRL :: Xricheditolecallback :: getinplaceContext

LPOLINPLACEFRAME * LPLPFRAME, LPOLINPLACEUIWINDOW * LPLPDOC,

LPOLEINPLACEFRAMEINFO LPFRAMEINFO)

{

Method_Prologue_ex (CMYRICHEDITCTRL, Richeditolecallback)

ATLTRACENOTIMPL (_t ("cmyricheditctrl :: Xricheditolecallback :: getInplaceContext () / r / n"));

}

STDMETHODIMP CMYRICHEDITCTRL :: Xricheditolecallback :: showcontainerui (bool fshow)

{

Method_Prologue_ex (CMYRICHEDITCTRL, Richeditolecallback)

ATLTRACENOTIMPL (_T ("CMYRICHEDITCTRL :: Xricheditolecallback :: showcontainerui () / r / n"));

}

STDMETHODIMP CMYRICHEDITCTRL :: Xricheditolecallback :: queryinsertobject (

LPCLSID / * LPCLSID * /, LPSTORAGE / * PSTG * /, long / * cp * /

{

Method_Prologue_ex (CMYRICHEDITCTRL, Richeditolecallback)

ATLTRACE (_T ("CMyricHeditctrl :: Xricheditolecallback :: queryInsertObject () / r / n")));

Return S_OK;

}

STDMETHODIMP CMYRICHEDITCTRL :: Xricheditolecallback :: deleteObject (lpoleObject / * lpoleobj * /)

{

Method_Prologue_ex_ (CMYRICHEDITCTRL, Richeditolecallback)

ATLTRACENOTIMPL (_T ("CMYRICHEDITCTRL :: Xricheditolecallback :: deleteObject () / r / n")));

}

STDMETHODIMP CMYRICHEDITCTRL :: Xricheditolecallback :: queryacceptdata

LPDataObject LPDataObj, ClipFormat * LPCFFORMAT, DWORD RECO,

Bool Freamy, HGlobal Hmetapict)

{

Method_Prologue_ex (CMYRICHEDITCTRL, Richeditolecallback)

ATLTRACENOTIMPL (_T ("CMYRICHEDITCTRL :: Xricheditolecallback :: queryacceptdata () / r / n"));}

StdMethodimp CMYRICHEDITCTRL :: Xricheditolecallback :: ContextSensitiveHelp (Bool / * fentermode * /)

{

ATLTRACENOTIMPL (_T ("CMYRICHEDITCTRL :: Xricheditolecallback :: ContextSensitiveHelp () / r / n"));

}

StdMethodimp Cmyricheditctrl :: Xricheditolecallback :: getClipboardData

Charrange * LPCHRG, DWORD RECO, LPDATAOBJECT * LPLPDATAOBJ)

{

Method_Prologue_ex (CMYRICHEDITCTRL, Richeditolecallback)

ATLTRACENOTIMPL (_T ("CMYRICHEDITCTRL :: Xricheditolecallback :: getclipboardData () / r / n"));

}

StdMethodimp CMYRICHEDITCTRL :: Xricheditolecallback :: getDragdropeffect

Bool FDRAG, DWORD GRFKEYSTATE, LPDWORD PDWEFFECT

{

RETURN E_NOTIMPL;

}

StdMethodimp CMYRICHEDITCTRL :: Xricheditolecallback :: getContextMenu

Word Seltype, LPoleObject LPoleobj, Charrange * LPCHRG,

Hmenu * lphmenu)

{

Method_Prologue_ex (CMYRICHEDITCTRL, Richeditolecallback)

ATLTRACE ("CMYRICHEDITCTRL :: Xricheditolecallback :: getContextMenu () / r / n")));

// Here you will delegate the processing of the right-click menu to the control.

HMENU HMENU = Pthis-> GetContextMenu (SELTYPE, LPOLEOBJ, LPCHRG);

IF (HMENU == Null)

RETURN E_NOTIMPL;

* lphmenu = HMENU;

Return S_OK;

}

// CMYRICHEDITCTRL message handler

Void cmyricheditctrl :: PreSubclassWindow ()

{

STEVENTMASK (ENM_SELCHANGE | ENM_CHANGE | ENM_SCROLL);

/ / Set the callback interface here

Verify (SETOLECALLBACK (& M_XRicHeditolecAlback);

CRICHEDITCTRL :: PRESUBCLASSWINDOW ();

}

// Realization of the callback interface, obtain different right-click menu according to different context

HMENU CMYRICHEDITCTRL :: getContextMenu (Word Seltype, LpoleObject Lpoleobj, Charrange * LPCHRG)

{

ATLTRACE (_T ("CMYRICHEDITCTRL:: GETCONTEXTMENU () / r / n"));

CMenu Menu, * psubmenu = null;

HMENU HMENU = NULL;

IF (SELTYPE == SEL_OBJECT)

{

Menu.LoadMenu (IDR_MENU1); psubmenu = menu.getsubmenu (0);

Point Pt;

GetCursorpos (& PT);

DWORD dwcmd = psubmenu-> TRACKPOPUPMENU (TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, PT.X, PT.Y, THIS);

IF (DWCMD == ID_OLE_SAVE2FILE)

{

CComptr spdyngif;

LPOLEOBJ-> QueryInterface (& SPDYNGIF);

IF (SPDYNGIF) {

CCOMBSTR BSTRFILE;

/ / Save the file to another file, here the control is set differently according to the file type in the control

// Different extensions, pay attention to the extension of the file when saving files in the form of a dialog box, to save the file type correctly.

SPDYNGIF-> GetFilePath (& BSTRFILE);

CopyFilew ((BSTR) BSTRFILE, L "D: //1111.gif", false);

}

}

}

Return Hmenu;

}

There is basically comment in the above code, which is not discussed here.

3, through the top two steps, the basic interface function can be implemented, if only the simple chat tool on the Windows platform, export / import information through the stream mode, but there is no scalability, which is not conducive to cross-platform expansion . If there is time, I will give a simple agreement implementation and a more complete implementation in the next article. (This article writing is relatively rushing, and there will be time to explain in detail later).

转载请注明原文地址:https://www.9cbs.com/read-53154.html

New Post(0)