VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/include/COMDefs.h@ 6900

Last change on this file since 6900 was 6900, checked in by vboxsync, 17 years ago

FE/Qt: Fixed array support for arrays of interface pointers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.2 KB
Line 
1/** @file
2 *
3 * VBox frontends: Qt GUI ("VirtualBox"):
4 * Various COM definitions and COM wrapper class declarations
5 *
6 * This header is used in conjunction with the header generated from
7 * XIDL expressed interface definitions to provide cross-platform Qt-based
8 * interface wrapper classes.
9 */
10
11/*
12 * Copyright (C) 2006-2007 innotek GmbH
13 *
14 * This file is part of VirtualBox Open Source Edition (OSE), as
15 * available from http://www.215389.xyz. This file is free software;
16 * you can redistribute it and/or modify it under the terms of the GNU
17 * General Public License (GPL) as published by the Free Software
18 * Foundation, in version 2 as it comes in the "COPYING" file of the
19 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
20 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
21 */
22
23#ifndef __COMDefs_h__
24#define __COMDefs_h__
25
26/** @defgroup grp_QT_COM Qt-COM Support Layer
27 * @{
28 *
29 * The Qt-COM support layer provides a set of defintions and smart classes for
30 * writing simple, clean and platform-independent code to access COM/XPCOM
31 * components through exposed COM interfaces. This layer is based on the
32 * COM/XPCOM Abstarction Layer library (the VBoxCOM glue library defined in
33 * include/VBox/com and implemented in src/VBox/Main/glue).
34 *
35 * ...
36 *
37 * @defgroup grp_QT_COM_arrays Arrays
38 * @{
39 *
40 * COM/XPCOM arrays are mapped to QValueVector objects. QValueVector templates
41 * declared with a type that corresponds to the COM type of elements in the
42 * array using normal Qt-COM type mapping rules. Here is a code example that
43 * demonstrates how to call interface methods that take and return arrays (this
44 * example is based on examples given in @ref grp_COM_arrays):
45 * @code
46
47 CSomething component;
48
49 // ...
50
51 QValueVector <LONG> in (3);
52 in [0] = -1;
53 in [1] = -2;
54 in [2] = -3;
55
56 QValueVector <LONG> out;
57 QValueVector <LONG> ret;
58
59 ret = component.TestArrays (in, out);
60
61 for (size_t i = 0; i < ret.size(); ++ i)
62 LogFlow (("*** ret[%u]=%d\n", i, ret [i]));
63
64 * @endcode
65 * @}
66 */
67
68/* Both VBox/com/assert.h and qglobal.h contain a definition of ASSERT.
69 * Either of them can be already included here, so try to shut them up. */
70#undef ASSERT
71
72#include <VBox/com/com.h>
73#include <VBox/com/array.h>
74#include <VBox/com/assert.h>
75
76#undef ASSERT
77
78#include <qglobal.h>
79#include <qstring.h>
80#include <quuid.h>
81#include <qvaluevector.h>
82
83#include <iprt/memory> // for auto_copy_ptr
84
85/*
86 * Additional COM / XPCOM defines and includes
87 */
88
89#define IN_BSTRPARAM INPTR BSTR
90#define IN_GUIDPARAM INPTR GUIDPARAM
91
92#if !defined (VBOX_WITH_XPCOM)
93
94#else /* !defined (VBOX_WITH_XPCOM) */
95
96#include <nsXPCOM.h>
97#include <nsMemory.h>
98#include <nsIComponentManager.h>
99
100class XPCOMEventQSocketListener;
101
102#endif /* !defined (VBOX_WITH_XPCOM) */
103
104
105/* VirtualBox interfaces declarations */
106#if !defined (VBOX_WITH_XPCOM)
107 #include <VirtualBox.h>
108#else /* !defined (VBOX_WITH_XPCOM) */
109 #include <VirtualBox_XPCOM.h>
110#endif /* !defined (VBOX_WITH_XPCOM) */
111
112#include "VBoxDefs.h"
113
114
115/////////////////////////////////////////////////////////////////////////////
116
117class CVirtualBoxErrorInfo;
118
119/** Represents extended error information */
120class COMErrorInfo
121{
122public:
123
124 COMErrorInfo()
125 : mIsNull (true)
126 , mIsBasicAvailable (false), mIsFullAvailable (false)
127 , mResultCode (S_OK) {}
128
129 COMErrorInfo (const CVirtualBoxErrorInfo &info) { init (info); }
130
131 /* the default copy ctor and assignment op are ok */
132
133 bool isNull() const { return mIsNull; }
134
135 bool isBasicAvailable() const { return mIsBasicAvailable; }
136 bool isFullAvailable() const { return mIsFullAvailable; }
137
138 HRESULT resultCode() const { return mResultCode; }
139 QUuid interfaceID() const { return mInterfaceID; }
140 QString component() const { return mComponent; }
141 QString text() const { return mText; }
142
143 const COMErrorInfo *next() const { return mNext.get(); }
144
145 QString interfaceName() const { return mInterfaceName; }
146 QUuid calleeIID() const { return mCalleeIID; }
147 QString calleeName() const { return mCalleeName; }
148
149private:
150
151 void init (const CVirtualBoxErrorInfo &info);
152 void fetchFromCurrentThread (IUnknown *callee, const GUID *calleeIID);
153
154 static QString getInterfaceNameFromIID (const QUuid &id);
155
156 bool mIsNull : 1;
157 bool mIsBasicAvailable : 1;
158 bool mIsFullAvailable : 1;
159
160 HRESULT mResultCode;
161 QUuid mInterfaceID;
162 QString mComponent;
163 QString mText;
164
165 cppx::auto_copy_ptr <COMErrorInfo> mNext;
166
167 QString mInterfaceName;
168 QUuid mCalleeIID;
169 QString mCalleeName;
170
171 friend class COMBaseWithEI;
172};
173
174/////////////////////////////////////////////////////////////////////////////
175
176/**
177 * Base COM class the CInterface template and all wrapper classes are derived
178 * from. Provides common functionality for all COM wrappers.
179 */
180class COMBase
181{
182public:
183
184 static HRESULT InitializeCOM();
185 static HRESULT CleanupCOM();
186
187 /**
188 * Returns the result code of the last interface method called
189 * by the wrapper instance or the result of CInterface::createInstance()
190 * operation.
191 */
192 HRESULT lastRC() const { return mRC; }
193
194 /**
195 * Returns error info set by the last unsuccessfully invoked interface
196 * method. Returned error info is useful only if CInterface::lastRC()
197 * represents a failure (i.e. CInterface::isOk() is false).
198 */
199 virtual COMErrorInfo errorInfo() const { return COMErrorInfo(); }
200
201#if !defined (VBOX_WITH_XPCOM)
202
203 /** Converts a GUID value to QUuid */
204 static QUuid ToQUuid (const GUID &id)
205 {
206 return QUuid (id.Data1, id.Data2, id.Data3,
207 id.Data4[0], id.Data4[1], id.Data4[2], id.Data4[3],
208 id.Data4[4], id.Data4[5], id.Data4[6], id.Data4[7]);
209 }
210
211#else /* !defined (VBOX_WITH_XPCOM) */
212
213 /** Converts a GUID value to QUuid */
214 static QUuid ToQUuid (const nsID &id)
215 {
216 return QUuid (id.m0, id.m1, id.m2,
217 id.m3[0], id.m3[1], id.m3[2], id.m3[3],
218 id.m3[4], id.m3[5], id.m3[6], id.m3[7]);
219 }
220
221#endif /* !defined (VBOX_WITH_XPCOM) */
222
223 /* Arrays of arbitrary types */
224
225 template <typename QT, typename CT>
226 static void ToSafeArray (const QValueVector <QT> &aVec, com::SafeArray <CT> &aArr)
227 {
228 AssertMsgFailedReturnVoid (("No conversion!\n"));
229 }
230
231 template <typename CT, typename QT>
232 static void FromSafeArray (const com::SafeArray <CT> &aArr, QValueVector <QT> &aVec)
233 {
234 AssertMsgFailedReturnVoid (("No conversion!\n"));
235 }
236
237 template <typename QT, typename CT>
238 static void ToSafeArray (const QValueVector <QT *> &aVec, com::SafeArray <CT *> &aArr)
239 {
240 AssertMsgFailedReturnVoid (("No conversion!\n"));
241 }
242
243 template <typename CT, typename QT>
244 static void FromSafeArray (const com::SafeArray <CT *> &aArr, QValueVector <QT *> &aVec)
245 {
246 AssertMsgFailedReturnVoid (("No conversion!\n"));
247 }
248
249 /* Arrays of equal types */
250
251 template <typename T>
252 static void ToSafeArray (const QValueVector <T> &aVec, com::SafeArray <T> &aArr)
253 {
254 aArr.reset (aVec.size());
255 size_t i = 0;
256 for (typename QValueVector <T>::const_iterator it = aVec.begin();
257 it != aVec.end(); ++ it, ++ i)
258 aArr [i] = *it;
259 }
260
261 template <typename T>
262 static void FromSafeArray (const com::SafeArray <T> &aArr, QValueVector <T> &aVec)
263 {
264 aVec = QValueVector <T> (aArr.size());
265 size_t i = 0;
266 for (typename QValueVector <T>::iterator it = aVec.begin();
267 it != aVec.end(); ++ it, ++ i)
268 *it = aArr [i];
269 }
270
271 /* Arrays of strings */
272
273 static void ToSafeArray (const QValueVector <QString> &aVec,
274 com::SafeArray <BSTR> &aArr);
275 static void FromSafeArray (const com::SafeArray <BSTR> &aArr,
276 QValueVector <QString> &aVec);
277
278 /* Arrays of interface pointers. Note: we need a separate pair of names
279 * only because the MSVC8 template matching algorithm is poor and tries to
280 * instantiate a com::SafeIfaceArray <BSTR> (!!!) template otherwise for
281 * *no* reason and fails. Note that it's also not possible to choose the
282 * correct function by specifying template arguments explicitly because then
283 * it starts to try to instantiate the com::SafeArray <I> template for
284 * *no* reason again and fails too. Definitely, broken. Works in GCC like a
285 * charm. */
286
287 template <class CI, class I>
288 static void ToSafeIfaceArray (const QValueVector <CI> &aVec,
289 com::SafeIfaceArray <I> &aArr)
290 {
291 aArr.reset (aVec.size());
292 size_t i = 0;
293 for (typename QValueVector <CI>::const_iterator it = aVec.begin();
294 it != aVec.end(); ++ it, ++ i)
295 {
296 aArr [i] = (*it).iface();
297 if (aArr [i])
298 aArr [i]->AddRef();
299 }
300 }
301
302 template <class I, class CI>
303 static void FromSafeIfaceArray (const com::SafeIfaceArray <I> &aArr,
304 QValueVector <CI> &aVec)
305 {
306 aVec = QValueVector <CI> (aArr.size());
307 size_t i = 0;
308 for (typename QValueVector <CI>::iterator it = aVec.begin();
309 it != aVec.end(); ++ it, ++ i)
310 (*it).attach (aArr [i]);
311 }
312
313protected:
314
315 /* no arbitrary instance creations */
316 COMBase() : mRC (S_OK) {};
317
318#if defined (VBOX_WITH_XPCOM)
319 static XPCOMEventQSocketListener *sSocketListener;
320#endif
321
322 /** Adapter to pass QString as input BSTR params */
323 class BSTRIn
324 {
325 public:
326
327 BSTRIn (const QString &s) : bstr (SysAllocString ((const OLECHAR *) s.ucs2())) {}
328
329 ~BSTRIn()
330 {
331 if (bstr)
332 SysFreeString (bstr);
333 }
334
335 operator BSTR() const { return bstr; }
336
337 private:
338
339 BSTR bstr;
340 };
341
342 /** Adapter to pass QString as output BSTR params */
343 class BSTROut
344 {
345 public:
346
347 BSTROut (QString &s) : str (s), bstr (0) {}
348
349 ~BSTROut()
350 {
351 if (bstr) {
352 str = QString::fromUcs2 (bstr);
353 SysFreeString (bstr);
354 }
355 }
356
357 operator BSTR *() { return &bstr; }
358
359 private:
360
361 QString &str;
362 BSTR bstr;
363 };
364
365 /**
366 * Adapter to pass CEnums enums as output COM enum params (*_T).
367 *
368 * @param QE CEnums enum.
369 * @param CE COM enum.
370 */
371 template <typename QE, typename CE>
372 class ENUMOut
373 {
374 public:
375
376 ENUMOut (QE &e) : qe (e), ce ((CE) 0) {}
377 ~ENUMOut() { qe = (QE) ce; }
378 operator CE *() { return &ce; }
379
380 private:
381
382 QE &qe;
383 CE ce;
384 };
385
386#if !defined (VBOX_WITH_XPCOM)
387
388 /** Adapter to pass QUuid as input GUID params */
389 static GUID GUIDIn (const QUuid &uuid) { return uuid; }
390
391 /** Adapter to pass QUuid as output GUID params */
392 class GUIDOut
393 {
394 public:
395
396 GUIDOut (QUuid &id) : uuid (id)
397 {
398 ::memset (&guid, 0, sizeof (GUID));
399 }
400
401 ~GUIDOut()
402 {
403 uuid = QUuid (
404 guid.Data1, guid.Data2, guid.Data3,
405 guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
406 guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
407 }
408
409 operator GUID *() { return &guid; }
410
411 private:
412
413 QUuid &uuid;
414 GUID guid;
415 };
416
417#else /* !defined (VBOX_WITH_XPCOM) */
418
419 /** Adapter to pass QUuid as input GUID params */
420 static const nsID &GUIDIn (const QUuid &uuid)
421 {
422 return *(const nsID *) &uuid;
423 }
424
425 /** Adapter to pass QUuid as output GUID params */
426 class GUIDOut
427 {
428 public:
429
430 GUIDOut (QUuid &id) : uuid (id), nsid (0) {}
431
432 ~GUIDOut()
433 {
434 if (nsid)
435 {
436 uuid = QUuid (
437 nsid->m0, nsid->m1, nsid->m2,
438 nsid->m3[0], nsid->m3[1], nsid->m3[2], nsid->m3[3],
439 nsid->m3[4], nsid->m3[5], nsid->m3[6], nsid->m3[7]);
440 nsMemory::Free (nsid);
441 }
442 }
443
444 operator nsID **() { return &nsid; }
445
446 private:
447
448 QUuid &uuid;
449 nsID *nsid;
450 };
451
452#endif /* !defined (VBOX_WITH_XPCOM) */
453
454 void fetchErrorInfo (IUnknown * /*callee*/, const GUID * /*calleeIID*/) const {}
455
456 mutable HRESULT mRC;
457
458 friend class COMErrorInfo;
459};
460
461/////////////////////////////////////////////////////////////////////////////
462
463/**
464 * Alternative base class for the CInterface template that adds
465 * the errorInfo() method for providing extended error info about
466 * unsuccessful invocation of the last called interface method.
467 */
468class COMBaseWithEI : public COMBase
469{
470public:
471
472 /**
473 * Returns error info set by the last unsuccessfully invoked interface
474 * method. Returned error info is useful only if CInterface::lastRC()
475 * represents a failure (i.e. CInterface::isOk() is false).
476 */
477 COMErrorInfo errorInfo() const { return mErrInfo; }
478
479protected:
480
481 /* no arbitrary instance creations */
482 COMBaseWithEI() : COMBase () {};
483
484 void fetchErrorInfo (IUnknown *callee, const GUID *calleeIID) const
485 {
486 mErrInfo.fetchFromCurrentThread (callee, calleeIID);
487 }
488
489 mutable COMErrorInfo mErrInfo;
490};
491
492/////////////////////////////////////////////////////////////////////////////
493
494/**
495 * Simple class that encapsulates the result code and COMErrorInfo.
496 */
497class COMResult
498{
499public:
500
501 COMResult() : mRC (S_OK) {}
502
503 /** Queries the current result code and error info from the given component */
504 COMResult (const COMBase &aComponent)
505 {
506 mErrInfo = aComponent.errorInfo();
507 mRC = aComponent.lastRC();
508 }
509
510 /** Queries the current result code and error info from the given component */
511 COMResult &operator= (const COMBase &aComponent)
512 {
513 mErrInfo = aComponent.errorInfo();
514 mRC = aComponent.lastRC();
515 return *this;
516 }
517
518 bool isNull() const { return mErrInfo.isNull(); }
519 bool isOk() const { return mErrInfo.isNull() && SUCCEEDED (mRC); }
520
521 COMErrorInfo errorInfo() const { return mErrInfo; }
522 HRESULT rc() const { return mRC; }
523
524private:
525
526 COMErrorInfo mErrInfo;
527 HRESULT mRC;
528};
529
530/////////////////////////////////////////////////////////////////////////////
531
532class CUnknown;
533
534/**
535 * Wrapper template class for all interfaces.
536 *
537 * All interface methods named as they are in the original, i.e. starting
538 * with the capital letter. All utility non-interface methods are named
539 * starting with the small letter. Utility methods should be not normally
540 * called by the end-user client application.
541 *
542 * @param I interface class (i.e. IUnknown/nsISupports derivant)
543 * @param B base class, either COMBase (by default) or COMBaseWithEI
544 */
545template <class I, class B = COMBase>
546class CInterface : public B
547{
548public:
549
550 typedef B Base;
551 typedef I Iface;
552
553 /* constructors & destructor */
554
555 CInterface() : mIface (NULL) {}
556
557 CInterface (const CInterface &that) : B (that), mIface (that.mIface)
558 {
559 addref (mIface);
560 }
561
562 CInterface (const CUnknown &that);
563
564 CInterface (I *i) : mIface (i) { addref (mIface); }
565
566 virtual ~CInterface() { release (mIface); }
567
568 /* utility methods */
569
570 void createInstance (const CLSID &clsid)
571 {
572 AssertMsg (!mIface, ("Instance is already non-NULL\n"));
573 if (!mIface)
574 {
575#if !defined (VBOX_WITH_XPCOM)
576
577 B::mRC = CoCreateInstance (clsid, NULL, CLSCTX_ALL,
578 _ATL_IIDOF (I), (void **) &mIface);
579
580#else /* !defined (VBOX_WITH_XPCOM) */
581
582 nsCOMPtr <nsIComponentManager> manager;
583 B::mRC = NS_GetComponentManager (getter_AddRefs (manager));
584 if (SUCCEEDED (B::mRC))
585 B::mRC = manager->CreateInstance (clsid, nsnull, NS_GET_IID (I),
586 (void **) &mIface);
587
588#endif /* !defined (VBOX_WITH_XPCOM) */
589
590 /* fetch error info, but don't assert if it's missing -- many other
591 * reasons can lead to an error (w/o providing error info), not only
592 * the instance initialization code (that should always provide it) */
593 B::fetchErrorInfo (NULL, NULL);
594 }
595 }
596
597 void attach (I *i)
598 {
599 /* be aware of self (from COM point of view) assignment */
600 I *old_iface = mIface;
601 mIface = i;
602 addref (mIface);
603 release (old_iface);
604 B::mRC = S_OK;
605 };
606
607 void attachUnknown (IUnknown *i)
608 {
609 /* be aware of self (from COM point of view) assignment */
610 I *old_iface = mIface;
611 mIface = NULL;
612 B::mRC = S_OK;
613 if (i)
614#if !defined (VBOX_WITH_XPCOM)
615 B::mRC = i->QueryInterface (_ATL_IIDOF (I), (void **) &mIface);
616#else /* !defined (VBOX_WITH_XPCOM) */
617 B::mRC = i->QueryInterface (NS_GET_IID (I), (void **) &mIface);
618#endif /* !defined (VBOX_WITH_XPCOM) */
619 release (old_iface);
620 };
621
622 void detach() { release (mIface); mIface = NULL; }
623
624 bool isNull() const { return mIface == NULL; }
625
626 bool isOk() const { return !isNull() && SUCCEEDED (B::mRC); }
627
628 /* utility operators */
629
630 CInterface &operator= (const CInterface &that)
631 {
632 attach (that.mIface);
633 B::operator= (that);
634 return *this;
635 }
636
637 I *iface() const { return mIface; }
638
639 bool operator== (const CInterface &that) const { return mIface == that.mIface; }
640 bool operator!= (const CInterface &that) const { return mIface != that.mIface; }
641
642 CInterface &operator= (const CUnknown &that);
643
644protected:
645
646 static void addref (I *i) { if (i) i->AddRef(); }
647 static void release (I *i) { if (i) i->Release(); }
648
649 mutable I *mIface;
650};
651
652/////////////////////////////////////////////////////////////////////////////
653
654class CUnknown : public CInterface <IUnknown, COMBaseWithEI>
655{
656public:
657
658 CUnknown() : CInterface <IUnknown, COMBaseWithEI> () {}
659
660 template <class C>
661 explicit CUnknown (const C &that)
662 {
663 mIface = NULL;
664 if (that.mIface)
665#if !defined (VBOX_WITH_XPCOM)
666 mRC = that.mIface->QueryInterface (_ATL_IIDOF (IUnknown), (void**) &mIface);
667#else /* !defined (VBOX_WITH_XPCOM) */
668 mRC = that.mIface->QueryInterface (NS_GET_IID (IUnknown), (void**) &mIface);
669#endif /* !defined (VBOX_WITH_XPCOM) */
670 if (SUCCEEDED (mRC))
671 {
672 mRC = that.lastRC();
673 mErrInfo = that.errorInfo();
674 }
675 }
676
677 /* specialization for CUnknown */
678 CUnknown (const CUnknown &that) : CInterface <IUnknown, COMBaseWithEI> ()
679 {
680 mIface = that.mIface;
681 addref (mIface);
682 COMBaseWithEI::operator= (that);
683 }
684
685 template <class C>
686 CUnknown &operator= (const C &that)
687 {
688 /* be aware of self (from COM point of view) assignment */
689 IUnknown *old_iface = mIface;
690 mIface = NULL;
691 mRC = S_OK;
692#if !defined (VBOX_WITH_XPCOM)
693 if (that.mIface)
694 mRC = that.mIface->QueryInterface (_ATL_IIDOF (IUnknown), (void**) &mIface);
695#else /* !defined (VBOX_WITH_XPCOM) */
696 if (that.mIface)
697 mRC = that.mIface->QueryInterface (NS_GET_IID (IUnknown), (void**) &mIface);
698#endif /* !defined (VBOX_WITH_XPCOM) */
699 if (SUCCEEDED (mRC))
700 {
701 mRC = that.lastRC();
702 mErrInfo = that.errorInfo();
703 }
704 release (old_iface);
705 return *this;
706 }
707
708 /* specialization for CUnknown */
709 CUnknown &operator= (const CUnknown &that)
710 {
711 attach (that.mIface);
712 COMBaseWithEI::operator= (that);
713 return *this;
714 }
715
716 /* @internal Used in wrappers. */
717 IUnknown *&ifaceRef() { return mIface; };
718};
719
720/* inlined CInterface methods that use CUnknown */
721
722template <class I, class B>
723inline CInterface <I, B>::CInterface (const CUnknown &that)
724 : mIface (NULL)
725{
726 attachUnknown (that.iface());
727 if (SUCCEEDED (B::mRC))
728 B::operator= ((B &) that);
729}
730
731template <class I, class B>
732inline CInterface <I, B> &CInterface <I, B>::operator =(const CUnknown &that)
733{
734 attachUnknown (that.iface());
735 if (SUCCEEDED (B::mRC))
736 B::operator= ((B &) that);
737 return *this;
738}
739
740/////////////////////////////////////////////////////////////////////////////
741
742/* include the generated header containing concrete wrapper definitions */
743#include "COMWrappers.h"
744
745/** @} */
746
747#endif // __COMDefs_h__
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette