VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/globals/COMDefs.cpp@ 103977

Last change on this file since 103977 was 103538, checked in by vboxsync, 9 months ago

FE/Qt: Moving out logging stuff from UIDefs.h to separate UILoggingDefs.h; This breaks dependency of UIDefs/UICommon headers from VBox/log.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.4 KB
Line 
1/* $Id: COMDefs.cpp 103538 2024-02-22 17:06:26Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - CInterface implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QSocketNotifier>
30
31/* GUI includes: */
32#include "COMDefs.h"
33#include "UILoggingDefs.h"
34
35/* COM includes: */
36#include "CVirtualBoxErrorInfo.h"
37
38/* VirtualBox interface declarations: */
39#include <VBox/com/VirtualBox.h>
40
41#ifdef VBOX_WITH_XPCOM
42
43/* Other VBox includes: */
44# include <nsEventQueueUtils.h>
45# include <nsIEventQueue.h>
46# include <nsIExceptionService.h>
47
48/* Mac OS X (Carbon mode) and OS/2 will notify the native queue
49 internally in plevent.c. Because moc doesn't seems to respect
50 #ifdefs, we still have to include the definition of the class.
51 very silly. */
52# if !defined (Q_OS_MAC) && !defined (Q_OS_OS2)
53XPCOMEventQSocketListener *COMBase::sSocketListener = 0;
54
55# endif
56
57/**
58 * Internal class to asynchronously handle IPC events on the GUI thread
59 * using the event queue socket FD and QSocketNotifier.
60 */
61class XPCOMEventQSocketListener : public QObject
62{
63 Q_OBJECT
64
65public:
66
67 XPCOMEventQSocketListener (nsIEventQueue *eq)
68 {
69 mEventQ = eq;
70 mNotifier = new QSocketNotifier (mEventQ->GetEventQueueSelectFD(),
71 QSocketNotifier::Read, this);
72 QObject::connect (mNotifier, SIGNAL (activated (int)),
73 this, SLOT (processEvents()));
74 }
75
76 virtual ~XPCOMEventQSocketListener()
77 {
78 delete mNotifier;
79 }
80
81public slots:
82
83 void processEvents() { mEventQ->ProcessPendingEvents(); }
84
85private:
86
87 QSocketNotifier *mNotifier;
88 nsCOMPtr <nsIEventQueue> mEventQ;
89};
90
91#endif /* !defined (VBOX_WITH_XPCOM) */
92
93/**
94 * Initializes COM/XPCOM.
95 */
96HRESULT COMBase::InitializeCOM(bool fGui)
97{
98 LogFlowFuncEnter();
99
100 HRESULT rc = com::Initialize(fGui ? VBOX_COM_INIT_F_DEFAULT | VBOX_COM_INIT_F_GUI : VBOX_COM_INIT_F_DEFAULT);
101
102#if defined (VBOX_WITH_XPCOM)
103
104# if !defined (RT_OS_DARWIN) && !defined (RT_OS_OS2)
105
106 if (NS_SUCCEEDED (rc))
107 {
108 nsCOMPtr <nsIEventQueue> eventQ;
109 rc = NS_GetMainEventQ (getter_AddRefs (eventQ));
110 if (NS_SUCCEEDED (rc))
111 {
112# ifdef DEBUG
113 BOOL isNative = FALSE;
114 eventQ->IsQueueNative (&isNative);
115 AssertMsg (isNative, ("The event queue must be native"));
116# endif
117 BOOL isOnMainThread = FALSE;
118 rc = eventQ->IsOnCurrentThread (&isOnMainThread);
119 if (NS_SUCCEEDED (rc) && isOnMainThread)
120 {
121 sSocketListener = new XPCOMEventQSocketListener (eventQ);
122 }
123 }
124 }
125
126# endif /* !defined (RT_OS_DARWIN) && !defined (RT_OS_OS) */
127
128#endif /* defined (VBOX_WITH_XPCOM) */
129
130 if (FAILED (rc))
131 CleanupCOM();
132
133 AssertComRC (rc);
134
135 LogFlowFunc (("rc=%08X\n", rc));
136 LogFlowFuncLeave();
137 return rc;
138
139}
140
141/**
142 * Cleans up COM/XPCOM.
143 */
144HRESULT COMBase::CleanupCOM()
145{
146 LogFlowFuncEnter();
147
148 HRESULT rc = S_OK;
149
150#if defined (VBOX_WITH_XPCOM)
151
152 /* scope the code to make smart references are released before calling
153 * com::Shutdown() */
154 {
155 nsCOMPtr <nsIEventQueue> eventQ;
156 rc = NS_GetMainEventQ (getter_AddRefs (eventQ));
157 if (NS_SUCCEEDED (rc))
158 {
159 BOOL isOnMainThread = FALSE;
160 rc = eventQ->IsOnCurrentThread (&isOnMainThread);
161 if (NS_SUCCEEDED (rc) && isOnMainThread)
162 {
163# if !defined (RT_OS_DARWIN) && !defined (RT_OS_OS2)
164 if (sSocketListener)
165 {
166 delete sSocketListener;
167 sSocketListener = NULL;
168 }
169# endif
170 }
171 }
172 }
173
174#endif /* defined (VBOX_WITH_XPCOM) */
175
176 HRESULT rc2 = com::Shutdown();
177 if (SUCCEEDED (rc))
178 rc = rc2;
179
180 AssertComRC (rc);
181
182 LogFlowFunc (("rc=%08X\n", rc));
183 LogFlowFuncLeave();
184 return rc;
185}
186
187/* static */
188void COMBase::ToSafeArray (const QVector <QString> &aVec,
189 com::SafeArray <BSTR> &aArr)
190{
191 aArr.reset (aVec.size());
192 for (int i = 0; i < aVec.size(); ++ i)
193 aArr [i] = SysAllocString ((const OLECHAR *)
194 (aVec.at (i).isNull() ? 0 : aVec.at (i).utf16()));
195}
196
197/* static */
198void COMBase::FromSafeArray (const com::SafeArray <BSTR> &aArr,
199 QVector <QString> &aVec)
200{
201 AssertCompile(sizeof(aArr[0][0]) == sizeof(ushort));
202 aVec.resize (static_cast <int> (aArr.size()));
203 for (int i = 0; i < aVec.size(); ++ i)
204 aVec [i] = QString::fromUtf16 ((const char16_t *)aArr [i]);
205}
206
207/* static */
208void COMBase::ToSafeArray (const QVector <QUuid> &aVec,
209 com::SafeGUIDArray &aArr)
210{
211 AssertCompileSize (GUID, sizeof (QUuid));
212 aArr.reset (aVec.size());
213 for (int i = 0; i < aVec.size(); ++ i)
214 aArr [i] = *(GUID*) &aVec [i];
215}
216
217/* static */
218void COMBase::FromSafeArray (const com::SafeGUIDArray &aArr,
219 QVector <QUuid> &aVec)
220{
221 AssertCompileSize (GUID, sizeof (QUuid));
222 aVec.resize (static_cast <int> (aArr.size()));
223 for (int i = 0; i < aVec.size(); ++ i)
224 {
225#ifdef VBOX_WITH_XPCOM
226 aVec [i] = *(QUuid*) &aArr [i];
227#else
228 /* No by-reference accessor, only by-value. So spell it out to avoid warnings. */
229 GUID Tmp = aArr[i];
230 aVec[i] = *(QUuid *)&Tmp;
231#endif
232 }
233}
234
235/* static */
236void COMBase::ToSafeArray (const QVector <QUuid> &aVec,
237 com::SafeArray <BSTR> &aArr)
238{
239 aArr.reset (aVec.size());
240 for (int i = 0; i < aVec.size(); ++ i)
241 aArr [i] = SysAllocString ((const OLECHAR *)
242 (aVec.at (i).isNull() ? 0 : aVec.at(i).toString().utf16()));
243}
244
245/* static */
246void COMBase::FromSafeArray (const com::SafeArray <BSTR> &aArr,
247 QVector <QUuid> &aVec)
248{
249 AssertCompile(sizeof(aArr[0][0]) == sizeof(ushort));
250 aVec.resize (static_cast <int> (aArr.size()));
251 for (int i = 0; i < aVec.size(); ++ i)
252 aVec [i] = QUuid(QString::fromUtf16 ((const char16_t *)aArr [i]));
253}
254
255////////////////////////////////////////////////////////////////////////////////
256
257void COMErrorInfo::init(const CVirtualBoxErrorInfo &info)
258{
259 if (info.isNull())
260 {
261 mIsNull = true;
262 mIsBasicAvailable = false;
263 mIsFullAvailable = false;
264 mResultCode = S_OK;
265 m_pNext = NULL;
266 AssertMsgFailedReturnVoid(("error info is NULL!\n"));
267 }
268
269 bool gotSomething = false;
270 bool gotAll = true;
271
272 mResultCode = info.GetResultCode();
273 gotSomething |= info.isOk();
274 gotAll &= info.isOk();
275
276 mInterfaceID = info.GetInterfaceID();
277 gotSomething |= info.isOk();
278 gotAll &= info.isOk();
279 if (info.isOk())
280 mInterfaceName = getInterfaceNameFromIID (mInterfaceID);
281
282 mComponent = info.GetComponent();
283 gotSomething |= info.isOk();
284 gotAll &= info.isOk();
285
286 mText = info.GetText();
287 gotSomething |= info.isOk();
288 gotAll &= info.isOk();
289
290 m_pNext = NULL;
291
292 CVirtualBoxErrorInfo next = info.GetNext();
293 if (info.isOk() && !next.isNull())
294 {
295 m_pNext = new COMErrorInfo(next);
296 Assert(m_pNext);
297 }
298
299 gotSomething |= info.isOk();
300 gotAll &= info.isOk();
301
302 mIsBasicAvailable = gotSomething;
303 mIsFullAvailable = gotAll;
304
305 mIsNull = !gotSomething;
306
307 AssertMsg (gotSomething, ("Nothing to fetch!\n"));
308}
309
310void COMErrorInfo::copyFrom(const COMErrorInfo &x)
311{
312 mIsNull = x.mIsNull;
313 mIsBasicAvailable = x.mIsBasicAvailable;
314 mIsFullAvailable = x.mIsFullAvailable;
315
316 mResultCode = x.mResultCode;
317 mInterfaceID = x.mInterfaceID;
318 mComponent = x.mComponent;
319 mText = x.mText;
320
321 if (x.m_pNext)
322 m_pNext = new COMErrorInfo(*x.m_pNext);
323 else
324 m_pNext = NULL;
325
326 mInterfaceName = x.mInterfaceName;
327 mCalleeIID = x.mCalleeIID;
328 mCalleeName = x.mCalleeName;
329}
330
331void COMErrorInfo::cleanup()
332{
333 if (m_pNext)
334 {
335 delete m_pNext;
336 m_pNext = NULL;
337 }
338}
339
340/**
341 * Fetches error info from the current thread.
342 * If callee is NULL, then error info is fetched in "interfaceless"
343 * manner (so calleeIID() and calleeName() will return null).
344 *
345 * @param callee
346 * pointer to the interface whose method returned an error
347 * @param calleeIID
348 * UUID of the callee's interface. Ignored when callee is NULL
349 */
350void COMErrorInfo::fetchFromCurrentThread(IUnknown *callee, const GUID *calleeIID)
351{
352 mIsNull = true;
353 mIsFullAvailable = mIsBasicAvailable = false;
354
355 AssertReturnVoid(!callee || calleeIID);
356
357 HRESULT rc = E_FAIL;
358
359#if !defined(VBOX_WITH_XPCOM)
360
361 if (callee)
362 {
363 ComPtr<IUnknown> iface(callee);
364 ComPtr<ISupportErrorInfo> serr(iface);
365 if (!serr)
366 return;
367 rc = serr->InterfaceSupportsErrorInfo(*calleeIID);
368 if (!SUCCEEDED(rc))
369 return;
370 }
371
372 ComPtr<IErrorInfo> err;
373 rc = ::GetErrorInfo(0, err.asOutParam());
374 if (rc == S_OK && err)
375 {
376 ComPtr<IVirtualBoxErrorInfo> info(err);
377 if (info)
378 init(CVirtualBoxErrorInfo(info));
379
380 if (!mIsFullAvailable)
381 {
382 bool gotSomething = false;
383
384 rc = err->GetGUID(COMBase::GUIDOut(mInterfaceID));
385 gotSomething |= SUCCEEDED(rc);
386 if (SUCCEEDED(rc))
387 mInterfaceName = getInterfaceNameFromIID(mInterfaceID);
388
389 rc = err->GetSource(COMBase::BSTROut(mComponent));
390 gotSomething |= SUCCEEDED(rc);
391
392 rc = err->GetDescription(COMBase::BSTROut(mText));
393 gotSomething |= SUCCEEDED(rc);
394
395 if (gotSomething)
396 mIsBasicAvailable = true;
397
398 mIsNull = !gotSomething;
399
400 AssertMsg(gotSomething,("Nothing to fetch!\n"));
401 }
402 }
403
404#else /* defined(VBOX_WITH_XPCOM) */
405
406 nsCOMPtr<nsIExceptionService> es;
407 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
408 if (NS_SUCCEEDED(rc))
409 {
410 nsCOMPtr<nsIExceptionManager> em;
411 rc = es->GetCurrentExceptionManager(getter_AddRefs(em));
412 if (NS_SUCCEEDED(rc))
413 {
414 nsCOMPtr<nsIException> ex;
415 rc = em->GetCurrentException(getter_AddRefs(ex));
416 if (NS_SUCCEEDED(rc) && ex)
417 {
418 nsCOMPtr<IVirtualBoxErrorInfo> info;
419 info = do_QueryInterface(ex, &rc);
420 if (NS_SUCCEEDED(rc) && info)
421 init(CVirtualBoxErrorInfo(info));
422
423 if (!mIsFullAvailable)
424 {
425 bool gotSomething = false;
426
427 rc = ex->GetResult(&mResultCode);
428 gotSomething |= NS_SUCCEEDED(rc);
429
430 char *message = NULL; // utf8
431 rc = ex->GetMessage(&message);
432 gotSomething |= NS_SUCCEEDED(rc);
433 if (NS_SUCCEEDED(rc) && message)
434 {
435 mText = QString::fromUtf8(message);
436 nsMemory::Free(message);
437 }
438
439 if (gotSomething)
440 mIsBasicAvailable = true;
441
442 mIsNull = !gotSomething;
443
444 AssertMsg(gotSomething, ("Nothing to fetch!\n"));
445 }
446
447 // set the exception to NULL (to emulate Win32 behavior)
448 em->SetCurrentException(NULL);
449
450 rc = NS_OK;
451 }
452 }
453 }
454
455 AssertComRC(rc);
456
457#endif /* !defined(VBOX_WITH_XPCOM) */
458
459 if (callee && calleeIID && mIsBasicAvailable)
460 {
461 mCalleeIID = COMBase::ToQUuid(*calleeIID);
462 mCalleeName = getInterfaceNameFromIID(mCalleeIID);
463 }
464}
465
466// static
467QString COMErrorInfo::getInterfaceNameFromIID (const QUuid &id)
468{
469 QString name;
470
471 com::GetInterfaceNameByIID (COMBase::GUIDIn (id), COMBase::BSTROut (name));
472
473 return name;
474}
475
476#if defined (VBOX_WITH_XPCOM)
477#include "COMDefs.moc"
478#endif
479
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