VirtualBox

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

Last change on this file since 27023 was 23223, checked in by vboxsync, 15 years ago

API: big medium handling change and lots of assorted other cleanups and fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1/** @file
2 * MS COM / XPCOM Abstraction Layer:
3 * Smart COM pointer classes declaration
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31#ifndef ___VBox_com_ptr_h
32#define ___VBox_com_ptr_h
33
34/* Make sure all the stdint.h macros are included - must come first! */
35#ifndef __STDC_LIMIT_MACROS
36# define __STDC_LIMIT_MACROS
37#endif
38#ifndef __STDC_CONSTANT_MACROS
39# define __STDC_CONSTANT_MACROS
40#endif
41
42#if !defined (VBOX_WITH_XPCOM)
43
44#include <atlbase.h>
45
46#ifndef _ATL_IIDOF
47# define _ATL_IIDOF(c) __uuidof(c)
48#endif
49
50#else /* !defined (VBOX_WITH_XPCOM) */
51
52#include <nsXPCOM.h>
53#include <nsIComponentManager.h>
54#include <nsCOMPtr.h>
55#include <ipcIService.h>
56#include <nsIServiceManagerUtils.h>
57#include <ipcCID.h>
58#include <ipcIDConnectService.h>
59
60// official XPCOM headers don't define it yet
61#define IPC_DCONNECTSERVICE_CONTRACTID \
62 "@mozilla.org/ipc/dconnect-service;1"
63
64#endif /* !defined (VBOX_WITH_XPCOM) */
65
66#include <VBox/com/defs.h>
67#include <VBox/com/assert.h>
68
69#define LOGREF(prefix, pObj, cRefs) com::LogRef("%s {%p} cRefs=%d\n", (prefix), (pObj), (cRefs))
70
71namespace com
72{
73 void LogRef(const char *pcszFormat, ...);
74}
75
76/**
77 * Strong referencing operators. Used as a second argument to ComPtr<>/ComObjPtr<>.
78 */
79template <class C>
80class ComStrongRef
81{
82protected:
83
84 static void addref(C *p)
85 {
86 p->AddRef();
87 }
88 static void release(C *p)
89 {
90 p->Release();
91 }
92};
93
94/**
95 * Weak referencing operators. Used as a second argument to ComPtr<>/ComObjPtr<>.
96 */
97template <class C>
98class ComWeakRef
99{
100protected:
101
102 static void addref(C * /* p */) {}
103 static void release(C * /* p */) {}
104};
105
106/**
107 * Returns @c true if two interface pointers are equal.
108 *
109 * According to the COM Identity Rule, interface pointers are considered to be
110 * equal if and only if IUnknown pointers queried on these interfaces pointers
111 * are equal (e.g. have the same binary value). Equal interface pointers
112 * represent the same object even if they are pointers to different interfaces.
113 *
114 * @param I1 Class of the first interface pointer (must be derived from
115 * IUnknown).
116 * @param I2 Class of the second interface pointer (must be derived from
117 * IUnknown).
118 */
119template <class I1, class I2>
120inline bool ComPtrEquals(I1 *aThis, I2 *aThat)
121{
122 IUnknown *thatUnk = NULL, *thisUnk = NULL;
123 if (aThat)
124 aThat->QueryInterface(COM_IIDOF(IUnknown), (void**)&thatUnk);
125 if (aThis)
126 aThis->QueryInterface(COM_IIDOF(IUnknown), (void**)&thisUnk);
127 bool equal = (thisUnk == thatUnk);
128 if (thisUnk)
129 thisUnk->Release();
130 if (thatUnk)
131 thatUnk->Release();
132 return equal;
133}
134
135/* specialization for <Any, IUnknown> */
136template <class I1>
137inline bool ComPtrEquals(I1 *aThis, IUnknown *aThat)
138{
139 IUnknown *thisUnk = NULL;
140 if (aThis)
141 aThis->QueryInterface(COM_IIDOF(IUnknown), (void**)&thisUnk);
142 bool equal = (thisUnk == aThat);
143 if (thisUnk)
144 thisUnk->Release();
145 return equal;
146}
147
148/** Specialization for <IUnknown, Any> */
149template <class I2>
150inline bool ComPtrEquals(IUnknown *aThis, I2 *aThat)
151{
152 IUnknown *thatUnk = NULL;
153 if (aThat)
154 aThat->QueryInterface(COM_IIDOF(IUnknown), (void**)&thatUnk);
155 bool equal = (aThis == thatUnk);
156 if (thatUnk)
157 thatUnk->Release();
158 return equal;
159}
160
161/* specialization for IUnknown */
162template<>
163inline bool ComPtrEquals<IUnknown, IUnknown>(IUnknown *aThis, IUnknown *aThat)
164{
165 return aThis == aThat;
166}
167
168/**
169 * Base template for smart COM pointers. Not intended to be used directly.
170 */
171template <class C, template <class> class RefOps = ComStrongRef>
172class ComPtrBase : protected RefOps <C>
173{
174public:
175
176 /* special template to disable AddRef()/Release() */
177 template <class I>
178 class NoAddRefRelease : public I
179 {
180 private:
181#if !defined (VBOX_WITH_XPCOM)
182 STDMETHOD_(ULONG, AddRef)() = 0;
183 STDMETHOD_(ULONG, Release)() = 0;
184#else /* !defined (VBOX_WITH_XPCOM) */
185 NS_IMETHOD_(nsrefcnt) AddRef(void) = 0;
186 NS_IMETHOD_(nsrefcnt) Release(void) = 0;
187#endif /* !defined (VBOX_WITH_XPCOM) */
188 };
189
190protected:
191
192 ComPtrBase () : p (NULL) {}
193 ComPtrBase (const ComPtrBase &that) : p (that.p) { addref(); }
194 ComPtrBase (C *that_p) : p (that_p) { addref(); }
195
196 ~ComPtrBase() { release(); }
197
198 ComPtrBase &operator= (const ComPtrBase &that)
199 {
200 safe_assign (that.p);
201 return *this;
202 }
203
204 ComPtrBase &operator= (C *that_p)
205 {
206 safe_assign (that_p);
207 return *this;
208 }
209
210public:
211
212 void setNull()
213 {
214 release();
215 p = NULL;
216 }
217
218 bool isNull() const
219 {
220 return (p == NULL);
221 }
222
223 bool operator! () const { return isNull(); }
224
225 bool operator< (C* that_p) const { return p < that_p; }
226 bool operator== (C* that_p) const { return p == that_p; }
227
228 template <class I>
229 bool equalsTo (I *aThat) const
230 {
231 return ComPtrEquals (p, aThat);
232 }
233
234 template <class OC>
235 bool equalsTo (const ComPtrBase <OC> &oc) const
236 {
237 return equalsTo ((OC *) oc);
238 }
239
240 /** Intended to pass instances as in parameters to interface methods */
241 operator C* () const { return p; }
242
243 /**
244 * Dereferences the instance (redirects the -> operator to the managed
245 * pointer).
246 */
247 NoAddRefRelease <C> *operator-> () const
248 {
249 AssertMsg (p, ("Managed pointer must not be null\n"));
250 return (NoAddRefRelease <C> *) p;
251 }
252
253 template <class I>
254 HRESULT queryInterfaceTo (I **pp) const
255 {
256 if (pp)
257 {
258 if (p)
259 {
260 return p->QueryInterface (COM_IIDOF (I), (void **) pp);
261 }
262 else
263 {
264 *pp = NULL;
265 return S_OK;
266 }
267 }
268
269 return E_INVALIDARG;
270 }
271
272 /** Intended to pass instances as out parameters to interface methods */
273 C **asOutParam()
274 {
275 setNull();
276 return &p;
277 }
278
279private:
280
281 void addref()
282 {
283 if (p)
284 RefOps <C>::addref (p);
285 }
286
287 void release()
288 {
289 if (p)
290 RefOps <C>::release (p);
291 }
292
293 void safe_assign (C *that_p)
294 {
295 /* be aware of self-assignment */
296 if (that_p)
297 RefOps <C>::addref (that_p);
298 release();
299 p = that_p;
300 }
301
302 C *p;
303};
304
305/**
306 * Smart COM pointer wrapper that automatically manages refcounting of
307 * interface pointers.
308 *
309 * @param I COM interface class
310 */
311template <class I, template <class> class RefOps = ComStrongRef>
312class ComPtr : public ComPtrBase <I, RefOps>
313{
314 typedef ComPtrBase <I, RefOps> Base;
315
316public:
317
318 ComPtr () : Base() {}
319 ComPtr (const ComPtr &that) : Base (that) {}
320 ComPtr &operator= (const ComPtr &that)
321 {
322 Base::operator= (that);
323 return *this;
324 }
325
326 template <class OI>
327 ComPtr (OI *that_p) : Base () { operator= (that_p); }
328
329 /* specialization for I */
330 ComPtr (I *that_p) : Base (that_p) {}
331
332 template <class OC>
333 ComPtr (const ComPtr <OC, RefOps> &oc) : Base () { operator= ((OC *) oc); }
334
335 template <class OI>
336 ComPtr &operator= (OI *that_p)
337 {
338 if (that_p)
339 that_p->QueryInterface (COM_IIDOF (I), (void **) Base::asOutParam());
340 else
341 Base::setNull();
342 return *this;
343 }
344
345 /* specialization for I */
346 ComPtr &operator=(I *that_p)
347 {
348 Base::operator= (that_p);
349 return *this;
350 }
351
352 template <class OC>
353 ComPtr &operator= (const ComPtr <OC, RefOps> &oc)
354 {
355 return operator= ((OC *) oc);
356 }
357
358 /**
359 * Creates an in-process object of the given class ID and starts to
360 * manage a reference to the created object in case of success.
361 */
362 HRESULT createInprocObject (const CLSID &clsid)
363 {
364 HRESULT rc;
365 I *obj = NULL;
366#if !defined (VBOX_WITH_XPCOM)
367 rc = CoCreateInstance (clsid, NULL, CLSCTX_INPROC_SERVER, _ATL_IIDOF (I),
368 (void **) &obj);
369#else /* !defined (VBOX_WITH_XPCOM) */
370 nsCOMPtr <nsIComponentManager> manager;
371 rc = NS_GetComponentManager (getter_AddRefs (manager));
372 if (SUCCEEDED (rc))
373 rc = manager->CreateInstance (clsid, nsnull, NS_GET_IID (I),
374 (void **) &obj);
375#endif /* !defined (VBOX_WITH_XPCOM) */
376 *this = obj;
377 if (SUCCEEDED (rc))
378 obj->Release();
379 return rc;
380 }
381
382 /**
383 * Creates a local (out-of-process) object of the given class ID and starts
384 * to manage a reference to the created object in case of success.
385 *
386 * Note: In XPCOM, the out-of-process functionality is currently emulated
387 * through in-process wrapper objects (that start a dedicated process and
388 * redirect all object requests to that process). For this reason, this
389 * method is fully equivalent to #createInprocObject() for now.
390 */
391 HRESULT createLocalObject (const CLSID &clsid)
392 {
393#if !defined (VBOX_WITH_XPCOM)
394 HRESULT rc;
395 I *obj = NULL;
396 rc = CoCreateInstance (clsid, NULL, CLSCTX_LOCAL_SERVER, _ATL_IIDOF (I),
397 (void **) &obj);
398 *this = obj;
399 if (SUCCEEDED (rc))
400 obj->Release();
401 return rc;
402#else /* !defined (VBOX_WITH_XPCOM) */
403 return createInprocObject (clsid);
404#endif /* !defined (VBOX_WITH_XPCOM) */
405 }
406
407#ifdef VBOX_WITH_XPCOM
408 /**
409 * Creates an object of the given class ID on the specified server and
410 * starts to manage a reference to the created object in case of success.
411 *
412 * @param serverName Name of the server to create an object within.
413 */
414 HRESULT createObjectOnServer (const CLSID &clsid, const char *serverName)
415 {
416 HRESULT rc;
417 I *obj = NULL;
418 nsCOMPtr <ipcIService> ipcServ = do_GetService (IPC_SERVICE_CONTRACTID, &rc);
419 if (SUCCEEDED (rc))
420 {
421 PRUint32 serverID = 0;
422 rc = ipcServ->ResolveClientName (serverName, &serverID);
423 if (SUCCEEDED (rc))
424 {
425 nsCOMPtr <ipcIDConnectService> dconServ =
426 do_GetService (IPC_DCONNECTSERVICE_CONTRACTID, &rc);
427 if (SUCCEEDED (rc))
428 rc = dconServ->CreateInstance (serverID, clsid, NS_GET_IID (I),
429 (void **) &obj);
430 }
431 }
432 *this = obj;
433 if (SUCCEEDED (rc))
434 obj->Release();
435 return rc;
436 }
437#endif
438};
439
440/**
441 * Specialization of ComPtr<> for IUnknown to guarantee identity
442 * by always doing QueryInterface() when constructing or assigning from
443 * another interface pointer disregarding its type.
444 */
445template <template <class> class RefOps>
446class ComPtr <IUnknown, RefOps> : public ComPtrBase <IUnknown, RefOps>
447{
448 typedef ComPtrBase <IUnknown, RefOps> Base;
449
450public:
451
452 ComPtr () : Base() {}
453 ComPtr (const ComPtr &that) : Base (that) {}
454 ComPtr &operator= (const ComPtr &that)
455 {
456 Base::operator= (that);
457 return *this;
458 }
459
460 template <class OI>
461 ComPtr (OI *that_p) : Base () { operator= (that_p); }
462
463 template <class OC>
464 ComPtr (const ComPtr <OC, RefOps> &oc) : Base () { operator= ((OC *) oc); }
465
466 template <class OI>
467 ComPtr &operator= (OI *that_p)
468 {
469 if (that_p)
470 that_p->QueryInterface (COM_IIDOF (IUnknown), (void **) Base::asOutParam());
471 else
472 Base::setNull();
473 return *this;
474 }
475
476 template <class OC>
477 ComPtr &operator= (const ComPtr <OC, RefOps> &oc)
478 {
479 return operator= ((OC *) oc);
480 }
481};
482
483/**
484 * Smart COM pointer wrapper that automatically manages refcounting of
485 * pointers to interface implementation classes created on the component's
486 * (i.e. the server's) side. Differs from ComPtr by providing additional
487 * platform independent operations for creating new class instances.
488 *
489 * @param C class that implements some COM interface
490 */
491template <class C, template <class> class RefOps = ComStrongRef>
492class ComObjPtr : public ComPtrBase <C, RefOps>
493{
494 typedef ComPtrBase <C, RefOps> Base;
495
496public:
497
498 ComObjPtr () : Base() {}
499 ComObjPtr (const ComObjPtr &that) : Base (that) {}
500 ComObjPtr (C *that_p) : Base (that_p) {}
501
502 ComObjPtr &operator= (const ComObjPtr &that)
503 {
504 Base::operator= (that);
505 return *this;
506 }
507
508 ComObjPtr &operator= (C *that_p)
509 {
510 Base::operator= (that_p);
511 return *this;
512 }
513
514 /**
515 * Creates a new server-side object of the given component class and
516 * immediately starts to manage a pointer to the created object (the
517 * previous pointer, if any, is of course released when appropriate).
518 *
519 * @note This method should be used with care on weakly referenced
520 * smart pointers because it leaves the newly created object completely
521 * unreferenced (i.e., with reference count equal to zero),
522 *
523 * @note Win32: when VBOX_COM_OUTOFPROC_MODULE is defined, the created
524 * object doesn't increase the lock count of the server module, as it
525 * does otherwise.
526 */
527 HRESULT createObject()
528 {
529 HRESULT rc;
530#if !defined (VBOX_WITH_XPCOM)
531# ifdef VBOX_COM_OUTOFPROC_MODULE
532 CComObjectNoLock <C> *obj = new CComObjectNoLock <C>();
533 if (obj)
534 {
535 obj->InternalFinalConstructAddRef();
536 rc = obj->FinalConstruct();
537 obj->InternalFinalConstructRelease();
538 }
539 else
540 rc = E_OUTOFMEMORY;
541# else
542 CComObject <C> *obj = NULL;
543 rc = CComObject <C>::CreateInstance (&obj);
544# endif
545#else /* !defined (VBOX_WITH_XPCOM) */
546 CComObject <C> *obj = new CComObject <C>();
547 if (obj)
548 rc = obj->FinalConstruct();
549 else
550 rc = E_OUTOFMEMORY;
551#endif /* !defined (VBOX_WITH_XPCOM) */
552 *this = obj;
553 return rc;
554 }
555};
556#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