VirtualBox

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

Last change on this file since 78759 was 78759, checked in by vboxsync, 6 years ago

VBox/com/ptr.h,VBox/com/microatl.h: Catch all bad_alloc exceptions in createObject and CreateInstance and turn them into E_OUTOFMEMORY return codes. This greatly simplifies exception analysis in code using these two methods. [build fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.0 KB
Line 
1/** @file
2 * MS COM / XPCOM Abstraction Layer - Smart COM pointer classes declaration.
3 */
4
5/*
6 * Copyright (C) 2006-2019 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_INCLUDED_com_ptr_h
27#define VBOX_INCLUDED_com_ptr_h
28#ifndef RT_WITHOUT_PRAGMA_ONCE
29# pragma once
30#endif
31
32/* Make sure all the stdint.h macros are included - must come first! */
33#ifndef __STDC_LIMIT_MACROS
34# define __STDC_LIMIT_MACROS
35#endif
36#ifndef __STDC_CONSTANT_MACROS
37# define __STDC_CONSTANT_MACROS
38#endif
39
40#ifdef VBOX_WITH_XPCOM
41# include <nsISupportsUtils.h>
42#endif /* VBOX_WITH_XPCOM */
43
44#include <VBox/com/defs.h>
45#include <new> /* For bad_alloc. */
46
47
48/** @defgroup grp_com_ptr Smart COM Pointer Classes
49 * @ingroup grp_com
50 * @{
51 */
52
53#ifdef VBOX_WITH_XPCOM
54
55namespace com
56{
57// declare a couple of XPCOM helper methods (defined in glue/com.cpp)
58// so we don't have to include a ton of XPCOM implementation headers here
59HRESULT GlueCreateObjectOnServer(const CLSID &clsid,
60 const char *serverName,
61 const nsIID &id,
62 void **ppobj);
63HRESULT GlueCreateInstance(const CLSID &clsid,
64 const nsIID &id,
65 void **ppobj);
66}
67
68#endif // VBOX_WITH_XPCOM
69
70/**
71 * COM autopointer class which takes care of all required reference counting.
72 *
73 * This automatically calls the required basic COM methods on COM pointers
74 * given to it:
75 *
76 * -- AddRef() gets called automatically whenever a new COM pointer is assigned
77 * to the ComPtr instance (either in the copy constructor or by assignment);
78 *
79 * -- Release() gets called automatically by the destructor and when an existing
80 * object gets released in assignment;
81 *
82 * -- QueryInterface() gets called automatically when COM pointers get converted
83 * from one interface to another.
84 *
85 * Example usage:
86 *
87 * @code
88 *
89 * {
90 * ComPtr<IMachine> pMachine = findMachine("blah"); // calls AddRef()
91 * ComPtr<IUnknown> pUnknown = pMachine; // calls QueryInterface()
92 * } # ComPtr destructor of both instances calls Release()
93 *
94 * @endcode
95 */
96template <class T>
97class ComPtr
98{
99public:
100
101 /**
102 * Default constructor, sets up a NULL pointer.
103 */
104 ComPtr()
105 : m_p(NULL)
106 { }
107
108 /**
109 * Destructor. Calls Release() on the contained COM object.
110 */
111 ~ComPtr()
112 {
113 cleanup();
114 }
115
116 /**
117 * Copy constructor from another ComPtr of any interface.
118 *
119 * This calls QueryInterface(T) and can result in a NULL pointer if the input
120 * pointer p does not support the ComPtr interface T.
121 *
122 * Does not call AddRef explicitly because if QueryInterface succeeded, then
123 * the refcount will have been increased by one already.
124 */
125 template <class T2>
126 ComPtr(const ComPtr<T2> &that)
127 {
128 m_p = NULL;
129 if (!that.isNull())
130 that->QueryInterface(COM_IIDOF(T), (void **)&m_p);
131 }
132
133 /**
134 * Specialization: copy constructor from another ComPtr<T>. Calls AddRef().
135 */
136 ComPtr(const ComPtr &that)
137 {
138 copyFrom(that.m_p);
139 }
140
141 /**
142 * Copy constructor from another interface pointer of any interface.
143 *
144 * This calls QueryInterface(T) and can result in a NULL pointer if the input
145 * pointer p does not support the ComPtr interface T.
146 *
147 * Does not call AddRef explicitly because if QueryInterface succeeded, then
148 * the refcount will have been increased by one already.
149 */
150 template <class T2>
151 ComPtr(T2 *p)
152 {
153 m_p = NULL;
154 if (p)
155 p->QueryInterface(COM_IIDOF(T), (void **)&m_p);
156 }
157
158 /**
159 * Specialization: copy constructor from a plain T * pointer. Calls AddRef().
160 */
161 ComPtr(T *that_p)
162 {
163 copyFrom(that_p);
164 }
165
166 /**
167 * Assignment from another ComPtr of any interface.
168 *
169 * This calls QueryInterface(T) and can result in a NULL pointer if the input
170 * pointer p does not support the ComPtr interface T.
171 *
172 * Does not call AddRef explicitly because if QueryInterface succeeded, then
173 * the refcount will have been increased by one already.
174 */
175 template <class T2>
176 ComPtr& operator=(const ComPtr<T2> &that)
177 {
178 return operator=((T2 *)that);
179 }
180
181 /**
182 * Specialization of the previous: assignment from another ComPtr<T>.
183 * Calls Release() on the previous member pointer, if any, and AddRef() on the new one.
184 */
185 ComPtr& operator=(const ComPtr &that)
186 {
187 return operator=((T *)that);
188 }
189
190 /**
191 * Assignment from another interface pointer of any interface.
192 *
193 * This calls QueryInterface(T) and can result in a NULL pointer if the input
194 * pointer p does not support the ComPtr interface T.
195 *
196 * Does not call AddRef explicitly because if QueryInterface succeeded, then
197 * the refcount will have been increased by one already.
198 */
199 template <class T2>
200 ComPtr& operator=(T2 *p)
201 {
202 cleanup();
203 if (p)
204 p->QueryInterface(COM_IIDOF(T), (void **)&m_p);
205 return *this;
206 }
207
208 /**
209 * Specialization of the previous: assignment from a plain T * pointer.
210 * Calls Release() on the previous member pointer, if any, and AddRef() on the new one.
211 */
212 ComPtr& operator=(T *p)
213 {
214 cleanup();
215 copyFrom(p);
216 return *this;
217 }
218
219 /**
220 * Resets the ComPtr to NULL. Works like a NULL assignment except it avoids the templates.
221 */
222 void setNull()
223 {
224 cleanup();
225 }
226
227 /**
228 * Returns true if the pointer is NULL.
229 */
230 bool isNull() const
231 {
232 return (m_p == NULL);
233 }
234
235 /**
236 * Returns true if the pointer is not NULL.
237 */
238 bool isNotNull() const
239 {
240 return (m_p != NULL);
241 }
242
243 bool operator<(T *p) const
244 {
245 return m_p < p;
246 }
247
248 /**
249 * Conversion operator, most often used to pass ComPtr instances as
250 * parameters to COM method calls.
251 */
252 operator T *() const
253 {
254 return m_p;
255 }
256
257 /**
258 * Dereferences the instance (redirects the -> operator to the managed
259 * pointer).
260 */
261 T *operator->() const
262 {
263 return m_p;
264 }
265
266 /**
267 * Special method which allows using a ComPtr as an output argument of a COM method.
268 * The ComPtr will then accept the method's interface pointer without calling AddRef()
269 * itself, since by COM convention this must has been done by the method which created
270 * the object that is being accepted.
271 *
272 * The ComPtr destructor will then still invoke Release() so that the returned object
273 * can get cleaned up properly.
274 */
275 T **asOutParam()
276 {
277 cleanup();
278 return &m_p;
279 }
280
281 /**
282 * Converts the contained pointer to a different interface
283 * by calling QueryInterface() on it.
284 * @param pp
285 * @return
286 */
287 template <class T2>
288 HRESULT queryInterfaceTo(T2 **pp) const
289 {
290 if (pp)
291 {
292 if (m_p)
293 return m_p->QueryInterface(COM_IIDOF(T2), (void **)pp);
294 *pp = NULL;
295 return S_OK;
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 * @note In order to make it easier to use, this method does _not_ throw
474 * bad_alloc, but instead returns E_OUTOFMEMORY.
475 */
476 HRESULT createObject()
477 {
478 HRESULT hrc;
479#ifndef VBOX_WITH_XPCOM
480# ifdef VBOX_COM_OUTOFPROC_MODULE
481 ATL::CComObjectNoLock<T> *obj = NULL;
482 try
483 {
484 obj = new ATL::CComObjectNoLock<T>();
485 }
486 catch (std::bad_alloc &)
487 {
488 obj = NULL;
489 }
490 if (obj)
491 {
492 obj->InternalFinalConstructAddRef();
493 try
494 {
495 hrc = obj->FinalConstruct();
496 }
497 catch (std::bad_alloc &)
498 {
499 hrc = E_OUTOFMEMORY;
500 }
501 obj->InternalFinalConstructRelease();
502 if (FAILED(hrc))
503 {
504 delete obj;
505 obj = NULL;
506 }
507 }
508 else
509 hrc = E_OUTOFMEMORY;
510# else
511 ATL::CComObject<T> *obj = NULL;
512 hrc = ATL::CComObject<T>::CreateInstance(&obj);
513# endif
514#else /* VBOX_WITH_XPCOM */
515 ATL::CComObject<T> *obj;
516# ifndef RT_EXCEPTIONS_ENABLED
517 obj = new ATL::CComObject<T>();
518# else
519 try
520 {
521 obj = new ATL::CComObject<T>();
522 }
523 catch (std::bad_alloc &)
524 {
525 obj = NULL;
526 }
527# endif
528 if (obj)
529 {
530# ifndef RT_EXCEPTIONS_ENABLED
531 try
532 {
533 hrc = obj->FinalConstruct();
534 }
535 catch (std::bad_alloc &)
536 {
537 hrc = E_OUTOFMEMORY;
538 }
539# else
540 hrc = obj->FinalConstruct();
541# endif
542 if (FAILED(hrc))
543 {
544 delete obj;
545 obj = NULL;
546 }
547 }
548 else
549 hrc = E_OUTOFMEMORY;
550#endif /* VBOX_WITH_XPCOM */
551 *this = obj;
552 return hrc;
553 }
554};
555
556/** @} */
557
558#endif /* !VBOX_INCLUDED_com_ptr_h */
559
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