Effective use and design of COM smart Pointers-clause 11

Source: Internet
Author: User

Clause 11: create resources and Query Interfaces in a type-safe manner
The following method is not uncommon in the compilation of COM components:

View plaincopy to clipboardprint? Void func ()
{
IX * pIX = NULL;
HrRetCode = CoCreateInstance (
CLSID_MYCOMPONENT,
NULL,
CLSCTX_INPROC_SERVER,
IID_IX
(Void **) pIX // amount ~~ Ship in the gutter ~
);
Assert (hrRetCode );
PIX-> IxFunction ();
}
Void func ()
{
IX * pIX = NULL;
HrRetCode = CoCreateInstance (
CLSID_MYCOMPONENT,
NULL,
CLSCTX_INPROC_SERVER,
IID_IX
(Void **) pIX // amount ~~ Ship in the gutter ~
);
Assert (hrRetCode );
PIX-> IxFunction ();
}
 
What will happen to the above Code? Its behavior is uncertain, and in most cases it is wrong. The reason is that the functions used when creating COM components or interface queries are not of type security.

In this case, you may think that we should use smart pointers to avoid this problem. Because smart pointers cannot be forcibly converted to the (void **) type. It seems that this can make your type safer, but the error still occurs:

View plaincopy to clipboardprint? Void func ()
{
CComPtr <IX> spIX = NULL;
HrRetCode = CoCreateInstance (
CLSID_MYCOMPONENT,
NULL,
CLSCTX_INPROC_SERVER,
IID_IY // amount ~~ An error occurs again :(
(Void **) & pIX
);
Assert (hrRetCode );
PIX-> IxFunction ();
}
Void func ()
{
CComPtr <IX> spIX = NULL;
HrRetCode = CoCreateInstance (
CLSID_MYCOMPONENT,
NULL,
CLSCTX_INPROC_SERVER,
IID_IY // amount ~~ An error occurs again :(
(Void **) & pIX
);
Assert (hrRetCode );
PIX-> IxFunction ();
}
Fortunately, the assertions later can give feedback on errors in a timely manner, but if we have a better way to avoid this problem, why not?

The best way to solve this problem is to use the interface query method provided by smart pointers:

View plaincopy to clipboardprint? Void func ()
{
CComPtr <IX> spIX = NULL; // The IID is bound to the smart pointer when it is created.
SpIX. CoCreateInstance (CLSID_MYCOMPONENT );
Assert (spIX );
PIX-> IxFunction ();
}
Void func ()
{
CComPtr <IX> spIX = NULL; // The IID is bound to the smart pointer when it is created.
SpIX. CoCreateInstance (CLSID_MYCOMPONENT );
Assert (spIX );
PIX-> IxFunction ();
}
Yes, that's right. We recommend that you use smart pointers, but we hope that you can use the functional functions provided by smart pointers to create and query resources. It not only makes the code concise, but also makes your code more secure in terms of type.

Sometimes, we usually consider the portability and compatibility of a class when considering its design. This leads us to exercise caution when using compiler-related features. Or more often, we can avoid some of the features that the compiler brings to us to pursue portability and compatibility with different platforms.

However, before considering these problems, we should first consider the proper execution of the program. A program that allows errors, even if it can be transplanted at will, does not make much sense.

First, let's take a look at the following interface and GUID definition:

View plaincopy to clipboardprint? // {994d80ac-a5b1-440a-a3e9-2533100b87ce}
DEFINE_GUID (IID_ICALCULATOR,
0x994d80ac, 0xa5b1, 0x430a, 0xa3, 0xe9, 0x25, 0x33, 0x10, 0xb, 0x87, 0xce );
Class ICalculator public: IUnknown
{
Public:
Virtual hresult stdmethodcalltype Add (
Const int nNum1,
Const int nNum2,
Int * pnSum
) Const = 0;

Virtual hresult stdmethodcalltype Sub (
Const int nMinuend,
Const int nSubtrahend,
Int * pnQuotient
) Const = 0;
};
// {994d80ac-a5b1-440a-a3e9-2533100b87ce}
DEFINE_GUID (IID_ICALCULATOR,
0x994d80ac, 0xa5b1, 0x430a, 0xa3, 0xe9, 0x25, 0x33, 0x10, 0xb, 0x87, 0xce );
Class ICalculator public: IUnknown
{
Public:
Virtual hresult stdmethodcalltype Add (
Const int nNum1,
Const int nNum2,
Int * pnSum
) Const = 0;

Virtual hresult stdmethodcalltype Sub (
Const int nMinuend,
Const int nSubtrahend,
Int * pnQuotient
) Const = 0;
};

 

There is no problem with this, and there will be no problems when using some smart pointers. For example, _ com_ptr_t allows you to bind the IID and the interface in the following way when you specifically define a smart pointer.

View plaincopy to clipboardprint? // This method is used to bind the IID and the interface when a smart pointer is specified.
_ COM_SMARTPTR_TYPEDEF (ICalculator, IID_ICALCULATOR );
HRESULT Calculaltor ()
{
ICalculatorPtr spCalculator (CLSID_CALCULATOR); // The constructor can create COM components.
Int nSum = 0;
SpCalculator-> Add (1, 2, & nSum );
Return S_ OK;
}
// This method is used to bind the IID and the interface when a smart pointer is specified.
_ COM_SMARTPTR_TYPEDEF (ICalculator, IID_ICALCULATOR );
HRESULT Calculaltor ()
{
ICalculatorPtr spCalculator (CLSID_CALCULATOR); // The constructor can create COM components.
Int nSum = 0;
SpCalculator-> Add (1, 2, & nSum );
Return S_ OK;
}
 
In this way, even in the case of specialization, it is easier to search and modify the IID and the corresponding ICalculator. Once the smart pointer is declared, the interface pointer and IID are bound together. In subsequent development, you do not need to consider the issue of matching between them.

However, if the above interface declaration and CComPtr are used in combination, the situation is very different. Your program may not be compiled at all:

View plaincopy to clipboardprint? Void func (void)
{
CComPtr <ICalculator> pCalculator = NULL;
// Compilation failed, prompt: no GUID has been associated with this object
HrRetCode = pCalculator. CoCreateInstance (CLSID_CALCULATOR ,);
Assert (hrRetCode );
SpCalculator-> DoSomething ();
}
Void func (void)
{
CComPtr <ICalculator> pCalculator = NULL;
// Compilation failed, prompt: no GUID has been associated with this object
HrRetCode = pCalculator. CoCreateInstance (CLSID_CALCULATOR ,);
Assert (hrRetCode );
SpCalculator-> DoSomething ();
}
We can see that CComPtr and _ com_ptr_t use two different methods to solve the problem of IID and interface binding. CComPtr requires developers to bind the IID to the interface when declaring the interface. But _ com_ptr_t can decide whether to use _ uuid as needed.

Therefore, to be compatible with these two smart pointers, we need to use the following method when defining them:

View plaincopy to clipboardprint? // Use the compiler to specify the IID for our security mechanism
Interface _ declspec (uuid ("994d80ac-a5b1-440a-a3e9-2533100b87ce") ICalculator:
IUnknown
{
Virtual hresult stdmethodcalltype Add (
Const int nNum1,
Const int nNum2,
Int * pnSum
) Const = 0;

Virtual hresult stdmethodcalltype Sub (
Const int nMinuend,
Const int nSubtrahend,
Int * pnQuotient
) Const = 0;
};
// Use the compiler to specify the IID for our security mechanism
Interface _ declspec (uuid ("994d80ac-a5b1-440a-a3e9-2533100b87ce") ICalculator:
IUnknown
{
Virtual hresult stdmethodcalltype Add (
Const int nNum1,
Const int nNum2,
Int * pnSum
) Const = 0;

Virtual hresult stdmethodcalltype Sub (
Const int nMinuend,
Const int nSubtrahend,
Int * pnQuotient
) Const = 0;
};

 

If you understand IDL, it is more reasonable to use IDL to define the interface and bind the IID with it. But for the time being, this will make the things we want to express in the example clearer and clearer.

Yes, although the portability is a little lower, it makes the interface more secure and convenient to use. You do not need to specify the corresponding IID for the interface each time you query the interface and create the COM component. This is often the cause of errors. We need to first consider how to write security code that is difficult to produce errors, followed by its compatibility.

If you want to know how to solve the porting and compatibility discussions brought about by uuid and _ uuidof.

Author's "liuchang5 column"

Related Article

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.