1 ///////////////////////////////////////////////////////////////////////////////
2 // $Source: x:/prj/tech/libsrc/comtools/RCS/comtools.txt $
4 // $Date: 1996/06/06 15:28:37 $
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
13 The headers are included in many, many places and should be
14 changed with the greatest care.
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
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
29 - three macros for implementing faster calling for select critical
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)
56 COMRelease(pInterface);
58 This expands in C++ to
60 pInterface->Release();
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
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
85 IPtrs These are only available in C and C++ source compiled using the C++
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
129 The general form of ultimate client use, using AddRef() as an example
132 // Get an automatic pointer to AddRef(), call it until "test" is false
134 IUnknown_CriticalAddRefBegin(pInterface);
136 IUnknown_CriticalAddRef(pInterface);
137 IUnknown_CriticalAddRefEnd(pInterface);
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.
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
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
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
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);
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
249 IMPLEMENT_SIMPLE_AGGREGATE_CONTROL_DELETE_CLIENT(cSomeClass);
251 cSomeClass::cSomeClass(IUnknown * pOuterUnknown)
252 : m_pOuterUnknown(pOuterUnknown), m_AggregateControl(this)
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
261 m_AggregateControl.Release();
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.
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
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.