How to Develop COM components using ATL

Source: Internet
Author: User
1. Where is progid?

This is the first problem I encountered when I used the ATL wizard. You cannot find the progid you want to modify. It used to hide in the. RGS file with the same name as the component. RGS is the script file registered by the component. When you register the component with regsvr32.exe, the component calls this file internally. RGS files are stored in dll as resources.

2. manually add a method to modify the location.

Assume that the component class is named cobj and the interface is called iobj. The method to be added is open. First, find the iobj definition of the interface in the idl file, and add the following method definition to it:

[ID (2), helpstring ("method open")] hresult open ([out, retval] variant_bool * RET );

Note: Do not repeat the number in ID with an existing ID.

Then, add the following member function declaration to the class definition header file of cobj:

Public:

Stdmethod (open) (variant_bool * RET );

Finally, add the function implementation to the cobj class implementation CPP file:

Stdmethodimp open (variant_bool * RET)

{

* Ret = varaint_true;

Return s_ OK;

}

3. Multi-Purpose assertions help debugging

Com is an independent entity. It does not know the environment for calling it, nor does it know whether the caller calls it as agreed by the developer. Therefore, you should use atlassert to set checkpoints for debugging. For example, for a database connection component, in the open method, you must first use assertions to check whether the connectionstring attribute is assigned a value:

Atlassert (m_connstr! = NULL );

Write error processing should be followed after assertionProgramBecause in release, all assertions are invalid and your error handlingCodeIt is time to take effect.

If (m_connstr = NULL)

Return e_fail;

What should I do if the assertion fails? Here we provide a judgment principle: the com you developed is a com used internally by your own software, that is, when both the client and COM are developed by one person or within the Development Group, you can check whether the code of the client that fails the assertions is incomplete without processing the assertions. When the com you write is to be submitted to "others", you must process the assertion failure.

4. Write some macros that can be "lazy.

If a component has many attributes, and the processing of attributes is just to directly access member variables, writing a lot of get and put functions is a little annoying. These functions look almost the same, but the types of accessed data are different:

Get function body: * pval = m_somemembervar;

Put function body: m_somemembervar = newval;

We may wish to write a set of macros to deal with this boring job. Inspired by the copy policy class in ATL, I wrote the following macro:

// A general macro for Attribute write operations

# Define prop_put_impl (name, type)

Stdmethod (put _ ## name) (type newval)

{

M _ ## name = newval;

Return s_ OK;

}

// A general macro for Attribute read Operations

# Define prop_get_impl (name, type, copyadapter)

Stdmethod (GET _ # Name) (type * pval)

{

Copyadapter: Destroy (pval );

Type src = M _ # name;

Return copyadapter: Copy (pval, & SRC );

}

// Implement a general macro for read/write attributes

# Define prop_impl (name, type, copyadapter)

Prop_put_impl (name, type)

Prop_get_impl (name, type, copyadapter)

The premise of using this macro is that the name of the member function that saves the attribute must be in the form of "M _ attribute name". For example, there is a read/write attribute name with the type of BSTR, I can implement it like this in the object class.

Class atl_no_vtable cobj

{

... ...

Public:

Prop_impl (name, BSTR, copybstr)

PRIVATE:

Ccombstr m_name;

}

Copybstr is a copy policy class I wrote, as follows:

Class copybstr

{

Public:

Static hresult copy (BSTR * P1, BSTR * P2)

{

Atlassert (P2! = NULL );

If (P2 = NULL)

Return e_pointer;

Ccombstr bstrtemp = * P2;

Return bstrtemp. copyto (P1 );

}

Static void Init (BSTR * Str ){}

Static void destroy (BSTR * Str) {sysfreestring (* Str );}

};

It is easy to implement read-only attributes:

......

Public:

Prop_get_impl (name, BSTR, copybstr)

PRIVATE:

M_name;

Common types are written as follows:

Prop_impl (propname, long, _ copy <long>)

Prop_impl (propname, short, _ copy <short>)

Prop_impl (propname, varaint_bool, _ copy <varaint_bool>)

Prop_impl (propname, idispatch *, _ copyinterface <idispatch *>)

Prop_impl (propname, BSTR, copybstr)

There is an additional benefit to using this macro: the built-in functions are defined, and the efficiency is better than the function generated by the wizard.

There is also a common code segment, such:

Hresult hR = obj-> methodcall ();

If (failed (HR ))

Return hr;

We can define a macro to replace it:

# Define ret_err_if_fail (exp)

Do {

Hresult _ hR = (exp );

If (failed (HR) return hr;

} While (false)

Then use the following code:

Ret_err_if_fail (obj-> methodcall ());

Ret_err_if_fail (obj-> methodcall2 ());

The code is much more neat.

5. Use of BSTR

Beginner COM must stick to BSTR, making allocation and release confusing. Memory leakage is inevitable. We recommend that you try not to use BSTR directly and replace it with encapsulation class _ bstr_t and ccombstr. _ Bstr_t is a class, which is an extension of ansi c ++ by Ms. With it, you can use the BSTR type conveniently in the SDK mode (non-MFC or ATL. Ccombstr is the encapsulation of BSTR in ATL. Generally, ccombstr can be used for development using ATL. In the READ function of the attribute, you can use the copyto method of ccombstr to return a BSTR. Ccombstr reloads the get address operator &, And the get address for ccombstr is equal to the get address for its internal BSTR. In this way, ccombstr can also be used in out and retval parameters of the method, for example:

A Method of a COM class is defined as follows:

Hresult GetUserName ([in] BSTR userid, [out, retval] BSTR * username );

This method can return the username Code as follows:

......

M_username.copyto (username); // m_username is a member variable and the type is ccombstr

When the COM Client calls GetUserName, you can also use the ccombstr type variable to get username.

......

Ccombstr bstruserid (L "001"), bstrusername;

OBJ-> GetUserName (bstruserid, & bstrusername );

Whether it is the internal method GetUserName or the client, the memory can be correctly and automatically allocated and released. There is only one exception, that is, when a ccombstr variable is used continuously as the real parameter of the output parameter, improper processing will cause memory leakage. For example:

Ccombstr bstrfieldname, bstrfieldvalue;

Bstrfieldname = L "usr_id ";

Recordsetobj-> getfieldvalueasstring (bstrfieldname, & bstrfieldvalue );

M_userid = bstrfieldvalue;

Bstrfieldname = L "usr_name ";

Recordsetobj-> getfieldvalueasstring (bstrfieldname, & bstrfieldvalue); // if the method directly overwrites the & bstrfieldvalue pointer internally, the BSTR value will be lost. If ccombstr. copyto is used internally, no.

The _ bstr_t type is not bad, but we always use it when it is not necessary, that is, when we use the # import precompiled command to import a com encapsulation class. The encapsulation class imported using import only uses the _ bstr_t type as the BSTR parameter type, and the back-and-forth conversion between ccombstr, _ bstr_t, and BSTR is also a top headache. As a result, I wrote a cbstradapt class to automatically complete the conversion.

Class cbstradapt

{

_ Bstr_t m_str;

Public:

Cbstradapt (const _ bstr_t & Str)

{

M_str = STR;

}

Cbstradapt (const BSTR Str)

{

M_str = STR;

}

Cbstradapt (const ccombstr & Str)

{

M_str = Str. m_str;

}

Operator BSTR ()

{

Return m_str.getbstr ();

}

Operator _ bstr_t ()

{

Return m_str;

}

Operator ccombstr ()

{

Return ccombstr (m_str.getbstr ());

}

};

It is mainly used to complete the conversion from ccombstr to _ bstr_t.

For example, you need to call the following method:

Bool islogin (_ bstr_t userid );

The call code is as follows:

Ccombstr bstruserid (L "007 ");

If (obj-> islogin (cbstradapt (bstruserid ))

{

......

}

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.