VirtualBox

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

最後變更 在這個檔案從108379是 107588,由 vboxsync 提交於 3 月 前

Main,Puel: Made the object tracker code a compile time option (VBOX_WITH_MAIN_OBJECT_TRACKER) and disabled it since it causes VBoxSVC to crash during uninit. It is also badly in need of a review + style-cleanup (did some). Making it optional eliminates the need for Puel to include the object tracker code which it won't need (neither does VBoxC/Client.dll). bugref:10806

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

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