VirtualBox

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

Last change on this file since 58920 was 58110, checked in by vboxsync, 9 years ago

include,misc: Doxygen grouping adjustments, collecting all the VMM bits under one parent group, ditto for the COM library.

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