mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-13 20:08:55 +00:00
Adds VirtualBox API for Python3 (not official).
This commit is contained in:
parent
53ee3dc5cc
commit
9ac2716826
1276
gns3server/modules/virtualbox/vboxapi_py3/VirtualBox_constants.py
Normal file
1276
gns3server/modules/virtualbox/vboxapi_py3/VirtualBox_constants.py
Normal file
File diff suppressed because it is too large
Load Diff
612
gns3server/modules/virtualbox/vboxapi_py3/__init__.py
Normal file
612
gns3server/modules/virtualbox/vboxapi_py3/__init__.py
Normal file
@ -0,0 +1,612 @@
|
||||
"""
|
||||
Copyright (C) 2009-2012 Oracle Corporation
|
||||
|
||||
This file is part of VirtualBox Open Source Edition (OSE), as
|
||||
available from http://www.virtualbox.org. This file is free software;
|
||||
you can redistribute it and/or modify it under the terms of the GNU
|
||||
General Public License (GPL) as published by the Free Software
|
||||
Foundation, in version 2 as it comes in the "COPYING" file of the
|
||||
VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
||||
hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
||||
"""
|
||||
|
||||
import sys,os
|
||||
import traceback
|
||||
|
||||
# To set Python bitness on OSX use 'export VERSIONER_PYTHON_PREFER_32_BIT=yes'
|
||||
|
||||
VboxBinDir = os.environ.get("VBOX_PROGRAM_PATH", None)
|
||||
VboxSdkDir = os.environ.get("VBOX_SDK_PATH", None)
|
||||
|
||||
if VboxBinDir is None:
|
||||
# Will be set by the installer
|
||||
VboxBinDir = "C:\\Program Files\\Oracle\\VirtualBox\\"
|
||||
|
||||
if VboxSdkDir is None:
|
||||
# Will be set by the installer
|
||||
VboxSdkDir = "C:\\Program Files\\Oracle\\VirtualBox\\sdk\\"
|
||||
|
||||
os.environ["VBOX_PROGRAM_PATH"] = VboxBinDir
|
||||
os.environ["VBOX_SDK_PATH"] = VboxSdkDir
|
||||
sys.path.append(VboxBinDir)
|
||||
|
||||
from .VirtualBox_constants import VirtualBoxReflectionInfo
|
||||
|
||||
class PerfCollector:
|
||||
""" This class provides a wrapper over IPerformanceCollector in order to
|
||||
get more 'pythonic' interface.
|
||||
|
||||
To begin collection of metrics use setup() method.
|
||||
|
||||
To get collected data use query() method.
|
||||
|
||||
It is possible to disable metric collection without changing collection
|
||||
parameters with disable() method. The enable() method resumes metric
|
||||
collection.
|
||||
"""
|
||||
|
||||
def __init__(self, mgr, vbox):
|
||||
""" Initializes the instance.
|
||||
|
||||
"""
|
||||
self.mgr = mgr
|
||||
self.isMscom = (mgr.type == 'MSCOM')
|
||||
self.collector = vbox.performanceCollector
|
||||
|
||||
def setup(self, names, objects, period, nsamples):
|
||||
""" Discards all previously collected values for the specified
|
||||
metrics, sets the period of collection and the number of retained
|
||||
samples, enables collection.
|
||||
"""
|
||||
self.collector.setupMetrics(names, objects, period, nsamples)
|
||||
|
||||
def enable(self, names, objects):
|
||||
""" Resumes metric collection for the specified metrics.
|
||||
"""
|
||||
self.collector.enableMetrics(names, objects)
|
||||
|
||||
def disable(self, names, objects):
|
||||
""" Suspends metric collection for the specified metrics.
|
||||
"""
|
||||
self.collector.disableMetrics(names, objects)
|
||||
|
||||
def query(self, names, objects):
|
||||
""" Retrieves collected metric values as well as some auxiliary
|
||||
information. Returns an array of dictionaries, one dictionary per
|
||||
metric. Each dictionary contains the following entries:
|
||||
'name': metric name
|
||||
'object': managed object this metric associated with
|
||||
'unit': unit of measurement
|
||||
'scale': divide 'values' by this number to get float numbers
|
||||
'values': collected data
|
||||
'values_as_string': pre-processed values ready for 'print' statement
|
||||
"""
|
||||
# Get around the problem with input arrays returned in output
|
||||
# parameters (see #3953) for MSCOM.
|
||||
if self.isMscom:
|
||||
(values, names, objects, names_out, objects_out, units, scales, sequence_numbers,
|
||||
indices, lengths) = self.collector.queryMetricsData(names, objects)
|
||||
else:
|
||||
(values, names_out, objects_out, units, scales, sequence_numbers,
|
||||
indices, lengths) = self.collector.queryMetricsData(names, objects)
|
||||
out = []
|
||||
for i in xrange(0, len(names_out)):
|
||||
scale = int(scales[i])
|
||||
if scale != 1:
|
||||
fmt = '%.2f%s'
|
||||
else:
|
||||
fmt = '%d %s'
|
||||
out.append({
|
||||
'name':str(names_out[i]),
|
||||
'object':str(objects_out[i]),
|
||||
'unit':str(units[i]),
|
||||
'scale':scale,
|
||||
'values':[int(values[j]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))],
|
||||
'values_as_string':'['+', '.join([fmt % (int(values[j])/scale, units[i]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))])+']'
|
||||
})
|
||||
return out
|
||||
|
||||
def ComifyName(name):
|
||||
return name[0].capitalize()+name[1:]
|
||||
|
||||
_COMForward = { 'getattr' : None,
|
||||
'setattr' : None}
|
||||
|
||||
def CustomGetAttr(self, attr):
|
||||
# fastpath
|
||||
if self.__class__.__dict__.get(attr) != None:
|
||||
return self.__class__.__dict__.get(attr)
|
||||
|
||||
# try case-insensitivity workaround for class attributes (COM methods)
|
||||
for k in self.__class__.__dict__.keys():
|
||||
if k.lower() == attr.lower():
|
||||
setattr(self.__class__, attr, self.__class__.__dict__[k])
|
||||
return getattr(self, k)
|
||||
try:
|
||||
return _COMForward['getattr'](self,ComifyName(attr))
|
||||
except AttributeError:
|
||||
return _COMForward['getattr'](self,attr)
|
||||
|
||||
def CustomSetAttr(self, attr, value):
|
||||
try:
|
||||
return _COMForward['setattr'](self, ComifyName(attr), value)
|
||||
except AttributeError:
|
||||
return _COMForward['setattr'](self, attr, value)
|
||||
|
||||
class PlatformMSCOM:
|
||||
# Class to fake access to constants in style of foo.bar.boo
|
||||
class ConstantFake:
|
||||
def __init__(self, parent, name):
|
||||
self.__dict__['_parent'] = parent
|
||||
self.__dict__['_name'] = name
|
||||
self.__dict__['_consts'] = {}
|
||||
try:
|
||||
self.__dict__['_depth']=parent.__dict__['_depth']+1
|
||||
except:
|
||||
self.__dict__['_depth']=0
|
||||
if self.__dict__['_depth'] > 4:
|
||||
raise AttributeError
|
||||
|
||||
def __getattr__(self, attr):
|
||||
import win32com
|
||||
from win32com.client import constants
|
||||
|
||||
if attr.startswith("__"):
|
||||
raise AttributeError
|
||||
|
||||
consts = self.__dict__['_consts']
|
||||
|
||||
fake = consts.get(attr, None)
|
||||
if fake != None:
|
||||
return fake
|
||||
try:
|
||||
name = self.__dict__['_name']
|
||||
parent = self.__dict__['_parent']
|
||||
while parent != None:
|
||||
if parent._name is not None:
|
||||
name = parent._name+'_'+name
|
||||
parent = parent._parent
|
||||
|
||||
if name is not None:
|
||||
name += "_" + attr
|
||||
else:
|
||||
name = attr
|
||||
return win32com.client.constants.__getattr__(name)
|
||||
except AttributeError as e:
|
||||
fake = PlatformMSCOM.ConstantFake(self, attr)
|
||||
consts[attr] = fake
|
||||
return fake
|
||||
|
||||
|
||||
class InterfacesWrapper:
|
||||
def __init__(self):
|
||||
self.__dict__['_rootFake'] = PlatformMSCOM.ConstantFake(None, None)
|
||||
|
||||
def __getattr__(self, a):
|
||||
import win32com
|
||||
from win32com.client import constants
|
||||
if a.startswith("__"):
|
||||
raise AttributeError
|
||||
try:
|
||||
return win32com.client.constants.__getattr__(a)
|
||||
except AttributeError as e:
|
||||
return self.__dict__['_rootFake'].__getattr__(a)
|
||||
|
||||
VBOX_TLB_GUID = '{46137EEC-703B-4FE5-AFD4-7C9BBBBA0259}'
|
||||
VBOX_TLB_LCID = 0
|
||||
VBOX_TLB_MAJOR = 1
|
||||
VBOX_TLB_MINOR = 0
|
||||
|
||||
def __init__(self, params):
|
||||
from win32com import universal
|
||||
from win32com.client import gencache, DispatchBaseClass
|
||||
from win32com.client import constants, getevents
|
||||
import win32com
|
||||
import pythoncom
|
||||
import win32api
|
||||
from win32con import DUPLICATE_SAME_ACCESS
|
||||
from win32api import GetCurrentThread,GetCurrentThreadId,DuplicateHandle,GetCurrentProcess
|
||||
import threading
|
||||
pid = GetCurrentProcess()
|
||||
self.tid = GetCurrentThreadId()
|
||||
handle = DuplicateHandle(pid, GetCurrentThread(), pid, 0, 0, DUPLICATE_SAME_ACCESS)
|
||||
self.handles = []
|
||||
self.handles.append(handle)
|
||||
_COMForward['getattr'] = DispatchBaseClass.__dict__['__getattr__']
|
||||
DispatchBaseClass.__getattr__ = CustomGetAttr
|
||||
_COMForward['setattr'] = DispatchBaseClass.__dict__['__setattr__']
|
||||
DispatchBaseClass.__setattr__ = CustomSetAttr
|
||||
win32com.client.gencache.EnsureDispatch('VirtualBox.Session')
|
||||
win32com.client.gencache.EnsureDispatch('VirtualBox.VirtualBox')
|
||||
self.oIntCv = threading.Condition()
|
||||
self.fInterrupted = False;
|
||||
|
||||
def getSessionObject(self, vbox):
|
||||
import win32com
|
||||
from win32com.client import Dispatch
|
||||
return win32com.client.Dispatch("VirtualBox.Session")
|
||||
|
||||
def getVirtualBox(self):
|
||||
import win32com
|
||||
from win32com.client import Dispatch
|
||||
return win32com.client.Dispatch("VirtualBox.VirtualBox")
|
||||
|
||||
def getType(self):
|
||||
return 'MSCOM'
|
||||
|
||||
def getRemote(self):
|
||||
return False
|
||||
|
||||
def getArray(self, obj, field):
|
||||
return obj.__getattr__(field)
|
||||
|
||||
def initPerThread(self):
|
||||
import pythoncom
|
||||
pythoncom.CoInitializeEx(0)
|
||||
|
||||
def deinitPerThread(self):
|
||||
import pythoncom
|
||||
pythoncom.CoUninitialize()
|
||||
|
||||
def createListener(self, impl, arg):
|
||||
d = {}
|
||||
d['BaseClass'] = impl
|
||||
d['arg'] = arg
|
||||
d['tlb_guid'] = PlatformMSCOM.VBOX_TLB_GUID
|
||||
str = ""
|
||||
str += "import win32com.server.util\n"
|
||||
str += "import pythoncom\n"
|
||||
|
||||
str += "class ListenerImpl(BaseClass):\n"
|
||||
str += " _com_interfaces_ = ['IEventListener']\n"
|
||||
str += " _typelib_guid_ = tlb_guid\n"
|
||||
str += " _typelib_version_ = 1, 0\n"
|
||||
str += " _reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER\n"
|
||||
# Maybe we'd better implement Dynamic invoke policy, to be more flexible here
|
||||
str += " _reg_policy_spec_ = 'win32com.server.policy.EventHandlerPolicy'\n"
|
||||
|
||||
# capitalized version of listener method
|
||||
str += " HandleEvent=BaseClass.handleEvent\n"
|
||||
str += " def __init__(self): BaseClass.__init__(self, arg)\n"
|
||||
str += "result = win32com.server.util.wrap(ListenerImpl())\n"
|
||||
exec(str,d,d)
|
||||
return d['result']
|
||||
|
||||
def waitForEvents(self, timeout):
|
||||
from win32api import GetCurrentThreadId
|
||||
from win32event import INFINITE
|
||||
from win32event import MsgWaitForMultipleObjects, \
|
||||
QS_ALLINPUT, WAIT_TIMEOUT, WAIT_OBJECT_0
|
||||
from pythoncom import PumpWaitingMessages
|
||||
import types
|
||||
|
||||
if not isinstance(timeout, types.IntType):
|
||||
raise TypeError("The timeout argument is not an integer")
|
||||
if (self.tid != GetCurrentThreadId()):
|
||||
raise Exception("wait for events from the same thread you inited!")
|
||||
|
||||
if timeout < 0: cMsTimeout = INFINITE
|
||||
else: cMsTimeout = timeout
|
||||
rc = MsgWaitForMultipleObjects(self.handles, 0, cMsTimeout, QS_ALLINPUT)
|
||||
if rc >= WAIT_OBJECT_0 and rc < WAIT_OBJECT_0+len(self.handles):
|
||||
# is it possible?
|
||||
rc = 2;
|
||||
elif rc==WAIT_OBJECT_0 + len(self.handles):
|
||||
# Waiting messages
|
||||
PumpWaitingMessages()
|
||||
rc = 0;
|
||||
else:
|
||||
# Timeout
|
||||
rc = 1;
|
||||
|
||||
# check for interruption
|
||||
self.oIntCv.acquire()
|
||||
if self.fInterrupted:
|
||||
self.fInterrupted = False
|
||||
rc = 1;
|
||||
self.oIntCv.release()
|
||||
|
||||
return rc;
|
||||
|
||||
def interruptWaitEvents(self):
|
||||
"""
|
||||
Basically a python implementation of EventQueue::postEvent().
|
||||
|
||||
The magic value must be in sync with the C++ implementation or this
|
||||
won't work.
|
||||
|
||||
Note that because of this method we cannot easily make use of a
|
||||
non-visible Window to handle the message like we would like to do.
|
||||
"""
|
||||
from win32api import PostThreadMessage
|
||||
from win32con import WM_USER
|
||||
self.oIntCv.acquire()
|
||||
self.fInterrupted = True
|
||||
self.oIntCv.release()
|
||||
try:
|
||||
PostThreadMessage(self.tid, WM_USER, None, 0xf241b819)
|
||||
except:
|
||||
return False;
|
||||
return True;
|
||||
|
||||
def deinit(self):
|
||||
import pythoncom
|
||||
from win32file import CloseHandle
|
||||
|
||||
for h in self.handles:
|
||||
if h is not None:
|
||||
CloseHandle(h)
|
||||
self.handles = None
|
||||
pythoncom.CoUninitialize()
|
||||
pass
|
||||
|
||||
def queryInterface(self, obj, klazzName):
|
||||
from win32com.client import CastTo
|
||||
return CastTo(obj, klazzName)
|
||||
|
||||
class PlatformXPCOM:
|
||||
def __init__(self, params):
|
||||
sys.path.append(VboxSdkDir+'/bindings/xpcom/python/')
|
||||
import xpcom.vboxxpcom
|
||||
import xpcom
|
||||
import xpcom.components
|
||||
|
||||
def getSessionObject(self, vbox):
|
||||
import xpcom.components
|
||||
return xpcom.components.classes["@virtualbox.org/Session;1"].createInstance()
|
||||
|
||||
def getVirtualBox(self):
|
||||
import xpcom.components
|
||||
return xpcom.components.classes["@virtualbox.org/VirtualBox;1"].createInstance()
|
||||
|
||||
def getType(self):
|
||||
return 'XPCOM'
|
||||
|
||||
def getRemote(self):
|
||||
return False
|
||||
|
||||
def getArray(self, obj, field):
|
||||
return obj.__getattr__('get'+ComifyName(field))()
|
||||
|
||||
def initPerThread(self):
|
||||
import xpcom
|
||||
xpcom._xpcom.AttachThread()
|
||||
|
||||
def deinitPerThread(self):
|
||||
import xpcom
|
||||
xpcom._xpcom.DetachThread()
|
||||
|
||||
def createListener(self, impl, arg):
|
||||
d = {}
|
||||
d['BaseClass'] = impl
|
||||
d['arg'] = arg
|
||||
str = ""
|
||||
str += "import xpcom.components\n"
|
||||
str += "class ListenerImpl(BaseClass):\n"
|
||||
str += " _com_interfaces_ = xpcom.components.interfaces.IEventListener\n"
|
||||
str += " def __init__(self): BaseClass.__init__(self, arg)\n"
|
||||
str += "result = ListenerImpl()\n"
|
||||
exec(str,d,d)
|
||||
return d['result']
|
||||
|
||||
def waitForEvents(self, timeout):
|
||||
import xpcom
|
||||
return xpcom._xpcom.WaitForEvents(timeout)
|
||||
|
||||
def interruptWaitEvents(self):
|
||||
import xpcom
|
||||
return xpcom._xpcom.InterruptWait()
|
||||
|
||||
def deinit(self):
|
||||
import xpcom
|
||||
xpcom._xpcom.DeinitCOM()
|
||||
|
||||
def queryInterface(self, obj, klazzName):
|
||||
import xpcom.components
|
||||
return obj.queryInterface(getattr(xpcom.components.interfaces, klazzName))
|
||||
|
||||
class PlatformWEBSERVICE:
|
||||
def __init__(self, params):
|
||||
sys.path.append(os.path.join(VboxSdkDir,'bindings', 'webservice', 'python', 'lib'))
|
||||
#import VirtualBox_services
|
||||
import VirtualBox_wrappers
|
||||
from VirtualBox_wrappers import IWebsessionManager2
|
||||
|
||||
if params is not None:
|
||||
self.user = params.get("user", "")
|
||||
self.password = params.get("password", "")
|
||||
self.url = params.get("url", "")
|
||||
else:
|
||||
self.user = ""
|
||||
self.password = ""
|
||||
self.url = None
|
||||
self.vbox = None
|
||||
|
||||
def getSessionObject(self, vbox):
|
||||
return self.wsmgr.getSessionObject(vbox)
|
||||
|
||||
def getVirtualBox(self):
|
||||
return self.connect(self.url, self.user, self.password)
|
||||
|
||||
def connect(self, url, user, passwd):
|
||||
if self.vbox is not None:
|
||||
self.disconnect()
|
||||
from VirtualBox_wrappers import IWebsessionManager2
|
||||
if url is None:
|
||||
url = ""
|
||||
self.url = url
|
||||
if user is None:
|
||||
user = ""
|
||||
self.user = user
|
||||
if passwd is None:
|
||||
passwd = ""
|
||||
self.password = passwd
|
||||
self.wsmgr = IWebsessionManager2(self.url)
|
||||
self.vbox = self.wsmgr.logon(self.user, self.password)
|
||||
if not self.vbox.handle:
|
||||
raise Exception("cannot connect to '"+self.url+"' as '"+self.user+"'")
|
||||
return self.vbox
|
||||
|
||||
def disconnect(self):
|
||||
if self.vbox is not None and self.wsmgr is not None:
|
||||
self.wsmgr.logoff(self.vbox)
|
||||
self.vbox = None
|
||||
self.wsmgr = None
|
||||
|
||||
def getType(self):
|
||||
return 'WEBSERVICE'
|
||||
|
||||
def getRemote(self):
|
||||
return True
|
||||
|
||||
def getArray(self, obj, field):
|
||||
return obj.__getattr__(field)
|
||||
|
||||
def initPerThread(self):
|
||||
pass
|
||||
|
||||
def deinitPerThread(self):
|
||||
pass
|
||||
|
||||
def createListener(self, impl, arg):
|
||||
raise Exception("no active listeners for webservices")
|
||||
|
||||
def waitForEvents(self, timeout):
|
||||
# Webservices cannot do that yet
|
||||
return 2;
|
||||
|
||||
def interruptWaitEvents(self, timeout):
|
||||
# Webservices cannot do that yet
|
||||
return False;
|
||||
|
||||
def deinit(self):
|
||||
try:
|
||||
disconnect()
|
||||
except:
|
||||
pass
|
||||
|
||||
def queryInterface(self, obj, klazzName):
|
||||
d = {}
|
||||
d['obj'] = obj
|
||||
str = ""
|
||||
str += "from VirtualBox_wrappers import "+klazzName+"\n"
|
||||
str += "result = "+klazzName+"(obj.mgr,obj.handle)\n"
|
||||
# wrong, need to test if class indeed implements this interface
|
||||
exec(str,d,d)
|
||||
return d['result']
|
||||
|
||||
class SessionManager:
|
||||
def __init__(self, mgr):
|
||||
self.mgr = mgr
|
||||
|
||||
def getSessionObject(self, vbox):
|
||||
return self.mgr.platform.getSessionObject(vbox)
|
||||
|
||||
class VirtualBoxManager:
|
||||
def __init__(self, style, platparams):
|
||||
if style is None:
|
||||
if sys.platform == 'win32':
|
||||
style = "MSCOM"
|
||||
else:
|
||||
style = "XPCOM"
|
||||
|
||||
|
||||
exec("self.platform = Platform"+style+"(platparams)")
|
||||
# for webservices, enums are symbolic
|
||||
self.constants = VirtualBoxReflectionInfo(style == "WEBSERVICE")
|
||||
self.type = self.platform.getType()
|
||||
self.remote = self.platform.getRemote()
|
||||
self.style = style
|
||||
self.mgr = SessionManager(self)
|
||||
|
||||
try:
|
||||
self.vbox = self.platform.getVirtualBox()
|
||||
except NameError as ne:
|
||||
print("Installation problem: check that appropriate libs in place")
|
||||
traceback.print_exc()
|
||||
raise ne
|
||||
except Exception as e:
|
||||
print("init exception: ",e)
|
||||
traceback.print_exc()
|
||||
if self.remote:
|
||||
self.vbox = None
|
||||
else:
|
||||
raise e
|
||||
|
||||
def getArray(self, obj, field):
|
||||
return self.platform.getArray(obj, field)
|
||||
|
||||
def getVirtualBox(self):
|
||||
return self.platform.getVirtualBox()
|
||||
|
||||
def __del__(self):
|
||||
self.deinit()
|
||||
|
||||
def deinit(self):
|
||||
if hasattr(self, "vbox"):
|
||||
del self.vbox
|
||||
self.vbox = None
|
||||
if hasattr(self, "platform"):
|
||||
self.platform.deinit()
|
||||
self.platform = None
|
||||
|
||||
def initPerThread(self):
|
||||
self.platform.initPerThread()
|
||||
|
||||
def openMachineSession(self, mach, permitSharing = True):
|
||||
session = self.mgr.getSessionObject(self.vbox)
|
||||
if permitSharing:
|
||||
type = self.constants.LockType_Shared
|
||||
else:
|
||||
type = self.constants.LockType_Write
|
||||
mach.lockMachine(session, type)
|
||||
return session
|
||||
|
||||
def closeMachineSession(self, session):
|
||||
if session is not None:
|
||||
session.unlockMachine()
|
||||
|
||||
def deinitPerThread(self):
|
||||
self.platform.deinitPerThread()
|
||||
|
||||
def createListener(self, impl, arg = None):
|
||||
return self.platform.createListener(impl, arg)
|
||||
|
||||
def waitForEvents(self, timeout):
|
||||
"""
|
||||
Wait for events to arrive and process them.
|
||||
|
||||
The timeout is in milliseconds. A negative value means waiting for
|
||||
ever, while 0 does not wait at all.
|
||||
|
||||
Returns 0 if events was processed.
|
||||
Returns 1 if timed out or interrupted in some way.
|
||||
Returns 2 on error (like not supported for web services).
|
||||
|
||||
Raises an exception if the calling thread is not the main thread (the one
|
||||
that initialized VirtualBoxManager) or if the time isn't an integer.
|
||||
"""
|
||||
return self.platform.waitForEvents(timeout)
|
||||
|
||||
def interruptWaitEvents(self):
|
||||
"""
|
||||
Interrupt a waitForEvents call.
|
||||
This is normally called from a worker thread.
|
||||
|
||||
Returns True on success, False on failure.
|
||||
"""
|
||||
return self.platform.interruptWaitEvents()
|
||||
|
||||
def getPerfCollector(self, vbox):
|
||||
return PerfCollector(self, vbox)
|
||||
|
||||
def getBinDir(self):
|
||||
global VboxBinDir
|
||||
return VboxBinDir
|
||||
|
||||
def getSdkDir(self):
|
||||
global VboxSdkDir
|
||||
return VboxSdkDir
|
||||
|
||||
def queryInterface(self, obj, klazzName):
|
||||
return self.platform.queryInterface(obj, klazzName)
|
Loading…
Reference in New Issue
Block a user