VirtualBox

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

Last change on this file since 66411 was 66411, checked in by vboxsync, 8 years ago

VBox/Main: ​​​bugref:3300: VBoxSVC from terminal server session is not 'visible' - extended validation for VBoxSDS issues

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette