convert line ends
[canaan.git] / prj / tech / libsrc / comtools / comtools.txt
blob6a1d34d4de39e31fdf9bc21e035490b0c9b18776
1 ///////////////////////////////////////////////////////////////////////////////
2 // $Source: x:/prj/tech/libsrc/comtools/RCS/comtools.txt $
3 // $Author: TOML $
4 // $Date: 1996/06/06 15:28:37 $
5 // $Revision: 1.4 $
6 //
8 This library presents tools useful for using and implementing
9 COM objects and OLE.  It includes several project and library
10 independent, cross-platform interfaces, possibly with
11 implementation tools.
13 The headers are included in many, many places and should be
14 changed with the greatest care.
16 Detail
17 ======
19 ComTools.h; Doc Updated: toml, 03-13-96
20 ---------------------------------------
21  comtools.h presents several tools for using and implementing COM
22  interfaces.  It should be included in place of objbase.h
24  The tools are:
25     - generic macros for implementing COM wrapper macros
26     - "Interface Pointers" that provide automatic naming, query/connect,
27       and release to reduce probability of error
28     - "Safe Release"
29     - three macros for implementing faster calling for select critical
30       functions
31     - implementation macros to eliminate the hassle of redundant
32     QI/AddRef/Release code
34  Macros for implementing COM wrapper macros:
36     To ease the use of COM interfaces in C, interface specifications
37     usually include some macros to handle the double-indirection of
38     vtable use.  Microsoft often hand-builds each macro, which has
39     two drawbacks: first it is cumbersome, second it it forces C
40     module being moved to C++ to change the call syntax, or use
41     special preprocessor defines.
43     These macros are of the form:
45         COMCallN(p, foo {, arg});
47     Where N matches the number of arguments.  For example, the default
48     interface functions are wrapped as follows:
50         #define COMQueryInterface(p, a, b)      COMCall2(p, QueryInterface, a, b)
51         #define COMAddRef(p)                    COMCall0(p, AddRef)
52         #define COMRelease(p)                   COMCall0(p, Release)
54     So given:
56         COMRelease(pInterface);
58     This expands in C++ to
60         pInterface->Release();
62     And in C to:
64         ((pInterface)->lpVtbl)->foo(pInterface);
66     Generally when defining an interface, you should define the
67     macros to access the interface from C at that time also, using
68     these macros.
70  "Interface Pointers" (C++ only)
72     Interface Pointers, or IPtrs, provide a convenient and general way
73     use pointers to interfaces.  They offer automatic query &
74     Release() of interface pointers. These simplify interface client code by:
76         1. Eliminating the need to explicitly QueryInterface()
77         2. Eliminating the need to Release() at every return point, for
78            robust and accurate reference counting.
79         3. Introducing a standard naming convention for interface pointers
80            by replacing the 'I' in the interface name with a 'p'. Thus
81            An IPtr to IUnknown defaults to pUnknown
82            Forms are available for finer control if default naming too is
83            restrictive
85  IPtrs These are only available in C and C++ source compiled using the C++
86  front end.
88  Safe Release:
90     It is typical when releasing an interface pointer to first test for
91     NULL before calling release, then setting the pointer to NULL after
92     release.  This way, code can cover all bases to ensure reference
93     counts are correct, without the storing any state outside the pointer
94     itself, and without the risk of accidental double-release.
96     The safe release macro encompasses this operation, and is generally
97     preferred over calling release directly.
99     "SimpleSafeRelease()" is used only in contexts where the pointer
100     is known to be going out of scope and thus need not be set to 0.
101     This version should generally be avoided if there is any doubt that
102     the instance in question is the absolute last use. It is generally
103     unneeded if your compiler's optimizer is working!
105     SafeRelease() is available from both C and C++ regardless of front end,
106     and works both with regular C pointers and IPtrs.
108  "Critical Use" macros:
110     The critical use macros allow for a level of indirection to be removed
111     when using truly critical functions.  They are advanced macros that
112     should be used with care.  They are intended as a tool for interface
113     designers to use to code simpler macros for clients
114     The interface specification should specify which operations are
115     useful this way, and provide macros to do critical use.
117     The macros essentially create an automatic function pointer, copy
118     the desired vtable entry, and allow for convenient call.  Thus
119     "((pInterface)->lpVtbl)->foo(pInterface)" becomes "auto_foo(pInterface)"
121     Be aware that these macros will cause no compile-time
122     type checking!  They also create a new scope.
124     Because constructs like this will be a maintenence problem,
125     and the net gain versus ordinary usage would be quite low,
126     these should be both implemented and used both sparingly and with
127     extreme caution.
129     The general form of ultimate client use, using AddRef() as an example
130     would be:
132     // Get an automatic pointer to AddRef(), call it until "test" is false
133     // Then let go.
134     IUnknown_CriticalAddRefBegin(pInterface);
135     while (test)
136         IUnknown_CriticalAddRef(pInterface);
137     IUnknown_CriticalAddRefEnd(pInterface);
139  Compare*s(), etc.:
141     Does correct comparisons of GUIDs
143  F_DECLARE_INTERFACE():
145     Forward declares an interface.  Interfaces that use other interfaces
146     should forward declare them rather than including the header
147     for them since interfaces are always accessed through pointers
149  DECLARE_UNKNOWN_PURE():
151     Expands to the pure declaration of IUnknown to make interface design
152     easier and more accurate.
154  DECLARE_UNKNOWN():
156     Expands to the declaration of IUnknown to make interface implementation
157     easier and more accurate.
159  DECLARE_UNAGGREGATABLE(), IMPLEMENT_UNAGGREGATABLE():
161     Expands to the declaration of IUnknown to make interface implementation
162     easier and more accurate.  Also implements the reference counting and
163     auto-destruction on release.
165  DECLARE_DELEGATION(), IMPLEMENT_DELEGATION():
167     Expands to the declaration of IUnknown to make interface implementation
168     easier and more accurate.  Also implements the code needed to delegate
169     to an outer object.
171  DECLARE_SINGLE_AGGREGATE(), IMPLEMENT_SINGLE_AGGREGATE():
173     These macros are for defining a shell which aggregates a single implementation
174     of an interface.  The interface should use delegation.
177 Creating Aggregatable Objects
178 =============================
180 Creating objects that can be aggregated is optional; however,
181 it is simple to do, and doing so has significant benefits. The
182 following rules must be followed in order to create an object
183 that is aggregatable (often called the inner object).
185     - The inner object's implementation of QueryInterface,
186       AddRef, and Release for the IUnknown interface controls
187       the inner object's reference count alone, and must not
188       delegate to the outer unknown. This IUnknown
189       implementation is sometimes called the implicit
190       IUnknown, somtimes referred to as the
191       controlling IUnknown.
193     - The implementation of QueryInterface, AddRef, and
194       Release members of all interfaces that the inner object
195       implements, other than IUnknown itself, must delegate
196       to the outer unknown. These implementations must not
197       directly affect the inner object's reference count.
199     - The implicit IUnknown must implement the
200       QueryInterface behavior for only the inner object.
202     - The aggregatable object must not call AddRef when
203       holding a reference to the outer unknown pointer.
205       The exception to this rule is when using the
206       IAggregate/IAggregateMemberControl protocol,
207       the outer aggregate makes all AddRefs() "weak"
208       during the "connect" phase of initialization. At
209       this time, the aggregateable object is allowed
210       to call QI or AddRef.
212     - If, when the object is created, any interface other
213       than IUnknown is requested, the creation must fail with
214       E_UNKNOWN.
216 Most of this detail has been wrapped up in the macros in
217 comtools.h and objcoll.h. The code fragment below illustrates a
218 correct implementation of an aggregatable object using these
219 macros (in C++, C is very similar):
221     class cSomeClass : public ISomeInterface
222         {
223     public:
224         // This macro declares QI/AddRef/Release, plus
225         // a pointer to the outer unknown (m_pOuterUnknown)
226         DECLARE_DELEGATION();
228         STDMETHOD (SomeMethod)();
230         // This macro declares an IUnknown derivation
231         // whose resonsible for notifying the
232         // outer cSomeClass instance that the reference
233         // count has reached zero.  This
234         // is the implicit or controlling IUnknown
235         // it also declares a member m_AggregateControl
236         DECLARE_SIMPLE_AGGREGATE_CONTROL(cSomeClass);
238         };
240     // This macro implements QI/AddRef/Release that
241     // delegate to m_pOuterUnknown.  cSomeClass is
242     // responsible for setting m_pOuterUnknown
243     IMPLEMENT_DELEGATION(cSomeClass);
245     // This macro implements QI/AddRef/Release for
246     // the implicit IUnknown.  This version
247     // automatically deletes the associated cSomeClass
248     // instance.
249     IMPLEMENT_SIMPLE_AGGREGATE_CONTROL_DELETE_CLIENT(cSomeClass);
251     cSomeClass::cSomeClass(IUnknown * pOuterUnknown)
252       : m_pOuterUnknown(pOuterUnknown), m_AggregateControl(this)
253         {
254         // Use convenience macro specified in IAggregate
255         // protocol header to add components into the aggregate
256         AddToAggregate1(pOuterUnknown, IID_ISomeClass, this, &m_AggregateControl);
258         // We hold the initial reference on the aggregate control,
259         // and now that the aggregate is referencing it, we can
260         // release it.
261         m_AggregateControl.Release();
262         }
264 Using this approach, not every aggregateable interface
265 implementation needs a controlling IUnknown.  Rather, every
266 conceptual object that can be cleaned up as a unit needs one
267 controlling IUnknown.
269 Note also that this example performs all run-time aggregation
270 hook-up in the constructor.  This is not a requirement.
272 Notes on IAggregate protocol
273 ----------------------------
275 Using the IAggregate protocol, the aggregate object
276 is not complete and ready to use until Init() is called.
277 Any QI for any interface other
279 Members of the aggregate entity *must* acquire any retained
280 references to other parts of the aggregate during the
281 connect phase.  Otherwise, the reference count of the aggregate
282 will be incorrect due to self-reference.
284 Also note that the IAggregate/IAggregateMemberControl protocol
285 is our own enhancement of the standard aggregation technique.
286 As a result, the predefined aggregate control macros are
287 optimized for the way we to aggregation.  They don't fulfill
288 the need of the implicit unknown to allow querying to all
289 interfaces represented in the object.
292 Aggregating Objects
293 -------------------
295 When developing an object that aggregates in another object,
296 these rules must be followed:
298   - When creating the inner object, the outer object must
299     explicitly ask for IUnknown.
301   - The outer object must protect its implementation of
302     Release from reentrancy with an artificial reference
303     count around its destruction code.
305   - The outer object must call its own outer unknown's
306     Release if it queries for a pointer to any of the inner
307     object's interfaces. To free this pointer, the outer
308     object calls its own outer unknown's AddRef followed by
309     Release on the inner object's pointer:
311     // Obtaining inner object interface pointer
312     pUnkInner->QueryInterface(IID_IFoo, &pIFoo);
313     pUnkOuter->Release();
315     // Releasing inner object interface pointer
316     pUnkOuter->AddRef();
317     pIFoo->Release();
319   - The outer object must not blindly delegate a query for any
320     unrecognized interface of the inner object unless that
321     behavior is specifically the intention of the outer object.