VirtualBox

source: vbox/trunk/src/VBox/Main/GuestImpl.cpp@ 28258

Last change on this file since 28258 was 28243, checked in by vboxsync, 15 years ago

Guest Control: Update (callback + error handling, --verbose for VBoxManage).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.9 KB
Line 
1/* $Id: GuestImpl.cpp 28243 2010-04-13 12:07:13Z vboxsync $ */
2
3/** @file
4 *
5 * VirtualBox COM class implementation
6 */
7
8/*
9 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24#include "GuestImpl.h"
25
26#include "Global.h"
27#include "ConsoleImpl.h"
28#include "ProgressImpl.h"
29#include "VMMDev.h"
30
31#include "AutoCaller.h"
32#include "Logging.h"
33
34#include <VBox/VMMDev.h>
35#ifdef VBOX_WITH_GUEST_CONTROL
36# include <VBox/HostServices/GuestControlSvc.h>
37# include <VBox/com/array.h>
38# include <hgcm/HGCM.h>
39#endif
40#include <iprt/cpp/utils.h>
41#include <iprt/getopt.h>
42#include <VBox/pgm.h>
43
44// defines
45/////////////////////////////////////////////////////////////////////////////
46
47// constructor / destructor
48/////////////////////////////////////////////////////////////////////////////
49
50DEFINE_EMPTY_CTOR_DTOR (Guest)
51
52HRESULT Guest::FinalConstruct()
53{
54 return S_OK;
55}
56
57void Guest::FinalRelease()
58{
59 uninit ();
60}
61
62// public methods only for internal purposes
63/////////////////////////////////////////////////////////////////////////////
64
65/**
66 * Initializes the guest object.
67 */
68HRESULT Guest::init (Console *aParent)
69{
70 LogFlowThisFunc(("aParent=%p\n", aParent));
71
72 ComAssertRet(aParent, E_INVALIDARG);
73
74 /* Enclose the state transition NotReady->InInit->Ready */
75 AutoInitSpan autoInitSpan(this);
76 AssertReturn(autoInitSpan.isOk(), E_FAIL);
77
78 unconst(mParent) = aParent;
79
80 /* mData.mAdditionsActive is FALSE */
81
82 /* Confirm a successful initialization when it's the case */
83 autoInitSpan.setSucceeded();
84
85 ULONG aMemoryBalloonSize;
86 HRESULT ret = mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize);
87 if (ret == S_OK)
88 mMemoryBalloonSize = aMemoryBalloonSize;
89 else
90 mMemoryBalloonSize = 0; /* Default is no ballooning */
91
92 mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */
93
94 /* Clear statistics. */
95 for (unsigned i = 0 ; i < GUESTSTATTYPE_MAX; i++)
96 mCurrentGuestStat[i] = 0;
97
98 return S_OK;
99}
100
101/**
102 * Uninitializes the instance and sets the ready flag to FALSE.
103 * Called either from FinalRelease() or by the parent when it gets destroyed.
104 */
105void Guest::uninit()
106{
107 LogFlowThisFunc(("\n"));
108
109 /* Enclose the state transition Ready->InUninit->NotReady */
110 AutoUninitSpan autoUninitSpan(this);
111 if (autoUninitSpan.uninitDone())
112 return;
113
114 unconst(mParent) = NULL;
115}
116
117// IGuest properties
118/////////////////////////////////////////////////////////////////////////////
119
120STDMETHODIMP Guest::COMGETTER(OSTypeId) (BSTR *aOSTypeId)
121{
122 CheckComArgOutPointerValid(aOSTypeId);
123
124 AutoCaller autoCaller(this);
125 if (FAILED(autoCaller.rc())) return autoCaller.rc();
126
127 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
128
129 // redirect the call to IMachine if no additions are installed
130 if (mData.mAdditionsVersion.isEmpty())
131 return mParent->machine()->COMGETTER(OSTypeId)(aOSTypeId);
132
133 mData.mOSTypeId.cloneTo(aOSTypeId);
134
135 return S_OK;
136}
137
138STDMETHODIMP Guest::COMGETTER(AdditionsActive) (BOOL *aAdditionsActive)
139{
140 CheckComArgOutPointerValid(aAdditionsActive);
141
142 AutoCaller autoCaller(this);
143 if (FAILED(autoCaller.rc())) return autoCaller.rc();
144
145 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
146
147 *aAdditionsActive = mData.mAdditionsActive;
148
149 return S_OK;
150}
151
152STDMETHODIMP Guest::COMGETTER(AdditionsVersion) (BSTR *aAdditionsVersion)
153{
154 CheckComArgOutPointerValid(aAdditionsVersion);
155
156 AutoCaller autoCaller(this);
157 if (FAILED(autoCaller.rc())) return autoCaller.rc();
158
159 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
160
161 mData.mAdditionsVersion.cloneTo(aAdditionsVersion);
162
163 return S_OK;
164}
165
166STDMETHODIMP Guest::COMGETTER(SupportsSeamless) (BOOL *aSupportsSeamless)
167{
168 CheckComArgOutPointerValid(aSupportsSeamless);
169
170 AutoCaller autoCaller(this);
171 if (FAILED(autoCaller.rc())) return autoCaller.rc();
172
173 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
174
175 *aSupportsSeamless = mData.mSupportsSeamless;
176
177 return S_OK;
178}
179
180STDMETHODIMP Guest::COMGETTER(SupportsGraphics) (BOOL *aSupportsGraphics)
181{
182 CheckComArgOutPointerValid(aSupportsGraphics);
183
184 AutoCaller autoCaller(this);
185 if (FAILED(autoCaller.rc())) return autoCaller.rc();
186
187 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
188
189 *aSupportsGraphics = mData.mSupportsGraphics;
190
191 return S_OK;
192}
193
194STDMETHODIMP Guest::COMGETTER(MemoryBalloonSize) (ULONG *aMemoryBalloonSize)
195{
196 CheckComArgOutPointerValid(aMemoryBalloonSize);
197
198 AutoCaller autoCaller(this);
199 if (FAILED(autoCaller.rc())) return autoCaller.rc();
200
201 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
202
203 *aMemoryBalloonSize = mMemoryBalloonSize;
204
205 return S_OK;
206}
207
208STDMETHODIMP Guest::COMSETTER(MemoryBalloonSize) (ULONG aMemoryBalloonSize)
209{
210 AutoCaller autoCaller(this);
211 if (FAILED(autoCaller.rc())) return autoCaller.rc();
212
213 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
214
215 HRESULT ret = mParent->machine()->COMSETTER(MemoryBalloonSize)(aMemoryBalloonSize);
216 if (ret == S_OK)
217 {
218 mMemoryBalloonSize = aMemoryBalloonSize;
219 /* forward the information to the VMM device */
220 VMMDev *vmmDev = mParent->getVMMDev();
221 if (vmmDev)
222 vmmDev->getVMMDevPort()->pfnSetMemoryBalloon(vmmDev->getVMMDevPort(), aMemoryBalloonSize);
223 }
224
225 return ret;
226}
227
228STDMETHODIMP Guest::COMGETTER(StatisticsUpdateInterval)(ULONG *aUpdateInterval)
229{
230 CheckComArgOutPointerValid(aUpdateInterval);
231
232 AutoCaller autoCaller(this);
233 if (FAILED(autoCaller.rc())) return autoCaller.rc();
234
235 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
236
237 *aUpdateInterval = mStatUpdateInterval;
238 return S_OK;
239}
240
241STDMETHODIMP Guest::COMSETTER(StatisticsUpdateInterval)(ULONG aUpdateInterval)
242{
243 AutoCaller autoCaller(this);
244 if (FAILED(autoCaller.rc())) return autoCaller.rc();
245
246 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
247
248 mStatUpdateInterval = aUpdateInterval;
249 /* forward the information to the VMM device */
250 VMMDev *vmmDev = mParent->getVMMDev();
251 if (vmmDev)
252 vmmDev->getVMMDevPort()->pfnSetStatisticsInterval(vmmDev->getVMMDevPort(), aUpdateInterval);
253
254 return S_OK;
255}
256
257STDMETHODIMP Guest::InternalGetStatistics(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle,
258 ULONG *aMemTotal, ULONG *aMemFree, ULONG *aMemBalloon,
259 ULONG *aMemCache, ULONG *aPageTotal,
260 ULONG *aMemAllocTotal, ULONG *aMemFreeTotal, ULONG *aMemBalloonTotal)
261{
262 CheckComArgOutPointerValid(aCpuUser);
263 CheckComArgOutPointerValid(aCpuKernel);
264 CheckComArgOutPointerValid(aCpuIdle);
265 CheckComArgOutPointerValid(aMemTotal);
266 CheckComArgOutPointerValid(aMemFree);
267 CheckComArgOutPointerValid(aMemBalloon);
268 CheckComArgOutPointerValid(aMemCache);
269 CheckComArgOutPointerValid(aPageTotal);
270
271 AutoCaller autoCaller(this);
272 if (FAILED(autoCaller.rc())) return autoCaller.rc();
273
274 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
275
276 *aCpuUser = mCurrentGuestStat[GUESTSTATTYPE_CPUUSER] * (_4K/_1K); /* page (4K) -> 1 KB units */
277 *aCpuKernel = mCurrentGuestStat[GUESTSTATTYPE_CPUKERNEL] * (_4K/_1K);
278 *aCpuIdle = mCurrentGuestStat[GUESTSTATTYPE_CPUIDLE] * (_4K/_1K);
279 *aMemTotal = mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K);
280 *aMemFree = mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K);
281 *aMemBalloon = mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K);
282 *aMemCache = mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K);
283 *aPageTotal = mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K);
284
285 Console::SafeVMPtr pVM (mParent);
286 if (pVM.isOk())
287 {
288 uint64_t uFreeTotal, uAllocTotal, uBalloonedTotal;
289 *aMemFreeTotal = 0;
290 int rc = PGMR3QueryVMMMemoryStats(pVM.raw(), &uAllocTotal, &uFreeTotal, &uBalloonedTotal);
291 AssertRC(rc);
292 if (rc == VINF_SUCCESS)
293 {
294 *aMemAllocTotal = (ULONG)(uAllocTotal / _1K); /* bytes -> KB */
295 *aMemFreeTotal = (ULONG)(uFreeTotal / _1K);
296 *aMemBalloonTotal = (ULONG)(uBalloonedTotal / _1K);
297 }
298 }
299 else
300 *aMemFreeTotal = 0;
301
302 return S_OK;
303}
304
305HRESULT Guest::SetStatistic(ULONG aCpuId, GUESTSTATTYPE enmType, ULONG aVal)
306{
307 AutoCaller autoCaller(this);
308 if (FAILED(autoCaller.rc())) return autoCaller.rc();
309
310 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
311
312 if (enmType >= GUESTSTATTYPE_MAX)
313 return E_INVALIDARG;
314
315 mCurrentGuestStat[enmType] = aVal;
316 return S_OK;
317}
318
319STDMETHODIMP Guest::SetCredentials(IN_BSTR aUserName, IN_BSTR aPassword,
320 IN_BSTR aDomain, BOOL aAllowInteractiveLogon)
321{
322 AutoCaller autoCaller(this);
323 if (FAILED(autoCaller.rc())) return autoCaller.rc();
324
325 /* forward the information to the VMM device */
326 VMMDev *vmmDev = mParent->getVMMDev();
327 if (vmmDev)
328 {
329 uint32_t u32Flags = VMMDEV_SETCREDENTIALS_GUESTLOGON;
330 if (!aAllowInteractiveLogon)
331 u32Flags = VMMDEV_SETCREDENTIALS_NOLOCALLOGON;
332
333 vmmDev->getVMMDevPort()->pfnSetCredentials(vmmDev->getVMMDevPort(),
334 Utf8Str(aUserName).raw(), Utf8Str(aPassword).raw(),
335 Utf8Str(aDomain).raw(), u32Flags);
336 return S_OK;
337 }
338
339 return setError(VBOX_E_VM_ERROR,
340 tr("VMM device is not available (is the VM running?)"));
341}
342
343#ifdef VBOX_WITH_GUEST_CONTROL
344/**
345 * Creates the argument list as an array used for executing a program.
346 *
347 * @returns VBox status code.
348 *
349 * @todo
350 *
351 * @todo Respect spaces when quoting for arguments, e.g. "c:\\program files\\".
352 * @todo Handle empty ("") argguments.
353 */
354int Guest::prepareExecuteArgs(const char *pszArgs, void **ppvList, uint32_t *pcbList, uint32_t *pcArgs)
355{
356 char **ppaArg;
357 int iArgs;
358 int rc = RTGetOptArgvFromString(&ppaArg, &iArgs, pszArgs, NULL);
359 if (RT_SUCCESS(rc))
360 {
361 char *pszTemp = NULL;
362 *pcbList = 0;
363 for (int i=0; i<iArgs; i++)
364 {
365 if (i > 0) /* Insert space as delimiter. */
366 rc = RTStrAAppendN(&pszTemp, " ", 1);
367
368 if (RT_FAILURE(rc))
369 break;
370 else
371 {
372 rc = RTStrAAppendN(&pszTemp, ppaArg[i], strlen(ppaArg[i]));
373 if (RT_FAILURE(rc))
374 break;
375 }
376 }
377 RTGetOptArgvFree(ppaArg);
378 if (RT_SUCCESS(rc))
379 {
380 *ppvList = pszTemp;
381 *pcArgs = iArgs;
382 if (pszTemp)
383 *pcbList = strlen(pszTemp) + 1; /* Include zero termination. */
384 }
385 else
386 RTStrFree(pszTemp);
387 }
388 return rc;
389}
390
391/**
392 * Appends environment variables to the environment block. Each var=value pair is separated
393 * by NULL (\0) sequence. The whole block will be stored in one blob and disassembled on the
394 * guest side later to fit into the HGCM param structure.
395 *
396 * @returns VBox status code.
397 *
398 * @todo
399 *
400 */
401int Guest::prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnv)
402{
403 int rc = VINF_SUCCESS;
404 uint32_t cbLen = strlen(pszEnv);
405 if (*ppvList)
406 {
407 uint32_t cbNewLen = *pcbList + cbLen + 1; /* Include zero termination. */
408 char *pvTmp = (char*)RTMemRealloc(*ppvList, cbNewLen);
409 if (NULL == pvTmp)
410 {
411 rc = VERR_NO_MEMORY;
412 }
413 else
414 {
415 memcpy(pvTmp + *pcbList, pszEnv, cbLen);
416 pvTmp[cbNewLen - 1] = '\0'; /* Add zero termination. */
417 *ppvList = (void**)pvTmp;
418 }
419 }
420 else
421 {
422 char *pcTmp;
423 if (RTStrAPrintf(&pcTmp, "%s", pszEnv) > 0)
424 {
425 *ppvList = (void**)pcTmp;
426 /* Reset counters. */
427 *pcEnv = 0;
428 *pcbList = 0;
429 }
430 }
431 if (RT_SUCCESS(rc))
432 {
433 *pcbList += cbLen + 1; /* Include zero termination. */
434 *pcEnv += 1; /* Increase env pairs count. */
435 }
436 return rc;
437}
438
439/**
440 * Static callback function for receiving updates on processes started on
441 * the guest side.
442 *
443 * @returns VBox status code.
444 *
445 * @todo
446 *
447 */
448DECLCALLBACK(int) Guest::doGuestCtrlExecNotification(void *pvExtension,
449 uint32_t u32Function,
450 void *pvParms,
451 uint32_t cbParms)
452{
453 using namespace guestControl;
454
455 /*
456 * No locking, as this is purely a notification which does not make any
457 * changes to the object state.
458 */
459 PHOSTEXECCALLBACKDATA pCBData = reinterpret_cast<PHOSTEXECCALLBACKDATA>(pvParms);
460 AssertPtr(pCBData);
461 AssertReturn(sizeof(HOSTEXECCALLBACKDATA) == cbParms, VERR_INVALID_PARAMETER);
462 AssertReturn(HOSTCALLBACKMAGIC == pCBData->u32Magic, VERR_INVALID_PARAMETER);
463 LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
464 pvExtension, u32Function, pvParms, cbParms));
465 PHOSTEXECCALLBACKDATA pExt = reinterpret_cast<HOSTEXECCALLBACKDATA *>(pvExtension);
466
467 int rc = VINF_SUCCESS;
468 if (u32Function == GUEST_EXEC_SEND_STATUS)
469 {
470 LogFlowFunc(("GUEST_EXEC_SEND_STATUS\n"));
471 pExt->pid = pCBData->pid;
472 pExt->status = pCBData->status;
473 pExt->flags = pCBData->flags;
474 /** @todo Copy void* buffer! */
475 }
476 else
477 rc = VERR_NOT_SUPPORTED;
478
479 ASMAtomicWriteBool(&pExt->called, true);
480 return rc;
481}
482#endif /* VBOX_WITH_GUEST_CONTROL */
483
484STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags,
485 ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
486 IN_BSTR aStdIn, IN_BSTR aStdOut, IN_BSTR aStdErr,
487 IN_BSTR aUserName, IN_BSTR aPassword,
488 ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress)
489{
490#ifndef VBOX_WITH_GUEST_CONTROL
491 ReturnComNotImplemented();
492#else /* VBOX_WITH_GUEST_CONTROL */
493 using namespace guestControl;
494
495 CheckComArgStrNotEmptyOrNull(aCommand);
496 CheckComArgOutPointerValid(aPID);
497 CheckComArgOutPointerValid(aProgress);
498 if (aFlags != 0) /* Flags are not supported at the moment. */
499 return E_INVALIDARG;
500
501 HRESULT rc = S_OK;
502
503 try
504 {
505 AutoCaller autoCaller(this);
506 if (FAILED(autoCaller.rc())) return autoCaller.rc();
507
508 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
509
510 /*
511 * Create progress object.
512 */
513#if 0
514 ComObjPtr <Progress> progress;
515 progress.createObject();
516 HRESULT rc = progress->init(/** @todo How to get the machine here? */
517 static_cast<IGuest*>(this),
518 BstrFmt(tr("Executing process")),
519 FALSE);
520 if (FAILED(rc)) return rc;
521#endif
522
523 /*
524 * Register the host notification callback
525 */
526 HGCMSVCEXTHANDLE hExt;
527 HOSTEXECCALLBACKDATA callbackData;
528 callbackData.called = false;
529 int vrc = HGCMHostRegisterServiceExtension(&hExt, "VBoxGuestControlSvc",
530 &Guest::doGuestCtrlExecNotification,
531 &callbackData);
532 if (RT_SUCCESS(vrc))
533 {
534 /*
535 * Prepare process execution.
536 */
537 Utf8Str Utf8Command(aCommand);
538
539 /* Prepare arguments. */
540 com::SafeArray<IN_BSTR> args(ComSafeArrayInArg(aArguments));
541 uint32_t uNumArgs = args.size();
542 char **papszArgv = NULL;
543 if(uNumArgs > 0)
544 {
545 papszArgv = (char**)RTMemAlloc(sizeof(char*) * (uNumArgs + 1));
546 AssertPtr(papszArgv);
547 for (unsigned i = 0; RT_SUCCESS(vrc) && i < uNumArgs; i++)
548 vrc = RTStrAPrintf(&papszArgv[i], "%s", Utf8Str(args[i]).raw());
549 papszArgv[uNumArgs] = NULL;
550 }
551
552 if (RT_SUCCESS(vrc))
553 {
554 char *pszArgs = NULL;
555 if (uNumArgs > 0)
556 vrc = RTGetOptArgvToString(&pszArgs, papszArgv, 0);
557 if (RT_SUCCESS(vrc))
558 {
559 uint32_t cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
560
561 /* Prepare environment. */
562 com::SafeArray<IN_BSTR> env(ComSafeArrayInArg(aEnvironment));
563
564 void *pvEnv = NULL;
565 uint32_t uNumEnv = 0;
566 uint32_t cbEnv = 0;
567
568 for (unsigned i = 0; i < env.size(); i++)
569 {
570 vrc = prepareExecuteEnv(Utf8Str(env[i]).raw(), &pvEnv, &cbEnv, &uNumEnv);
571 if (RT_FAILURE(vrc))
572 break;
573 }
574
575 if (RT_SUCCESS(vrc))
576 {
577 Utf8Str Utf8StdIn(aStdIn);
578 Utf8Str Utf8StdOut(aStdOut);
579 Utf8Str Utf8StdErr(aStdErr);
580 Utf8Str Utf8UserName(aUserName);
581 Utf8Str Utf8Password(aPassword);
582
583 VBOXHGCMSVCPARM paParms[14];
584 int i = 0;
585 paParms[i++].setPointer((void*)Utf8Command.raw(), (uint32_t)strlen(Utf8Command.raw()) + 1);
586 paParms[i++].setUInt32(aFlags);
587 paParms[i++].setUInt32(uNumArgs);
588 paParms[i++].setPointer((void*)pszArgs, cbArgs);
589 paParms[i++].setUInt32(uNumEnv);
590 paParms[i++].setUInt32(cbEnv);
591 paParms[i++].setPointer((void*)pvEnv, cbEnv);
592 paParms[i++].setPointer((void*)Utf8StdIn.raw(), (uint32_t)strlen(Utf8StdIn.raw()) + 1);
593 paParms[i++].setPointer((void*)Utf8StdOut.raw(), (uint32_t)strlen(Utf8StdOut.raw()) + 1);
594 paParms[i++].setPointer((void*)Utf8StdErr.raw(), (uint32_t)strlen(Utf8StdErr.raw()) + 1);
595 paParms[i++].setPointer((void*)Utf8UserName.raw(), (uint32_t)strlen(Utf8UserName.raw()) + 1);
596 paParms[i++].setPointer((void*)Utf8Password.raw(), (uint32_t)strlen(Utf8Password.raw()) + 1);
597 paParms[i++].setUInt32(aTimeoutMS);
598
599 /* Forward the information to the VMM device. */
600 AssertPtr(mParent);
601 VMMDev *vmmDev = mParent->getVMMDev();
602 if (vmmDev)
603 {
604 LogFlowFunc(("hgcmHostCall numParms=%d\n", i));
605 vrc = vmmDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_CMD,
606 i, paParms);
607 }
608 RTMemFree(pvEnv);
609 }
610 RTStrFree(pszArgs);
611 }
612 if (RT_SUCCESS(vrc))
613 {
614 LogFlowFunc(("Waiting for HGCM callback (timeout=%ldms) ...\n", aTimeoutMS));
615
616 /*
617 * Wait for the HGCM low level callback until the process
618 * has been started (or something went wrong). This is necessary to
619 * get the PID.
620 */
621 uint64_t u64Started = RTTimeMilliTS();
622 do
623 {
624 unsigned cMsWait;
625 if (aTimeoutMS == RT_INDEFINITE_WAIT)
626 cMsWait = 1000;
627 else
628 {
629 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
630 if (cMsElapsed >= aTimeoutMS)
631 break; /* timed out */
632 cMsWait = RT_MIN(1000, aTimeoutMS - (uint32_t)cMsElapsed);
633 }
634 RTThreadSleep(100);
635 } while (!callbackData.called);
636
637 /* Did we get some status? */
638 if (callbackData.called)
639 {
640 switch (callbackData.status)
641 {
642 case PROC_STS_STARTED:
643 *aPID = callbackData.pid;
644 break;
645
646 case PROC_STS_ERROR:
647 vrc = callbackData.flags; /* flags member contains IPRT error code. */
648 break;
649
650 default:
651 vrc = VERR_INVALID_PARAMETER;
652 break;
653 }
654 }
655
656 if (RT_FAILURE(vrc))
657 {
658 if (vrc == VERR_FILE_NOT_FOUND) /* This is the most likely error. */
659 {
660 rc = setError(VBOX_E_IPRT_ERROR,
661 tr("The file \"%s\" was not found on guest"), Utf8Command.raw());
662 }
663 else
664 {
665 rc = setError(E_UNEXPECTED,
666 tr("The service call failed with the error %Rrc"), vrc);
667 }
668 }
669#if 0
670 progress.queryInterfaceTo(aProgress);
671#endif
672 }
673 else
674 {
675 /* HGCM call went wrong. */
676 rc = setError(E_UNEXPECTED,
677 tr("The service call failed with the error %Rrc"), vrc);
678 }
679
680 for (unsigned i = 0; i < uNumArgs; i++)
681 RTMemFree(papszArgv[i]);
682 RTMemFree(papszArgv);
683 }
684 /* Unregister HGCM extension */
685 HGCMHostUnregisterServiceExtension(hExt);
686 }
687 }
688 catch (std::bad_alloc &)
689 {
690 rc = E_OUTOFMEMORY;
691 }
692 return rc;
693#endif /* VBOX_WITH_GUEST_CONTROL */
694}
695
696// public methods only for internal purposes
697/////////////////////////////////////////////////////////////////////////////
698
699void Guest::setAdditionsVersion(Bstr aVersion, VBOXOSTYPE aOsType)
700{
701 AutoCaller autoCaller(this);
702 AssertComRCReturnVoid (autoCaller.rc());
703
704 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
705
706 mData.mAdditionsVersion = aVersion;
707 mData.mAdditionsActive = !aVersion.isEmpty();
708 /* Older Additions didn't have this finer grained capability bit,
709 * so enable it by default. Newer Additions will disable it immediately
710 * if relevant. */
711 mData.mSupportsGraphics = mData.mAdditionsActive;
712
713 mData.mOSTypeId = Global::OSTypeId (aOsType);
714}
715
716void Guest::setSupportsSeamless (BOOL aSupportsSeamless)
717{
718 AutoCaller autoCaller(this);
719 AssertComRCReturnVoid (autoCaller.rc());
720
721 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
722
723 mData.mSupportsSeamless = aSupportsSeamless;
724}
725
726void Guest::setSupportsGraphics (BOOL aSupportsGraphics)
727{
728 AutoCaller autoCaller(this);
729 AssertComRCReturnVoid (autoCaller.rc());
730
731 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
732
733 mData.mSupportsGraphics = aSupportsGraphics;
734}
735/* 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