Recently, attempting to write an ActiveX control that can display static and dynamic images, just like QQ, you can insert into the RicheDit control. Since it is only attempt, many functions are not implemented, only displayed. It is very simple if you display a still picture with a single order. But if you display a dynamic GIF picture, you have a certain difficulty, first analyze the number of frames, but also the control image is displayed in order. If you write a control, you have to make it more difficult to insert into the RicheDit control, because ATL has many difficulties to overcome when responding to Timer events.
For the picture display, because I just try, I only provide an interface function play (), the picture is written in the control. Let the control display image as long as the function is called. Based on the principle, in play (), load the picture, determine that the picture is a dynamic GIF picture, not, directly display, is a dynamic GIF, create a Timer object, set the time interval of Timer to the picture The length of the time that the frame should be displayed, in the onTimer (), the frame should be displayed to the next frame, and modify the time interval of the Timer to show the length of the length of the frame. As for how to display dynamic GIF pictures, you can see another article I wrote.
There is an article on the Internet that let the ATL control respond to the Timer message, just set the control to a window, then call setTimer () to set the Timer, then respond to the Timer message in ONTIMER (). I did it, when the control is to be generated display dynamic pictures, it will move when testing in the test container, but when the control is inserted into the Richedit control, the picture will not move. According to inspection, the reason should be that the window handle is NULL. (Mingming is set to have a window control, M_hwnd is still null, I really don't know why. If someone knows, I hope you can tell me. Because I just exposed to the COM component).
Don't have, I have to change it to a windowless control. But how can the window respond to Timer messages, no window handle. In this way, no handle is unable to receive Timer messages. One way is to respond with TimeProc, that is, when settingtimer (), the window handle can be empty, but we pass a callback function for the last parameter of this function. Then, realize the frame in our callback function. But this method has a bad thing that you want to access the member variable of the control object in the callback function, but also manage the Timer object of each control, you must map each control and its Timer to centralize, because The TimeProc callback function is called by the system, no matter which control Timer interval, it is called, that is, TimeProc is shared by the control instance, you have to judge which control is now in TimeProc. In addition, just said that the callback function to access the control object, like a target pointer to TimeProc, and the TimeProc format is fixed, you can only be implemented through the full game function. In short, it is very complicated to manage.
Since there is no handle, we give it one. How to give? There is a method that is stupid but looks good, it is to introduce an auxiliary object, which is a window object, of course, it has a handle. Handle, we can give it setTimer, and can respond to the Timer message via the ontimer () response, we only need to call the control to change the frame in this onTimer. Here is the implementation of the code: class csimgctl; // Our control class
class CWinHidden: public CWindowImpl
Lresult Cwinhidden :: Ontimer (uint UMSG, WPARAM WPARAM, LPARAM LPARAM, BOOL & BHAND) {IF ((UINT) WPARAM! = M_ntimer Return -1;
IF (m_pfullctrl! = null) m_pfullctrl-> Ontimer (UMSG, WPARAM, LPARAM, BHAND); // Call the function Return 0 of the control object;}
First, in our control class, add a member of a secondary class
CWINHIDEN M_HIDEWND;
Then, when we want to display pictures, we add the following code in the Play () function.
IF (m_pimg == null) {m_pimg = new imageex (l "wk.gif"); if (m_pimg == null) Return S_OK;
IF (m_pimg-> isanimatedGIF ()) {long lframetime = m_pimg-> getFrametime (); m_hidewnd.attachctl (this); // Bind the secondary object with this object M_Hidewnd.SetThistimer (1, lframetime, null); / / To set the clock to auxiliary class} fireviewchange ();
}
Finally, in the ONTIMER () of our control, you can implement it.
From the code, we are only indirectly realized Ontimer, which is true, this is also a way, the reason is above. However, we can see that if we want to write a windowless control, we can also achieve the desired functionality through this function, as long as you call the auxiliary class ontimer () The control implements the function you want, and then shut down the clock immediately. When you want to call these features, you will call SetTimer () on the secondary object. such as:
m_hidewnd.attachctl (this); // Bind the secondary object with this object M_Hidewnd.SetThistimer (1, 50, null); / / Set the clock for the secondary object
After executing the above code 50ms, ONTIMER () will be called, we implement this in our ONTIMER ()
Lresult Cwinhidden :: Ontimer (uint UMSG, WPARAM WPARAM, LPARAM LPARAM, BOOL & BHAND) {IF ((UINT) WPARAM! = M_ntimer Return -1;
If (m_pfullctrl! = null) m_pfullctrl-> someFunc (); // call the function of the control object, implement our function Return 0 in this function;}
Add: I used to write, I didn't pay attention to the bug. If I write it above, serious BUG will appear when the control is deleted and causes the program to crash. The reason for the error is that the window is not deleted when CWINHIDEN sector is destructed, so we have to modify its designer function to:
~ Cwinhidden () {if (m_ntimer! = 0) {killtimer (m_ntimer); m_ntimer = 0;} if (m_hwnd! = Null) {: destroyWindow (m_hwnd); m_hwnd = null;}}
A few lines of bold are supplemented.