VirtualBox

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

Last change on this file since 102493 was 101567, checked in by vboxsync, 11 months ago

FE/Qt: bugref:10450: Get rid of Qt5 stuff; This one is about type changes.

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