VirtualBox

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

Last change on this file since 100347 was 100068, checked in by vboxsync, 20 months ago

FE/Qt and Debugger: bugref:10450: Qt6 compatibility bits for QString::fromUtf16 calls; ushort is replaced with char16_t.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.7 KB
Line 
1/* $Id: COMDefs.cpp 100068 2023-06-05 12:42:04Z 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#ifndef VBOX_IS_QT6_OR_LATER
207 aVec [i] = QString::fromUtf16 ((const ushort *)aArr [i]);
208#else
209 aVec [i] = QString::fromUtf16 ((const char16_t *)aArr [i]);
210#endif
211}
212
213/* static */
214void COMBase::ToSafeArray (const QVector <QUuid> &aVec,
215 com::SafeGUIDArray &aArr)
216{
217 AssertCompileSize (GUID, sizeof (QUuid));
218 aArr.reset (aVec.size());
219 for (int i = 0; i < aVec.size(); ++ i)
220 aArr [i] = *(GUID*) &aVec [i];
221}
222
223/* static */
224void COMBase::FromSafeArray (const com::SafeGUIDArray &aArr,
225 QVector <QUuid> &aVec)
226{
227 AssertCompileSize (GUID, sizeof (QUuid));
228 aVec.resize (static_cast <int> (aArr.size()));
229 for (int i = 0; i < aVec.size(); ++ i)
230 {
231#ifdef VBOX_WITH_XPCOM
232 aVec [i] = *(QUuid*) &aArr [i];
233#else
234 /* No by-reference accessor, only by-value. So spell it out to avoid warnings. */
235 GUID Tmp = aArr[i];
236 aVec[i] = *(QUuid *)&Tmp;
237#endif
238 }
239}
240
241/* static */
242void COMBase::ToSafeArray (const QVector <QUuid> &aVec,
243 com::SafeArray <BSTR> &aArr)
244{
245 aArr.reset (aVec.size());
246 for (int i = 0; i < aVec.size(); ++ i)
247 aArr [i] = SysAllocString ((const OLECHAR *)
248 (aVec.at (i).isNull() ? 0 : aVec.at(i).toString().utf16()));
249}
250
251/* static */
252void COMBase::FromSafeArray (const com::SafeArray <BSTR> &aArr,
253 QVector <QUuid> &aVec)
254{
255 AssertCompile(sizeof(aArr[0][0]) == sizeof(ushort));
256 aVec.resize (static_cast <int> (aArr.size()));
257 for (int i = 0; i < aVec.size(); ++ i)
258#ifndef VBOX_IS_QT6_OR_LATER
259 aVec [i] = QUuid(QString::fromUtf16 ((const ushort *)aArr [i]));
260#else
261 aVec [i] = QUuid(QString::fromUtf16 ((const char16_t *)aArr [i]));
262#endif
263}
264
265////////////////////////////////////////////////////////////////////////////////
266
267void COMErrorInfo::init(const CVirtualBoxErrorInfo &info)
268{
269 if (info.isNull())
270 {
271 mIsNull = true;
272 mIsBasicAvailable = false;
273 mIsFullAvailable = false;
274 mResultCode = S_OK;
275 m_pNext = NULL;
276 AssertMsgFailedReturnVoid(("error info is NULL!\n"));
277 }
278
279 bool gotSomething = false;
280 bool gotAll = true;
281
282 mResultCode = info.GetResultCode();
283 gotSomething |= info.isOk();
284 gotAll &= info.isOk();
285
286 mInterfaceID = info.GetInterfaceID();
287 gotSomething |= info.isOk();
288 gotAll &= info.isOk();
289 if (info.isOk())
290 mInterfaceName = getInterfaceNameFromIID (mInterfaceID);
291
292 mComponent = info.GetComponent();
293 gotSomething |= info.isOk();
294 gotAll &= info.isOk();
295
296 mText = info.GetText();
297 gotSomething |= info.isOk();
298 gotAll &= info.isOk();
299
300 m_pNext = NULL;
301
302 CVirtualBoxErrorInfo next = info.GetNext();
303 if (info.isOk() && !next.isNull())
304 {
305 m_pNext = new COMErrorInfo(next);
306 Assert(m_pNext);
307 }
308
309 gotSomething |= info.isOk();
310 gotAll &= info.isOk();
311
312 mIsBasicAvailable = gotSomething;
313 mIsFullAvailable = gotAll;
314
315 mIsNull = !gotSomething;
316
317 AssertMsg (gotSomething, ("Nothing to fetch!\n"));
318}
319
320void COMErrorInfo::copyFrom(const COMErrorInfo &x)
321{
322 mIsNull = x.mIsNull;
323 mIsBasicAvailable = x.mIsBasicAvailable;
324 mIsFullAvailable = x.mIsFullAvailable;
325
326 mResultCode = x.mResultCode;
327 mInterfaceID = x.mInterfaceID;
328 mComponent = x.mComponent;
329 mText = x.mText;
330
331 if (x.m_pNext)
332 m_pNext = new COMErrorInfo(*x.m_pNext);
333 else
334 m_pNext = NULL;
335
336 mInterfaceName = x.mInterfaceName;
337 mCalleeIID = x.mCalleeIID;
338 mCalleeName = x.mCalleeName;
339}
340
341void COMErrorInfo::cleanup()
342{
343 if (m_pNext)
344 {
345 delete m_pNext;
346 m_pNext = NULL;
347 }
348}
349
350/**
351 * Fetches error info from the current thread.
352 * If callee is NULL, then error info is fetched in "interfaceless"
353 * manner (so calleeIID() and calleeName() will return null).
354 *
355 * @param callee
356 * pointer to the interface whose method returned an error
357 * @param calleeIID
358 * UUID of the callee's interface. Ignored when callee is NULL
359 */
360void COMErrorInfo::fetchFromCurrentThread(IUnknown *callee, const GUID *calleeIID)
361{
362 mIsNull = true;
363 mIsFullAvailable = mIsBasicAvailable = false;
364
365 AssertReturnVoid(!callee || calleeIID);
366
367 HRESULT rc = E_FAIL;
368
369#if !defined(VBOX_WITH_XPCOM)
370
371 if (callee)
372 {
373 ComPtr<IUnknown> iface(callee);
374 ComPtr<ISupportErrorInfo> serr(iface);
375 if (!serr)
376 return;
377 rc = serr->InterfaceSupportsErrorInfo(*calleeIID);
378 if (!SUCCEEDED(rc))
379 return;
380 }
381
382 ComPtr<IErrorInfo> err;
383 rc = ::GetErrorInfo(0, err.asOutParam());
384 if (rc == S_OK && err)
385 {
386 ComPtr<IVirtualBoxErrorInfo> info(err);
387 if (info)
388 init(CVirtualBoxErrorInfo(info));
389
390 if (!mIsFullAvailable)
391 {
392 bool gotSomething = false;
393
394 rc = err->GetGUID(COMBase::GUIDOut(mInterfaceID));
395 gotSomething |= SUCCEEDED(rc);
396 if (SUCCEEDED(rc))
397 mInterfaceName = getInterfaceNameFromIID(mInterfaceID);
398
399 rc = err->GetSource(COMBase::BSTROut(mComponent));
400 gotSomething |= SUCCEEDED(rc);
401
402 rc = err->GetDescription(COMBase::BSTROut(mText));
403 gotSomething |= SUCCEEDED(rc);
404
405 if (gotSomething)
406 mIsBasicAvailable = true;
407
408 mIsNull = !gotSomething;
409
410 AssertMsg(gotSomething,("Nothing to fetch!\n"));
411 }
412 }
413
414#else /* defined(VBOX_WITH_XPCOM) */
415
416 nsCOMPtr<nsIExceptionService> es;
417 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
418 if (NS_SUCCEEDED(rc))
419 {
420 nsCOMPtr<nsIExceptionManager> em;
421 rc = es->GetCurrentExceptionManager(getter_AddRefs(em));
422 if (NS_SUCCEEDED(rc))
423 {
424 nsCOMPtr<nsIException> ex;
425 rc = em->GetCurrentException(getter_AddRefs(ex));
426 if (NS_SUCCEEDED(rc) && ex)
427 {
428 nsCOMPtr<IVirtualBoxErrorInfo> info;
429 info = do_QueryInterface(ex, &rc);
430 if (NS_SUCCEEDED(rc) && info)
431 init(CVirtualBoxErrorInfo(info));
432
433 if (!mIsFullAvailable)
434 {
435 bool gotSomething = false;
436
437 rc = ex->GetResult(&mResultCode);
438 gotSomething |= NS_SUCCEEDED(rc);
439
440 char *message = NULL; // utf8
441 rc = ex->GetMessage(&message);
442 gotSomething |= NS_SUCCEEDED(rc);
443 if (NS_SUCCEEDED(rc) && message)
444 {
445 mText = QString::fromUtf8(message);
446 nsMemory::Free(message);
447 }
448
449 if (gotSomething)
450 mIsBasicAvailable = true;
451
452 mIsNull = !gotSomething;
453
454 AssertMsg(gotSomething, ("Nothing to fetch!\n"));
455 }
456
457 // set the exception to NULL (to emulate Win32 behavior)
458 em->SetCurrentException(NULL);
459
460 rc = NS_OK;
461 }
462 }
463 }
464
465 AssertComRC(rc);
466
467#endif /* !defined(VBOX_WITH_XPCOM) */
468
469 if (callee && calleeIID && mIsBasicAvailable)
470 {
471 mCalleeIID = COMBase::ToQUuid(*calleeIID);
472 mCalleeName = getInterfaceNameFromIID(mCalleeIID);
473 }
474}
475
476// static
477QString COMErrorInfo::getInterfaceNameFromIID (const QUuid &id)
478{
479 QString name;
480
481 com::GetInterfaceNameByIID (COMBase::GUIDIn (id), COMBase::BSTROut (name));
482
483 return name;
484}
485
486#if defined (VBOX_WITH_XPCOM)
487#include "COMDefs.moc"
488#endif
489
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