VirtualBox

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

Last change on this file since 72101 was 69107, checked in by vboxsync, 7 years ago

include/VBox/: (C) year

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