We also discuss how to insert a dynamic GIF into RichEdit.

Source: Internet
Author: User
Tags ole

Http://www.deadc0de.com/archives/insert-gif-to-richedit.html#more-14

 

Recently I am working on IM software. I need to insert an expression into RichEdit. The expression is a dynamic GIF image.

Since I have not developed RichEdit before, Baidu has to use OLE technology. That is to say, the inserted images are all OLE objects. RichEdit is an OLE container. The related links are as follows.

How to insert a bitmap into an RTF document using the RichEdit control in Visual C ++ 6.0
Http://support.microsoft.com/default.aspx? SCID = KB; en-US; 220844

Animated emoticons like those in MSN Messenger (English version)
Http://www.codeproject.com/KB/edit/AnimatedEmoticon.aspx

Animated emoticons like those in MSN Messenger (Chinese Version)
Http://blog.csdn.net/dTianx/archive/2004/11/17/184949.aspx

Blog by dynamicgif
Http://blog.csdn.net/kql01

 

The first link is part of the Code provided by Microsoft and can only be used to insert BMP images. OLE object created using olecreatefromfile.

The second and third links are written in dtianx. The OLE object is created using QQ's imageole. dll. Provides all source code.

The fourth link is a control made by yiniu. The export function insertgiftorichedit2a allows you to easily insert any GIF. Only DLL files are provided, and only version 1.21 is available. It is said that the author has developed version 1.4, but it is not open for download.
I tried these four methods one by one and found that these solutions were not reliable. I will introduce it in detail below. I suppose that you have never touched RichEdit to embed Ole, and I did not know anything about it two weeks ago ......

First of all, we can only insert BMP images, which does not meet our requirements. However, this code shows us all the steps to insert an OLE object.

The third dynamicgif uses the export function insertgiftorichedit2a to easily insert any GIF image. However, I found that the version 1.21 He released has a problem. This problem occurs when the scroll bar is dragged, richEdit will be abnormal ......

After giving up using dynamicgif, I added all the bets to imageole, but when I implemented everything in assembly. I found that the nightmare is coming ...... (-__-! ).

First. In the above example, create a gifanimator instance, obtain the igifanimator interface, igifanimator: loadfromfile to load the image, call the magic igifanimator: triggerframechange function, and call iricheditole: insertobject. This example shows that the background is not erased when a transparent GIF is displayed. As shown in.

 

In addition, when I implemented the compilation, I found that there was a flash problem with the refresh. It may be that the third parameter berase of invalidaterect was set to true, however, I found that when imageole calls this API, The berase value is false. After studying it for a few days, I finally found that all this was caused by an extended style, ws_ex_transparent, transparent style, and dtianx and QQ RichEdit did have this extended style. -_-!!! After I added this style to RichEdit, the refresh did not flash, but the RichEdit background is the same as the form. This requires the subclass RichEdit to respond to the wm_erasebkgnd message, and the background is painted white manually.

After solving this problem, I began to solve the problem of transparent GIF display. This problem should be caused by the gdipimagedrawrecti function of GDI +, which only draws the opaque part to the DC. I don't know how QQ solves it, I think there should be a function that can turn off this feature of GID +: only draw the opaque part to DC. However, I am not familiar with GDI +. I haven't found it for a long time. The solution I came up with is to hook this code, add a white brush to create a white background, and then call gdipimagedrawrecti to draw GIF frames. In this way, the background of each GIF frame will be painted white. And it does ~

During the experiment, I also found that if the RichEdit class named RICHEDIT20A is used, memory leakage may occur, that is, the inserted image object memory is deleted and will not be released, this problem does not occur when you use RichEdit whose class name is RichEdit. Qq uses RICHEDIT20A. I copied the richedbench DLL of the QQ directory, but this problem still exists. I don't know if QQ has this problem or how it solves it.

Then, when I transferred the code to my IM project, I found a more serious problem. If you embed too many OLE files, the program will crash. The broken Point is riched‑dll. You can view the call stack and find it is internal. I cannot find out the cause. This error is so strange that no matter how many images are inserted in the experiment project, it will not crash. As soon as it is transferred to the IM project, there will be a problem. I have shielded a lot of code, it may be related to threads. There is no problem with how many values are inserted in wm_initdialog, and there is a problem with inserting data in another thread. I think we should put the inserted OLE Code in the window process. If sendmessage is used to trigger addition, The result still does not work. It is strange and strange...

There is another problem that caused me to crash. The first time you create RichEdit, you can insert a GIF image. But when you destroy this window with RichEdit, you can create a GIF image again, the image will not be moved (open the chat window, insert GIF, normal; close the chat window, open the chat window, insert GIF, GIF will not be moved ). In addition, I was puzzled. For this reason, I debugged imageole and learned how imageole works.

After imageole reads an image, it relies on the iviewobject: ondraw interface to refresh different frames of GIF In the OLE area. This ondraw must be triggered by invalidaterect. In this case, a timer is required to call invalidaterect for Refresh. This timer is created inside imageole and is created at createinstance. In addition, he has a judgment that if he has already created (the handle cannot be 0), he does not need to create any more. When I destroyed my chat window, this timer suddenly disappeared ...... Therefore, you cannot dynamically refresh the GIF by inserting it again. Dtianx's MFC project, which does not destroy the window. With spy ++, we can see that when the window is closed, the window is changed to invisable ...... So there is no such bug.

This kind of problem forces me to find other alternative DLL.

I found that there is also an imageole ON THE haofang platform, and the interface name has changed, but there are also loadfromfile and triggerframechange, which are surprisingly similar to QQ's imageole ~ Is there a correlation between the two? Who is the developer of imageole? Regardless of this, I cannot call haofang's imageole. dll. Then I searched for Feixin, Baidu Hi ......

Found a lot. Do not understand.

This forces me to choose another rugged path.

The other one is the most likely to succeed ..

Create ActiveX to implement OLE object embedding ..

Programming to Implement n com Interfaces
Idispatch
Ioleobject
Ioleinplaceobject
Ioleinplaceactiveobject
Iolecontrol
Idataobject
Iprovideclassinfo
Ipersiststorage
Ipersiststreaminit
Ipersistpropertybag
Iviewobject2
Ispecifypropertypages
Icategorizeproperties
Iconnectionpointcontainer
Irunnableobject

There are too many interfaces and a huge amount of work, so I'm sure I can't do it myself. Fortunately, there is an asmctrl project in masm32, which is an ActiveX control that can be called by VB, we have already implemented these things and found masm32 V9. Try to insert it into RichEdit and find that there is a problem with inserting more than one Ole. Read readme to know the author of this project.

He is a German compilation Superman ......

Works include cool X-ray comview and cool X-ray MASM compatible compiler jwasm. Otz

His research on com is very thorough. Otherwise, how can he dare to write ActiveX using assembler ~~

Superman's website http://www.japheth.de

The com & assembly column of the website contains an asmctrl project. The version is 2.5.5 and V9 may be version 1.0. We can see from the history that later versions have corrected the bugs. In addition, a large number of macros are used after version 2.0. Because of these macros, it is very difficult for me to read his code .. After reading the code of Superman Japheth, I realized that the compilation was so interesting ...... It's too speechless. I can't understand it. I wrote a 1.3 version to Superman. The 1.3 code is better than 2. x and only a small number of macros are used. However, there is still a bug in inserting RichEdit after compilation. Instead, you only need to use version 2.5.5 as the template for my picoleplus.

Then I learned how to debug imageole and gdiplus. It was very laborious to modify the asmctrl project and get the great picoleplus. dll stuff.

Below are some major changes I made.

1. Add some class private variables in casmclass. INC and declare them in the member of casmclass.

Hgdiplus dd?
Pimage dd?
Dwwidth dd?
Dwheight dd?
Dwframecount dd?
Ppropertyitem dd? ; Id Len type pvalue []
Dwframe0tick dd?

2. initialize GDI + in casmclass: Create, release the image in casmclass: destroy, and release GDI +. Code omitted

3. modified the iasmclass interface, added a loadfromfile method, and called the loadimagefile function.
Loadimagefile proc lpszfile
Local wszfile [260]: Word

Invoke multibytetowidechar, cp_oemcp, mb_precomposed, lpszfile,-1, ADDR wszfile, 255
Invoke gdiploadimagefromfile, ADDR wszfile, ADDR m_pimage
. If! Eax
Invoke gdipgetimagewidth, m_pimage, ADDR m_dwwidth
Invoke gdipgetimageheight, m_pimage, ADDR m_dwheight
Invoke setoleextent; Set Ole size
Invoke sendviewchange @ casmclass, EBX ;!!! Notification OLE container Ole size change
Invoke isanimatedgif
XOR eax, eax
. Endif
RET
Loadimagefile endp

Isanimatedgif proc
Local dwdimensioncount
Local pdimensionids
Local nsize

Invoke gdipimagegetframedimensionscount, m_pimage, ADDR dwdimensioncount
MoV eax, dwdimensioncount
SHL eax, 4
Invoke localalloc, lptr, eax
MoV pdimensionids, eax
Invoke gdipimagegetframedimensionslist, m_pimage, pdimensionids, dwdimensioncount
Invoke gdipimagegetframecount, m_pimage, pdimensionids, ADDR m_dwframecount
Invoke gdipgetpropertyitemsize, m_pimage, propertytagframedelay, ADDR nsize
. If! Eax
Invoke localalloc, lptr, nsize
MoV m_ppropertyitem, eax
Invoke gdipgetpropertyitem, m_pimage, propertytagframedelay, nsize, m_ppropertyitem
. Endif
Invoke localfree, pdimensionids
Invoke timegettime
MoV m_dwframe0tick, eax
RET
Isanimatedgif endp

Setoleextent proc; Calculate the size
Pushad
Invoke getdc, 0
MoV ESI, eax
Invoke getdevicecaps, ESI, logpixelsx
Push eax
MoV eax, m_dwwidth
MoV m_pixelextent.cx _, eax
MoV ECx, himetric_per_inch
Mul ECx
Pop ECx
XOR edX, EDX
Div ECx
MoV m_himetricextent.cx _, eax

Invoke getdevicecaps, ESI, logpixelsy
Push eax
MoV eax, m_dwheight
MoV m_pixelextent.cy, eax
MoV ECx, himetric_per_inch
Mul ECx
Pop ECx
XOR edX, EDX
Div ECx
MoV m_himetricextent.cy, eax
Invoke deleteobject, ESI
Popad
RET
Setoleextent endp

4. Modify the iviewobject: ondraw code to call drawimage.

Siid_framedimensiontime textequ <{06aedbd6dh, 03fb5h, 0418ah, {083 H, 0a6h, 07fh, 045 H, 022 H, 09dh, 0c8h, 072 h}>
Framedimensiontime guid siid_framedimensiontime

Drawimage proc uses esi edi ebx hdc, X, Y
Local dwticks
Local hgraphics
Local RT: rect
Local hscrdc, htempdc, hbitmap

. If m_ppropertyitem; Calculate the currently displayed frame through the Frame delay data and the elapsed time
Invoke timegettime; timegettime precision is 1 ms
Sub eax, m_dwframe0tick
XOR edX, EDX
MoV ECx, 10
Div ECx
MoV dwticks, eax

MoV ESI, m_ppropertyitem
MoV ESI, dword ptr [ESI + 12]
Xor edi, EDI
. While true
MoV eax, [ESI + EDI * 4]
. Break. If dwticks <eax
Sub dwticks, eax
INC EDI
. If EDI = m_dwframecount
Xor edi, EDI
. Endif
. Endw

Invoke gdipimageselectactiveframe, m_pimage, ADDR framedimensiontime, EDI; select Frame
. Endif

Invoke getdc, 0; create buffer DC
MoV hscrdc, eax
Invoke createcompatibledc, hscrdc
MoV htempdc, eax
Invoke createcompatiblebitmap, hscrdc, m_dwwidth, m_dwheight
MoV hbitmap, eax
Invoke SelectObject, htempdc, hbitmap
Invoke deleteobject, eax
Invoke deletedc, hscrdc

Invoke setrect, addr rt, 0, 0, m_dwwidth, m_dwheight; fill the background in white
Invoke getstockobject, white_brush
Invoke fillrect, htempdc, addr rt, eax

Invoke gdipcreatefromhdc, htempdc, ADDR hgraphics
Invoke gdipdrawimagerecti, hgraphics, m_pimage, 0, 0, m_dwwidth, m_dwheight; GIF Frame
Invoke gdipdeletegraphics, hgraphics

Invoke bitblt, HDC, X, Y, m_dwwidth, m_dwheight, htempdc, 0, srccopy
Invoke deleteobject, hbitmap
Invoke deletedc, htempdc
RET
Drawimage endp
In this way, an ole component that supports GIF is ready ~ However, there is no refresh here. I just refreshed it. There is an external code control to refresh.

The following is the code for inserting a GIF.

Insertobject proc uses esi edi ebx hwnd, ID, lpszfile
Local lpoleinterface
Local lplockbytes
Local lpstorage
Local lpclientsite
Local PVS
Local lpoleobject
Local lppicoleplus
Local CLSID: guid
Local reo: reobject

MoV lpoleinterface, 0
MoV lplockbytes, 0
MoV lpstorage, 0
MoV lpclientsite, 0
MoV PV, 0
MoV lpoleobject, 0
MoV lppicoleplus, 0

Invoke senddlgitemmessage, hwnd, ID, em_getoleinterface, 0, ADDR lpoleinterface
CMP lpoleinterface, 0
JZ exit

Invoke createilockbytesonhglobal, null, true, ADDR lplockbytes
CMP lplockbytes, 0
JZ exit

Invoke stgcreatedocfileonilockbytes, lplockbytes, stgm_1__exclusive or stgm_create or stgm_readwrite, 0, ADDR lpstorage
CMP lpstorage, 0
JZ exit

MoV ESI, lpoleinterface
MoV ESI, dword ptr [esi]
Assume ESI: PTR iricheditole
Invoke [esi]. getclientsite, lpoleinterface, ADDR lpclientsite
CMP lpclientsite, 0
JZ exit

Invoke coinitializeex, null, coinit_apartmentthreaded
Invoke cocreateinstance, ADDR iid_picoleplus, 0, clsctx_inproc_server or clsctx_inproc_handler or clsctx_local_server, ADDR iid_iunknown, ADDR PVS
Invoke olerun, GMM

MoV ECx, PVS
MoV ECx, [ECx]
Invoke [ECx] [iunknown. QueryInterface], GMM, ADDR iid_ipicoleplus, ADDR lppicoleplus
CMP lppicoleplus, 0
JZ exit

MoV eax, GMM
MoV eax, [eax]
Invoke [eax] [iunknown. Release], GMM

MoV EDI, lppicoleplus
MoV EDI, dword ptr [EDI]
Assume EDI: PTR ipicoleplus

Invoke [EDI]. loadfromfile, lppicoleplus, lpszfile
CMP eax, 0
Jnz exit

Invoke [EDI]. QueryInterface, lppicoleplus, ADDR iid_ioleobject, ADDR lpoleobject
CMP lpoleobject, 0
JZ exit

Invoke olesetcontainedobject, lpoleobject, true
. If eax
RET
. Endif

MoV EDI, lpoleobject
MoV EDI, dword ptr [EDI]
Assume EDI: PTR ioleobject
Invoke [EDI]. getuserclassid, lpoleobject, ADDR CLSID

MoV REO. cbstruct, sizeof REO
MoV REO. CP,-1
Invoke rtlmovememory, addr reo. CLSID, addr clsid, sizeof CLSID
M2M REO. poleobj, lpoleobject
M2M REO. pstg, lpstorage
M2M REO. polesite, lpclientsite
MoV REO. sizel. X, 0
MoV REO. sizel. Y, 0
MoV REO. dvaspect, 1; dvaspect_content
MoV REO. dwflags, 2; reo_belowbaseline
MoV REO. dwuser, 0
Invoke [esi]. insertobject, lpoleinterface, ADDR REO

Exit:. If maid
MoV eax, lpclientsite
MoV eax, [eax]
Invoke [eax] [iunknown. Release], lpclientsite
. Endif

. If lpoleobject
MoV eax, lpoleobject
MoV eax, [eax]
Invoke [eax] [iunknown. Release], lpoleobject
. Endif

. If lpstorage
MoV eax, lpstorage
MoV eax, [eax]
Invoke [eax] [iunknown. Release], lpstorage
. Endif

. If lppicoleplus
MoV eax, lppicoleplus
MoV eax, [eax]
Invoke [eax] [iunknown. Release], lppicoleplus
. Endif

. If lplockbytes
MoV eax, lplockbytes
MoV eax, [eax]
Invoke [eax] [iunknown. Release], lplockbytes
. Endif
RET
Insertobject endp
Register a timer in the window and call redrawobject to refresh. This code is somewhat different from imageole.

Himetricx2pixel proc dwhimetricx
Local HDC

Invoke getdc, 0
MoV HDC, eax
Invoke getdevicecaps, HDC, logpixelsx
Push eax
Invoke deleteobject, HDC
Pop eax
MoV ECx, dwhimetricx
Mul ECx
XOR edX, EDX
MoV ECx, 2540
Div ECx
. If edX
INC eax
. Endif
RET
Himetricx2pixel endp

Redrawobject proc uses esi edi ebx hwnd, ID
Local hrichedit
Local lpoleinterface
Local dwobjectcount
Local reo: reobject
Local sztemp [256]: byte
Local PT: Point
Local rcclient: rect
Local RC: rect
Local isinclient

Invoke getdlgitem, hwnd, ID
MoV hrichedit, eax

Invoke sendmessage, hrichedit, em_getoleinterface, 0, ADDR lpoleinterface
CMP lpoleinterface, 0
JZ exit

MoV ESI, lpoleinterface
MoV ESI, [esi]
Assume ESI: PTR iricheditole

Invoke [esi]. getobjectcount, lpoleinterface; number of OLE objects
MoV dwobjectcount, eax

Invoke getclientrect, hrichedit, ADDR rcclient

Xor ebx and EBX; obtain each Ole cyclically and refresh it as needed
. While EBX <dwobjectcount
MoV isinclient, 0

Invoke rtlzeromemory, ADDR reo, sizeof REO
MoV REO. cbstruct, sizeof REO
Invoke [esi]. _ GetObject, lpoleinterface, EBX, ADDR reo, 1; 1 = reo_getobj_poleobj

Invoke sendmessage, hrichedit, em_posfromchar, addr pt, Reo. CP
M2M RC. Left, Pt. x
M2M RC. Top, Pt. Y
M2M RC. Right, Pt. x
Invoke himetricx2pixel, Reo. sizel. x
Add RC. Right, eax
M2M RC. Bottom, rcclient. Bottom

MoV eax, Reo. poleobj
MoV eax, [eax]
Invoke [eax. ioleobject. Release], Reo. poleobj

Invoke ptinrect, ADDR rcclient, RC. Left, RC. Top
. If eax
INC isinclient
JMP @ F
. Endif

Invoke ptinrect, ADDR rcclient, RC. Right, RC. Top
. If eax
INC isinclient
JMP @ F
. Endif

Invoke ptinrect, ADDR rcclient, RC. Left, RC. Bottom
. If eax
INC isinclient
JMP @ F
. Endif

Invoke ptinrect, ADDR rcclient, RC. Right, RC. Bottom
. If eax
INC isinclient
JMP @ F
. Endif

@@:
. If isinclient
Invoke invalidaterect, hrichedit, addr rc, 0
. Endif
INC EBX
. Endw
Exit:
RET
Redrawobject endp

The final result is as follows:

TEST project package download http://www.deadc0de.com/wp-content/uploads/2009/05/richole2.rar

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.