Populating Your Interfaces with Properties

 < Free Open Study > 



Up until this point we have created interfaces supporting a collection of semantically related methods. We have seen that most methods, when described in IDL, support a physical return value (HRESULT) as well as a logical return value ([out, retval]). Beyond this, many COM-enabled languages support the use of properties in an interface definition. Furthermore, some languages support class properties in the language itself.

For example, in Visual Basic, a class property (such as Name) is internally represented by a pair of Property Let and Property Get methods. The VB object user triggers the correct variation based on the object's calling syntax. If we, as a VB class builder, write the following code in a CLS file (named CEmployee), we can define a property (Name) for a single private String called m_name:

click to expand
Figure 6-24: A Visual Basic class defining a single property.

Note 

Before you try this at home, realize that only Visual Basic 4.0 and higher support user-defined classes. A class is defined in VB by simple virtue of the CLS file extension; there is no VB keyword used to define a class.

Once the property is defined, as a VB object user you can now write the following:

' Form_Load is an event sent just before the VB form is about to be shown. ' This event is in response to a WM_CREATE message. ' Private Sub Form_Load()      Dim Fred as CEmployee      Set Fred = New CEmployee      Fred.Name = "Fred"                ' Calls Property Let     (C++ mutator)          MsgBox "Name is " & Fred.Name     ' Calls Property Get     (C++ accessor) End Sub 

In Visual Basic, a class is seen as a collection of properties and methods (and events for that matter). Notice how the Name property in the VB example above seems to suggest the object user is directly using public data (which would break encapsulation). This is not true. Under the hood we are calling the VB equivalent of accessors and mutators.

In COM, we can equip our vTable interfaces (as well as dispinterfaces and dual interfaces which we examine later) to expose properties. With ATL, this process is automated with the Add Property Wizard, accessible by right-clicking on your coclass from the ClassView tab. Assume that CoHexagon supports a new interface named IShapeID that allows users to provide a friendly name to identify their CoHexagon. IShapeID contains a single BSTR property called Name. We can configure this property using the Add Property Wizard (see Figure 6-25).

click to expand
Figure 6-25: The Add Property Wizard.

Notice that we can configure a property to be read-only or write-only by deselecting the appropriate Function Type check box. If you want a read-only property, deselect the Put Function option. If you want a write-only property, deselect Get Function. As you can see, it is possible for properties to take parameters; however, this is rare. It is always safe to ignore the Parameters edit box.

Note 

For the record, if you should ever need to add (or remove) a property to an interface without the Add Property Wizard, the steps below may be implemented by hand. Always remember that wizards do little more than save you some typing.

IDL Syntax for Interface Properties

We can see that our single Name property has been mapped to two separate IDL function definitions. The [propget] attribute marks a method as an accessor function, whereas [propput] marks a mutator:

// IShapeID supports the Name property. interface IShapeID : IUnknown {      [propget, helpstring("property Name")]           // Accessor.      HRESULT Name([out, retval] BSTR *pVal);      [propput, helpstring("property Name")]           // Mutator.      HRESULT Name([in] BSTR newVal); };

One important thing to keep in mind is that COM properties are always represented internally as methods. Interfaces can only contain methods, and the fact that some languages support properties is not much more than "syntactic sugar" provided by the target language. If we examine the header file for CoHexagon, we can see that in C++ syntax the Name property has been prototyped by the wizard as the following:

// Cohexagon.h // A single property resolves to "get" and "put" functions. STDMETHOD(get_Name)(/*[out, retval]*/ BSTR *pVal); STDMETHOD(put_Name)(/*[in]*/ BSTR newVal);

From an implementation point of view, a property is identical to fleshing out the details for a COM interface method. Assume we have added a private BSTR data member (named m_bstrName) to CoHexagon. We could then complete the Name property as so:

// [propget] Name implementation. STDMETHODIMP CCoHexagon::get_Name(BSTR *pVal) {      // return private BSTR.      *pVal = SysAllocString(m_bstrName);      return S_OK; } // [propput] Name implementation. STDMETHODIMP CCoHexagon::put_Name(BSTR newVal) {      // Reset the internal BSTR.      SysReAllocString(&m_bstrName, newVal);      return S_OK; }

Properties: The Client's Point of View

Different COM language mappings interpret the [propput] and [propget] attributes in different ways. Clients using straight C++ access the Name property as any other interface method:

 // Create a new CoHexagon named Fred. BSTR hexName; hexName = SysAllocString(L"Fred"); pShapeID -> put_Name(hexName); SysFreeString(hexName); // Print out name of my CoHex. char buff[80]; pShapeID -> get_Name(&hexName); WideCharToMultiByte(CP_ACP, NULL, hexName, -1, buff, 80, NULL, NULL); cout << "Your CoHex is called" << buff << endl; SysFreeString(hexName); 

Visual Basic developers can get at the Name property as such:

' A little VB code illustrating property manipulation. ' Dim myHex as New CoHexagon Dim itfShapeID as IShapeID Set itfShapeID = myHex itfShapeID.Name = "Fred"                    ' [propput] MsgBox itfShapeID.Name, , "My Hex is named..."      ' [propget]

Note 

If you have opted to use the C++ COM import statement (see Chapter 4), a C++ client can manipulate [propput] and [propget] in the same fashion as a VB developer.

And finally, a Java (J++) client can exercise the Name property as so. Notice how jactivex.exe prefixes "get" to [propget] functions and "set" to [propput] functions:

// A little bit of Java code. CoHexagon myHex = new CoHexagon(); IShapeID itfShapeID; itfShapeID = myHex; // Get and Put the Name property. itfShapeID.setName(new String("Fred")); MessageBox.show(     itfShapeID.getName(), "Your CoHex is named",                MessageBox.ICONEXCLAMATION);

You may be wondering if there are times when a property is a better choice than a method, or vice versa. In many cases, this is just another design issue for you to contend with. COM properties allow your interfaces to mesh into a given language mapping more naturally if the language supports the [propget] and [propput] attributes.

Other times, properties are a completely bad idea. For example, if we have a coclass that allows the user to set the state of the object using properties, we might have to make five [propput] calls to configure a new instance. Now what if the object resided on a distant machine? That would, of course, mean five round trips. Obviously, COM properties make for lousy remotable interfaces. If you have a number of properties that are serving to set the state of a COM object (e.g., Name, ID, SSN, DeptID), you will be wise to define a single method (e.g., Create(BSTR, int, BSTR, int)) for remote access.



 < Free Open Study > 



Developer's Workshop to COM and ATL 3.0
Developers Workshop to COM and ATL 3.0
ISBN: 1556227043
EAN: 2147483647
Year: 2000
Pages: 171

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net