VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/VirtualBoxClientImpl.cpp@ 94521

Last change on this file since 94521 was 93115, checked in by vboxsync, 2 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.4 KB
Line 
1/* $Id: VirtualBoxClientImpl.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2010-2022 Oracle Corporation
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
18#define LOG_GROUP LOG_GROUP_MAIN_VIRTUALBOXCLIENT
19#include "LoggingNew.h"
20
21#include "VirtualBoxClientImpl.h"
22
23#include "AutoCaller.h"
24#include "VBoxEvents.h"
25#include "VBox/com/ErrorInfo.h"
26#include "VBox/com/listeners.h"
27
28#include <iprt/asm.h>
29#include <iprt/thread.h>
30#include <iprt/critsect.h>
31#include <iprt/path.h>
32#include <iprt/semaphore.h>
33#include <iprt/cpp/utils.h>
34#include <iprt/utf16.h>
35#ifdef RT_OS_WINDOWS
36# include <iprt/err.h>
37# include <iprt/ldr.h>
38# include <msi.h>
39# include <WbemIdl.h>
40#endif
41
42#include <new>
43
44
45/** Waiting time between probing whether VBoxSVC is alive. */
46#define VBOXCLIENT_DEFAULT_INTERVAL 30000
47
48
49/** Initialize instance counter class variable */
50uint32_t VirtualBoxClient::g_cInstances = 0;
51
52LONG VirtualBoxClient::s_cUnnecessaryAtlModuleLocks = 0;
53
54#ifdef VBOX_WITH_MAIN_NLS
55
56/* listener class for language updates */
57class VBoxEventListener
58{
59public:
60 VBoxEventListener()
61 {}
62
63
64 HRESULT init(void *)
65 {
66 return S_OK;
67 }
68
69 HRESULT init()
70 {
71 return S_OK;
72 }
73
74 void uninit()
75 {
76 }
77
78 virtual ~VBoxEventListener()
79 {
80 }
81
82 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
83 {
84 switch(aType)
85 {
86 case VBoxEventType_OnLanguageChanged:
87 {
88 /*
89 * Proceed with uttmost care as we might be racing com::Shutdown()
90 * and have the ground open up beneath us.
91 */
92 LogFunc(("VBoxEventType_OnLanguageChanged\n"));
93 VirtualBoxTranslator *pTranslator = VirtualBoxTranslator::tryInstance();
94 if (pTranslator)
95 {
96 ComPtr<ILanguageChangedEvent> pEvent = aEvent;
97 Assert(pEvent);
98
99 /* This call may fail if we're racing COM shutdown. */
100 com::Bstr bstrLanguageId;
101 HRESULT hrc = pEvent->COMGETTER(LanguageId)(bstrLanguageId.asOutParam());
102 if (SUCCEEDED(hrc))
103 {
104 try
105 {
106 com::Utf8Str strLanguageId(bstrLanguageId);
107 LogFunc(("New language ID: %s\n", strLanguageId.c_str()));
108 pTranslator->i_loadLanguage(strLanguageId.c_str());
109 }
110 catch (std::bad_alloc &)
111 {
112 LogFunc(("Caught bad_alloc"));
113 }
114 }
115 else
116 LogFunc(("Failed to get new language ID: %Rhrc\n", hrc));
117
118 pTranslator->release();
119 }
120 break;
121 }
122
123 default:
124 AssertFailed();
125 }
126
127 return S_OK;
128 }
129};
130
131typedef ListenerImpl<VBoxEventListener> VBoxEventListenerImpl;
132
133VBOX_LISTENER_DECLARE(VBoxEventListenerImpl)
134
135#endif /* VBOX_WITH_MAIN_NLS */
136
137// constructor / destructor
138/////////////////////////////////////////////////////////////////////////////
139
140/** @relates VirtualBoxClient::FinalConstruct() */
141HRESULT VirtualBoxClient::FinalConstruct()
142{
143 HRESULT rc = init();
144 BaseFinalConstruct();
145 return rc;
146}
147
148void VirtualBoxClient::FinalRelease()
149{
150 uninit();
151 BaseFinalRelease();
152}
153
154
155// public initializer/uninitializer for internal purposes only
156/////////////////////////////////////////////////////////////////////////////
157
158/**
159 * Initializes the VirtualBoxClient object.
160 *
161 * @returns COM result indicator
162 */
163HRESULT VirtualBoxClient::init()
164{
165 LogFlowThisFuncEnter();
166
167 /* Enclose the state transition NotReady->InInit->Ready */
168 AutoInitSpan autoInitSpan(this);
169 AssertReturn(autoInitSpan.isOk(), E_FAIL);
170
171 /* Important: DO NOT USE any kind of "early return" (except the single
172 * one above, checking the init span success) in this method. It is vital
173 * for correct error handling that it has only one point of return, which
174 * does all the magic on COM to signal object creation success and
175 * reporting the error later for every API method. COM translates any
176 * unsuccessful object creation to REGDB_E_CLASSNOTREG errors or similar
177 * unhelpful ones which cause us a lot of grief with troubleshooting. */
178
179 HRESULT rc = S_OK;
180 try
181 {
182 if (ASMAtomicIncU32(&g_cInstances) != 1)
183 AssertFailedStmt(throw setError(E_FAIL, "Attempted to create more than one VirtualBoxClient instance"));
184
185 mData.m_ThreadWatcher = NIL_RTTHREAD;
186 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
187
188 rc = mData.m_pVirtualBox.createLocalObject(CLSID_VirtualBox);
189 if (FAILED(rc))
190#ifdef RT_OS_WINDOWS
191 throw i_investigateVirtualBoxObjectCreationFailure(rc);
192#else
193 throw rc;
194#endif
195
196 /* VirtualBox error return is postponed to method calls, fetch it. */
197 ULONG rev;
198 rc = mData.m_pVirtualBox->COMGETTER(Revision)(&rev);
199 if (FAILED(rc))
200 throw rc;
201
202 rc = unconst(mData.m_pEventSource).createObject();
203 AssertComRCThrow(rc, setError(rc, "Could not create EventSource for VirtualBoxClient"));
204 rc = mData.m_pEventSource->init();
205 AssertComRCThrow(rc, setError(rc, "Could not initialize EventSource for VirtualBoxClient"));
206
207 /* HACK ALERT! This is for DllCanUnloadNow(). */
208 s_cUnnecessaryAtlModuleLocks++;
209 AssertMsg(s_cUnnecessaryAtlModuleLocks == 1, ("%d\n", s_cUnnecessaryAtlModuleLocks));
210
211 int vrc;
212#ifdef VBOX_WITH_MAIN_NLS
213 /* Create the translator singelton (must work) and try load translations (non-fatal). */
214 mData.m_pVBoxTranslator = VirtualBoxTranslator::instance();
215 if (mData.m_pVBoxTranslator == NULL)
216 throw setError(VBOX_E_IPRT_ERROR, "Failed to create translator instance");
217
218 char szNlsPath[RTPATH_MAX];
219 vrc = RTPathAppPrivateNoArch(szNlsPath, sizeof(szNlsPath));
220 if (RT_SUCCESS(vrc))
221 vrc = RTPathAppend(szNlsPath, sizeof(szNlsPath), "nls" RTPATH_SLASH_STR "VirtualBoxAPI");
222
223 if (RT_SUCCESS(vrc))
224 {
225 vrc = mData.m_pVBoxTranslator->registerTranslation(szNlsPath, true, &mData.m_pTrComponent);
226 if (RT_SUCCESS(vrc))
227 {
228 rc = i_reloadApiLanguage();
229 if (SUCCEEDED(rc))
230 i_registerEventListener(); /* for updates */
231 else
232 LogRelFunc(("i_reloadApiLanguage failed: %Rhrc\n", rc));
233 }
234 else
235 LogRelFunc(("Register translation failed: %Rrc\n", vrc));
236 }
237 else
238 LogRelFunc(("Path constructing failed: %Rrc\n", vrc));
239#endif
240 /* Setting up the VBoxSVC watcher thread. If anything goes wrong here it
241 * is not considered important enough to cause any sort of visible
242 * failure. The monitoring will not be done, but that's all. */
243 vrc = RTSemEventCreate(&mData.m_SemEvWatcher);
244 if (RT_FAILURE(vrc))
245 {
246 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
247 AssertRCStmt(vrc, throw setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Failed to create semaphore (rc=%Rrc)"), vrc));
248 }
249
250 vrc = RTThreadCreate(&mData.m_ThreadWatcher, SVCWatcherThread, this, 0,
251 RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "VBoxSVCWatcher");
252 if (RT_FAILURE(vrc))
253 {
254 RTSemEventDestroy(mData.m_SemEvWatcher);
255 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
256 AssertRCStmt(vrc, throw setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Failed to create watcher thread (rc=%Rrc)"), vrc));
257 }
258 }
259 catch (HRESULT err)
260 {
261 /* we assume that error info is set by the thrower */
262 rc = err;
263 }
264 catch (...)
265 {
266 rc = VirtualBoxBase::handleUnexpectedExceptions(this, RT_SRC_POS);
267 }
268
269 /* Confirm a successful initialization when it's the case. Must be last,
270 * as on failure it will uninitialize the object. */
271 if (SUCCEEDED(rc))
272 autoInitSpan.setSucceeded();
273 else
274 autoInitSpan.setFailed(rc);
275
276 LogFlowThisFunc(("rc=%Rhrc\n", rc));
277 LogFlowThisFuncLeave();
278 /* Unconditionally return success, because the error return is delayed to
279 * the attribute/method calls through the InitFailed object state. */
280 return S_OK;
281}
282
283#ifdef RT_OS_WINDOWS
284
285/**
286 * Looks into why we failed to create the VirtualBox object.
287 *
288 * @returns hrcCaller thru setError.
289 * @param hrcCaller The failure status code.
290 */
291HRESULT VirtualBoxClient::i_investigateVirtualBoxObjectCreationFailure(HRESULT hrcCaller)
292{
293 HRESULT hrc;
294
295# ifdef VBOX_WITH_SDS
296 /*
297 * Check that the VBoxSDS service is configured to run as LocalSystem and is enabled.
298 */
299 WCHAR wszBuffer[256];
300 uint32_t uStartType;
301 int vrc = i_getServiceAccountAndStartType(L"VBoxSDS", wszBuffer, RT_ELEMENTS(wszBuffer), &uStartType);
302 if (RT_SUCCESS(vrc))
303 {
304 LogRelFunc(("VBoxSDS service is running under the '%ls' account with start type %u.\n", wszBuffer, uStartType));
305 if (RTUtf16Cmp(wszBuffer, L"LocalSystem") != 0)
306 return setError(hrcCaller,
307 tr("VBoxSDS is misconfigured to run under the '%ls' account instead of the SYSTEM one.\n"
308 "Reinstall VirtualBox to fix it. Alternatively you can fix it using the Windows Service Control "
309 "Manager or by running 'sc config VBoxSDS obj=LocalSystem' on a command line."), wszBuffer);
310 if (uStartType == SERVICE_DISABLED)
311 return setError(hrcCaller,
312 tr("The VBoxSDS windows service is disabled.\n"
313 "Reinstall VirtualBox to fix it. Alternatively try reenable the service by setting it to "
314 " 'Manual' startup type in the Windows Service management console, or by runing "
315 "'sc config VBoxSDS start=demand' on the command line."));
316 }
317 else if (vrc == VERR_NOT_FOUND)
318 return setError(hrcCaller,
319 tr("The VBoxSDS windows service was not found.\n"
320 "Reinstall VirtualBox to fix it. Alternatively you can try start VirtualBox as Administrator, this "
321 "should automatically reinstall the service, or you can run "
322 "'VBoxSDS.exe --regservice' command from an elevated Administrator command line."));
323 else
324 LogRelFunc(("VirtualBoxClient::i_getServiceAccount failed: %Rrc\n", vrc));
325# endif
326
327 /*
328 * First step is to try get an IUnknown interface of the VirtualBox object.
329 *
330 * This will succeed even when oleaut32.msm (see @bugref{8016}, @ticketref{12087})
331 * is accidentally installed and messes up COM. It may also succeed when the COM
332 * registration is partially broken (though that's unlikely to happen these days).
333 */
334 IUnknown *pUnknown = NULL;
335 hrc = CoCreateInstance(CLSID_VirtualBox, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void **)&pUnknown);
336 if (FAILED(hrc))
337 {
338 if (hrc == hrcCaller)
339 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox: %Rhrc"), hrcCaller);
340 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox: %Rhrc & %Rhrc"), hrcCaller, hrc);
341 }
342
343 /*
344 * Try query the IVirtualBox interface (should fail), if it succeed we return
345 * straight away so we have more columns to spend on long messages below.
346 */
347 IVirtualBox *pVirtualBox;
348 hrc = pUnknown->QueryInterface(IID_IVirtualBox, (void **)&pVirtualBox);
349 if (SUCCEEDED(hrc))
350 {
351 pVirtualBox->Release();
352 pUnknown->Release();
353 return setError(hrcCaller,
354 tr("Failed to instantiate CLSID_VirtualBox the first time, but worked when checking out why ... weird"));
355 }
356
357 /*
358 * Check for oleaut32.msm traces in the registry.
359 */
360 HKEY hKey;
361 LSTATUS lrc = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"CLSID\\{00020420-0000-0000-C000-000000000046}\\InprocServer32",
362 0 /*fFlags*/, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | STANDARD_RIGHTS_READ, &hKey);
363 if (lrc == ERROR_SUCCESS)
364 {
365 wchar_t wszBuf[8192];
366 DWORD cbBuf = sizeof(wszBuf) - sizeof(wchar_t);
367 DWORD dwType = 0;
368 lrc = RegQueryValueExW(hKey, L"InprocServer32", NULL /*pvReserved*/, &dwType, (BYTE *)&wszBuf[0], &cbBuf);
369 if (lrc == ERROR_SUCCESS)
370 {
371 wszBuf[cbBuf / sizeof(wchar_t)] = '\0';
372 bool fSetError = false;
373
374 /*
375 * Try decode the string and improve the message.
376 */
377 typedef UINT (WINAPI *PFNMSIDECOMPOSEDESCRIPTORW)(PCWSTR pwszDescriptor,
378 LPWSTR pwszProductCode /*[40]*/,
379 LPWSTR pwszFeatureId /*[40]*/,
380 LPWSTR pwszComponentCode /*[40]*/,
381 DWORD *poffArguments);
382 PFNMSIDECOMPOSEDESCRIPTORW pfnMsiDecomposeDescriptorW;
383 pfnMsiDecomposeDescriptorW = (PFNMSIDECOMPOSEDESCRIPTORW)RTLdrGetSystemSymbol("msi.dll", "MsiDecomposeDescriptorW");
384 if ( pfnMsiDecomposeDescriptorW
385 && ( dwType == REG_SZ
386 || dwType == REG_MULTI_SZ))
387 {
388 wchar_t wszProductCode[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
389 wchar_t wszFeatureId[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
390 wchar_t wszComponentCode[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
391 DWORD offArguments = ~(DWORD)0;
392 UINT uRc = pfnMsiDecomposeDescriptorW(wszBuf, wszProductCode, wszFeatureId, wszComponentCode, &offArguments);
393 if (uRc == 0)
394 {
395 /*
396 * Can we resolve the product code into a name?
397 */
398 typedef UINT (WINAPI *PFNMSIOPENPRODUCTW)(PCWSTR, MSIHANDLE *);
399 PFNMSIOPENPRODUCTW pfnMsiOpenProductW;
400 pfnMsiOpenProductW = (PFNMSIOPENPRODUCTW)RTLdrGetSystemSymbol("msi.dll", "MsiOpenProductW");
401
402 typedef UINT (WINAPI *PFNMSICLOSEHANDLE)(MSIHANDLE);
403 PFNMSICLOSEHANDLE pfnMsiCloseHandle;
404 pfnMsiCloseHandle = (PFNMSICLOSEHANDLE)RTLdrGetSystemSymbol("msi.dll", "MsiCloseHandle");
405
406 typedef UINT (WINAPI *PFNGETPRODUCTPROPERTYW)(MSIHANDLE, PCWSTR, PWSTR, PDWORD);
407 PFNGETPRODUCTPROPERTYW pfnMsiGetProductPropertyW;
408 pfnMsiGetProductPropertyW = (PFNGETPRODUCTPROPERTYW)RTLdrGetSystemSymbol("msi.dll", "MsiGetProductPropertyW");
409 if ( pfnMsiGetProductPropertyW
410 && pfnMsiCloseHandle
411 && pfnMsiOpenProductW)
412 {
413 MSIHANDLE hMsi = 0;
414 uRc = pfnMsiOpenProductW(wszProductCode, &hMsi);
415 if (uRc == 0)
416 {
417 static wchar_t const * const s_apwszProps[] =
418 {
419 INSTALLPROPERTY_INSTALLEDPRODUCTNAME,
420 INSTALLPROPERTY_PRODUCTNAME,
421 INSTALLPROPERTY_PACKAGENAME,
422 };
423
424 wchar_t wszProductName[1024];
425 DWORD cwcProductName;
426 unsigned i = 0;
427 do
428 {
429 cwcProductName = RT_ELEMENTS(wszProductName) - 1;
430 uRc = pfnMsiGetProductPropertyW(hMsi, s_apwszProps[i], wszProductName, &cwcProductName);
431 }
432 while ( ++i < RT_ELEMENTS(s_apwszProps)
433 && ( uRc != 0
434 || cwcProductName < 2
435 || cwcProductName >= RT_ELEMENTS(wszProductName)) );
436 uRc = pfnMsiCloseHandle(hMsi);
437 if (uRc == 0 && cwcProductName >= 2)
438 {
439 wszProductName[RT_MIN(cwcProductName, RT_ELEMENTS(wszProductName) - 1)] = '\0';
440 setError(hrcCaller,
441 tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
442 "PSDispatch looks broken by the '%ls' (%ls) program, suspecting that it features the broken oleaut32.msm module as component %ls.\n"
443 "\n"
444 "We suggest you try uninstall '%ls'.\n"
445 "\n"
446 "See also https://support.microsoft.com/en-us/kb/316911 "),
447 wszProductName, wszProductCode, wszComponentCode, wszProductName);
448 fSetError = true;
449 }
450 }
451 }
452
453 /* MSI uses COM and may mess up our stuff. So, we wait with the fallback till afterwards in this case. */
454 if (!fSetError)
455 {
456 setError(hrcCaller,
457 tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, CLSID_VirtualBox w/ IUnknown works.\n"
458 "PSDispatch looks broken by installer %ls featuring the broken oleaut32.msm module as component %ls.\n"
459 "\n"
460 "See also https://support.microsoft.com/en-us/kb/316911 "),
461 wszProductCode, wszComponentCode);
462 fSetError = true;
463 }
464 }
465 }
466 if (!fSetError)
467 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, CLSID_VirtualBox w/ IUnknown works.\n"
468 "PSDispatch looks broken by some installer featuring the broken oleaut32.msm module as a component.\n"
469 "\n"
470 "See also https://support.microsoft.com/en-us/kb/316911 "));
471 }
472 else if (lrc == ERROR_FILE_NOT_FOUND)
473 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
474 "PSDispatch looks fine. Weird"));
475 else
476 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
477 "Checking out PSDispatch registration ended with error: %u (%#x)"), lrc, lrc);
478 RegCloseKey(hKey);
479 }
480
481 pUnknown->Release();
482 return hrcCaller;
483}
484
485# ifdef VBOX_WITH_SDS
486/**
487 * Gets the service account name and start type for the given service.
488 *
489 * @returns IPRT status code (for some reason).
490 * @param pwszServiceName The name of the service.
491 * @param pwszAccountName Where to return the account name.
492 * @param cwcAccountName The length of the account name buffer (in WCHARs).
493 * @param puStartType Where to return the start type.
494 */
495int VirtualBoxClient::i_getServiceAccountAndStartType(const wchar_t *pwszServiceName,
496 wchar_t *pwszAccountName, size_t cwcAccountName, uint32_t *puStartType)
497{
498 AssertPtr(pwszServiceName);
499 AssertPtr(pwszAccountName);
500 Assert(cwcAccountName);
501 *pwszAccountName = '\0';
502 *puStartType = SERVICE_DEMAND_START;
503
504 int vrc;
505
506 // Get a handle to the SCM database.
507 SC_HANDLE hSCManager = OpenSCManagerW(NULL /*pwszMachineName*/, NULL /*pwszDatabaseName*/, SC_MANAGER_CONNECT);
508 if (hSCManager != NULL)
509 {
510 SC_HANDLE hService = OpenServiceW(hSCManager, pwszServiceName, SERVICE_QUERY_CONFIG);
511 if (hService != NULL)
512 {
513 DWORD cbNeeded = sizeof(QUERY_SERVICE_CONFIGW) + _1K;
514 if (!QueryServiceConfigW(hService, NULL, 0, &cbNeeded))
515 {
516 Assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
517 LPQUERY_SERVICE_CONFIGW pSc = (LPQUERY_SERVICE_CONFIGW)RTMemTmpAllocZ(cbNeeded + _1K);
518 if (pSc)
519 {
520 DWORD cbNeeded2 = 0;
521 if (QueryServiceConfigW(hService, pSc, cbNeeded + _1K, &cbNeeded2))
522 {
523 *puStartType = pSc->dwStartType;
524 vrc = RTUtf16Copy(pwszAccountName, cwcAccountName, pSc->lpServiceStartName);
525 if (RT_FAILURE(vrc))
526 LogRel(("Error: SDS service name is too long (%Rrc): %ls\n", vrc, pSc->lpServiceStartName));
527 }
528 else
529 {
530 int dwError = GetLastError();
531 vrc = RTErrConvertFromWin32(dwError);
532 LogRel(("Error: Failed querying '%ls' service config: %Rwc (%u) -> %Rrc; cbNeeded=%d cbNeeded2=%d\n",
533 pwszServiceName, dwError, dwError, vrc, cbNeeded, cbNeeded2));
534 }
535 RTMemTmpFree(pSc);
536 }
537 else
538 {
539 LogRel(("Error: Failed allocating %#x bytes of memory for service config!\n", cbNeeded + _1K));
540 vrc = VERR_NO_TMP_MEMORY;
541 }
542 }
543 else
544 {
545 AssertLogRelMsgFailed(("Error: QueryServiceConfigW returns success with zero buffer!\n"));
546 vrc = VERR_IPE_UNEXPECTED_STATUS;
547 }
548 CloseServiceHandle(hService);
549 }
550 else
551 {
552 int dwError = GetLastError();
553 vrc = RTErrConvertFromWin32(dwError);
554 LogRel(("Error: Could not open service '%ls': %Rwc (%u) -> %Rrc\n", pwszServiceName, dwError, dwError, vrc));
555 }
556 CloseServiceHandle(hSCManager);
557 }
558 else
559 {
560 int dwError = GetLastError();
561 vrc = RTErrConvertFromWin32(dwError);
562 LogRel(("Error: Could not open SCM: %Rwc (%u) -> %Rrc\n", dwError, dwError, vrc));
563 }
564 return vrc;
565}
566# endif /* VBOX_WITH_SDS */
567
568#endif /* RT_OS_WINDOWS */
569
570/**
571 * Uninitializes the instance and sets the ready flag to FALSE.
572 * Called either from FinalRelease() or by the parent when it gets destroyed.
573 */
574void VirtualBoxClient::uninit()
575{
576 LogFlowThisFunc(("\n"));
577
578 /* Enclose the state transition Ready->InUninit->NotReady */
579 AutoUninitSpan autoUninitSpan(this);
580 if (autoUninitSpan.uninitDone())
581 {
582 LogFlowThisFunc(("already done\n"));
583 return;
584 }
585
586#ifdef VBOX_WITH_MAIN_NLS
587 i_unregisterEventListener();
588#endif
589
590 if (mData.m_ThreadWatcher != NIL_RTTHREAD)
591 {
592 /* Signal the event semaphore and wait for the thread to terminate.
593 * if it hangs for some reason exit anyway, this can cause a crash
594 * though as the object will no longer be available. */
595 RTSemEventSignal(mData.m_SemEvWatcher);
596 RTThreadWait(mData.m_ThreadWatcher, 30000, NULL);
597 mData.m_ThreadWatcher = NIL_RTTHREAD;
598 RTSemEventDestroy(mData.m_SemEvWatcher);
599 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
600 }
601#ifdef VBOX_WITH_MAIN_NLS
602 if (mData.m_pVBoxTranslator != NULL)
603 {
604 mData.m_pVBoxTranslator->release();
605 mData.m_pVBoxTranslator = NULL;
606 mData.m_pTrComponent = NULL;
607 }
608#endif
609 mData.m_pToken.setNull();
610 mData.m_pVirtualBox.setNull();
611
612 ASMAtomicDecU32(&g_cInstances);
613
614 LogFlowThisFunc(("returns\n"));
615}
616
617// IVirtualBoxClient properties
618/////////////////////////////////////////////////////////////////////////////
619
620/**
621 * Returns a reference to the VirtualBox object.
622 *
623 * @returns COM status code
624 * @param aVirtualBox Address of result variable.
625 */
626HRESULT VirtualBoxClient::getVirtualBox(ComPtr<IVirtualBox> &aVirtualBox)
627{
628 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
629 aVirtualBox = mData.m_pVirtualBox;
630 return S_OK;
631}
632
633/**
634 * Create a new Session object and return a reference to it.
635 *
636 * @returns COM status code
637 * @param aSession Address of result variable.
638 */
639HRESULT VirtualBoxClient::getSession(ComPtr<ISession> &aSession)
640{
641 /* this is not stored in this object, no need to lock */
642 ComPtr<ISession> pSession;
643 HRESULT rc = pSession.createInprocObject(CLSID_Session);
644 if (SUCCEEDED(rc))
645 aSession = pSession;
646 return rc;
647}
648
649/**
650 * Return reference to the EventSource associated with this object.
651 *
652 * @returns COM status code
653 * @param aEventSource Address of result variable.
654 */
655HRESULT VirtualBoxClient::getEventSource(ComPtr<IEventSource> &aEventSource)
656{
657 /* this is const, no need to lock */
658 aEventSource = mData.m_pEventSource;
659 return aEventSource.isNull() ? E_FAIL : S_OK;
660}
661
662// IVirtualBoxClient methods
663/////////////////////////////////////////////////////////////////////////////
664
665/**
666 * Checks a Machine object for any pending errors.
667 *
668 * @returns COM status code
669 * @param aMachine Machine object to check.
670 */
671HRESULT VirtualBoxClient::checkMachineError(const ComPtr<IMachine> &aMachine)
672{
673 BOOL fAccessible = FALSE;
674 HRESULT rc = aMachine->COMGETTER(Accessible)(&fAccessible);
675 if (FAILED(rc))
676 return setError(rc, tr("Could not check the accessibility status of the VM"));
677 else if (!fAccessible)
678 {
679 ComPtr<IVirtualBoxErrorInfo> pAccessError;
680 rc = aMachine->COMGETTER(AccessError)(pAccessError.asOutParam());
681 if (FAILED(rc))
682 return setError(rc, tr("Could not get the access error message of the VM"));
683 else
684 {
685 ErrorInfo info(pAccessError);
686 ErrorInfoKeeper eik(info);
687 return info.getResultCode();
688 }
689 }
690 return S_OK;
691}
692
693// private methods
694/////////////////////////////////////////////////////////////////////////////
695
696
697/// @todo AM Add pinging of VBoxSDS
698/*static*/
699DECLCALLBACK(int) VirtualBoxClient::SVCWatcherThread(RTTHREAD ThreadSelf,
700 void *pvUser)
701{
702 NOREF(ThreadSelf);
703 Assert(pvUser);
704 VirtualBoxClient *pThis = (VirtualBoxClient *)pvUser;
705 RTSEMEVENT sem = pThis->mData.m_SemEvWatcher;
706 RTMSINTERVAL cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
707 int vrc;
708
709 /* The likelihood of early crashes are high, so start with a short wait. */
710 vrc = RTSemEventWait(sem, cMillies / 2);
711
712 /* As long as the waiting times out keep retrying the wait. */
713 while (RT_FAILURE(vrc))
714 {
715 {
716 HRESULT rc = S_OK;
717 ComPtr<IVirtualBox> pV;
718 {
719 AutoReadLock alock(pThis COMMA_LOCKVAL_SRC_POS);
720 pV = pThis->mData.m_pVirtualBox;
721 }
722 if (!pV.isNull())
723 {
724 ULONG rev;
725 rc = pV->COMGETTER(Revision)(&rev);
726 if (FAILED_DEAD_INTERFACE(rc))
727 {
728 LogRel(("VirtualBoxClient: detected unresponsive VBoxSVC (rc=%Rhrc)\n", rc));
729 {
730 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
731 /* Throw away the VirtualBox reference, it's no longer
732 * usable as VBoxSVC terminated in the mean time. */
733 pThis->mData.m_pVirtualBox.setNull();
734 }
735 ::FireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, FALSE);
736 }
737 }
738 else
739 {
740 /* Try to get a new VirtualBox reference straight away, and if
741 * this fails use an increased waiting time as very frequent
742 * restart attempts in some wedged config can cause high CPU
743 * and disk load. */
744 ComPtr<IVirtualBox> pVirtualBox;
745 ComPtr<IToken> pToken;
746 rc = pVirtualBox.createLocalObject(CLSID_VirtualBox);
747 if (FAILED(rc))
748 cMillies = 3 * VBOXCLIENT_DEFAULT_INTERVAL;
749 else
750 {
751 LogRel(("VirtualBoxClient: detected working VBoxSVC (rc=%Rhrc)\n", rc));
752 {
753 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
754 /* Update the VirtualBox reference, there's a working
755 * VBoxSVC again from now on. */
756 pThis->mData.m_pVirtualBox = pVirtualBox;
757 pThis->mData.m_pToken = pToken;
758#ifdef VBOX_WITH_MAIN_NLS
759 /* update language using new instance of IVirtualBox in case the language settings was changed */
760 pThis->i_reloadApiLanguage();
761 pThis->i_registerEventListener();
762#endif
763 }
764 ::FireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, TRUE);
765 cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
766 }
767 }
768 }
769 vrc = RTSemEventWait(sem, cMillies);
770 }
771 return 0;
772}
773
774#ifdef VBOX_WITH_MAIN_NLS
775
776HRESULT VirtualBoxClient::i_reloadApiLanguage()
777{
778 if (mData.m_pVBoxTranslator == NULL)
779 return S_OK;
780
781 HRESULT rc = mData.m_pVBoxTranslator->loadLanguage(mData.m_pVirtualBox);
782 if (FAILED(rc))
783 setError(rc, tr("Failed to load user language instance"));
784 return rc;
785}
786
787HRESULT VirtualBoxClient::i_registerEventListener()
788{
789 HRESULT rc = mData.m_pVirtualBox->COMGETTER(EventSource)(mData.m_pVBoxEventSource.asOutParam());
790 if (SUCCEEDED(rc))
791 {
792 ComObjPtr<VBoxEventListenerImpl> pVBoxListener;
793 pVBoxListener.createObject();
794 pVBoxListener->init(new VBoxEventListener());
795 mData.m_pVBoxEventListener = pVBoxListener;
796 com::SafeArray<VBoxEventType_T> eventTypes;
797 eventTypes.push_back(VBoxEventType_OnLanguageChanged);
798 rc = mData.m_pVBoxEventSource->RegisterListener(pVBoxListener, ComSafeArrayAsInParam(eventTypes), true);
799 if (FAILED(rc))
800 {
801 rc = setError(rc, tr("Failed to register listener"));
802 mData.m_pVBoxEventListener.setNull();
803 mData.m_pVBoxEventSource.setNull();
804 }
805 }
806 else
807 rc = setError(rc, tr("Failed to get event source from VirtualBox"));
808 return rc;
809}
810
811void VirtualBoxClient::i_unregisterEventListener()
812{
813 if (mData.m_pVBoxEventListener.isNotNull())
814 {
815 if (mData.m_pVBoxEventSource.isNotNull())
816 mData.m_pVBoxEventSource->UnregisterListener(mData.m_pVBoxEventListener);
817 mData.m_pVBoxEventListener.setNull();
818 }
819 mData.m_pVBoxEventSource.setNull();
820}
821
822#endif /* VBOX_WITH_MAIN_NLS */
823
824/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use