VirtualBox

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

Last change on this file since 91503 was 91503, checked in by vboxsync, 3 years ago

Main: bugref:1909: Added missed translation marks, removed redundant ones. Expanded one macro to make the lupdate get string correctly. Removed GuestBase::setErrorExternal and changed calls from it to setErrorBoth to handle translation correctly.

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