VirtualBox

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

Last change on this file since 28155 was 28132, checked in by vboxsync, 15 years ago

Guest Control: Update (fixed leak in host service, --wait option for VBoxManage).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.2 KB
Line 
1/* $Id: GuestImpl.cpp 28132 2010-04-09 10:02:00Z 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#endif
39#include <iprt/cpp/utils.h>
40#include <iprt/getopt.h>
41#include <VBox/pgm.h>
42
43// defines
44/////////////////////////////////////////////////////////////////////////////
45
46// constructor / destructor
47/////////////////////////////////////////////////////////////////////////////
48
49DEFINE_EMPTY_CTOR_DTOR (Guest)
50
51HRESULT Guest::FinalConstruct()
52{
53 return S_OK;
54}
55
56void Guest::FinalRelease()
57{
58 uninit ();
59}
60
61// public methods only for internal purposes
62/////////////////////////////////////////////////////////////////////////////
63
64/**
65 * Initializes the guest object.
66 */
67HRESULT Guest::init (Console *aParent)
68{
69 LogFlowThisFunc(("aParent=%p\n", aParent));
70
71 ComAssertRet(aParent, E_INVALIDARG);
72
73 /* Enclose the state transition NotReady->InInit->Ready */
74 AutoInitSpan autoInitSpan(this);
75 AssertReturn(autoInitSpan.isOk(), E_FAIL);
76
77 unconst(mParent) = aParent;
78
79 /* mData.mAdditionsActive is FALSE */
80
81 /* Confirm a successful initialization when it's the case */
82 autoInitSpan.setSucceeded();
83
84 ULONG aMemoryBalloonSize;
85 HRESULT ret = mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize);
86 if (ret == S_OK)
87 mMemoryBalloonSize = aMemoryBalloonSize;
88 else
89 mMemoryBalloonSize = 0; /* Default is no ballooning */
90
91 mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */
92
93 /* Clear statistics. */
94 for (unsigned i = 0 ; i < GUESTSTATTYPE_MAX; i++)
95 mCurrentGuestStat[i] = 0;
96
97 return S_OK;
98}
99
100/**
101 * Uninitializes the instance and sets the ready flag to FALSE.
102 * Called either from FinalRelease() or by the parent when it gets destroyed.
103 */
104void Guest::uninit()
105{
106 LogFlowThisFunc(("\n"));
107
108 /* Enclose the state transition Ready->InUninit->NotReady */
109 AutoUninitSpan autoUninitSpan(this);
110 if (autoUninitSpan.uninitDone())
111 return;
112
113 unconst(mParent) = NULL;
114}
115
116// IGuest properties
117/////////////////////////////////////////////////////////////////////////////
118
119STDMETHODIMP Guest::COMGETTER(OSTypeId) (BSTR *aOSTypeId)
120{
121 CheckComArgOutPointerValid(aOSTypeId);
122
123 AutoCaller autoCaller(this);
124 if (FAILED(autoCaller.rc())) return autoCaller.rc();
125
126 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
127
128 // redirect the call to IMachine if no additions are installed
129 if (mData.mAdditionsVersion.isEmpty())
130 return mParent->machine()->COMGETTER(OSTypeId)(aOSTypeId);
131
132 mData.mOSTypeId.cloneTo(aOSTypeId);
133
134 return S_OK;
135}
136
137STDMETHODIMP Guest::COMGETTER(AdditionsActive) (BOOL *aAdditionsActive)
138{
139 CheckComArgOutPointerValid(aAdditionsActive);
140
141 AutoCaller autoCaller(this);
142 if (FAILED(autoCaller.rc())) return autoCaller.rc();
143
144 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
145
146 *aAdditionsActive = mData.mAdditionsActive;
147
148 return S_OK;
149}
150
151STDMETHODIMP Guest::COMGETTER(AdditionsVersion) (BSTR *aAdditionsVersion)
152{
153 CheckComArgOutPointerValid(aAdditionsVersion);
154
155 AutoCaller autoCaller(this);
156 if (FAILED(autoCaller.rc())) return autoCaller.rc();
157
158 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
159
160 mData.mAdditionsVersion.cloneTo(aAdditionsVersion);
161
162 return S_OK;
163}
164
165STDMETHODIMP Guest::COMGETTER(SupportsSeamless) (BOOL *aSupportsSeamless)
166{
167 CheckComArgOutPointerValid(aSupportsSeamless);
168
169 AutoCaller autoCaller(this);
170 if (FAILED(autoCaller.rc())) return autoCaller.rc();
171
172 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
173
174 *aSupportsSeamless = mData.mSupportsSeamless;
175
176 return S_OK;
177}
178
179STDMETHODIMP Guest::COMGETTER(SupportsGraphics) (BOOL *aSupportsGraphics)
180{
181 CheckComArgOutPointerValid(aSupportsGraphics);
182
183 AutoCaller autoCaller(this);
184 if (FAILED(autoCaller.rc())) return autoCaller.rc();
185
186 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
187
188 *aSupportsGraphics = mData.mSupportsGraphics;
189
190 return S_OK;
191}
192
193STDMETHODIMP Guest::COMGETTER(MemoryBalloonSize) (ULONG *aMemoryBalloonSize)
194{
195 CheckComArgOutPointerValid(aMemoryBalloonSize);
196
197 AutoCaller autoCaller(this);
198 if (FAILED(autoCaller.rc())) return autoCaller.rc();
199
200 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
201
202 *aMemoryBalloonSize = mMemoryBalloonSize;
203
204 return S_OK;
205}
206
207STDMETHODIMP Guest::COMSETTER(MemoryBalloonSize) (ULONG aMemoryBalloonSize)
208{
209 AutoCaller autoCaller(this);
210 if (FAILED(autoCaller.rc())) return autoCaller.rc();
211
212 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
213
214 HRESULT ret = mParent->machine()->COMSETTER(MemoryBalloonSize)(aMemoryBalloonSize);
215 if (ret == S_OK)
216 {
217 mMemoryBalloonSize = aMemoryBalloonSize;
218 /* forward the information to the VMM device */
219 VMMDev *vmmDev = mParent->getVMMDev();
220 if (vmmDev)
221 vmmDev->getVMMDevPort()->pfnSetMemoryBalloon(vmmDev->getVMMDevPort(), aMemoryBalloonSize);
222 }
223
224 return ret;
225}
226
227STDMETHODIMP Guest::COMGETTER(StatisticsUpdateInterval)(ULONG *aUpdateInterval)
228{
229 CheckComArgOutPointerValid(aUpdateInterval);
230
231 AutoCaller autoCaller(this);
232 if (FAILED(autoCaller.rc())) return autoCaller.rc();
233
234 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
235
236 *aUpdateInterval = mStatUpdateInterval;
237 return S_OK;
238}
239
240STDMETHODIMP Guest::COMSETTER(StatisticsUpdateInterval)(ULONG aUpdateInterval)
241{
242 AutoCaller autoCaller(this);
243 if (FAILED(autoCaller.rc())) return autoCaller.rc();
244
245 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
246
247 mStatUpdateInterval = aUpdateInterval;
248 /* forward the information to the VMM device */
249 VMMDev *vmmDev = mParent->getVMMDev();
250 if (vmmDev)
251 vmmDev->getVMMDevPort()->pfnSetStatisticsInterval(vmmDev->getVMMDevPort(), aUpdateInterval);
252
253 return S_OK;
254}
255
256STDMETHODIMP Guest::InternalGetStatistics(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle,
257 ULONG *aMemTotal, ULONG *aMemFree, ULONG *aMemBalloon,
258 ULONG *aMemCache, ULONG *aPageTotal,
259 ULONG *aMemAllocTotal, ULONG *aMemFreeTotal, ULONG *aMemBalloonTotal)
260{
261 CheckComArgOutPointerValid(aCpuUser);
262 CheckComArgOutPointerValid(aCpuKernel);
263 CheckComArgOutPointerValid(aCpuIdle);
264 CheckComArgOutPointerValid(aMemTotal);
265 CheckComArgOutPointerValid(aMemFree);
266 CheckComArgOutPointerValid(aMemBalloon);
267 CheckComArgOutPointerValid(aMemCache);
268 CheckComArgOutPointerValid(aPageTotal);
269
270 AutoCaller autoCaller(this);
271 if (FAILED(autoCaller.rc())) return autoCaller.rc();
272
273 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
274
275 *aCpuUser = mCurrentGuestStat[GUESTSTATTYPE_CPUUSER] * (_4K/_1K); /* page (4K) -> 1 KB units */
276 *aCpuKernel = mCurrentGuestStat[GUESTSTATTYPE_CPUKERNEL] * (_4K/_1K);
277 *aCpuIdle = mCurrentGuestStat[GUESTSTATTYPE_CPUIDLE] * (_4K/_1K);
278 *aMemTotal = mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K);
279 *aMemFree = mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K);
280 *aMemBalloon = mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K);
281 *aMemCache = mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K);
282 *aPageTotal = mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K);
283
284 Console::SafeVMPtr pVM (mParent);
285 if (pVM.isOk())
286 {
287 uint64_t uFreeTotal, uAllocTotal, uBalloonedTotal;
288 *aMemFreeTotal = 0;
289 int rc = PGMR3QueryVMMMemoryStats(pVM.raw(), &uAllocTotal, &uFreeTotal, &uBalloonedTotal);
290 AssertRC(rc);
291 if (rc == VINF_SUCCESS)
292 {
293 *aMemAllocTotal = (ULONG)(uAllocTotal / _1K); /* bytes -> KB */
294 *aMemFreeTotal = (ULONG)(uFreeTotal / _1K);
295 *aMemBalloonTotal = (ULONG)(uBalloonedTotal / _1K);
296 }
297 }
298 else
299 *aMemFreeTotal = 0;
300
301 return S_OK;
302}
303
304HRESULT Guest::SetStatistic(ULONG aCpuId, GUESTSTATTYPE enmType, ULONG aVal)
305{
306 AutoCaller autoCaller(this);
307 if (FAILED(autoCaller.rc())) return autoCaller.rc();
308
309 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
310
311 if (enmType >= GUESTSTATTYPE_MAX)
312 return E_INVALIDARG;
313
314 mCurrentGuestStat[enmType] = aVal;
315 return S_OK;
316}
317
318STDMETHODIMP Guest::SetCredentials(IN_BSTR aUserName, IN_BSTR aPassword,
319 IN_BSTR aDomain, BOOL aAllowInteractiveLogon)
320{
321 AutoCaller autoCaller(this);
322 if (FAILED(autoCaller.rc())) return autoCaller.rc();
323
324 /* forward the information to the VMM device */
325 VMMDev *vmmDev = mParent->getVMMDev();
326 if (vmmDev)
327 {
328 uint32_t u32Flags = VMMDEV_SETCREDENTIALS_GUESTLOGON;
329 if (!aAllowInteractiveLogon)
330 u32Flags = VMMDEV_SETCREDENTIALS_NOLOCALLOGON;
331
332 vmmDev->getVMMDevPort()->pfnSetCredentials(vmmDev->getVMMDevPort(),
333 Utf8Str(aUserName).raw(), Utf8Str(aPassword).raw(),
334 Utf8Str(aDomain).raw(), u32Flags);
335 return S_OK;
336 }
337
338 return setError(VBOX_E_VM_ERROR,
339 tr("VMM device is not available (is the VM running?)"));
340}
341
342#ifdef VBOX_WITH_GUEST_CONTROL
343/**
344 * Creates the argument list as an array used for executing a program.
345 *
346 * @returns VBox status code.
347 *
348 * @todo
349 *
350 * @todo Respect spaces when quoting for arguments, e.g. "c:\\program files\\".
351 * @todo Handle empty ("") argguments.
352 */
353int Guest::prepareExecuteArgs(const char *pszArgs, void **ppvList, uint32_t *pcbList, uint32_t *pcArgs)
354{
355 char **ppaArg;
356 int iArgs;
357 int rc = RTGetOptArgvFromString(&ppaArg, &iArgs, pszArgs, NULL);
358 if (RT_SUCCESS(rc))
359 {
360 char *pszTemp = NULL;
361 *pcbList = 0;
362 for (int i=0; i<iArgs; i++)
363 {
364 if (i > 0) /* Insert space as delimiter. */
365 rc = RTStrAAppendN(&pszTemp, " ", 1);
366
367 if (RT_FAILURE(rc))
368 break;
369 else
370 {
371 rc = RTStrAAppendN(&pszTemp, ppaArg[i], strlen(ppaArg[i]));
372 if (RT_FAILURE(rc))
373 break;
374 }
375 }
376 RTGetOptArgvFree(ppaArg);
377 if (RT_SUCCESS(rc))
378 {
379 *ppvList = pszTemp;
380 *pcArgs = iArgs;
381 if (pszTemp)
382 *pcbList = strlen(pszTemp) + 1; /* Include zero termination. */
383 }
384 else
385 RTStrFree(pszTemp);
386 }
387 return rc;
388}
389
390/**
391 * Appends environment variables to the environment block. Each var=value pair is separated
392 * by NULL (\0) sequence. The whole block will be stored in one blob and disassembled on the
393 * guest side later to fit into the HGCM param structure.
394 *
395 * @returns VBox status code.
396 *
397 * @todo
398 *
399 */
400int Guest::prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnv)
401{
402 int rc = VINF_SUCCESS;
403 uint32_t cbLen = strlen(pszEnv);
404 if (*ppvList)
405 {
406 uint32_t cbNewLen = *pcbList + cbLen + 1; /* Include zero termination. */
407 char *pvTmp = (char*)RTMemRealloc(*ppvList, cbNewLen);
408 if (NULL == pvTmp)
409 {
410 rc = VERR_NO_MEMORY;
411 }
412 else
413 {
414 memcpy(pvTmp + *pcbList, pszEnv, cbLen);
415 pvTmp[cbNewLen - 1] = '\0'; /* Add zero termination. */
416 *ppvList = (void**)pvTmp;
417 }
418 }
419 else
420 {
421 char *pcTmp;
422 if (RTStrAPrintf(&pcTmp, "%s", pszEnv) > 0)
423 {
424 *ppvList = (void**)pcTmp;
425 /* Reset counters. */
426 *pcEnv = 0;
427 *pcbList = 0;
428 }
429 }
430 if (RT_SUCCESS(rc))
431 {
432 *pcbList += cbLen + 1; /* Include zero termination. */
433 *pcEnv += 1; /* Increase env pairs count. */
434 }
435 return rc;
436}
437#endif /* VBOX_WITH_GUEST_CONTROL */
438
439STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags,
440 ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
441 IN_BSTR aStdIn, IN_BSTR aStdOut, IN_BSTR aStdErr,
442 IN_BSTR aUserName, IN_BSTR aPassword,
443 ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress)
444{
445#ifndef VBOX_WITH_GUEST_CONTROL
446 ReturnComNotImplemented();
447#else /* VBOX_WITH_GUEST_CONTROL */
448 using namespace guestControl;
449
450 CheckComArgStrNotEmptyOrNull(aCommand);
451 CheckComArgOutPointerValid(aPID);
452 CheckComArgOutPointerValid(aProgress);
453 if (aFlags != 0) /* Flags are not supported at the moment. */
454 return E_INVALIDARG;
455
456 HRESULT rc = S_OK;
457
458 try
459 {
460 AutoCaller autoCaller(this);
461 if (FAILED(autoCaller.rc())) return autoCaller.rc();
462
463 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
464
465 /*
466 * Create progress object.
467 */
468#if 0
469 ComObjPtr <Progress> progress;
470 progress.createObject();
471 HRESULT rc = progress->init(/** @todo How to get the machine here? */
472 static_cast<IGuest*>(this),
473 BstrFmt(tr("Executing process")),
474 FALSE);
475 if (FAILED(rc)) return rc;
476#endif
477
478 /*
479 * Prepare process execution.
480 */
481 int vrc = VINF_SUCCESS;
482 Utf8Str Utf8Command(aCommand);
483
484 /* Prepare arguments. */
485 com::SafeArray<IN_BSTR> args(ComSafeArrayInArg(aArguments));
486 uint32_t uNumArgs = args.size();
487 char **papszArgv = NULL;
488 if(uNumArgs > 0)
489 {
490 papszArgv = (char**)RTMemAlloc(sizeof(char*) * (uNumArgs + 1));
491 AssertPtr(papszArgv);
492 for (unsigned i = 0; RT_SUCCESS(vrc) && i < uNumArgs; i++)
493 vrc = RTStrAPrintf(&papszArgv[i], "%s", Utf8Str(args[i]).raw());
494 papszArgv[uNumArgs] = NULL;
495 }
496
497 if (RT_SUCCESS(vrc))
498 {
499 char *pszArgs = NULL;
500 if (uNumArgs > 0)
501 vrc = RTGetOptArgvToString(&pszArgs, papszArgv, 0);
502 if (RT_SUCCESS(vrc))
503 {
504 uint32_t cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
505
506 /* Prepare environment. */
507 com::SafeArray<IN_BSTR> env(ComSafeArrayInArg(aEnvironment));
508
509 void *pvEnv = NULL;
510 uint32_t uNumEnv = 0;
511 uint32_t cbEnv = 0;
512
513 for (unsigned i = 0; i < env.size(); i++)
514 {
515 vrc = prepareExecuteEnv(Utf8Str(env[i]).raw(), &pvEnv, &cbEnv, &uNumEnv);
516 if (RT_FAILURE(vrc))
517 break;
518 }
519
520 if (RT_SUCCESS(vrc))
521 {
522 Utf8Str Utf8StdIn(aStdIn);
523 Utf8Str Utf8StdOut(aStdOut);
524 Utf8Str Utf8StdErr(aStdErr);
525 Utf8Str Utf8UserName(aUserName);
526 Utf8Str Utf8Password(aPassword);
527
528 VBOXHGCMSVCPARM paParms[14];
529 int i = 0;
530 paParms[i++].setPointer((void*)Utf8Command.raw(), (uint32_t)strlen(Utf8Command.raw()) + 1);
531 paParms[i++].setUInt32(aFlags);
532 paParms[i++].setUInt32(uNumArgs);
533 paParms[i++].setPointer((void*)pszArgs, cbArgs);
534 paParms[i++].setUInt32(uNumEnv);
535 paParms[i++].setUInt32(cbEnv);
536 paParms[i++].setPointer((void*)pvEnv, cbEnv);
537 paParms[i++].setPointer((void*)Utf8StdIn.raw(), (uint32_t)strlen(Utf8StdIn.raw()) + 1);
538 paParms[i++].setPointer((void*)Utf8StdOut.raw(), (uint32_t)strlen(Utf8StdOut.raw()) + 1);
539 paParms[i++].setPointer((void*)Utf8StdErr.raw(), (uint32_t)strlen(Utf8StdErr.raw()) + 1);
540 paParms[i++].setPointer((void*)Utf8UserName.raw(), (uint32_t)strlen(Utf8UserName.raw()) + 1);
541 paParms[i++].setPointer((void*)Utf8Password.raw(), (uint32_t)strlen(Utf8Password.raw()) + 1);
542 paParms[i++].setUInt32(aTimeoutMS);
543
544 /* Forward the information to the VMM device. */
545 AssertPtr(mParent);
546 VMMDev *vmmDev = mParent->getVMMDev();
547 if (vmmDev)
548 {
549 LogFlow(("Guest::ExecuteProgram: numParms=%d\n", i));
550 vrc = vmmDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_CMD,
551 i, paParms);
552 /** @todo Get the PID. */
553 }
554 RTMemFree(pvEnv);
555 }
556 RTStrFree(pszArgs);
557 }
558 if (RT_SUCCESS(vrc))
559 {
560#if 0
561 progress.queryInterfaceTo(aProgress);
562#endif
563 rc = S_OK;
564 }
565 else
566 rc = setError(E_UNEXPECTED,
567 tr("The service call failed with the error %Rrc"),
568 vrc);
569
570 for (unsigned i = 0; i < uNumArgs; i++)
571 RTMemFree(papszArgv[i]);
572 RTMemFree(papszArgv);
573 }
574 }
575 catch (std::bad_alloc &)
576 {
577 rc = E_OUTOFMEMORY;
578 };
579
580 return rc;
581#endif /* VBOX_WITH_GUEST_CONTROL */
582}
583
584// public methods only for internal purposes
585/////////////////////////////////////////////////////////////////////////////
586
587void Guest::setAdditionsVersion(Bstr aVersion, VBOXOSTYPE aOsType)
588{
589 AutoCaller autoCaller(this);
590 AssertComRCReturnVoid (autoCaller.rc());
591
592 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
593
594 mData.mAdditionsVersion = aVersion;
595 mData.mAdditionsActive = !aVersion.isEmpty();
596 /* Older Additions didn't have this finer grained capability bit,
597 * so enable it by default. Newer Additions will disable it immediately
598 * if relevant. */
599 mData.mSupportsGraphics = mData.mAdditionsActive;
600
601 mData.mOSTypeId = Global::OSTypeId (aOsType);
602}
603
604void Guest::setSupportsSeamless (BOOL aSupportsSeamless)
605{
606 AutoCaller autoCaller(this);
607 AssertComRCReturnVoid (autoCaller.rc());
608
609 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
610
611 mData.mSupportsSeamless = aSupportsSeamless;
612}
613
614void Guest::setSupportsGraphics (BOOL aSupportsGraphics)
615{
616 AutoCaller autoCaller(this);
617 AssertComRCReturnVoid (autoCaller.rc());
618
619 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
620
621 mData.mSupportsGraphics = aSupportsGraphics;
622}
623/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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