VirtualBox

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

Last change on this file since 41279 was 32844, checked in by vboxsync, 14 years ago

Main: and _again_ was it wrong ...

  • 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:
3 * Smart COM pointer classes declaration
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27#ifndef ___VBox_com_ptr_h
28#define ___VBox_com_ptr_h
29
30/* Make sure all the stdint.h macros are included - must come first! */
31#ifndef __STDC_LIMIT_MACROS
32# define __STDC_LIMIT_MACROS
33#endif
34#ifndef __STDC_CONSTANT_MACROS
35# define __STDC_CONSTANT_MACROS
36#endif
37
38#if !defined (VBOX_WITH_XPCOM)
39 #include <atlbase.h>
40 #ifndef _ATL_IIDOF
41 # define _ATL_IIDOF(c) __uuidof(c)
42 #endif
43#else
44 #include <nsISupportsUtils.h>
45
46#endif /* !defined (VBOX_WITH_XPCOM) */
47
48#include <VBox/com/defs.h>
49
50#ifdef VBOX_WITH_XPCOM
51
52namespace com
53{
54// declare a couple of XPCOM helper methods (defined in glue/com.cpp)
55// so we don't have to include a ton of XPCOM implementation headers here
56HRESULT GlueCreateObjectOnServer(const CLSID &clsid,
57 const char *serverName,
58 const nsIID &id,
59 void** ppobj);
60HRESULT GlueCreateInstance(const CLSID &clsid,
61 const nsIID &id,
62 void** ppobj);
63}
64
65#endif // VBOX_WITH_XPCOM
66
67/**
68 * COM autopointer class which takes care of all required reference counting.
69 *
70 * This automatically calls the required basic COM methods on COM pointers
71 * given to it:
72 *
73 * -- AddRef() gets called automatically whenever a new COM pointer is assigned
74 * to the ComPtr instance (either in the copy constructor or by assignment);
75 *
76 * -- Release() gets called automatically by the destructor and when an existing
77 * object gets released in assignment;
78 *
79 * -- QueryInterface() gets called automatically when COM pointers get converted
80 * from one interface to another.
81 *
82 * Example usage:
83 *
84 * @code
85 *
86 * {
87 * ComPtr<IMachine> pMachine = findMachine("blah"); // calls AddRef()
88 * ComPtr<IUnknown> pUnknown = pMachine; // calls QueryInterface()
89 * } # ComPtr destructor of both instances calls Release()
90 *
91 * @endcode
92 */
93template <class T>
94class ComPtr
95{
96public:
97
98 /**
99 * Default constructor, sets up a NULL pointer.
100 */
101 ComPtr()
102 : m_p(NULL)
103 { }
104
105 /**
106 * Destructor. Calls Release() on the contained COM object.
107 */
108 ~ComPtr()
109 {
110 cleanup();
111 }
112
113 /**
114 * Copy constructor from another ComPtr of any interface.
115 *
116 * This calls QueryInterface(T) and can result in a NULL pointer if the input
117 * pointer p does not support the ComPtr interface T.
118 *
119 * Does not call AddRef explicitly because if QueryInterface succeeded, then
120 * the refcount will have been increased by one already .
121 */
122 template <class T2>
123 ComPtr(const ComPtr<T2> &that)
124 {
125 m_p = NULL;
126 if (!that.isNull())
127 that->QueryInterface(COM_IIDOF(T), (void**)&m_p);
128 }
129
130 /**
131 * Specialization: copy constructor from another ComPtr<T>. Calls AddRef().
132 */
133 ComPtr(const ComPtr &that)
134 {
135 copyFrom(that.m_p);
136 }
137
138 /**
139 * Copy constructor from another interface pointer of any interface.
140 *
141 * This calls QueryInterface(T) and can result in a NULL pointer if the input
142 * pointer p does not support the ComPtr interface T.
143 *
144 * Does not call AddRef explicitly because if QueryInterface succeeded, then
145 * the refcount will have been increased by one already .
146 */
147 template <class T2>
148 ComPtr(T2 *p)
149 {
150 m_p = NULL;
151 if (p)
152 p->QueryInterface(COM_IIDOF(T), (void**)&m_p);
153 }
154
155 /**
156 * Specialization: copy constructor from a plain T* pointer. Calls AddRef().
157 */
158 ComPtr(T *that_p)
159 {
160 copyFrom(that_p);
161 }
162
163 /**
164 * Assignment from another ComPtr of any interface.
165 *
166 * This calls QueryInterface(T) and can result in a NULL pointer if the input
167 * pointer p does not support the ComPtr interface T.
168 *
169 * Does not call AddRef explicitly because if QueryInterface succeeded, then
170 * the refcount will have been increased by one already .
171 */
172 template <class T2>
173 ComPtr& operator=(const ComPtr<T2> &that)
174 {
175 return operator=((T2*)that);
176 }
177
178 /**
179 * Specialization of the previous: assignment from another ComPtr<T>.
180 * Calls Release() on the previous member pointer, if any, and AddRef() on the new one.
181 */
182 ComPtr& operator=(const ComPtr &that)
183 {
184 return operator=((T*)that);
185 }
186
187 /**
188 * Assignment from another interface pointer of any interface.
189 *
190 * This calls QueryInterface(T) and can result in a NULL pointer if the input
191 * pointer p does not support the ComPtr interface T.
192 *
193 * Does not call AddRef explicitly because if QueryInterface succeeded, then
194 * the refcount will have been increased by one already .
195 */
196 template <class T2>
197 ComPtr& operator=(T2 *p)
198 {
199 cleanup();
200 if (p)
201 p->QueryInterface(COM_IIDOF(T), (void**)&m_p);
202 return *this;
203 }
204
205 /**
206 * Specialization of the previous: assignment from a plain T* pointer.
207 * Calls Release() on the previous member pointer, if any, and AddRef() on the new one.
208 */
209 ComPtr& operator=(T *p)
210 {
211 cleanup();
212 copyFrom(p);
213 return *this;
214 }
215
216 /**
217 * Resets the ComPtr to NULL. Works like a NULL assignment except it avoids the templates.
218 */
219 void setNull()
220 {
221 cleanup();
222 }
223
224 /**
225 * Returns true if the pointer is NULL.
226 */
227 bool isNull() const
228 {
229 return (m_p == NULL);
230 }
231
232 bool operator<(T* p) const
233 {
234 return m_p < p;
235 }
236
237 /**
238 * Conversion operator, most often used to pass ComPtr instances as
239 * parameters to COM method calls.
240 */
241 operator T*() const
242 {
243 return m_p;
244 }
245
246 /**
247 * Dereferences the instance (redirects the -> operator to the managed
248 * pointer).
249 */
250 T* operator->() const
251 {
252 return m_p;
253 }
254
255 /**
256 * Special method which allows using a ComPtr as an output argument of a COM method.
257 * The ComPtr will then accept the method's interface pointer without calling AddRef()
258 * itself, since by COM convention this must has been done by the method which created
259 * the object that is being accepted.
260 *
261 * The ComPtr destructor will then still invoke Release() so that the returned object
262 * can get cleaned up properly.
263 */
264 T** asOutParam()
265 {
266 cleanup();
267 return &m_p;
268 }
269
270 /**
271 * Converts the contained pointer to a different interface
272 * by calling QueryInterface() on it.
273 * @param pp
274 * @return
275 */
276 template <class T2>
277 HRESULT queryInterfaceTo(T2 **pp) const
278 {
279 if (pp)
280 {
281 if (m_p)
282 return m_p->QueryInterface(COM_IIDOF(T2), (void**)pp);
283 else
284 {
285 *pp = NULL;
286 return S_OK;
287 }
288 }
289
290 return E_INVALIDARG;
291 }
292
293 /**
294 * Equality test operator. By COM definition, two COM objects are considered
295 * equal if their IUnknown interface pointers are equal.
296 */
297 template <class T2>
298 bool operator==(T2* p)
299 {
300 IUnknown *p1 = NULL;
301 bool fNeedsRelease1 = false;
302 if (m_p)
303 fNeedsRelease1 = (SUCCEEDED(m_p->QueryInterface(COM_IIDOF(IUnknown), (void**)&p1)));
304
305 IUnknown *p2 = NULL;
306 bool fNeedsRelease2 = false;
307 if (p)
308 fNeedsRelease2 = (SUCCEEDED(p->QueryInterface(COM_IIDOF(IUnknown), (void**)&p2)));
309
310 bool f = p1 == p2;
311 if (fNeedsRelease1)
312 p1->Release();
313 if (fNeedsRelease2)
314 p2->Release();
315 return f;
316 }
317
318 /**
319 * Creates an in-process object of the given class ID and starts to
320 * manage a reference to the created object in case of success.
321 */
322 HRESULT createInprocObject(const CLSID &clsid)
323 {
324 HRESULT rc;
325 T *obj = NULL;
326#if !defined (VBOX_WITH_XPCOM)
327 rc = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, _ATL_IIDOF(T),
328 (void**)&obj);
329#else /* !defined (VBOX_WITH_XPCOM) */
330 using namespace com;
331 rc = GlueCreateInstance(clsid, NS_GET_IID(T), (void**)&obj);
332#endif /* !defined (VBOX_WITH_XPCOM) */
333 *this = obj;
334 if (SUCCEEDED(rc))
335 obj->Release();
336 return rc;
337 }
338
339 /**
340 * Creates a local (out-of-process) object of the given class ID and starts
341 * to manage a reference to the created object in case of success.
342 *
343 * Note: In XPCOM, the out-of-process functionality is currently emulated
344 * through in-process wrapper objects (that start a dedicated process and
345 * redirect all object requests to that process). For this reason, this
346 * method is fully equivalent to #createInprocObject() for now.
347 */
348 HRESULT createLocalObject(const CLSID &clsid)
349 {
350#if !defined (VBOX_WITH_XPCOM)
351 HRESULT rc;
352 T *obj = NULL;
353 rc = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, _ATL_IIDOF(T),
354 (void**)&obj);
355 *this = obj;
356 if (SUCCEEDED(rc))
357 obj->Release();
358 return rc;
359#else /* !defined (VBOX_WITH_XPCOM) */
360 return createInprocObject(clsid);
361#endif /* !defined (VBOX_WITH_XPCOM) */
362 }
363
364#ifdef VBOX_WITH_XPCOM
365 /**
366 * Creates an object of the given class ID on the specified server and
367 * starts to manage a reference to the created object in case of success.
368 *
369 * @param serverName Name of the server to create an object within.
370 */
371 HRESULT createObjectOnServer(const CLSID &clsid, const char *serverName)
372 {
373 T *obj = NULL;
374 HRESULT rc = GlueCreateObjectOnServer(clsid, serverName, NS_GET_IID(T), (void**)&obj);
375 *this = obj;
376 if (SUCCEEDED(rc))
377 obj->Release();
378 return rc;
379 }
380#endif
381
382protected:
383 void copyFrom(T* p)
384 {
385 if ((m_p = 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 rc;
466#if !defined (VBOX_WITH_XPCOM)
467# ifdef VBOX_COM_OUTOFPROC_MODULE
468 CComObjectNoLock<T> *obj = new CComObjectNoLock<T>();
469 if (obj)
470 {
471 obj->InternalFinalConstructAddRef();
472 rc = obj->FinalConstruct();
473 obj->InternalFinalConstructRelease();
474 }
475 else
476 rc = E_OUTOFMEMORY;
477# else
478 CComObject<T> *obj = NULL;
479 rc = CComObject<T>::CreateInstance(&obj);
480# endif
481#else /* !defined (VBOX_WITH_XPCOM) */
482 CComObject<T> *obj = new CComObject<T>();
483 if (obj)
484 rc = obj->FinalConstruct();
485 else
486 rc = E_OUTOFMEMORY;
487#endif /* !defined (VBOX_WITH_XPCOM) */
488 *this = obj;
489 return rc;
490 }
491};
492#endif
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