Download source code
I. Preface
A window is generated when my COM component is running. When you double-click the window, I need to notify the caller;
My COM component downloads a file on the network in thread mode. After I finish the task, I need to notify the caller;
My COM component completes a clock function. When the scheduled time is reached, I need to notify the caller;
............
In this book, there are many com events, notifications, connection points, and so on. I will introduce them twice (four times in total.
Ii. Notification Methods
When an event occurs within Party A, Party B must be notified to use the following methods:
Notification Method |
Simple Description |
Comment |
Direct Message |
Postmessage () Postthreadmessage () |
Send a message to a window or thread |
No matter when you execute it. |
Sendmessage () |
Immediate execution of the message Response Function |
If the message processing function is not executed, no response is returned. |
Sendmessage (wm_copydata ...) |
When sending messages, you can also include some custom data. |
It is commonly used, so it is listed separately. |
Indirect message |
Invalidaterect () Settimer () ...... |
The called function sends related messages. |
There are too many such functions. |
Callback Function |
Getopenfilename ()...... |
When the user changes the file selection, the callback function is executed. |
Hi! Dude, this is my phone number. Let's just say something. |
In the era of COM, the above methods are basically not fun, because...The COM component is running in a distributed environment.How can I send messages to your window from components running on the other side of the earth's computer? Of course not! (But again, for ActiveX components that can only run locally, you can also send window messages .)
The callback function is used to design the com
The basis of the notification method. In essence, the callback function tells me the pointer of a function in advance. When necessary, I call the function directly. What does the callback function do? How does it do, I am not at all
Concerned. Okay. Let me ask you a question: What is com?
? An interface is actually a set of related functions (this definition is not rigorous, But you can understand it so well ). Therefore, instead of using the "callback function" in COM, you can use the "Callback interface" (more clearly
Some, that is, using a lot of encapsulated "callback function" sets), callback interface, we also call it "receiver interface ".
Figure 1. The client transmits the receiver interface pointer to com. When an event occurs, com calls the receiver interface function to complete the notification.
The functions completed by the sample program are as follows:
Start the client component (simple11.ievent1.1) and obtain the interface pointer ievent1 *;
Call the interface method ievent1: advise () to pass a sink interface pointer (icallback *) inside the client to the component server;
Call ievent1: add () to calculate the sum of two integers;
However, the calculation result is returned to the client through icallback: fire_result () instead of using this function;
When the client no longer needs to accept the event, call ievent1: unadvise () to disconnect from the component.
3. component implementation steps
1. Create a solution
2. Create an ATL Project in the solution. In the example program, the project name is simple12, and "attribute-based" is canceled. Other options are accepted by default.
3. Select a project and right-click the menu and choose "Add/Add class ".
3-1. Select ATL for the left-side category, and select simple ATL object for the right-side Template
3-2. Enter the component name in the name card. In the example, event1 (Note 1)
3-3. In the tab, modify the interface type "Custom" (note 2)
4. Select the ienvent1 interface, right-click the menu, and choose "Add/Add method"
Figure 2. Add ([in] Long N1, [in] Long N2) an interface function)
Figure 3. added the advise ([in] icallback * pcallback, [out] Long * pdwcookie) function)
Figure 4. added the interface function unadvise ([in] Long dwcookie)
You should have noticed that in the add () function, there are no IDL attributes such as [out] and [retval]. Hey, because we didn't intend to use add ()
The function directly obtains the calculation result. Otherwise, how can I demonstrate the callback interface? :-) In addition, In the advise () function, an integer must be returned.
Dwcookie, what is this? The principle is simple, because our components want to support multiple object callback connections at the same time. Therefore, when the client passes an interface to our component, I return a unique
A cookie number is used to indicate the identity. In the future, unadvise () will be disconnected.
Give me the ID number, so that I can know who wants to disconnect it.
5. added the IDL definition of the callback interface icallback. Open the IDL file and enter it manually (the black text part is manually entered), and save:
Import "oaidl. IDL ";
Import "ocidl. IDL ";
[
Object,
UUID (DB72DF86-70E9-4ABC-B2F8-5E04062D3B2E), // This IID can be generated using gudigen. exe
Helpstring ("icallback interface "),
Pointer_default (unique)
]
Interface icallback: iunknown
{
};
[
Object, // The following content is the same as the sample program. Of course, if it is your own program, there must be something different.
UUID (DB72DF85-70E9-4ABC-B2F8-5E04062D3B2E ),
Helpstring ("ievent1 interface "),
Pointer_default (unique)
]
Interface ievent1: iunknown
{
[Helpstring ("Method Add")] hresult add ([in] Long N1, [in] Long N2 );
[Helpstring ("method advise")] hresult advise ([in] icallback * pcallback, [out] Long * pdwcookie );
[Helpstring ("method unadvise")] hresult unadvise ([in] Long dwcookie );
};
[
UUID (FBA1E0F0-49CD-4B77-B9B1-4DC066AF8A8E ),
Version (1.0 ),
Helpstring ("simple12 1.0 Type Library ")
]
Library simple11lib
{
Importlib ("stdole32.tlb ");
Importlib ("stdole2.tlb ");
[
UUID (53e00126-b1a0-4510-b9bc-75ed87ce2db7 ),
Helpstring ("event1 class ")
]
Coclass event1
{
[Default] interface ievent1;
// Manual input is required. If VB is used, the attribute [Source, default] is not available.
[Source, default] interface icallback;
};
};
6. Added callback interface functions.
Figure 5. Add callback interface functions
In fact, it is the same as the previous method, as long as you do not select the wrong interface.
Figure 6. Add the interface function fire_result ([in] Long nresult)
After calculating the integer and the obtained result, we need to rely on this callback interface function to feedback it to the client.
7. Add a component to save the array of callback interface pointers.
As we have already said, this component is intended to support callback connections for multiple objects. Therefore, we need to use an array to save the connection. Because vc.net cannot use the Wizard to add member variables in the form of arrays, we should open the header file of the cevent1 class and enter it manually:
......
private:
ICallBack * m_pCallBack[10];
......
You can save an array in multiple ways. The sample program is relatively simple and defines a member array variable of 10 Element Spaces. If you have learned how to use STL, you can also implement it using containers such as vector.Note! Note! Note! In the constructor, do not forget to initialize the array element as null..
8. Now, complete all the code below.
Stdmethodimp cevent1: add (long N1, long N2)
{
Long nresult = N1 + N2;
For (INT I = 0; I <10; I ++)
{
If (m_pcallback [I]) // If the callback interface is valid
M_pcallback [I]-> fire_result (nresult); // event/notification
}
Return s_ OK;
}
Stdmethodimp cevent1: advise (icallback * pcallback, long * pdwcookie)
{
If (null = pcallback) // actually give me a null pointer ?!
Return e_invalidarg;
For (INT I = 0; I <10; I ++) // find a location to save the interface pointer
{
If (null = m_pcallback [I]) // found
{
M_pcallback [I] = pcallback; // save it to an array.
M_pcallback [I]-> addref (); // pointer counter + 1
* Pdwcookie = I + 1; // cookie is the array subscript
// The purpose of + 1 is to avoid using 0, because 0 indicates invalid
Return s_ OK;
}
}
Return e_outofmemory; // more than 10 connections, insufficient memory
}
Stdmethodimp cevent1: unadvise (long dwcookie)
{
If (dwcookie <1 | dwcookie> 10) // who did this? Randomly assigned Parameters
Return e_invalidarg;
If (null = m_pcallback [dwcookie-1]) // The parameter is incorrect, or the interface pointer is invalid.
Return e_invalidarg;
M_pcallback [dwcookie-1]-> release (); // pointer counter-1
M_pcallback [dwcookie-1] = NULL; // empty the array element of the lower mark
Return s_ OK;
}
Iv. Client implementation steps
After downloading the sample program, you can browse the client implementation program. Here I will only explain how the receiver is constructed:
Figure 7. derived receiver class csink from icallback
Here icallback is a COM interface, so csink cannot be case-based. If you compile it, you will get an error (note 3). The report says that you have not implemented the virtual function. Then, we can implement all the virtual functions according to the error report:
// Stdmethodimp is a macro, which is equivalent to long _ stdcall.
Stdmethodimp csink: QueryInterface (const struct _ guid & IID, void ** GMM)
{
* GMM = This; // no matter what interface you want, it is actually the object itself
Return s_ OK;
}
Ulong _ stdcall csink: addref (void)
{Return 1;} // make a false statement, because the object will not exit before the end of the program.
Ulong _ stdcall csink: release (void)
{Return 0;} // make a false statement, because the object will not exit before the end of the program.
Stdmethodimp csink: raw_fire_result (long nresult)
{
... // Display the calculation result in the window
Return s_ OK;
}
V., Summary
Com
There are two basic methods for implementing functions such as events and notifications by components. The callback interface method introduced today is very good, with fast speed, clear structure, and not complicated implementation. The next response introduces the connection point method (Support
Connection points), the connection point method is actually not very good, the speed is slow (if it is a remote DCOM method, you should choose it with caution), the structure is complex, the only benefit is ATL
It is simple to implement because it is packaged. I don't want to introduce it, but I can't do it because the components that Microsoft supports a large number of events are implemented using connection points. I hate Microsoft (note 4 ).
Note 1: I have come up with several more examples. Therefore, the first name is event1. After writing it, I feel that the program is complicated and I will not continue to do it again.
NOTE 2: Of course, you can choose to use dual interface. Note that in the following steps, when you add a callback interface to modify the IDL file, you must use custom (derived from iunknown instead of idispatch.
NOTE 3: A pile of shit is often used to describe a pile of shit.
Note 4: Do not take jokes seriously from Microsoft comrades! I come to dinner with you.