COM Component Design and Application (15th) -- connection point (vc6.0)

Source: Internet
Author: User

Download source code

I. Preface

The callback interface is introduced in the previous response. On this basis, it is much easier to understand the connection points.

Ii. Principles


Figure 1. Schematic diagram of the connection point component. Client on the left and server on the right (Component Object)

Look complicated... haha, actually simple: (Note 1)
1. a COM component allows multiple connection point objects (iconnectionpoint ).
That is to say, there can be multiple sources where "events" occur. There are three connection points;
2. The interface for managing these connection points is called the "connection point container" (iconnectionpointcontainer ).

The connection point container interface is very simple, because there are only two functions, one is findconnectionpoint (), which indicates to find the desired connection point; the other is
Enumconnectionpoints () indicates to list all the connection points, and then you can select which one to use. In actual applications, the lookup method is used most, accounting for 90%, while the enumeration method is used
It only accounts for 10% of all plug-ins. It is generally used when third-party plug-ins (plug in) are supported. (Do you want to write an IE Plug-in? We will talk about it later)
3. Each connection point can be connected by the receivers of multiple clients;
We are familiar with this. Do you still remember that we used cookies to manage multiple callback interfaces in the previous response ?!

Iii. Implementation components (I)

1. Create a workspace)
2. Create an ATL Project in the workspace ). In the example program, the project name is simple15. All default options are accepted.
3. In classview, run the right-click menu command new ATL object... to add the alt class.
4. Select objects for category on the left and simpleobject for objects on the right (which is actually the default project ).
5. Enter the component name in the name card. In this example, dispconnect is used.

6. In the attribute attributes card, the interface type is dual. Be sure to select support connection points to support connection points.

7. In classview, select the interface (idispconnect) and right-click the menu to add the function add method...

8. Add a function. Like the program in the previous response, an interface function compute addition is added, but the calculation result is returned through the connection point interface.

9. Add the "event" function below. Select the event interface (_ idispconnectevents) and add the function.

10. This function is used to return the calculation result of the add () function.

11. Switch to the FileView card and compile the IDL file. Of course, you can also compile all the projects directly. In fact, the purpose of compilation is to generate a TLB file from the IDL file, because the vc ide environment can generate the following "event proxy program code" only after knowing TLB ".

12. Generate the event proxy program code. Select the component class Object (cdispconnect) and right-click the component and choose "implement connection point"

13. Select the proxy code at which point you want the IDE to generate for you. We have only one connection point for this component, so we have to choose it. (In example 2, we need to implement two connection points. At that time, you need to select two)

14. At this point, VC's ide finally helped us complete all the frameworks. Now let's write our own task code.

Stdmethodimp cdispconnect: add (long N1, long N2)
{
Long nval = N1 + N2;
Fire_result (nval); // call the Agent Function Code generated by IDE to send events.

Return s_ OK;
}

15. Correct Errors in the code generated by IDE. You don't have to memorize the error points. An error will be reported after compilation. Generally, two bugs may occur in the code generated by vc6. First, open the header file, find the connection point, and modify the macro as follows:

Begin_connection_point_map (cdispconnect)
Connection_point_entry (diid _ idispconnectevents)// Change iid_xxxx to diid_xxxx
End_connection_point_map ()

 
This error is simply hateful. Since we are using a dual-interface connection point, the code generated by it will not be judged? Another possible error may occur in fire_xxxx () in the proxy class ()
Function. In the example program, fire_result ()
Function code. You can read it by yourself. In short, it means to cyclically obtain the interface pointer of each object connected to yourself (the object represented by each cookie). (if it is an automated interface, you can obtain
Idispatch
Interface pointer), and then call the event function. You don't understand that it doesn't have much to do with it now, but in the second example, the code it generates is incorrect and we need to modify it. This is coming soon
Let's talk about it.

IV. Implementation of callers (1)

1. Create an MFC project ). The project name in the sample project is use.
2. Add # import, afxoleinit (),... according to our previous knowledge. If you still don't know, read it again from the fourth round. (Note 2)
3. Here we will only introduce the key parts. We need to add the "receiver" object in the caller project. Do you still remember the method for adding the "Callback receiver" object in the previous response? In the previous process, our callback interface was inherited from iunknown. In this return, because our components are dual interfaces and the connection points are also dual interfaces, our receiver needs to be derived from idispatch this time.

4. Complete csink class interface functions (virtual functions)

Stdmethodimp csink: QueryInterface (const struct _ guid & IID, void ** GMM)
{
* GMM = this;
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: gettypeinfocount (unsigned int *)
{Return e_notimpl;} // No need to implement it. No need to implement it anyway.

Stdmethodimp csink: gettypeinfo (unsigned int, unsigned long, struct itypeinfo **)
{Return e_notimpl;} // No need to implement it. No need to implement it anyway.

Stdmethodimp csink: getidsofnames (const struct _ guid &, unsigned short **, unsigned int, unsigned long, long *)
{Return e_notimpl;} // No need to implement it. No need to implement it anyway.

Stdmethodimp csink: invoke (
Long dispid,
Const struct _ guid &,
Unsigned long,
Unsigned short,
Struct tagdispparams * pparams,
Struct tagvariant *,
Struct tag1_info *,
Unsigned int *)
{// You only need to implement this.
Switch (dispid) // complete different callback functions based on different dispid
{
Case 1:
... // You will be able to receive the event from Com.
Break;
Case 2:
... // The Event code dispid is actually the ID (n) of the connection point function in the IDL file.
Break;
Default: break;
}
Return s_ OK;
}

V., Example (2)

In the example program's 2nd components (multconnect), we add another connection point (_ idispconnectevents2 ). This interface object is responsible for completing a clock, and sends a "clock event" to the caller every certain interval of milliseconds ". To add the second connection point, manually modify the IDL file.

......
Library multconnectlib
{
Importlib ("stdole32.tlb ");
Importlib ("stdole2.tlb ");

... // The first one. The ATL framework gives us the generated connection point interface description by default.
[// Manually add the second or more connection points
UUID (F81DB93F-4F63-4A55-8114-A32BC78466D3), // CLSID can be generated using guidgen. exe
Helpstring ("_ idispconnectevents2 interface ")
]
Dispinterface _ idispconnectevents2
{
Properties:
Methods:
};

[
UUID (9461be82-0d64-4e3b-b0db-2306d1bfe3f0), // This is the Type Library ID of the sample program. It must be different from what you have generated.
Helpstring ("dispconnect class ")
]
Coclass dispconnect
{
[Default] interface idispconnect;
[Default, source] dispinterface _ idispconnectevents;
[Source] dispinterface _ idispconnectevents2; // do not forget, there is a line here
};
};

 
Okay, just like in the previous method, add interface functions, compile IDL files, and let ide help us implement proxy code, input program code, and modify bugs in framework code. In the example
The function is called hresult timer ([in] variant vardata) and vardata.
(Note 3 ). Let's take a look at the errors in the proxy code:

Hresult fire_timer (variant vardate)
{
Ccomvariant varresult;
T * PT = static_cast (this );
Int nconnectionindex;
Ccomvariant * pvars = new ccomvariant [1];
Int nconnections = m_vec.getsize ();

For (nconnectionindex = 0; nconnectionindex <nconnections; nconnectionindex ++)
{
Pt-> lock ();
Ccomptr sp = m_vec.getat (nconnectionindex );
Pt-> unlock ();
Idispatch * pdispatch = reinterpret_cast (sp. P );
If (pdispatch! = NULL)
{
Variantclear (& varresult );
     // Original code. pvars [0] = & vardata? Stupid! You have to modify it yourself.
Pvars [0] = vardate;

Dispparams disp = {pvars, null, 1, 0 };
Pdispatch-> invoke (0x1, iid_null, locale_user_default, dispatch_method, & disp, & varresult, null, null );
}
}
Delete [] pvars;
Return varresult. scode;
}

To write the caller's client code, if you need to receive clock events, you can repeatedly derive a clock receiver from idispatch, as shown in the following example. You can download the sample code, which contains a wealth of comments.

Vi. Summary

Connection points, especially double interface connection points, are less efficient in remote (DCOM) environments. If you only want to complete the simple "notification" function, the "Callback interface" in the previous one is a wise solution and can run in the DCOM environment. The connection point solution is also very important, because many Microsoft applications (ie, office...) support connection points, and ActiveX can only provide the "event" function through the connection point interface. Therefore, we can still master it as good. Shanzai, shanzai ......

NOTE 1: In the martial arts novels of Mr. Jin Yong, "XX is always used to express" XX ". I also want to learn.
NOTE 2: If you have read it several times, you will not be able to do so. 5555
Note
3: the data type is an 8-byte double, and its integer part indicates
The total number of days from January 1, December 30, 1899. The decimal part indicates the number of days that have elapsed. This time type, represented by variant, is the vt_date class.
Type, expressed by coledatetime in MFC. The example program demonstrates this type of operation.

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.