home *** CD-ROM | disk | FTP | other *** search
- AUTOMATING COLLECTIONS
-
- Frequently an application organizes data and objects in
- collections of various types, such as arrays, containers,
- or linked lists, or it utilizes such capabilites inherent in
- the operating platform. Collections generally expose an
- iterator, a counter, a random-access function, and
- optionally methods for managing the collection. Exposing
- collections for automation generally involves three steps:
-
- 1. The collection is exposed as a property which returns
- an object.
-
- 2. A C++ class is created, or enhanced, to support the
- collection methods.
-
- 3. An iterator is defined to provide code to iterate
- through the collection.
-
-
- The iterator is internally exposed to the script controller
- as a property having the reserved name "_NewEnum" which
- returns an object supporting the IENUMVariant interface.
- This interface contains methods to perform iteration. With
- VisualBasic for Applications, the following syntax is used
- for iteration:
-
- For Each Thing In Owner.Bunch ("Thing" is an arbitrary
- iterator name)
- Thing.Member...... (can access methods and
- properties)
- Next Thing (loops through all items
- in collection)
-
- Note that the server can return any data type for items,
- values or objects.
-
-
- CREATING C++ CLASSES SPECIFICALLY FOR AUTOMATION
-
- Frequently C++ classes do not already exist to encapsulate
- items to be exposed for automation, such as collections,
- simple structures, and system objects represented by
- handles. The only C++ methods required are a constructor
- and support methods for the exposed automation. Instances
- of these classes are exposed as properties of their parent
- classes and are constructed as the properties are retrieved
- (as opposed to returning references to existing C++
- instances). The constructor must accept a single argument
- from the parent class: member data, result of an accessor
- function, or the object's this pointer. The parent class
- must supply an AUTOxxx macro that supplies this constructor
- argument as a data member or function, and declares its
- type with the templatized pointer class
- TAutoObjectByVal<T>, where T is the new automated C++
- class. TAutoObjectByVal<T> causes an instance of T to be
- constructed that persists until all external references to
- that instance are released (when the exposed object goes
- out of scope in the automation controller). Examples of
- the macros used within the DECLARE_AUTOCLASS and
- DEFINE_AUTOCLASS sections are given below:
-
- AUTODATARO(Documents, DocList, TAutoObjectByVal<TDocumentList>,)
- // DocList is a TDocument*, head of a linked list of.
- // type TDocument. TDocumentList is a new class, constructor:
- // TDocumentList(TDocument*)
- EXPOSE_PROPRO(Documents, TDocumentList, "Documents", "Doc Collection", 270)
-
- AUTOTHIS(Views, TAutoObjectByVal<TViewList>,)
- // TViewList is a new class, constructor: TView(TDocument* owner)
- // In this case the parent's this pointer is passed to the constuctor
- EXPOSE_PROPRO(Views, TViewList, "Views", "View Collection", 240)
-
- AUTOFUNC0(Buttons, GetWindow(), TAutoObjectByVal<TCalcButtons>, )
- // GetWindow() gets the window handle of the parent window of
- // the buttons. TCalcButtons is a new class, constructor:
- // TCalcButtons(HWND parent)
- EXPOSE_PROPRO(Buttons, TCalcButtons, "Buttons", Button Collection", 170)
-
- AUTODATARO(MyArray, Elem, TAutoObjectByVal<TMyArray>,)
- // Elem is an array of shorts, defined as short Elem[COUNT]
- // TMyArray is a new class, constructor: TMyArray(short* array)
- EXPOSE_PROPRO(MyArray, TMyArray, "Array", "Array as collection", 110)
-
-
- COLLECTION CLASSES
-
- A C++ class must be defined to host the automation
- declarations along with the supporting C++ methods. For
- some collections, a C++ class might already exist. Otherwise
- one must be defined to represent a collection object.
-
-
- EXPOSING COLLECTION OBJECTS
-
- EXPOSING ITERATORS
-
- Iterators are defined for automation using the AUTOITERATOR
- macro, which defines the iteration algorithm for the
- enclosing collection class. No internal name is supplied,
- as only one iterator may exist within a class. The macro
- has five arguments, each representing a code fragment,
- ordered as in a "for" loop.
-
- 1. Declaration of state variables, e.g. int Index
- 2. Loop initializer assigments, e.g. Index = 0
- 3. Loop entry test boolean expression, e.g. Index < This->Total
- 4. Loop iteration statements, e.g. Index++
- 5. Current element access expression, e.g. (This->Array)[Index]
-
- Commas cannot be used unless inside parentheses. Semicolons
- can be used to separate multiple statements, but cannot
- be used to end a macro argument. In common with automated
- methods, "This" is defined to be the "this" pointer of the
- enclosing C++ class, in this case the collection itself.
-
- The AUTOITERATOR macro generates a nested class definition.
- For complex iterators, this class can be specified directly
- in C++ as shown below:
-
- class TIterator : public TAutoIterator {
- public:
- ThisClass* This;
- /* declare state variables here as members */
- void Init() {/* loop initialization function body */}
- bool Test() {/* loop entry test function body */}
- void Step() {/* loop iteration function body;}
- void Return(TAutoVal& v) {/* current element return: v = expr */}
- TIterator* Copy() {return new TIterator(*this);}
- TIterator(ThisClass* obj, TServedObject& owner)
- : This(obj), TAutoIterator(owner) {}
- static TAutoIterator* Build(ObjectPtr obj, TServedObject& owner)
- { return new TIterator((ThisClass*)obj, owner); }
- }; friend class TIterator;
-
- Iterators are exposed as properties using the
- EXPOSE_ITERATOR macro. Note that no internal or external
- names are supplied (the external name is internally
- hard-wired as "_NewEnum"). The automation type describes the
- type of the items returned from the iterator, in the same
- manner as a function return.
-
- AUTOITERATOR(int Index, Index=0, Index<COUNT, Index++,
- (This->Array)[Index])
- // Array is a member array of shorts for which an iterator
- // is defined. It will exposed as a "_NewEnum" property which
- // returns an OLE enumerator.
- EXPOSE_ITERATOR(TAutoShort, "Array Iterator", HC_ARRAY_ITERATOR)
-
- In addition to exposing an iterator, a collection class by
- convention exposes a "Count" method to return the number of
- items in the collections, an "Index" method to randomly
- access an element of the collection, and optionally,
- methods to externally manage the collection, such as add and
- delete.
-
- ____________________________________________________________
-
-
- ----example code from AutoCalc------
-
- class TCalcButtons {
- public:
- TCalcButtons(HWND window) : HWnd(window) {}
- short GetCount() { return IDC_LASTID - IDC_FIRSTID; }
- HWND HWnd;
-
- DECLARE_AUTOCLASS(TCalcButtons)
- AUTOFUNC0 (Count, GetCount, short,)
- AUTOITERATOR(int Id, Id = IDC_FIRSTID+1,
- Id <= IDC_LASTID, Id++,
- TAutoObjectByVal<TCalcButton>(::GetDlgItem(This->HWnd,Id)))
- };
-
- DEFINE_AUTOCLASS(TCalcButtons)
-
- EXPOSE_PROPRO(Count, TAutoLong, "!Count","Button Count",
- HC_TCALCBUTTONS_COUNT)
- EXPOSE_ITERATOR(TCalcButton, "Button Iterator",
- HC_TCALCBUTTONS_ITERATOR)
- EXPOSE_METHOD_ID(0, Item, TCalcButton,"!Item",
- "Button Collection Item", 0)
- REQUIRED_ARG(TAutoShort, "!Index")
-
- END_AUTOCLASS(TCalcButtons, "ButtonCollection",
- "Button Collection", HC_TCALCBUTTONS)
-
-
-