VirtualBox

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

Last change on this file since 98123 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

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