VirtualBox

source: vbox/trunk/include/VBox/com/ptr.h@ 30632

Last change on this file since 30632 was 30632, checked in by vboxsync, 14 years ago

Main: simplify and document ComPtr<> template; speeds up compiling a bit

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.5 KB
Line 
1/** @file
2 * MS COM / XPCOM Abstraction Layer:
3 * Smart COM pointer classes declaration
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27#ifndef ___VBox_com_ptr_h
28#define ___VBox_com_ptr_h
29
30/* Make sure all the stdint.h macros are included - must come first! */
31#ifndef __STDC_LIMIT_MACROS
32# define __STDC_LIMIT_MACROS
33#endif
34#ifndef __STDC_CONSTANT_MACROS
35# define __STDC_CONSTANT_MACROS
36#endif
37
38#if !defined (VBOX_WITH_XPCOM)
39 #include <atlbase.h>
40 #ifndef _ATL_IIDOF
41 # define _ATL_IIDOF(c) __uuidof(c)
42 #endif
43#else
44 #include <nsISupportsUtils.h>
45#endif /* !defined (VBOX_WITH_XPCOM) */
46
47#include <VBox/com/com.h>
48
49/**
50 * COM autopointer class which takes care of all required reference counting.
51 *
52 * This automatically calls the required basic COM methods on COM pointers
53 * given to it:
54 *
55 * -- AddRef() gets called automatically whenever a new COM pointer is assigned
56 * to the ComPtr instance (either in the copy constructor or by assignment);
57 *
58 * -- Release() gets called automatically by the destructor and when an existing
59 * object gets released in assignment;
60 *
61 * -- QueryInterface() gets called automatically when COM pointers get converted
62 * from one interface to another.
63 *
64 * Example usage:
65 *
66 * @code
67 *
68 * {
69 * ComPtr<IMachine> pMachine = findMachine("blah"); // calls AddRef()
70 * ComPtr<IUnknown> pUnknown = pMachine; // calls QueryInterface()
71 * } # ComPtr destructor of both instances calls Release()
72 *
73 * @endcode
74 */
75template <class T>
76class ComPtr
77{
78public:
79
80 /**
81 * Default constructor, sets up a NULL pointer.
82 */
83 ComPtr()
84 : m_p(NULL)
85 { }
86
87 /**
88 * Destructor. Calls Release() on the contained COM object.
89 */
90 ~ComPtr()
91 {
92 cleanup();
93 }
94
95 /**
96 * Copy constructor from another ComPtr of any interface.
97 *
98 * This calls QueryInterface(T) and can result in a NULL pointer if the input
99 * pointer p does not support the ComPtr interface T.
100 *
101 * Does not call AddRef explicitly because if QueryInterface succeeded, then
102 * the refcount will have been increased by one already .
103 */
104 template <class T2>
105 ComPtr(const ComPtr<T2> &that)
106 {
107 m_p = NULL;
108 if (!that.isNull())
109 that->QueryInterface(COM_IIDOF(T), (void**)&m_p);
110 }
111
112 /**
113 * Specialization: copy constructor from another ComPtr<T>. Calls AddRef().
114 */
115 ComPtr(const ComPtr &that)
116 {
117 copyFrom(that.m_p);
118 }
119
120 /**
121 * Copy constructor from another interface pointer of any interface.
122 *
123 * This calls QueryInterface(T) and can result in a NULL pointer if the input
124 * pointer p does not support the ComPtr interface T.
125 *
126 * Does not call AddRef explicitly because if QueryInterface succeeded, then
127 * the refcount will have been increased by one already .
128 */
129 template <class T2>
130 ComPtr(T2 *p)
131 {
132 m_p = NULL;
133 if (p)
134 p->QueryInterface(COM_IIDOF(T), (void**)&m_p);
135 }
136
137 /**
138 * Specialization: copy constructor from a plain T* pointer. Calls AddRef().
139 */
140 ComPtr(T *that_p)
141 {
142 copyFrom(that_p);
143 }
144
145 /**
146 * Assignment from another ComPtr of any interface.
147 *
148 * This calls QueryInterface(T) and can result in a NULL pointer if the input
149 * pointer p does not support the ComPtr interface T.
150 *
151 * Does not call AddRef explicitly because if QueryInterface succeeded, then
152 * the refcount will have been increased by one already .
153 */
154 template <class T2>
155 ComPtr& operator=(const ComPtr<T2> &that)
156 {
157 return operator=((T2*)that);
158 }
159
160 /**
161 * Specialization of the previous: assignment from another ComPtr<T>.
162 * Calls Release() on the previous member pointer, if any, and AddRef() on the new one.
163 */
164 ComPtr& operator=(const ComPtr &that)
165 {
166 return operator=((T*)that);
167 }
168
169 /**
170 * Assignment from another interface pointer of any interface.
171 *
172 * This calls QueryInterface(T) and can result in a NULL pointer if the input
173 * pointer p does not support the ComPtr interface T.
174 *
175 * Does not call AddRef explicitly because if QueryInterface succeeded, then
176 * the refcount will have been increased by one already .
177 */
178 template <class T2>
179 ComPtr& operator=(T2 *p)
180 {
181 cleanup();
182 if (p)
183 p->QueryInterface(COM_IIDOF(T), (void**)&m_p);
184 return *this;
185 }
186
187 /**
188 * Specialization of the previous: assignment from a plain T* pointer.
189 * Calls Release() on the previous member pointer, if any, and AddRef() on the new one.
190 */
191 ComPtr& operator=(T *p)
192 {
193 cleanup();
194 copyFrom(p);
195 return *this;
196 }
197
198 /**
199 * Resets the ComPtr to NULL. Works like a NULL assignment except it avoids the templates.
200 */
201 void setNull()
202 {
203 cleanup();
204 }
205
206 /**
207 * Returns true if the pointer is NULL.
208 */
209 bool isNull() const
210 {
211 return (m_p == NULL);
212 }
213
214 bool operator<(T* p) const
215 {
216 return m_p < p;
217 }
218
219 /**
220 * Conversion operator, most often used to pass ComPtr instances as
221 * parameters to COM method calls.
222 */
223 operator T*() const
224 {
225 return m_p;
226 }
227
228 /**
229 * Dereferences the instance (redirects the -> operator to the managed
230 * pointer).
231 */
232 T* operator->() const
233 {
234 return m_p;
235 }
236
237 /**
238 * Special method which allows using a ComPtr as an output argument of a COM method.
239 * The ComPtr will then accept the method's interface pointer without calling AddRef()
240 * itself, since by COM convention this must has been done by the method which created
241 * the object that is being accepted.
242 *
243 * The ComPtr destructor will then still invoke Release() so that the returned object
244 * can get cleaned up properly.
245 */
246 T** asOutParam()
247 {
248 cleanup();
249 return &m_p;
250 }
251
252 /**
253 * Converts the contained pointer to a different interface
254 * by calling QueryInterface() on it.
255 * @param pp
256 * @return
257 */
258 template <class T2>
259 HRESULT queryInterfaceTo(T2 **pp) const
260 {
261 if (pp)
262 {
263 if (m_p)
264 return m_p->QueryInterface(COM_IIDOF(T2), (void**)pp);
265 else
266 {
267 *pp = NULL;
268 return S_OK;
269 }
270 }
271
272 return E_INVALIDARG;
273 }
274
275 /**
276 * Equality test operator. By COM definition, two COM objects are considered
277 * equal if their IUnknown interface pointers are equal.
278 */
279 template <class T2>
280 bool operator==(T2* p)
281 {
282 IUnknown *p1 = NULL;
283 bool fNeedsRelease1 = false;
284 if (m_p)
285 fNeedsRelease1 = (SUCCEEDED(m_p->QueryInterface(COM_IIDOF(IUnknown), (void**)&p1)));
286
287 IUnknown *p2 = NULL;
288 bool fNeedsRelease2 = false;
289 if (p)
290 fNeedsRelease2 = (SUCCEEDED(p->QueryInterface(COM_IIDOF(IUnknown), (void**)&p2)));
291
292 bool f = p1 == p2;
293 if (fNeedsRelease1)
294 p1->Release();
295 if (fNeedsRelease2)
296 p2->Release();
297 return f;
298 }
299
300 /**
301 * Creates an in-process object of the given class ID and starts to
302 * manage a reference to the created object in case of success.
303 */
304 HRESULT createInprocObject(const CLSID &clsid)
305 {
306 HRESULT rc;
307 T *obj = NULL;
308#if !defined (VBOX_WITH_XPCOM)
309 rc = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, _ATL_IIDOF(T),
310 (void**)&obj);
311#else /* !defined (VBOX_WITH_XPCOM) */
312 using namespace com;
313 rc = GlueCreateInstance(clsid, NS_GET_IID(T), (void**)&obj);
314#endif /* !defined (VBOX_WITH_XPCOM) */
315 *this = obj;
316 if (SUCCEEDED(rc))
317 obj->Release();
318 return rc;
319 }
320
321 /**
322 * Creates a local (out-of-process) object of the given class ID and starts
323 * to manage a reference to the created object in case of success.
324 *
325 * Note: In XPCOM, the out-of-process functionality is currently emulated
326 * through in-process wrapper objects (that start a dedicated process and
327 * redirect all object requests to that process). For this reason, this
328 * method is fully equivalent to #createInprocObject() for now.
329 */
330 HRESULT createLocalObject(const CLSID &clsid)
331 {
332#if !defined (VBOX_WITH_XPCOM)
333 HRESULT rc;
334 T *obj = NULL;
335 rc = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, _ATL_IIDOF(T),
336 (void**)&obj);
337 *this = obj;
338 if (SUCCEEDED(rc))
339 obj->Release();
340 return rc;
341#else /* !defined (VBOX_WITH_XPCOM) */
342 return createInprocObject(clsid);
343#endif /* !defined (VBOX_WITH_XPCOM) */
344 }
345
346#ifdef VBOX_WITH_XPCOM
347 /**
348 * Creates an object of the given class ID on the specified server and
349 * starts to manage a reference to the created object in case of success.
350 *
351 * @param serverName Name of the server to create an object within.
352 */
353 HRESULT createObjectOnServer(const CLSID &clsid, const char *serverName)
354 {
355 T *obj = NULL;
356 HRESULT rc = GlueCreateObjectOnServer(clsid, serverName, NS_GET_IID(T), (void**)&obj);
357 *this = obj;
358 if (SUCCEEDED(rc))
359 obj->Release();
360 return rc;
361 }
362#endif
363
364protected:
365 void copyFrom(T* p)
366 {
367 if ((m_p = p))
368 m_p->AddRef();
369 }
370
371 void cleanup()
372 {
373 if (m_p)
374 {
375 m_p->Release();
376 m_p = NULL;
377 }
378 }
379
380 T *m_p;
381};
382
383/**
384 * ComObjPtr is a more specialized variant of ComPtr designed to be used for implementation
385 * objects. For example, use ComPtr<IMachine> for a client pointer that calls the interface
386 * but ComObjPtr<Machine> for a pointer to an implementation object.
387 *
388 * The methods behave the same except that ComObjPtr has the additional createObject()
389 * method which allows for instantiating a new implementation object.
390 */
391template <class T>
392class ComObjPtr : public ComPtr<T>
393{
394public:
395
396 ComObjPtr()
397 : ComPtr<T>()
398 {}
399
400 ComObjPtr(const ComObjPtr &that)
401 : ComPtr<T>(that)
402 {}
403
404 ComObjPtr(T *that_p)
405 : ComPtr<T>(that_p)
406 {}
407
408 ComObjPtr& operator=(const ComObjPtr &that)
409 {
410 ComPtr<T>::operator=(that);
411 return *this;
412 }
413
414 ComObjPtr& operator=(T *that_p)
415 {
416 ComPtr<T>::operator=(that_p);
417 return *this;
418 }
419
420 /**
421 * Creates a new server-side object of the given component class and
422 * immediately starts to manage a pointer to the created object (the
423 * previous pointer, if any, is of course released when appropriate).
424 *
425 * @note Win32: when VBOX_COM_OUTOFPROC_MODULE is defined, the created
426 * object doesn't increase the lock count of the server module, as it
427 * does otherwise.
428 */
429 HRESULT createObject()
430 {
431 HRESULT rc;
432#if !defined (VBOX_WITH_XPCOM)
433# ifdef VBOX_COM_OUTOFPROC_MODULE
434 CComObjectNoLock<T> *obj = new CComObjectNoLock<T>();
435 if (obj)
436 {
437 obj->InternalFinalConstructAddRef();
438 rc = obj->FinalConstruct();
439 obj->InternalFinalConstructRelease();
440 }
441 else
442 rc = E_OUTOFMEMORY;
443# else
444 CComObject<T> *obj = NULL;
445 rc = CComObject<T>::CreateInstance(&obj);
446# endif
447#else /* !defined (VBOX_WITH_XPCOM) */
448 CComObject<T> *obj = new CComObject<T>();
449 if (obj)
450 rc = obj->FinalConstruct();
451 else
452 rc = E_OUTOFMEMORY;
453#endif /* !defined (VBOX_WITH_XPCOM) */
454 *this = obj;
455 return rc;
456 }
457};
458#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette