VirtualBox

source: vbox/trunk/src/VBox/Main/glue/vboxapi.py@ 50174

Last change on this file since 50174 was 49741, checked in by vboxsync, 11 years ago

Main/glue/vboxapi.py: fix copy/paste bug

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.6 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: vboxapi.py 49741 2013-12-02 14:47:37Z vboxsync $
3"""
4VirtualBox Python API Glue.
5"""
6
7__copyright__ = \
8"""
9Copyright (C) 2009-2013 Oracle Corporation
10
11This file is part of VirtualBox Open Source Edition (OSE), as
12available from http://www.virtualbox.org. This file is free software;
13you can redistribute it and/or modify it under the terms of the GNU
14General Public License (GPL) as published by the Free Software
15Foundation, in version 2 as it comes in the "COPYING" file of the
16VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18"""
19__version__ = "$Revision: 49741 $"
20
21
22# Note! To set Python bitness on OSX use 'export VERSIONER_PYTHON_PREFER_32_BIT=yes'
23
24
25# Standard Python imports.
26import sys, os
27import traceback
28
29
30#
31# Globals, environment and sys.path changes.
32#
33VBoxBinDir = os.environ.get("VBOX_PROGRAM_PATH", None)
34VBoxSdkDir = os.environ.get("VBOX_SDK_PATH", None)
35
36if VBoxBinDir is None:
37 # Will be set by the installer
38 VBoxBinDir = "%VBOX_INSTALL_PATH%"
39else:
40 VBoxBinDir = os.path.abspath(VBoxBinDir);
41
42if VBoxSdkDir is None:
43 # Will be set by the installer
44 VBoxSdkDir = "%VBOX_SDK_PATH%"
45else:
46 VBoxSdkDir = os.path.abspath(VBoxSdkDir);
47
48os.environ["VBOX_PROGRAM_PATH"] = VBoxBinDir
49os.environ["VBOX_SDK_PATH"] = VBoxSdkDir
50sys.path.append(VBoxBinDir)
51
52
53#
54# Import the generated VirtualBox constants.
55#
56from VirtualBox_constants import VirtualBoxReflectionInfo
57
58
59class PerfCollector(object):
60 """ This class provides a wrapper over IPerformanceCollector in order to
61 get more 'pythonic' interface.
62
63 To begin collection of metrics use setup() method.
64
65 To get collected data use query() method.
66
67 It is possible to disable metric collection without changing collection
68 parameters with disable() method. The enable() method resumes metric
69 collection.
70 """
71
72 def __init__(self, mgr, vbox):
73 """ Initializes the instance.
74
75 """
76 self.mgr = mgr
77 self.isMscom = (mgr.type == 'MSCOM')
78 self.collector = vbox.performanceCollector
79
80 def setup(self, names, objects, period, nsamples):
81 """ Discards all previously collected values for the specified
82 metrics, sets the period of collection and the number of retained
83 samples, enables collection.
84 """
85 self.collector.setupMetrics(names, objects, period, nsamples)
86
87 def enable(self, names, objects):
88 """ Resumes metric collection for the specified metrics.
89 """
90 self.collector.enableMetrics(names, objects)
91
92 def disable(self, names, objects):
93 """ Suspends metric collection for the specified metrics.
94 """
95 self.collector.disableMetrics(names, objects)
96
97 def query(self, names, objects):
98 """ Retrieves collected metric values as well as some auxiliary
99 information. Returns an array of dictionaries, one dictionary per
100 metric. Each dictionary contains the following entries:
101 'name': metric name
102 'object': managed object this metric associated with
103 'unit': unit of measurement
104 'scale': divide 'values' by this number to get float numbers
105 'values': collected data
106 'values_as_string': pre-processed values ready for 'print' statement
107 """
108 # Get around the problem with input arrays returned in output
109 # parameters (see #3953) for MSCOM.
110 if self.isMscom:
111 (values, names, objects, names_out, objects_out, units, scales, sequence_numbers,
112 indices, lengths) = self.collector.queryMetricsData(names, objects)
113 else:
114 (values, names_out, objects_out, units, scales, sequence_numbers,
115 indices, lengths) = self.collector.queryMetricsData(names, objects)
116 out = []
117 for i in xrange(0, len(names_out)):
118 scale = int(scales[i])
119 if scale != 1:
120 fmt = '%.2f%s'
121 else:
122 fmt = '%d %s'
123 out.append({
124 'name':str(names_out[i]),
125 'object':str(objects_out[i]),
126 'unit':str(units[i]),
127 'scale':scale,
128 'values':[int(values[j]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))],
129 'values_as_string':'['+', '.join([fmt % (int(values[j])/scale, units[i]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))])+']'
130 })
131 return out
132
133#
134# Attribute hacks.
135#
136def ComifyName(name):
137 return name[0].capitalize() + name[1:]
138
139
140## This is for saving the original DispatchBaseClass __getattr__ and __setattr__
141# method references.
142_g_dCOMForward = {
143 'getattr': None,
144 'setattr': None,
145}
146
147def _CustomGetAttr(self, sAttr):
148 """ Our getattr replacement for DispatchBaseClass. """
149 # Fastpath.
150 oRet = self.__class__.__dict__.get(sAttr);
151 if oRet != None:
152 return oRet;
153
154 # Try case-insensitivity workaround for class attributes (COM methods).
155 sAttrLower = sAttr.lower();
156 for sKey in self.__class__.__dict__.keys():
157 if sKey.lower() == sAttrLower:
158 self.__class__.__dict__[sAttr] = self.__class__.__dict__[sKey]
159 return getattr(self, sKey)
160
161 # Slow path.
162 try:
163 return _g_dCOMForward['getattr'](self, ComifyName(sAttr))
164 except AttributeError:
165 return _g_dCOMForward['getattr'](self, sAttr)
166
167def _CustomSetAttr(self, sAttr, oValue):
168 """ Our setattr replacement for DispatchBaseClass. """
169 try:
170 return _g_dCOMForward['setattr'](self, ComifyName(sAttr), oValue)
171 except AttributeError:
172 return _g_dCOMForward['setattr'](self, sAttr, oValue)
173
174
175
176class PlatformBase(object):
177 """
178 Base class for the platform specific code.
179 """
180
181 def __init__(self, aoParams):
182 _ = aoParams;
183
184 def getVirtualBox(self):
185 """
186 Gets a the IVirtualBox singleton.
187 """
188 return None;
189
190 def getSessionObject(self, oIVBox):
191 """
192 Get a session object that can be used for opening machine sessions.
193
194 The oIVBox parameter is an getVirtualBox() return value, i.e. an
195 IVirtualBox reference.
196
197 See also openMachineSession.
198 """
199 _ = oIVBox;
200 return None;
201
202 def getType(self):
203 """ Returns the platform type (class name sans 'Platform'). """
204 return None;
205
206 def isRemote(self):
207 """
208 Returns True if remote (web services) and False if local (COM/XPCOM).
209 """
210 return False
211
212 def getArray(self, oInterface, sAttrib):
213 """
214 Retrives the value of the array attribute 'sAttrib' from
215 interface 'oInterface'.
216
217 This is for hiding platform specific differences in attributes
218 returning arrays.
219 """
220 _ = oInterface;
221 _ = sAttrib;
222 return None;
223
224 def initPerThread(self):
225 """
226 Does backend specific initialization for the calling thread.
227 """
228 return True;
229
230 def deinitPerThread(self):
231 """
232 Does backend specific uninitialization for the calling thread.
233 """
234 return True;
235
236 def createListener(self, oImplClass, dArgs):
237 """
238 Instantiates and wraps an active event listener class so it can be
239 passed to an event source for registration.
240
241 oImplClass is a class (type, not instance) which implements
242 IEventListener.
243
244 dArgs is a dictionary with string indexed variables. This may be
245 modified by the method to pass platform specific parameters. Can
246 be None.
247
248 This currently only works on XPCOM. COM support is not possible due to
249 shortcuts taken in the COM bridge code, which is not under our control.
250 Use passive listeners for COM and web services.
251 """
252 _ = oImplClass;
253 _ = dArgs;
254 raise Exception("No active listeners for this platform");
255 return None;
256
257 def waitForEvents(self, cMsTimeout):
258 """
259 Wait for events to arrive and process them.
260
261 The timeout (cMsTimeout) is in milliseconds for how long to wait for
262 events to arrive. A negative value means waiting for ever, while 0
263 does not wait at all.
264
265 Returns 0 if events was processed.
266 Returns 1 if timed out or interrupted in some way.
267 Returns 2 on error (like not supported for web services).
268
269 Raises an exception if the calling thread is not the main thread (the one
270 that initialized VirtualBoxManager) or if the time isn't an integer.
271 """
272 _ = cMsTimeout;
273 return 2;
274
275 def interruptWaitEvents(self):
276 """
277 Interrupt a waitForEvents call.
278 This is normally called from a worker thread to wake up the main thread.
279
280 Returns True on success, False on failure.
281 """
282 return False;
283
284 def deinit(self):
285 """
286 Unitializes the platform specific backend.
287 """
288 return None;
289
290 def queryInterface(self, oIUnknown, sClassName):
291 """
292 IUnknown::QueryInterface wrapper.
293
294 oIUnknown is who to ask.
295 sClassName is the name of the interface we're asking for.
296 """
297 return None;
298
299 #
300 # Error (exception) access methods.
301 #
302
303 def xcptGetStatus(self, oXcpt):
304 """
305 Returns the COM status code from the VBox API given exception.
306 """
307 return None;
308
309 def xcptIsDeadInterface(self, oXcpt):
310 """
311 Returns True if the exception indicates that the interface is dead, False if not.
312 """
313 return False;
314
315 def xcptIsEqual(self, oXcpt, hrStatus):
316 """
317 Checks if the exception oXcpt is equal to the COM/XPCOM status code
318 hrStatus.
319
320 The oXcpt parameter can be any kind of object, we'll just return True
321 if it doesn't behave like a our exception class.
322
323 Will not raise any exception as long as hrStatus and self are not bad.
324 """
325 try:
326 hrXcpt = self.xcptGetStatus(oXcpt);
327 except AttributeError:
328 return False;
329 if hrXcpt == hrStatus:
330 return True;
331
332 # Fudge for 32-bit signed int conversion.
333 if hrStatus > 0x7fffffff and hrStatus <= 0xffffffff and hrXcpt < 0:
334 if (hrStatus - 0x100000000) == hrXcpt:
335 return True;
336 return False;
337
338 def xcptGetMessage(self, oXcpt):
339 """
340 Returns the best error message found in the COM-like exception.
341 Returns None to fall back on xcptToString.
342 Raises exception if oXcpt isn't our kind of exception object.
343 """
344 return None;
345
346 def xcptGetBaseXcpt(self):
347 """
348 Returns the base exception class.
349 """
350 return None;
351
352 def xcptSetupConstants(self, oDst):
353 """
354 Copy/whatever all error constants onto oDst.
355 """
356 return oDst;
357
358 @staticmethod
359 def xcptCopyErrorConstants(oDst, oSrc):
360 """
361 Copy everything that looks like error constants from oDst to oSrc.
362 """
363 for sAttr in dir(oSrc):
364 if sAttr[0].isupper() and (sAttr[1].isupper() or sAttr[1] == '_'):
365 oAttr = getattr(oSrc, sAttr);
366 if type(oAttr) is int:
367 setattr(oDst, sAttr, oAttr);
368 return oDst;
369
370
371
372class PlatformMSCOM(PlatformBase):
373 """
374 Platform specific code for MS COM.
375 """
376
377 ## @name VirtualBox COM Typelib definitions (should be generate)
378 #
379 # @remarks Must be updated when the corresponding VirtualBox.xidl bits
380 # are changed. Fortunately this isn't very often.
381 # @{
382 VBOX_TLB_GUID = '{D7569351-1750-46F0-936E-BD127D5BC264}'
383 VBOX_TLB_LCID = 0
384 VBOX_TLB_MAJOR = 1
385 VBOX_TLB_MINOR = 3
386 ## @}
387
388
389 class ConstantFake(object):
390 """ Class to fake access to constants in style of foo.bar.boo """
391
392 def __init__(self, parent, name):
393 self.__dict__['_parent'] = parent
394 self.__dict__['_name'] = name
395 self.__dict__['_consts'] = {}
396 try:
397 self.__dict__['_depth']=parent.__dict__['_depth']+1
398 except:
399 self.__dict__['_depth']=0
400 if self.__dict__['_depth'] > 4:
401 raise AttributeError
402
403 def __getattr__(self, attr):
404 import win32com
405 from win32com.client import constants
406
407 if attr.startswith("__"):
408 raise AttributeError
409
410 consts = self.__dict__['_consts']
411
412 fake = consts.get(attr, None)
413 if fake != None:
414 return fake
415 try:
416 name = self.__dict__['_name']
417 parent = self.__dict__['_parent']
418 while parent != None:
419 if parent._name is not None:
420 name = parent._name+'_'+name
421 parent = parent._parent
422
423 if name is not None:
424 name += "_" + attr
425 else:
426 name = attr
427 return win32com.client.constants.__getattr__(name)
428 except AttributeError, e:
429 fake = PlatformMSCOM.ConstantFake(self, attr)
430 consts[attr] = fake
431 return fake
432
433
434 class InterfacesWrapper:
435 def __init__(self):
436 self.__dict__['_rootFake'] = PlatformMSCOM.ConstantFake(None, None)
437
438 def __getattr__(self, a):
439 import win32com
440 from win32com.client import constants
441 if a.startswith("__"):
442 raise AttributeError
443 try:
444 return win32com.client.constants.__getattr__(a)
445 except AttributeError, e:
446 return self.__dict__['_rootFake'].__getattr__(a)
447
448 def __init__(self, dParams):
449 PlatformBase.__init__(self, dParams);
450
451 #
452 # Since the code runs on all platforms, we have to do a lot of
453 # importing here instead of at the top of the file where it's normally located.
454 #
455 from win32com import universal
456 from win32com.client import gencache, DispatchBaseClass
457 from win32com.client import constants, getevents
458 import win32com
459 import pythoncom
460 import win32api
461 import winerror
462 from win32con import DUPLICATE_SAME_ACCESS
463 from win32api import GetCurrentThread, GetCurrentThreadId, DuplicateHandle, GetCurrentProcess
464 import threading
465
466 self.winerror = winerror;
467
468 pid = GetCurrentProcess()
469 self.tid = GetCurrentThreadId()
470 handle = DuplicateHandle(pid, GetCurrentThread(), pid, 0, 0, DUPLICATE_SAME_ACCESS)
471 self.handles = []
472 self.handles.append(handle)
473
474 # Hack the COM dispatcher base class so we can modify method and
475 # attribute names to match those in xpcom.
476 if _g_dCOMForward['setattr'] is None:
477 _g_dCOMForward['getattr'] = DispatchBaseClass.__dict__['__getattr__']
478 DispatchBaseClass.__dict__['__getattr__'] = _CustomGetAttr
479 _g_dCOMForward['setattr'] = DispatchBaseClass.__dict__['__setattr__']
480 DispatchBaseClass.__dict__['__setattr__'] = _CustomSetAttr
481
482 # Hack the exception base class so the users doesn't need to check for
483 # XPCOM or COM and do different things.
484 ## @todo
485
486 #
487 # Make sure the gencache is correct (we don't quite follow the COM
488 # versioning rules).
489 #
490 self.flushGenPyCache(win32com.client.gencache);
491 win32com.client.gencache.EnsureDispatch('VirtualBox.Session');
492 win32com.client.gencache.EnsureDispatch('VirtualBox.VirtualBox');
493
494 self.oIntCv = threading.Condition()
495 self.fInterrupted = False;
496
497 _ = dParams;
498
499 def flushGenPyCache(self, oGenCache):
500 """
501 Flushes VBox related files in the win32com gen_py cache.
502
503 This is necessary since we don't follow the typelib versioning rules
504 that everyeone else seems to subscribe to.
505 """
506 #
507 # The EnsureModule method have broken validation code, it doesn't take
508 # typelib module directories into account. So we brute force them here.
509 # (It's possible the directory approach is from some older pywin
510 # version or the result of runnig makepy or gencache manually, but we
511 # need to cover it as well.)
512 #
513 sName = oGenCache.GetGeneratedFileName(self.VBOX_TLB_GUID, self.VBOX_TLB_LCID,
514 self.VBOX_TLB_MAJOR, self.VBOX_TLB_MINOR);
515 sGenPath = oGenCache.GetGeneratePath();
516 if len(sName) > 36 and len(sGenPath) > 5:
517 sTypelibPath = os.path.join(sGenPath, sName);
518 if os.path.isdir(sTypelibPath):
519 import shutil;
520 shutil.rmtree(sTypelibPath, ignore_errors = True);
521
522 #
523 # Ensure that our typelib is valid.
524 #
525 return oGenCache.EnsureModule(self.VBOX_TLB_GUID, self.VBOX_TLB_LCID, self.VBOX_TLB_MAJOR, self.VBOX_TLB_MINOR);
526
527 def getSessionObject(self, oIVBox):
528 _ = oIVBox
529 import win32com
530 from win32com.client import Dispatch
531 return win32com.client.Dispatch("VirtualBox.Session")
532
533 def getVirtualBox(self):
534 import win32com
535 from win32com.client import Dispatch
536 return win32com.client.Dispatch("VirtualBox.VirtualBox")
537
538 def getType(self):
539 return 'MSCOM'
540
541 def getArray(self, oInterface, sAttrib):
542 return oInterface.__getattr__(sAttrib)
543
544 def initPerThread(self):
545 import pythoncom
546 pythoncom.CoInitializeEx(0)
547
548 def deinitPerThread(self):
549 import pythoncom
550 pythoncom.CoUninitialize()
551
552 def createListener(self, oImplClass, dArgs):
553 if True:
554 raise Exception('no active listeners on Windows as PyGatewayBase::QueryInterface() '
555 'returns new gateway objects all the time, thus breaking EventQueue '
556 'assumptions about the listener interface pointer being constants between calls ');
557 # Did this code ever really work?
558 d = {}
559 d['BaseClass'] = oImplClass
560 d['dArgs'] = dArgs
561 d['tlb_guid'] = PlatformMSCOM.VBOX_TLB_GUID
562 d['tlb_major'] = PlatformMSCOM.VBOX_TLB_MAJOR
563 d['tlb_minor'] = PlatformMSCOM.VBOX_TLB_MINOR
564 str = ""
565 str += "import win32com.server.util\n"
566 str += "import pythoncom\n"
567
568 str += "class ListenerImpl(BaseClass):\n"
569 str += " _com_interfaces_ = ['IEventListener']\n"
570 str += " _typelib_guid_ = tlb_guid\n"
571 str += " _typelib_version_ = tlb_major, tlb_minor\n"
572 str += " _reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER\n"
573 # Maybe we'd better implement Dynamic invoke policy, to be more flexible here
574 str += " _reg_policy_spec_ = 'win32com.server.policy.EventHandlerPolicy'\n"
575
576 # capitalized version of listener method
577 str += " HandleEvent=BaseClass.handleEvent\n"
578 str += " def __init__(self): BaseClass.__init__(self, dArgs)\n"
579 str += "result = win32com.server.util.wrap(ListenerImpl())\n"
580 exec(str, d, d)
581 return d['result']
582
583 def waitForEvents(self, timeout):
584 from win32api import GetCurrentThreadId
585 from win32event import INFINITE
586 from win32event import MsgWaitForMultipleObjects, \
587 QS_ALLINPUT, WAIT_TIMEOUT, WAIT_OBJECT_0
588 from pythoncom import PumpWaitingMessages
589 import types
590
591 if not isinstance(timeout, types.IntType):
592 raise TypeError("The timeout argument is not an integer")
593 if (self.tid != GetCurrentThreadId()):
594 raise Exception("wait for events from the same thread you inited!")
595
596 if timeout < 0:
597 cMsTimeout = INFINITE
598 else:
599 cMsTimeout = timeout
600 rc = MsgWaitForMultipleObjects(self.handles, 0, cMsTimeout, QS_ALLINPUT)
601 if rc >= WAIT_OBJECT_0 and rc < WAIT_OBJECT_0+len(self.handles):
602 # is it possible?
603 rc = 2;
604 elif rc==WAIT_OBJECT_0 + len(self.handles):
605 # Waiting messages
606 PumpWaitingMessages()
607 rc = 0;
608 else:
609 # Timeout
610 rc = 1;
611
612 # check for interruption
613 self.oIntCv.acquire()
614 if self.fInterrupted:
615 self.fInterrupted = False
616 rc = 1;
617 self.oIntCv.release()
618
619 return rc;
620
621 def interruptWaitEvents(self):
622 """
623 Basically a python implementation of NativeEventQueue::postEvent().
624
625 The magic value must be in sync with the C++ implementation or this
626 won't work.
627
628 Note that because of this method we cannot easily make use of a
629 non-visible Window to handle the message like we would like to do.
630 """
631 from win32api import PostThreadMessage
632 from win32con import WM_USER
633 self.oIntCv.acquire()
634 self.fInterrupted = True
635 self.oIntCv.release()
636 try:
637 PostThreadMessage(self.tid, WM_USER, None, 0xf241b819)
638 except:
639 return False;
640 return True;
641
642 def deinit(self):
643 import pythoncom
644 from win32file import CloseHandle
645
646 for h in self.handles:
647 if h is not None:
648 CloseHandle(h)
649 self.handles = None
650 pythoncom.CoUninitialize()
651 pass
652
653 def queryInterface(self, oIUnknown, sClassName):
654 from win32com.client import CastTo
655 return CastTo(oIUnknown, sClassName)
656
657 def xcptGetStatus(self, oXcpt):
658 # The DISP_E_EXCEPTION + excptinfo fun needs checking up, only
659 # empirical info on it so far.
660 hrXcpt = oXcpt.hresult
661 if hrXcpt == self.winerror.DISP_E_EXCEPTION:
662 try: hrXcpt = oXcpt.excepinfo[5];
663 except: pass;
664 return hrXcpt;
665
666 def xcptIsDeadInterface(self, oXcpt):
667 return self.xcptGetStatus(oXcpt) in [
668 0x800706ba, -2147023174, # RPC_S_SERVER_UNAVAILABLE.
669 0x800706be, -2147023170, # RPC_S_CALL_FAILED.
670 0x800706bf, -2147023169, # RPC_S_CALL_FAILED_DNE.
671 0x80010108, -2147417848, # RPC_E_DISCONNECTED.
672 0x800706b5, -2147023179, # RPC_S_UNKNOWN_IF
673 ];
674
675
676 def xcptGetMessage(self, oXcpt):
677 if hasattr(oXcpt, 'excepinfo'):
678 try:
679 if len(oXcpt.excepinfo) >= 3:
680 sRet = oXcpt.excepinfo[2];
681 if len(sRet) > 0:
682 return sRet[0:];
683 except:
684 pass;
685 if hasattr(oXcpt, 'strerror'):
686 try:
687 sRet = oXcpt.strerror;
688 if len(sRet) > 0:
689 return sRet;
690 except:
691 pass;
692 return None;
693
694 def xcptGetBaseXcpt(self):
695 import pythoncom;
696 return pythoncom.com_error;
697
698 def xcptSetupConstants(self, oDst):
699 import winerror;
700 oDst = self.xcptCopyErrorConstants(oDst, winerror);
701
702 # XPCOM compatability constants.
703 oDst.NS_OK = oDst.S_OK;
704 oDst.NS_ERROR_FAILURE = oDst.E_FAIL;
705 oDst.NS_ERROR_ABORT = oDst.E_ABORT;
706 oDst.NS_ERROR_NULL_POINTER = oDst.E_POINTER;
707 oDst.NS_ERROR_NO_INTERFACE = oDst.E_NOINTERFACE;
708 oDst.NS_ERROR_INVALID_ARG = oDst.E_INVALIDARG;
709 oDst.NS_ERROR_OUT_OF_MEMORY = oDst.E_OUTOFMEMORY;
710 oDst.NS_ERROR_NOT_IMPLEMENTED = oDst.E_NOTIMPL;
711 oDst.NS_ERROR_UNEXPECTED = oDst.E_UNEXPECTED;
712 return oDst;
713
714
715class PlatformXPCOM(PlatformBase):
716 """
717 Platform specific code for XPCOM.
718 """
719
720 def __init__(self, dParams):
721 PlatformBase.__init__(self, dParams);
722 sys.path.append(VBoxSdkDir+'/bindings/xpcom/python/')
723 import xpcom.vboxxpcom
724 import xpcom
725 import xpcom.components
726 _ = dParams;
727
728 def getSessionObject(self, oIVBox):
729 _ = oIVBox;
730 import xpcom.components
731 return xpcom.components.classes["@virtualbox.org/Session;1"].createInstance()
732
733 def getVirtualBox(self):
734 import xpcom.components
735 return xpcom.components.classes["@virtualbox.org/VirtualBox;1"].createInstance()
736
737 def getType(self):
738 return 'XPCOM'
739
740 def getArray(self, oInterface, sAttrib):
741 return oInterface.__getattr__('get'+ComifyName(sAttrib))()
742
743 def initPerThread(self):
744 import xpcom
745 xpcom._xpcom.AttachThread()
746
747 def deinitPerThread(self):
748 import xpcom
749 xpcom._xpcom.DetachThread()
750
751 def createListener(self, oImplClass, dArgs):
752 d = {}
753 d['BaseClass'] = oImplClass
754 d['dArgs'] = dArgs
755 str = ""
756 str += "import xpcom.components\n"
757 str += "class ListenerImpl(BaseClass):\n"
758 str += " _com_interfaces_ = xpcom.components.interfaces.IEventListener\n"
759 str += " def __init__(self): BaseClass.__init__(self, dArgs)\n"
760 str += "result = ListenerImpl()\n"
761 exec (str, d, d)
762 return d['result']
763
764 def waitForEvents(self, timeout):
765 import xpcom
766 return xpcom._xpcom.WaitForEvents(timeout)
767
768 def interruptWaitEvents(self):
769 import xpcom
770 return xpcom._xpcom.InterruptWait()
771
772 def deinit(self):
773 import xpcom
774 xpcom._xpcom.DeinitCOM()
775
776 def queryInterface(self, oIUnknown, sClassName):
777 import xpcom.components
778 return oIUnknown.queryInterface(getattr(xpcom.components.interfaces, sClassName))
779
780 def xcptGetStatus(self, oXcpt):
781 return oXcpt.errno;
782
783 def xcptIsDeadInterface(self, oXcpt):
784 return self.xcptGetStatus(oXcpt) in [
785 0x80004004, -2147467260, # NS_ERROR_ABORT
786 0x800706be, -2147023170, # NS_ERROR_CALL_FAILED (RPC_S_CALL_FAILED)
787 ];
788
789 def xcptGetMessage(self, oXcpt):
790 if hasattr(oXcpt, 'msg'):
791 try:
792 sRet = oXcpt.msg;
793 if len(sRet) > 0:
794 return sRet;
795 except:
796 pass;
797 return None;
798
799 def xcptGetBaseXcpt(self):
800 import xpcom;
801 return xpcom.Exception;
802
803 def xcptSetupConstants(self, oDst):
804 import xpcom;
805 oDst = self.xcptCopyErrorConstants(oDst, xpcom.nsError);
806
807 # COM compatability constants.
808 oDst.E_ACCESSDENIED = -2147024891; # see VBox/com/defs.h
809 oDst.S_OK = oDst.NS_OK;
810 oDst.E_FAIL = oDst.NS_ERROR_FAILURE;
811 oDst.E_ABORT = oDst.NS_ERROR_ABORT;
812 oDst.E_POINTER = oDst.NS_ERROR_NULL_POINTER;
813 oDst.E_NOINTERFACE = oDst.NS_ERROR_NO_INTERFACE;
814 oDst.E_INVALIDARG = oDst.NS_ERROR_INVALID_ARG;
815 oDst.E_OUTOFMEMORY = oDst.NS_ERROR_OUT_OF_MEMORY;
816 oDst.E_NOTIMPL = oDst.NS_ERROR_NOT_IMPLEMENTED;
817 oDst.E_UNEXPECTED = oDst.NS_ERROR_UNEXPECTED;
818 oDst.DISP_E_EXCEPTION = -2147352567; # For COM compatability only.
819 return oDst;
820
821
822class PlatformWEBSERVICE(PlatformBase):
823 """
824 VirtualBox Web Services API specific code.
825 """
826
827 def __init__(self, dParams):
828 PlatformBase.__init__(self, dParams);
829 # Import web services stuff. Fix the sys.path the first time.
830 sWebServLib = os.path.join(VBoxSdkDir, 'bindings', 'webservice', 'python', 'lib');
831 if sWebServLib not in sys.path:
832 sys.path.append(sWebServLib);
833 import VirtualBox_wrappers
834 from VirtualBox_wrappers import IWebsessionManager2
835
836 # Initialize instance variables from parameters.
837 if dParams is not None:
838 self.user = dParams.get("user", "")
839 self.password = dParams.get("password", "")
840 self.url = dParams.get("url", "")
841 else:
842 self.user = ""
843 self.password = ""
844 self.url = None
845 self.vbox = None
846 self.wsmgr = None;
847
848 #
849 # Base class overrides.
850 #
851
852 def getSessionObject(self, oIVBox):
853 return self.wsmgr.getSessionObject(oIVBox)
854
855 def getVirtualBox(self):
856 return self.connect(self.url, self.user, self.password)
857
858 def getType(self):
859 return 'WEBSERVICE'
860
861 def isRemote(self):
862 """ Returns True if remote VBox host, False if local. """
863 return True
864
865 def getArray(self, oInterface, sAttrib):
866 return oInterface.__getattr__(sAttrib)
867
868 def waitForEvents(self, timeout):
869 # Webservices cannot do that yet
870 return 2;
871
872 def interruptWaitEvents(self, timeout):
873 # Webservices cannot do that yet
874 return False;
875
876 def deinit(self):
877 try:
878 disconnect()
879 except:
880 pass
881
882 def queryInterface(self, oIUnknown, sClassName):
883 d = {}
884 d['oIUnknown'] = oIUnknown
885 str = ""
886 str += "from VirtualBox_wrappers import "+sClassName+"\n"
887 str += "result = "+sClassName+"(oIUnknown.mgr, oIUnknown.handle)\n"
888 # wrong, need to test if class indeed implements this interface
889 exec (str, d, d)
890 return d['result']
891
892 #
893 # Web service specific methods.
894 #
895
896 def connect(self, url, user, passwd):
897 if self.vbox is not None:
898 self.disconnect()
899 from VirtualBox_wrappers import IWebsessionManager2
900 if url is None:
901 url = ""
902 self.url = url
903 if user is None:
904 user = ""
905 self.user = user
906 if passwd is None:
907 passwd = ""
908 self.password = passwd
909 self.wsmgr = IWebsessionManager2(self.url)
910 self.vbox = self.wsmgr.logon(self.user, self.password)
911 if not self.vbox.handle:
912 raise Exception("cannot connect to '"+self.url+"' as '"+self.user+"'")
913 return self.vbox
914
915 def disconnect(self):
916 if self.vbox is not None and self.wsmgr is not None:
917 self.wsmgr.logoff(self.vbox)
918 self.vbox = None
919 self.wsmgr = None
920
921
922## The current (last) exception class.
923# This is reinitalized whenever VirtualBoxManager is called, so it will hold
924# the reference to the error exception class for the last platform/style that
925# was used. Most clients does talk to multiple VBox instance on different
926# platforms at the same time, so this should be sufficent for most uses and
927# be way simpler to use than VirtualBoxManager::oXcptClass.
928CurXctpClass = None;
929
930
931class VirtualBoxManager(object):
932 """
933 VirtualBox API manager class.
934
935 The API users will have to instantiate this. If no parameters are given,
936 it will default to interface with the VirtualBox running on the local
937 machine. sStyle can be None (default), MSCOM, XPCOM or WEBSERVICES. Most
938 users will either be specifying None or WEBSERVICES.
939
940 The dPlatformParams is an optional dictionary for passing parameters to the
941 WEBSERVICE backend.
942 """
943
944 class Statuses(object):
945 def __init__(self):
946 pass;
947
948 def __init__(self, sStyle = None, dPlatformParams = None):
949 if sStyle is None:
950 if sys.platform == 'win32':
951 sStyle = "MSCOM"
952 else:
953 sStyle = "XPCOM"
954 if sStyle == 'XPCOM':
955 self.platform = PlatformXPCOM(dPlatformParams);
956 elif sStyle == 'MSCOM':
957 self.platform = PlatformMSCOM(dPlatformParams);
958 elif sStyle == 'WEBSERVICE':
959 self.platform = PlatformWEBSERVICE(dPlatformParams);
960 else:
961 raise Exception('Unknown sStyle=%s' % (sStyle,));
962 self.style = sStyle
963 self.type = self.platform.getType()
964 self.remote = self.platform.isRemote()
965 ## VirtualBox API constants (for webservices, enums are symbolic).
966 self.constants = VirtualBoxReflectionInfo(sStyle == "WEBSERVICE")
967
968 ## Status constants.
969 self.statuses = self.platform.xcptSetupConstants(VirtualBoxManager.Statuses());
970 ## @todo Add VBOX_E_XXX to statuses? They're already in constants...
971 ## Dictionary for errToString, built on demand.
972 self._dErrorValToName = None;
973
974 ## The exception class for the selected platform.
975 self.oXcptClass = self.platform.xcptGetBaseXcpt();
976 global CurXcptClass;
977 CurXcptClass = self.oXcptClass;
978
979 # Get the virtualbox singleton.
980 try:
981 self.vbox = self.platform.getVirtualBox()
982 except NameError, ne:
983 print "Installation problem: check that appropriate libs in place"
984 traceback.print_exc()
985 raise ne
986 except Exception, e:
987 print "init exception: ", e
988 traceback.print_exc()
989 if self.remote:
990 self.vbox = None
991 else:
992 raise e
993 ## @deprecated
994 # This used to refer to a session manager class with only one method
995 # called getSessionObject. The method has moved into this call.
996 self.mgr = self;
997
998 def __del__(self):
999 self.deinit()
1000
1001 def getPythonApiRevision(self):
1002 """
1003 Returns a Python API revision number.
1004 This will be incremented when features are added to this file.
1005 """
1006 return 3;
1007
1008
1009 #
1010 # Wrappers for self.platform methods.
1011 #
1012
1013 def getVirtualBox(self):
1014 """ See PlatformBase::getVirtualBox(). """
1015 return self.platform.getVirtualBox()
1016
1017 def getSessionObject(self, oIVBox):
1018 """ See PlatformBase::getSessionObject(). """
1019 return self.platform.getSessionObject(oIVBox);
1020
1021 def getArray(self, oInterface, sAttrib):
1022 """ See PlatformBase::getArray(). """
1023 return self.platform.getArray(oInterface, sAttrib)
1024
1025 def createListener(self, oImplClass, dArgs = None):
1026 """ See PlatformBase::createListener(). """
1027 return self.platform.createListener(oImplClass, dArgs)
1028
1029 def waitForEvents(self, cMsTimeout):
1030 """ See PlatformBase::waitForEvents(). """
1031 return self.platform.waitForEvents(cMsTimeout)
1032
1033 def interruptWaitEvents(self):
1034 """ See PlatformBase::interruptWaitEvents(). """
1035 return self.platform.interruptWaitEvents()
1036
1037 def queryInterface(self, oIUnknown, sClassName):
1038 """ See PlatformBase::queryInterface(). """
1039 return self.platform.queryInterface(oIUnknown, sClassName)
1040
1041
1042 #
1043 # Init and uninit.
1044 #
1045
1046 def initPerThread(self):
1047 """ See PlatformBase::deinitPerThread(). """
1048 self.platform.initPerThread()
1049
1050 def deinitPerThread(self):
1051 """ See PlatformBase::deinitPerThread(). """
1052 return self.platform.deinitPerThread()
1053
1054 def deinit(self):
1055 """
1056 For unitializing the manager.
1057 Do not access it after calling this method.
1058 """
1059 if hasattr(self, "vbox"):
1060 del self.vbox
1061 self.vbox = None
1062 if hasattr(self, "platform"):
1063 self.platform.deinit()
1064 self.platform = None
1065 return True;
1066
1067
1068 #
1069 # Utility methods.
1070 #
1071
1072 def openMachineSession(self, oIMachine, fPermitSharing = True):
1073 """
1074 Attemts to open the a session to the machine.
1075 Returns a session object on success.
1076 Raises exception on failure.
1077 """
1078 oSession = self.mgr.getSessionObject(self.vbox);
1079 if fPermitSharing:
1080 type = self.constants.LockType_Shared;
1081 else:
1082 type = self.constants.LockType_Write;
1083 oIMachine.lockMachine(oSession, type);
1084 return oSession;
1085
1086 def closeMachineSession(self, oSession):
1087 """
1088 Closes a session opened by openMachineSession.
1089 Ignores None parameters.
1090 """
1091 if oSession is not None:
1092 oSession.unlockMachine()
1093 return True;
1094
1095 def getPerfCollector(self, oIVBox):
1096 """
1097 Returns a helper class (PerfCollector) for accessing performance
1098 collector goodies. See PerfCollector for details.
1099 """
1100 return PerfCollector(self, oIVBox)
1101
1102 def getBinDir(self):
1103 """
1104 Returns the VirtualBox binary directory.
1105 """
1106 global VBoxBinDir
1107 return VBoxBinDir
1108
1109 def getSdkDir(self):
1110 """
1111 Returns the VirtualBox SDK directory.
1112 """
1113 global VBoxSdkDir
1114 return VBoxSdkDir
1115
1116
1117 #
1118 # Error code utilities.
1119 #
1120
1121 ## @todo port to webservices!
1122
1123 def xcptGetStatus(self, oXcpt = None):
1124 """
1125 Gets the status code from an exception. If the exception parameter
1126 isn't specified, the current exception is examined.
1127 """
1128 if oXcpt is None:
1129 oXcpt = sys.exc_info()[1];
1130 return self.platform.xcptGetStatus(oXcpt);
1131
1132 def xcptIsDeadInterface(self, oXcpt = None):
1133 """
1134 Returns True if the exception indicates that the interface is dead,
1135 False if not. If the exception parameter isn't specified, the current
1136 exception is examined.
1137 """
1138 if oXcpt is None:
1139 oXcpt = sys.exc_info()[1];
1140 return self.platform.xcptIsDeadInterface(oXcpt);
1141
1142 def xcptIsOurXcptKind(self, oXcpt = None):
1143 """
1144 Checks if the exception is one that could come from the VBox API. If
1145 the exception parameter isn't specified, the current exception is
1146 examined.
1147 """
1148 if self.oXcptClass is None: ## @todo find the exception class for web services!
1149 return False;
1150 if oXcpt is None:
1151 oXcpt = sys.exc_info()[1];
1152 return isinstance(oXcpt, self.oXcptClass);
1153
1154 def xcptIsEqual(self, oXcpt, hrStatus):
1155 """
1156 Checks if the exception oXcpt is equal to the COM/XPCOM status code
1157 hrStatus.
1158
1159 The oXcpt parameter can be any kind of object, we'll just return True
1160 if it doesn't behave like a our exception class. If it's None, we'll
1161 query the current exception and examine that.
1162
1163 Will not raise any exception as long as hrStatus and self are not bad.
1164 """
1165 if oXcpt is None:
1166 oXcpt = sys.exc_info()[1];
1167 return self.platform.xcptIsEqual(oXcpt, hrStatus);
1168
1169 def xcptIsNotEqual(self, oXcpt, hrStatus):
1170 """
1171 Negated xcptIsEqual.
1172 """
1173 return not self.xcptIsEqual(oXcpt, hrStatus);
1174
1175 def xcptToString(self, hrStatusOrXcpt = None):
1176 """
1177 Converts the specified COM status code, or the status code of the
1178 specified exception, to a C constant string. If the parameter isn't
1179 specified (is None), the current exception is examined.
1180 """
1181
1182 # Deal with exceptions.
1183 if hrStatusOrXcpt is None or self.xcptIsOurXcptKind(hrStatusOrXcpt):
1184 hrStatus = self.xcptGetStatus(hrStatusOrXcpt);
1185 else:
1186 hrStatus = hrStatusOrXcpt;
1187
1188 # Build the dictionary on demand.
1189 if self._dErrorValToName is None:
1190 dErrorValToName = dict();
1191 for sKey in dir(self.statuses):
1192 if sKey[0].isupper():
1193 oValue = getattr(self.statuses, sKey);
1194 if type(oValue) is int:
1195 dErrorValToName[oValue] = sKey;
1196 self._dErrorValToName = dErrorValToName;
1197
1198 # Do the lookup, falling back on formatting the status number.
1199 try:
1200 sStr = self._dErrorValToName[int(hrStatus)];
1201 except KeyError:
1202 hrLong = long(hrStatus);
1203 sStr = '%#x (%d)' % (hrLong, hrLong);
1204 return sStr;
1205
1206 def xcptGetMessage(self, oXcpt = None):
1207 """
1208 Returns the best error message found in the COM-like exception. If the
1209 exception parameter isn't specified, the current exception is examined.
1210 """
1211 if oXcpt is None:
1212 oXcpt = sys.exc_info()[1];
1213 sRet = self.platform.xcptGetMessage(oXcpt);
1214 if sRet is None:
1215 sRet = self.xcptToString(oXcpt);
1216 return sRet;
1217
1218 # Legacy, remove in a day or two.
1219 errGetStatus = xcptGetStatus
1220 errIsDeadInterface = xcptIsDeadInterface
1221 errIsOurXcptKind = xcptIsOurXcptKind
1222 errGetMessage = xcptGetMessage
1223
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