VirtualBox

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

Last change on this file since 47368 was 47368, checked in by vboxsync, 11 years ago

Build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.7 KB
Line 
1/** @file
2 * MS COM / XPCOM Abstraction Layer - Smart COM pointer classes declaration.
3 */
4
5/*
6 * Copyright (C) 2006-2012 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#endif /* !defined (VBOX_WITH_XPCOM) */
45
46#include <new> /* For bad_alloc. */
47#include <VBox/com/defs.h>
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 bool operator<(T* p) const
232 {
233 return m_p < p;
234 }
235
236 /**
237 * Conversion operator, most often used to pass ComPtr instances as
238 * parameters to COM method calls.
239 */
240 operator T*() const
241 {
242 return m_p;
243 }
244
245 /**
246 * Dereferences the instance (redirects the -> operator to the managed
247 * pointer).
248 */
249 T* operator->() const
250 {
251 return m_p;
252 }
253
254 /**
255 * Special method which allows using a ComPtr as an output argument of a COM method.
256 * The ComPtr will then accept the method's interface pointer without calling AddRef()
257 * itself, since by COM convention this must has been done by the method which created
258 * the object that is being accepted.
259 *
260 * The ComPtr destructor will then still invoke Release() so that the returned object
261 * can get cleaned up properly.
262 */
263 T** asOutParam()
264 {
265 cleanup();
266 return &m_p;
267 }
268
269 /**
270 * Converts the contained pointer to a different interface
271 * by calling QueryInterface() on it.
272 * @param pp
273 * @return
274 */
275 template <class T2>
276 HRESULT queryInterfaceTo(T2 **pp) const
277 {
278 if (pp)
279 {
280 if (m_p)
281 return m_p->QueryInterface(COM_IIDOF(T2), (void**)pp);
282 else
283 {
284 *pp = NULL;
285 return S_OK;
286 }
287 }
288
289 return E_INVALIDARG;
290 }
291
292 /**
293 * Equality test operator. By COM definition, two COM objects are considered
294 * equal if their IUnknown interface pointers are equal.
295 */
296 template <class T2>
297 bool operator==(T2* p)
298 {
299 IUnknown *p1 = NULL;
300 bool fNeedsRelease1 = false;
301 if (m_p)
302 fNeedsRelease1 = (SUCCEEDED(m_p->QueryInterface(COM_IIDOF(IUnknown), (void**)&p1)));
303
304 IUnknown *p2 = NULL;
305 bool fNeedsRelease2 = false;
306 if (p)
307 fNeedsRelease2 = (SUCCEEDED(p->QueryInterface(COM_IIDOF(IUnknown), (void**)&p2)));
308
309 bool f = p1 == p2;
310 if (fNeedsRelease1)
311 p1->Release();
312 if (fNeedsRelease2)
313 p2->Release();
314 return f;
315 }
316
317 /**
318 * Creates an in-process object of the given class ID and starts to
319 * manage a reference to the created object in case of success.
320 */
321 HRESULT createInprocObject(const CLSID &clsid)
322 {
323 HRESULT rc;
324 T *obj = NULL;
325#if !defined (VBOX_WITH_XPCOM)
326 rc = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, _ATL_IIDOF(T),
327 (void**)&obj);
328#else /* !defined (VBOX_WITH_XPCOM) */
329 using namespace com;
330 rc = GlueCreateInstance(clsid, NS_GET_IID(T), (void**)&obj);
331#endif /* !defined (VBOX_WITH_XPCOM) */
332 *this = obj;
333 if (SUCCEEDED(rc))
334 obj->Release();
335 return rc;
336 }
337
338 /**
339 * Creates a local (out-of-process) object of the given class ID and starts
340 * to manage a reference to the created object in case of success.
341 *
342 * Note: In XPCOM, the out-of-process functionality is currently emulated
343 * through in-process wrapper objects (that start a dedicated process and
344 * redirect all object requests to that process). For this reason, this
345 * method is fully equivalent to #createInprocObject() for now.
346 */
347 HRESULT createLocalObject(const CLSID &clsid)
348 {
349#if !defined (VBOX_WITH_XPCOM)
350 HRESULT rc;
351 T *obj = NULL;
352 rc = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, _ATL_IIDOF(T),
353 (void**)&obj);
354 *this = obj;
355 if (SUCCEEDED(rc))
356 obj->Release();
357 return rc;
358#else /* !defined (VBOX_WITH_XPCOM) */
359 return createInprocObject(clsid);
360#endif /* !defined (VBOX_WITH_XPCOM) */
361 }
362
363#ifdef VBOX_WITH_XPCOM
364 /**
365 * Creates an object of the given class ID on the specified server and
366 * starts to manage a reference to the created object in case of success.
367 *
368 * @param serverName Name of the server to create an object within.
369 */
370 HRESULT createObjectOnServer(const CLSID &clsid, const char *serverName)
371 {
372 T *obj = NULL;
373 HRESULT rc = GlueCreateObjectOnServer(clsid, serverName, NS_GET_IID(T), (void**)&obj);
374 *this = obj;
375 if (SUCCEEDED(rc))
376 obj->Release();
377 return rc;
378 }
379#endif
380
381protected:
382 void copyFrom(T* p)
383 {
384 m_p = p;
385 if (m_p)
386 m_p->AddRef();
387 }
388
389 void cleanup()
390 {
391 if (m_p)
392 {
393 m_p->Release();
394 m_p = NULL;
395 }
396 }
397
398 T *m_p;
399};
400
401/**
402 * ComObjPtr is a more specialized variant of ComPtr designed to be used for implementation
403 * objects. For example, use ComPtr<IMachine> for a client pointer that calls the interface
404 * but ComObjPtr<Machine> for a pointer to an implementation object.
405 *
406 * The methods behave the same except that ComObjPtr has the additional createObject()
407 * method which allows for instantiating a new implementation object.
408 *
409 * Note: To convert a ComObjPtr<InterfaceImpl> to a ComObj<IInterface> you have
410 * to query the interface. See the following example code for the IProgress
411 * interface:
412 *
413 * @code
414 *
415 * {
416 * ComObjPtr<Progress> pProgress; // create the server side object
417 * pProgress.createObject(); // ...
418 * pProgress->init(...); // ...
419 * ComPtr<IProgress> pProgress2; // create an interface pointer
420 * pProgress.queryInterfaceTo(pProgress2.asOutParam()); // transfer the interface
421 * }
422 *
423 * @endcode
424 */
425template <class T>
426class ComObjPtr : public ComPtr<T>
427{
428public:
429
430 ComObjPtr()
431 : ComPtr<T>()
432 {}
433
434 ComObjPtr(const ComObjPtr &that)
435 : ComPtr<T>(that)
436 {}
437
438 ComObjPtr(T *that_p)
439 : ComPtr<T>(that_p)
440 {}
441
442 ComObjPtr& operator=(const ComObjPtr &that)
443 {
444 ComPtr<T>::operator=(that);
445 return *this;
446 }
447
448 ComObjPtr& operator=(T *that_p)
449 {
450 ComPtr<T>::operator=(that_p);
451 return *this;
452 }
453
454 /**
455 * Creates a new server-side object of the given component class and
456 * immediately starts to manage a pointer to the created object (the
457 * previous pointer, if any, is of course released when appropriate).
458 *
459 * @note Win32: when VBOX_COM_OUTOFPROC_MODULE is defined, the created
460 * object doesn't increase the lock count of the server module, as it
461 * does otherwise.
462 */
463 HRESULT createObject()
464 {
465 HRESULT hr;
466 try
467 {
468#if !defined (VBOX_WITH_XPCOM)
469# ifdef VBOX_COM_OUTOFPROC_MODULE
470 CComObjectNoLock<T> *obj = new CComObjectNoLock<T>();
471 obj->InternalFinalConstructAddRef();
472 hr = obj->FinalConstruct();
473 obj->InternalFinalConstructRelease();
474# else
475 CComObject<T> *obj = NULL;
476 hr = CComObject<T>::CreateInstance(&obj);
477# endif
478#else /* !defined (VBOX_WITH_XPCOM) */
479 CComObject<T> *obj = new CComObject<T>();
480 hr = obj->FinalConstruct();
481#endif /* !defined (VBOX_WITH_XPCOM) */
482 *this = obj;
483 }
484 catch(std::bad_alloc &)
485 {
486 hr = E_OUTOFMEMORY;
487 }
488
489 return hr;
490 }
491};
492#endif
493
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