VirtualBox

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

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

Pass on memory balloon property to the vmm device during startup.

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