Simplifying IDispatch::Invoke

[Previous] [Next]

As we mentioned at the beginning of this chapter, C++ lacks the built-in support for Automation that Visual Basic provides. When dealing with the Visual Basic_centric Automation data types BSTR and VARIANT, C++ code can get a bit messy. But nowhere is the "impedance mismatch" between Automation and C++ more obvious than when you're using the IDispatch interface. Recall this Visual Basic code, which first appeared as Listing 5-1:

 Dim App As Object Private Sub Form_Load()     Set App = CreateObject("MSDEV.Application")     App.Visible = True     App.Quit End Sub 

As shown in Listing 5-2 in the section, "Is COM Tedious?", the equivalent functionality in C++ requires over 250 lines of code. Fortunately, working directly with dispinterfaces (groupings of methods and properties exposed via the IDispatch interface) is not frequently required because vtable interfaces have become the norm. Still, at times you'll need to work with dispinterfaces, especially when hosting Microsoft ActiveX controls.

The CComDispatchDriver Class

To simplify the occasional but necessary client use of the IDispatch interface, ATL provides the CComDispatchDriver class. You can think of CComDispatchDriver as a simplified specialization of the CComQIPtr class described earlier in the chapter, with a few additional helper methods that simplify the syntax required to call methods and properties using the IDispatch interface. The following pseudocode will serve as an example:

 try {     CComPtr<IUnknown> unk;     HRESULT hr = unk.CoCreateInstance(OLESTR("MSDEV.Application"));     OleRun(unk);     CComDispatchDriver disp(unk);    // QI for IDispatch     if(!disp)                        // Is pointer NULL?         throw(E_NOINTERFACE);     // Calling IDispatch methods directly     DISPID dispid;     LPOLESTR lpStr[] = {L"Visible", NULL};     disp->GetIDsOfNames(IID_NULL, lpStr, 1,         LOCALE_USER_DEFAULT, &dispid);     CComVariant vtVisible(VARIANT_TRUE);     DISPPARAMS dispparams = {NULL, NULL, 1, 1};     dispparams.rgvarg = &vtVisible;     DISPID dispidPut = DISPID_PROPERTYPUT;     dispparams.rgdispidNamedArgs = &dispidPut;     disp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,         DISPATCH_PROPERTYPUTREF, &dispparams, &vtVisible,         NULL, NULL);     // Using helper functions     disp.PutPropertyByName(L"Visible", &CComVariant(VARIANT_FALSE));     disp.Invoke0(L"Quit"); } catch(HRESULT hr) {     // Handle HRESULT } 

CComDispatchDriver has an overloaded constructor that takes an IUnknown pointer argument and queries for IDispatch. Similar to CComQIPtr<IDispatch>, CComDispatchDriver implements the necessary operator overloading that allows it to be used anywhere IDispatch* is required:

 class CComDispatchDriver {          operator IDispatch*() {return p;}     IDispatch& operator*() {ATLASSERT(p!=NULL); return *p; }     IDispatch** operator&() {ATLASSERT(p==NULL); return &p; }     IDispatch* operator->() {ATLASSERT(p!=NULL); return p; }      }; 

Previous Versions of ATL: CComDispatchDriver

In versions of ATL previous to 3.0, the CComDispatchDriver class provided only the GetProperty and PutProperty helper functions. The GetPropertyByName, PutPropertyByName, and InvokeX methods were introduced in version 3.0.

When using CComDispatchDriver, you can call IDispatch methods directly using the overloaded indirection operator (->) or one of several simplified helper methods defined by the class, as shown in Table 5-5.

Table 5-5. Frequently Used CComDispatchDriver Methods.

CComDispatchDriver Method Description
GetProperty, PutProperty Get or set a dispinterface property using its DISPID. For convenience, static-member versions of these functions exist that take an IDispatch* parameter, allowing you to call these methods without having to construct a CComDispatchDriver variable.
GetPropertyByName,PutPropertyByName Similar to the GetProperty and SetProperty methods, except that these methods allow you to invoke a property by name rather than by DISPID. The implementation of these methods simply calls IDispatch::GetIDsOfNames under the hood and forwards the returned DISPID to the GetProperty and PutProperty methods described in the first row of this table. Because this algorithm doesn't cache the DISPID to improve the performance of repeated calls to these methods, you should use GetProperty and PutProperty directly if you repeatedly invoke the same property.
Invoke0, Invoke1, Invoke2 Simplify the parameter list required to call IDispatch::Invoke.

Inside Atl
Inside ATL (Programming Languages/C)
ISBN: 1572318589
EAN: 2147483647
Year: 1998
Pages: 127 © 2008-2017.
If you may any questions please contact us: