VirtualBox

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

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

VBox/Main: ​​​bugref:3300: VBoxSVC from terminal server session is not 'visible' - fix to make WMI validation of Disabled Windows service to be optional. switched VBOX_WITH_SDS =1 temporary agian

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.8 KB
Line 
1/* $Id: VirtualBoxClientImpl.cpp 66563 2017-04-13 16:08:23Z 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#if defined(RT_OS_WINDOWS) && defined(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#if defined(RT_OS_WINDOWS) && defined(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 NOREF(hrGUICoInitializeSecurity);
302 Assert(SUCCEEDED(hrGUICoInitializeSecurity) || hrGUICoInitializeSecurity == RPC_E_TOO_LATE);
303#endif
304
305 LogFlowThisFuncEnter();
306
307 /* Enclose the state transition NotReady->InInit->Ready */
308 AutoInitSpan autoInitSpan(this);
309 AssertReturn(autoInitSpan.isOk(), E_FAIL);
310
311 /* Important: DO NOT USE any kind of "early return" (except the single
312 * one above, checking the init span success) in this method. It is vital
313 * for correct error handling that it has only one point of return, which
314 * does all the magic on COM to signal object creation success and
315 * reporting the error later for every API method. COM translates any
316 * unsuccessful object creation to REGDB_E_CLASSNOTREG errors or similar
317 * unhelpful ones which cause us a lot of grief with troubleshooting. */
318
319 HRESULT rc = S_OK;
320 try
321 {
322 if (ASMAtomicIncU32(&g_cInstances) != 1)
323 AssertFailedStmt(throw setError(E_FAIL,
324 tr("Attempted to create more than one VirtualBoxClient instance")));
325
326 mData.m_ThreadWatcher = NIL_RTTHREAD;
327 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
328
329#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_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 LogRelFunc(("Warning: Failed to get information about VBoxSDS using WMI:: %Rhrc & %Rhrc"), hrcCaller, hrc));
443 bIsVBoxSDSDisabled = false;
444 //return setError(hrcCaller, tr("Failed to get information about VBoxSDS using WMI:: %Rhrc & %Rhrc"), hrcCaller, hrc);
445 }
446 if (bIsVBoxSDSDisabled)
447 {
448 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox using VBoxSDS: "
449 "VBoxSDS windows service disabled.\n"
450 "Enable VBoxSDS Windows Service using Windows Service Management Console.\n %Rhrc"), hrcCaller);
451 }
452
453 // Check the VBoxSDS windows service is enabled
454 ComPtr<IVirtualBox> aVirtualBox;
455 hrc = CreateVirtualBoxThroughSDS(aVirtualBox);
456 if (FAILED(hrc))
457 {
458 if (hrc == hrcCaller)
459 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox using VBoxSDS: %Rhrc"), hrcCaller);
460 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox using VBoxSDS: %Rhrc & %Rhrc"), hrcCaller, hrc);
461 }
462
463 hrc = aVirtualBox.queryInterfaceTo<IUnknown>(&pUnknown);
464 if (FAILED(hrc))
465 {
466 if (hrc == hrcCaller)
467 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox using VBoxSDS: %Rhrc"), hrcCaller);
468 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox using VBoxSDS: %Rhrc & %Rhrc"), hrcCaller, hrc);
469 }
470#else
471 HRESULT hrc = CoCreateInstance(CLSID_VirtualBox, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void **)&pUnknown);
472 if (FAILED(hrc))
473 {
474 if (hrc == hrcCaller)
475 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox: %Rhrc"), hrcCaller);
476 return setError(hrcCaller, tr("Completely failed to instantiate CLSID_VirtualBox: %Rhrc & %Rhrc"), hrcCaller, hrc);
477 }
478#endif
479
480 /*
481 * Try query the IVirtualBox interface (should fail), if it succeed we return
482 * straight away so we have more columns to spend on long messages below.
483 */
484 IVirtualBox *pVirtualBox;
485 hrc = pUnknown->QueryInterface(IID_IVirtualBox, (void **)&pVirtualBox);
486 if (SUCCEEDED(hrc))
487 {
488 pVirtualBox->Release();
489 pUnknown->Release();
490 return setError(hrcCaller,
491 tr("Failed to instantiate CLSID_VirtualBox the first time, but worked when checking out why ... weird"));
492 }
493
494 /*
495 * Check for oleaut32.msm traces in the registry.
496 */
497 HKEY hKey;
498 LSTATUS lrc = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"CLSID\\{00020420-0000-0000-C000-000000000046}\\InprocServer32",
499 0 /*fFlags*/, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | STANDARD_RIGHTS_READ, &hKey);
500 if (lrc == ERROR_SUCCESS)
501 {
502 wchar_t wszBuf[8192];
503 DWORD cbBuf = sizeof(wszBuf) - sizeof(wchar_t);
504 DWORD dwType = 0;
505 lrc = RegQueryValueExW(hKey, L"InprocServer32", NULL /*pvReserved*/, &dwType, (BYTE *)&wszBuf[0], &cbBuf);
506 if (lrc == ERROR_SUCCESS)
507 {
508 wszBuf[cbBuf / sizeof(wchar_t)] = '\0';
509 bool fSetError = false;
510
511 /*
512 * Try decode the string and improve the message.
513 */
514 typedef UINT (WINAPI *PFNMSIDECOMPOSEDESCRIPTORW)(PCWSTR pwszDescriptor,
515 LPWSTR pwszProductCode /*[40]*/,
516 LPWSTR pwszFeatureId /*[40]*/,
517 LPWSTR pwszComponentCode /*[40]*/,
518 DWORD *poffArguments);
519 PFNMSIDECOMPOSEDESCRIPTORW pfnMsiDecomposeDescriptorW;
520 pfnMsiDecomposeDescriptorW = (PFNMSIDECOMPOSEDESCRIPTORW)RTLdrGetSystemSymbol("msi.dll", "MsiDecomposeDescriptorW");
521 if ( pfnMsiDecomposeDescriptorW
522 && ( dwType == REG_SZ
523 || dwType == REG_MULTI_SZ))
524 {
525 wchar_t wszProductCode[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
526 wchar_t wszFeatureId[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
527 wchar_t wszComponentCode[RTUUID_STR_LENGTH + 2 + 16] = { 0 };
528 DWORD offArguments = ~(DWORD)0;
529 UINT uRc = pfnMsiDecomposeDescriptorW(wszBuf, wszProductCode, wszFeatureId, wszComponentCode, &offArguments);
530 if (uRc == 0)
531 {
532 /*
533 * Can we resolve the product code into a name?
534 */
535 typedef UINT (WINAPI *PFNMSIOPENPRODUCTW)(PCWSTR, MSIHANDLE *);
536 PFNMSIOPENPRODUCTW pfnMsiOpenProductW;
537 pfnMsiOpenProductW = (PFNMSIOPENPRODUCTW)RTLdrGetSystemSymbol("msi.dll", "MsiOpenProductW");
538
539 typedef UINT (WINAPI *PFNMSICLOSEHANDLE)(MSIHANDLE);
540 PFNMSICLOSEHANDLE pfnMsiCloseHandle;
541 pfnMsiCloseHandle = (PFNMSICLOSEHANDLE)RTLdrGetSystemSymbol("msi.dll", "MsiCloseHandle");
542
543 typedef UINT (WINAPI *PFNGETPRODUCTPROPERTYW)(MSIHANDLE, PCWSTR, PWSTR, PDWORD);
544 PFNGETPRODUCTPROPERTYW pfnMsiGetProductPropertyW;
545 pfnMsiGetProductPropertyW = (PFNGETPRODUCTPROPERTYW)RTLdrGetSystemSymbol("msi.dll", "MsiGetProductPropertyW");
546 if ( pfnMsiGetProductPropertyW
547 && pfnMsiCloseHandle
548 && pfnMsiOpenProductW)
549 {
550 MSIHANDLE hMsi = 0;
551 uRc = pfnMsiOpenProductW(wszProductCode, &hMsi);
552 if (uRc == 0)
553 {
554 static wchar_t const * const s_apwszProps[] =
555 {
556 INSTALLPROPERTY_INSTALLEDPRODUCTNAME,
557 INSTALLPROPERTY_PRODUCTNAME,
558 INSTALLPROPERTY_PACKAGENAME,
559 };
560
561 wchar_t wszProductName[1024];
562 DWORD cwcProductName;
563 unsigned i = 0;
564 do
565 {
566 cwcProductName = RT_ELEMENTS(wszProductName) - 1;
567 uRc = pfnMsiGetProductPropertyW(hMsi, s_apwszProps[i], wszProductName, &cwcProductName);
568 }
569 while ( ++i < RT_ELEMENTS(s_apwszProps)
570 && ( uRc != 0
571 || cwcProductName < 2
572 || cwcProductName >= RT_ELEMENTS(wszProductName)) );
573 uRc = pfnMsiCloseHandle(hMsi);
574 if (uRc == 0 && cwcProductName >= 2)
575 {
576 wszProductName[RT_MIN(cwcProductName, RT_ELEMENTS(wszProductName) - 1)] = '\0';
577 setError(hrcCaller,
578 tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
579 "PSDispatch looks broken by the '%ls' (%ls) program, suspecting that it features the broken oleaut32.msm module as component %ls.\n"
580 "\n"
581 "We suggest you try uninstall '%ls'.\n"
582 "\n"
583 "See also https://support.microsoft.com/en-us/kb/316911 "),
584 wszProductName, wszProductCode, wszComponentCode, wszProductName);
585 fSetError = true;
586 }
587 }
588 }
589
590 /* MSI uses COM and may mess up our stuff. So, we wait with the fallback till afterwards in this case. */
591 if (!fSetError)
592 {
593 setError(hrcCaller,
594 tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, CLSID_VirtualBox w/ IUnknown works.\n"
595 "PSDispatch looks broken by installer %ls featuring the broken oleaut32.msm module as component %ls.\n"
596 "\n"
597 "See also https://support.microsoft.com/en-us/kb/316911 "),
598 wszProductCode, wszComponentCode);
599 fSetError = true;
600 }
601 }
602 }
603 if (!fSetError)
604 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, CLSID_VirtualBox w/ IUnknown works.\n"
605 "PSDispatch looks broken by some installer featuring the broken oleaut32.msm module as a component.\n"
606 "\n"
607 "See also https://support.microsoft.com/en-us/kb/316911 "));
608 }
609 else if (lrc == ERROR_FILE_NOT_FOUND)
610 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
611 "PSDispatch looks fine. Weird"));
612 else
613 setError(hrcCaller, tr("Failed to instantiate CLSID_VirtualBox w/ IVirtualBox, but CLSID_VirtualBox w/ IUnknown works.\n"
614 "Checking out PSDispatch registration ended with error: %u (%#x)"), lrc, lrc);
615 RegCloseKey(hKey);
616 }
617
618 pUnknown->Release();
619 return hrcCaller;
620}
621#endif /* RT_OS_WINDOWS */
622
623/**
624 * Uninitializes the instance and sets the ready flag to FALSE.
625 * Called either from FinalRelease() or by the parent when it gets destroyed.
626 */
627void VirtualBoxClient::uninit()
628{
629 LogFlowThisFunc(("\n"));
630
631#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_SDS)
632 ReleaseVirtualBoxThroughSDS();
633#endif
634
635 /* Enclose the state transition Ready->InUninit->NotReady */
636 AutoUninitSpan autoUninitSpan(this);
637 if (autoUninitSpan.uninitDone())
638 return;
639
640 if (mData.m_ThreadWatcher != NIL_RTTHREAD)
641 {
642 /* Signal the event semaphore and wait for the thread to terminate.
643 * if it hangs for some reason exit anyway, this can cause a crash
644 * though as the object will no longer be available. */
645 RTSemEventSignal(mData.m_SemEvWatcher);
646 RTThreadWait(mData.m_ThreadWatcher, 30000, NULL);
647 mData.m_ThreadWatcher = NIL_RTTHREAD;
648 RTSemEventDestroy(mData.m_SemEvWatcher);
649 mData.m_SemEvWatcher = NIL_RTSEMEVENT;
650 }
651
652 mData.m_pVirtualBox.setNull();
653
654 ASMAtomicDecU32(&g_cInstances);
655}
656
657// IVirtualBoxClient properties
658/////////////////////////////////////////////////////////////////////////////
659
660/**
661 * Returns a reference to the VirtualBox object.
662 *
663 * @returns COM status code
664 * @param aVirtualBox Address of result variable.
665 */
666HRESULT VirtualBoxClient::getVirtualBox(ComPtr<IVirtualBox> &aVirtualBox)
667{
668 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
669 aVirtualBox = mData.m_pVirtualBox;
670 return S_OK;
671}
672
673/**
674 * Create a new Session object and return a reference to it.
675 *
676 * @returns COM status code
677 * @param aSession Address of result variable.
678 */
679HRESULT VirtualBoxClient::getSession(ComPtr<ISession> &aSession)
680{
681 /* this is not stored in this object, no need to lock */
682 ComPtr<ISession> pSession;
683 HRESULT rc = pSession.createInprocObject(CLSID_Session);
684 if (SUCCEEDED(rc))
685 aSession = pSession;
686 return rc;
687}
688
689/**
690 * Return reference to the EventSource associated with this object.
691 *
692 * @returns COM status code
693 * @param aEventSource Address of result variable.
694 */
695HRESULT VirtualBoxClient::getEventSource(ComPtr<IEventSource> &aEventSource)
696{
697 /* this is const, no need to lock */
698 aEventSource = mData.m_pEventSource;
699 return aEventSource.isNull() ? E_FAIL : S_OK;
700}
701
702// IVirtualBoxClient methods
703/////////////////////////////////////////////////////////////////////////////
704
705/**
706 * Checks a Machine object for any pending errors.
707 *
708 * @returns COM status code
709 * @param aMachine Machine object to check.
710 */
711HRESULT VirtualBoxClient::checkMachineError(const ComPtr<IMachine> &aMachine)
712{
713 BOOL fAccessible = FALSE;
714 HRESULT rc = aMachine->COMGETTER(Accessible)(&fAccessible);
715 if (FAILED(rc))
716 return setError(rc, tr("Could not check the accessibility status of the VM"));
717 else if (!fAccessible)
718 {
719 ComPtr<IVirtualBoxErrorInfo> pAccessError;
720 rc = aMachine->COMGETTER(AccessError)(pAccessError.asOutParam());
721 if (FAILED(rc))
722 return setError(rc, tr("Could not get the access error message of the VM"));
723 else
724 {
725 ErrorInfo info(pAccessError);
726 ErrorInfoKeeper eik(info);
727 return info.getResultCode();
728 }
729 }
730 return S_OK;
731}
732
733// private methods
734/////////////////////////////////////////////////////////////////////////////
735
736
737// TODO: AM Add pinging of VBoxSDS
738/*static*/
739DECLCALLBACK(int) VirtualBoxClient::SVCWatcherThread(RTTHREAD ThreadSelf,
740 void *pvUser)
741{
742 NOREF(ThreadSelf);
743 Assert(pvUser);
744 VirtualBoxClient *pThis = (VirtualBoxClient *)pvUser;
745 RTSEMEVENT sem = pThis->mData.m_SemEvWatcher;
746 RTMSINTERVAL cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
747 int vrc;
748
749 /* The likelihood of early crashes are high, so start with a short wait. */
750 vrc = RTSemEventWait(sem, cMillies / 2);
751
752 /* As long as the waiting times out keep retrying the wait. */
753 while (RT_FAILURE(vrc))
754 {
755 {
756 HRESULT rc = S_OK;
757 ComPtr<IVirtualBox> pV;
758 {
759 AutoReadLock alock(pThis COMMA_LOCKVAL_SRC_POS);
760 pV = pThis->mData.m_pVirtualBox;
761 }
762 if (!pV.isNull())
763 {
764 ULONG rev;
765 rc = pV->COMGETTER(Revision)(&rev);
766 if (FAILED_DEAD_INTERFACE(rc))
767 {
768 LogRel(("VirtualBoxClient: detected unresponsive VBoxSVC (rc=%Rhrc)\n", rc));
769 {
770 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
771 /* Throw away the VirtualBox reference, it's no longer
772 * usable as VBoxSVC terminated in the mean time. */
773 pThis->mData.m_pVirtualBox.setNull();
774 }
775 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, FALSE);
776 }
777 }
778 else
779 {
780 /* Try to get a new VirtualBox reference straight away, and if
781 * this fails use an increased waiting time as very frequent
782 * restart attempts in some wedged config can cause high CPU
783 * and disk load. */
784 ComPtr<IVirtualBox> pVirtualBox;
785 rc = pVirtualBox.createLocalObject(CLSID_VirtualBox);
786 if (FAILED(rc))
787 cMillies = 3 * VBOXCLIENT_DEFAULT_INTERVAL;
788 else
789 {
790 LogRel(("VirtualBoxClient: detected working VBoxSVC (rc=%Rhrc)\n", rc));
791 {
792 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
793 /* Update the VirtualBox reference, there's a working
794 * VBoxSVC again from now on. */
795 pThis->mData.m_pVirtualBox = pVirtualBox;
796 }
797 fireVBoxSVCAvailabilityChangedEvent(pThis->mData.m_pEventSource, TRUE);
798 cMillies = VBOXCLIENT_DEFAULT_INTERVAL;
799 }
800 }
801 }
802 vrc = RTSemEventWait(sem, cMillies);
803 }
804 return 0;
805}
806
807/* 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