VirtualBox

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

Last change on this file since 78756 was 78756, 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.

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