VirtualBox

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

Last change on this file since 67180 was 65441, checked in by vboxsync, 8 years ago

comment whitespace fix

  • 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-2016 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 else
291 {
292 *pp = NULL;
293 return S_OK;
294 }
295 }
296
297 return E_INVALIDARG;
298 }
299
300 /**
301 * Equality test operator. By COM definition, two COM objects are considered
302 * equal if their IUnknown interface pointers are equal.
303 */
304 template <class T2>
305 bool operator==(T2 *p)
306 {
307 IUnknown *p1 = NULL;
308 bool fNeedsRelease1 = false;
309 if (m_p)
310 fNeedsRelease1 = (SUCCEEDED(m_p->QueryInterface(COM_IIDOF(IUnknown), (void **)&p1)));
311
312 IUnknown *p2 = NULL;
313 bool fNeedsRelease2 = false;
314 if (p)
315 fNeedsRelease2 = (SUCCEEDED(p->QueryInterface(COM_IIDOF(IUnknown), (void **)&p2)));
316
317 bool f = p1 == p2;
318 if (fNeedsRelease1)
319 p1->Release();
320 if (fNeedsRelease2)
321 p2->Release();
322 return f;
323 }
324
325 /**
326 * Creates an in-process object of the given class ID and starts to
327 * manage a reference to the created object in case of success.
328 */
329 HRESULT createInprocObject(const CLSID &clsid)
330 {
331 HRESULT rc;
332 T *obj = NULL;
333#ifndef VBOX_WITH_XPCOM
334 rc = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, COM_IIDOF(T),
335 (void **)&obj);
336#else /* VBOX_WITH_XPCOM */
337 using namespace com;
338 rc = GlueCreateInstance(clsid, NS_GET_IID(T), (void **)&obj);
339#endif /* VBOX_WITH_XPCOM */
340 *this = obj;
341 if (SUCCEEDED(rc))
342 obj->Release();
343 return rc;
344 }
345
346 /**
347 * Creates a local (out-of-process) object of the given class ID and starts
348 * to manage a reference to the created object in case of success.
349 *
350 * Note: In XPCOM, the out-of-process functionality is currently emulated
351 * through in-process wrapper objects (that start a dedicated process and
352 * redirect all object requests to that process). For this reason, this
353 * method is fully equivalent to #createInprocObject() for now.
354 */
355 HRESULT createLocalObject(const CLSID &clsid)
356 {
357#ifndef VBOX_WITH_XPCOM
358 HRESULT rc;
359 T *obj = NULL;
360 rc = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, COM_IIDOF(T),
361 (void **)&obj);
362 *this = obj;
363 if (SUCCEEDED(rc))
364 obj->Release();
365 return rc;
366#else /* VBOX_WITH_XPCOM */
367 return createInprocObject(clsid);
368#endif /* VBOX_WITH_XPCOM */
369 }
370
371#ifdef VBOX_WITH_XPCOM
372 /**
373 * Creates an object of the given class ID on the specified server and
374 * starts to manage a reference to the created object in case of success.
375 *
376 * @param serverName Name of the server to create an object within.
377 */
378 HRESULT createObjectOnServer(const CLSID &clsid, const char *serverName)
379 {
380 T *obj = NULL;
381 HRESULT rc = GlueCreateObjectOnServer(clsid, serverName, NS_GET_IID(T), (void **)&obj);
382 *this = obj;
383 if (SUCCEEDED(rc))
384 obj->Release();
385 return rc;
386 }
387#endif
388
389protected:
390 void copyFrom(T *p)
391 {
392 m_p = p;
393 if (m_p)
394 m_p->AddRef();
395 }
396
397 void cleanup()
398 {
399 if (m_p)
400 {
401 m_p->Release();
402 m_p = NULL;
403 }
404 }
405
406public:
407 // Do NOT access this member unless you really know what you're doing!
408 T *m_p;
409};
410
411/**
412 * ComObjPtr is a more specialized variant of ComPtr designed to be used for implementation
413 * objects. For example, use ComPtr<IMachine> for a client pointer that calls the interface
414 * but ComObjPtr<Machine> for a pointer to an implementation object.
415 *
416 * The methods behave the same except that ComObjPtr has the additional createObject()
417 * method which allows for instantiating a new implementation object.
418 *
419 * Note: To convert a ComObjPtr<InterfaceImpl> to a ComObj<IInterface> you have
420 * to query the interface. See the following example code for the IProgress
421 * interface:
422 *
423 * @code
424 *
425 * {
426 * ComObjPtr<Progress> pProgress; // create the server side object
427 * pProgress.createObject(); // ...
428 * pProgress->init(...); // ...
429 * ComPtr<IProgress> pProgress2; // create an interface pointer
430 * pProgress.queryInterfaceTo(pProgress2.asOutParam()); // transfer the interface
431 * }
432 *
433 * @endcode
434 */
435template <class T>
436class ComObjPtr : public ComPtr<T>
437{
438public:
439
440 ComObjPtr()
441 : ComPtr<T>()
442 {}
443
444 ComObjPtr(const ComObjPtr &that)
445 : ComPtr<T>(that)
446 {}
447
448 ComObjPtr(T *that_p)
449 : ComPtr<T>(that_p)
450 {}
451
452 ComObjPtr& operator=(const ComObjPtr &that)
453 {
454 ComPtr<T>::operator=(that);
455 return *this;
456 }
457
458 ComObjPtr& operator=(T *that_p)
459 {
460 ComPtr<T>::operator=(that_p);
461 return *this;
462 }
463
464 /**
465 * Creates a new server-side object of the given component class and
466 * immediately starts to manage a pointer to the created object (the
467 * previous pointer, if any, is of course released when appropriate).
468 *
469 * @note Win32: when VBOX_COM_OUTOFPROC_MODULE is defined, the created
470 * object doesn't increase the lock count of the server module, as it
471 * does otherwise.
472 */
473 HRESULT createObject()
474 {
475 HRESULT rc;
476#ifndef VBOX_WITH_XPCOM
477# ifdef VBOX_COM_OUTOFPROC_MODULE
478 ATL::CComObjectNoLock<T> *obj = new ATL::CComObjectNoLock<T>();
479 if (obj)
480 {
481 obj->InternalFinalConstructAddRef();
482 rc = obj->FinalConstruct();
483 obj->InternalFinalConstructRelease();
484 }
485 else
486 rc = E_OUTOFMEMORY;
487# else
488 ATL::CComObject<T> *obj = NULL;
489 rc = ATL::CComObject<T>::CreateInstance(&obj);
490# endif
491#else /* VBOX_WITH_XPCOM */
492 ATL::CComObject<T> *obj = new ATL::CComObject<T>();
493 if (obj)
494 rc = obj->FinalConstruct();
495 else
496 rc = E_OUTOFMEMORY;
497#endif /* VBOX_WITH_XPCOM */
498 *this = obj;
499 return rc;
500 }
501};
502
503/** @} */
504
505#endif
506
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