VirtualBox

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

Last change on this file since 31607 was 31607, checked in by vboxsync, 14 years ago

vboxapi.py: Made tdPython1.py work on windows.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.0 KB
Line 
1#
2# Copyright (C) 2009 Oracle Corporation
3#
4# This file is part of VirtualBox Open Source Edition (OSE), as
5# available from http://www.virtualbox.org. This file is free software;
6# you can redistribute it and/or modify it under the terms of the GNU
7# General Public License (GPL) as published by the Free Software
8# Foundation, in version 2 as it comes in the "COPYING" file of the
9# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
10# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
11#
12import sys,os
13import traceback
14
15# To set Python bitness on OSX use 'export VERSIONER_PYTHON_PREFER_32_BIT=yes'
16
17VboxBinDir = os.environ.get("VBOX_PROGRAM_PATH", None)
18VboxSdkDir = os.environ.get("VBOX_SDK_PATH", None)
19
20if VboxBinDir is None:
21 # Will be set by the installer
22 VboxBinDir = "%VBOX_INSTALL_PATH%"
23
24if VboxSdkDir is None:
25 # Will be set by the installer
26 VboxSdkDir = "%VBOX_SDK_PATH%"
27
28os.environ["VBOX_PROGRAM_PATH"] = VboxBinDir
29os.environ["VBOX_SDK_PATH"] = VboxSdkDir
30sys.path.append(VboxBinDir)
31
32from VirtualBox_constants import VirtualBoxReflectionInfo
33
34class PerfCollector:
35 """ This class provides a wrapper over IPerformanceCollector in order to
36 get more 'pythonic' interface.
37
38 To begin collection of metrics use setup() method.
39
40 To get collected data use query() method.
41
42 It is possible to disable metric collection without changing collection
43 parameters with disable() method. The enable() method resumes metric
44 collection.
45 """
46
47 def __init__(self, mgr, vbox):
48 """ Initializes the instance.
49
50 """
51 self.mgr = mgr
52 self.isMscom = (mgr.type == 'MSCOM')
53 self.collector = vbox.performanceCollector
54
55 def setup(self, names, objects, period, nsamples):
56 """ Discards all previously collected values for the specified
57 metrics, sets the period of collection and the number of retained
58 samples, enables collection.
59 """
60 self.collector.setupMetrics(names, objects, period, nsamples)
61
62 def enable(self, names, objects):
63 """ Resumes metric collection for the specified metrics.
64 """
65 self.collector.enableMetrics(names, objects)
66
67 def disable(self, names, objects):
68 """ Suspends metric collection for the specified metrics.
69 """
70 self.collector.disableMetrics(names, objects)
71
72 def query(self, names, objects):
73 """ Retrieves collected metric values as well as some auxiliary
74 information. Returns an array of dictionaries, one dictionary per
75 metric. Each dictionary contains the following entries:
76 'name': metric name
77 'object': managed object this metric associated with
78 'unit': unit of measurement
79 'scale': divide 'values' by this number to get float numbers
80 'values': collected data
81 'values_as_string': pre-processed values ready for 'print' statement
82 """
83 # Get around the problem with input arrays returned in output
84 # parameters (see #3953) for MSCOM.
85 if self.isMscom:
86 (values, names, objects, names_out, objects_out, units, scales, sequence_numbers,
87 indices, lengths) = self.collector.queryMetricsData(names, objects)
88 else:
89 (values, names_out, objects_out, units, scales, sequence_numbers,
90 indices, lengths) = self.collector.queryMetricsData(names, objects)
91 out = []
92 for i in xrange(0, len(names_out)):
93 scale = int(scales[i])
94 if scale != 1:
95 fmt = '%.2f%s'
96 else:
97 fmt = '%d %s'
98 out.append({
99 'name':str(names_out[i]),
100 'object':str(objects_out[i]),
101 'unit':str(units[i]),
102 'scale':scale,
103 'values':[int(values[j]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))],
104 'values_as_string':'['+', '.join([fmt % (int(values[j])/scale, units[i]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))])+']'
105 })
106 return out
107
108def ComifyName(name):
109 return name[0].capitalize()+name[1:]
110
111_COMForward = { 'getattr' : None,
112 'setattr' : None}
113
114def CustomGetAttr(self, attr):
115 # fastpath
116 if self.__class__.__dict__.get(attr) != None:
117 return self.__class__.__dict__.get(attr)
118
119 # try case-insensitivity workaround for class attributes (COM methods)
120 for k in self.__class__.__dict__.keys():
121 if k.lower() == attr.lower():
122 self.__class__.__dict__[attr] = self.__class__.__dict__[k]
123 return getattr(self, k)
124 try:
125 return _COMForward['getattr'](self,ComifyName(attr))
126 except AttributeError:
127 return _COMForward['getattr'](self,attr)
128
129def CustomSetAttr(self, attr, value):
130 try:
131 return _COMForward['setattr'](self, ComifyName(attr), value)
132 except AttributeError:
133 return _COMForward['setattr'](self, attr, value)
134
135class PlatformMSCOM:
136 # Class to fake access to constants in style of foo.bar.boo
137 class ConstantFake:
138 def __init__(self, parent, name):
139 self.__dict__['_parent'] = parent
140 self.__dict__['_name'] = name
141 self.__dict__['_consts'] = {}
142 try:
143 self.__dict__['_depth']=parent.__dict__['_depth']+1
144 except:
145 self.__dict__['_depth']=0
146 if self.__dict__['_depth'] > 4:
147 raise AttributeError
148
149 def __getattr__(self, attr):
150 import win32com
151 from win32com.client import constants
152
153 if attr.startswith("__"):
154 raise AttributeError
155
156 consts = self.__dict__['_consts']
157
158 fake = consts.get(attr, None)
159 if fake != None:
160 return fake
161 try:
162 name = self.__dict__['_name']
163 parent = self.__dict__['_parent']
164 while parent != None:
165 if parent._name is not None:
166 name = parent._name+'_'+name
167 parent = parent._parent
168
169 if name is not None:
170 name += "_" + attr
171 else:
172 name = attr
173 return win32com.client.constants.__getattr__(name)
174 except AttributeError,e:
175 fake = PlatformMSCOM.ConstantFake(self, attr)
176 consts[attr] = fake
177 return fake
178
179
180 class InterfacesWrapper:
181 def __init__(self):
182 self.__dict__['_rootFake'] = PlatformMSCOM.ConstantFake(None, None)
183
184 def __getattr__(self, a):
185 import win32com
186 from win32com.client import constants
187 if a.startswith("__"):
188 raise AttributeError
189 try:
190 return win32com.client.constants.__getattr__(a)
191 except AttributeError,e:
192 return self.__dict__['_rootFake'].__getattr__(a)
193
194 VBOX_TLB_GUID = '{46137EEC-703B-4FE5-AFD4-7C9BBBBA0259}'
195 VBOX_TLB_LCID = 0
196 VBOX_TLB_MAJOR = 1
197 VBOX_TLB_MINOR = 0
198
199 def __init__(self, params):
200 from win32com import universal
201 from win32com.client import gencache, DispatchBaseClass
202 from win32com.client import constants, getevents
203 import win32com
204 import pythoncom
205 import win32api
206 from win32con import DUPLICATE_SAME_ACCESS
207 from win32api import GetCurrentThread,GetCurrentThreadId,DuplicateHandle,GetCurrentProcess
208 import threading
209 pid = GetCurrentProcess()
210 self.tid = GetCurrentThreadId()
211 handle = DuplicateHandle(pid, GetCurrentThread(), pid, 0, 0, DUPLICATE_SAME_ACCESS)
212 self.handles = []
213 self.handles.append(handle)
214 _COMForward['getattr'] = DispatchBaseClass.__dict__['__getattr__']
215 DispatchBaseClass.__dict__['__getattr__'] = CustomGetAttr
216 _COMForward['setattr'] = DispatchBaseClass.__dict__['__setattr__']
217 DispatchBaseClass.__dict__['__setattr__'] = CustomSetAttr
218 win32com.client.gencache.EnsureDispatch('VirtualBox.Session')
219 win32com.client.gencache.EnsureDispatch('VirtualBox.VirtualBox')
220 self.oIntCv = threading.Condition()
221 self.fInterrupted = False;
222
223 def getSessionObject(self, vbox):
224 import win32com
225 from win32com.client import Dispatch
226 return win32com.client.Dispatch("VirtualBox.Session")
227
228 def getVirtualBox(self):
229 import win32com
230 from win32com.client import Dispatch
231 return win32com.client.Dispatch("VirtualBox.VirtualBox")
232
233 def getType(self):
234 return 'MSCOM'
235
236 def getRemote(self):
237 return False
238
239 def getArray(self, obj, field):
240 return obj.__getattr__(field)
241
242 def initPerThread(self):
243 import pythoncom
244 pythoncom.CoInitializeEx(0)
245
246 def deinitPerThread(self):
247 import pythoncom
248 pythoncom.CoUninitialize()
249
250 def createListener(self, impl, arg):
251 d = {}
252 d['BaseClass'] = impl
253 d['arg'] = arg
254 d['tlb_guid'] = PlatformMSCOM.VBOX_TLB_GUID
255 str = ""
256 str += "import win32com.server.util\n"
257 str += "import pythoncom\n"
258
259 str += "class ListenerImpl(BaseClass):\n"
260 str += " _com_interfaces_ = ['IEventListener']\n"
261 str += " _typelib_guid_ = tlb_guid\n"
262 str += " _typelib_version_ = 1, 0\n"
263 str += " _reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER\n"
264 # Maybe we'd better implement Dynamic invoke policy, to be more flexible here
265 str += " _reg_policy_spec_ = 'win32com.server.policy.EventHandlerPolicy'\n"
266
267 # capitalized version of listener method
268 str += " HandleEvent=BaseClass.handleEvent\n"
269 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
270 str += "result = win32com.server.util.wrap(ListenerImpl())\n"
271 exec (str,d,d)
272 return d['result']
273
274 def waitForEvents(self, timeout):
275 from win32api import GetCurrentThreadId
276 from win32event import INFINITE
277 from win32event import MsgWaitForMultipleObjects, \
278 QS_ALLINPUT, WAIT_TIMEOUT, WAIT_OBJECT_0
279 from pythoncom import PumpWaitingMessages
280 import types
281
282 if not isinstance(timeout, types.IntType):
283 raise TypeError("The timeout argument is not an integer")
284 if (self.tid != GetCurrentThreadId()):
285 raise Exception("wait for events from the same thread you inited!")
286
287 if timeout < 0: cMsTimeout = INFINITE
288 else: cMsTimeout = timeout
289 rc = MsgWaitForMultipleObjects(self.handles, 0, cMsTimeout, QS_ALLINPUT)
290 if rc >= WAIT_OBJECT_0 and rc < WAIT_OBJECT_0+len(self.handles):
291 # is it possible?
292 rc = 2;
293 elif rc==WAIT_OBJECT_0 + len(self.handles):
294 # Waiting messages
295 PumpWaitingMessages()
296 rc = 0;
297 else:
298 # Timeout
299 rc = 1;
300
301 # check for interruption
302 self.oIntCv.acquire()
303 if self.fInterrupted:
304 self.fInterrupted = False
305 rc = 1;
306 self.oIntCv.release()
307
308 return rc;
309
310 def interruptWaitEvents(self):
311 """
312 Basically a python implementation of EventQueue::postEvent().
313
314 The magic value must be in sync with the C++ implementation or this
315 won't work.
316
317 Note that because of this method we cannot easily make use of a
318 non-visible Window to handle the message like we would like to do.
319 """
320 from win32api import PostThreadMessage
321 from win32con import WM_USER
322 self.oIntCv.acquire()
323 self.fInterrupted = True
324 self.oIntCv.release()
325 try:
326 PostThreadMessage(self.tid, WM_USER, None, 0xf241b819)
327 except:
328 return False;
329 return True;
330
331 def deinit(self):
332 import pythoncom
333 from win32file import CloseHandle
334
335 for h in self.handles:
336 if h is not None:
337 CloseHandle(h)
338 self.handles = None
339 pythoncom.CoUninitialize()
340 pass
341
342 def queryInterface(self, obj, klazzName):
343 from win32com.client import CastTo
344 return CastTo(obj, klazzName)
345
346class PlatformXPCOM:
347 def __init__(self, params):
348 sys.path.append(VboxSdkDir+'/bindings/xpcom/python/')
349 import xpcom.vboxxpcom
350 import xpcom
351 import xpcom.components
352
353 def getSessionObject(self, vbox):
354 import xpcom.components
355 return xpcom.components.classes["@virtualbox.org/Session;1"].createInstance()
356
357 def getVirtualBox(self):
358 import xpcom.components
359 return xpcom.components.classes["@virtualbox.org/VirtualBox;1"].createInstance()
360
361 def getType(self):
362 return 'XPCOM'
363
364 def getRemote(self):
365 return False
366
367 def getArray(self, obj, field):
368 return obj.__getattr__('get'+ComifyName(field))()
369
370 def initPerThread(self):
371 import xpcom
372 xpcom._xpcom.AttachThread()
373
374 def deinitPerThread(self):
375 import xpcom
376 xpcom._xpcom.DetachThread()
377
378 def createListener(self, impl, arg):
379 d = {}
380 d['BaseClass'] = impl
381 d['arg'] = arg
382 str = ""
383 str += "import xpcom.components\n"
384 str += "class ListenerImpl(BaseClass):\n"
385 str += " _com_interfaces_ = xpcom.components.interfaces.IEventListener\n"
386 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
387 str += "result = ListenerImpl()\n"
388 exec (str,d,d)
389 return d['result']
390
391 def waitForEvents(self, timeout):
392 import xpcom
393 return xpcom._xpcom.WaitForEvents(timeout)
394
395 def interruptWaitEvents(self):
396 import xpcom
397 return xpcom._xpcom.InterruptWait()
398
399 def deinit(self):
400 import xpcom
401 xpcom._xpcom.DeinitCOM()
402
403 def queryInterface(self, obj, klazzName):
404 import xpcom.components
405 return obj.queryInterface(getattr(xpcom.components.interfaces, klazzName))
406
407class PlatformWEBSERVICE:
408 def __init__(self, params):
409 sys.path.append(os.path.join(VboxSdkDir,'bindings', 'webservice', 'python', 'lib'))
410 # not really needed, but just fail early if misconfigured
411 import VirtualBox_services
412 import VirtualBox_wrappers
413 from VirtualBox_wrappers import IWebsessionManager2
414
415 if params is not None:
416 self.user = params.get("user", "")
417 self.password = params.get("password", "")
418 self.url = params.get("url", "")
419 else:
420 self.user = ""
421 self.password = ""
422 self.url = None
423 self.vbox = None
424
425 def getSessionObject(self, vbox):
426 return self.wsmgr.getSessionObject(vbox)
427
428 def getVirtualBox(self):
429 return self.connect(self.url, self.user, self.password)
430
431 def connect(self, url, user, passwd):
432 if self.vbox is not None:
433 self.disconnect()
434 from VirtualBox_wrappers import IWebsessionManager2
435 if url is None:
436 url = ""
437 self.url = url
438 if user is None:
439 user = ""
440 self.user = user
441 if passwd is None:
442 passwd = ""
443 self.password = passwd
444 self.wsmgr = IWebsessionManager2(self.url)
445 self.vbox = self.wsmgr.logon(self.user, self.password)
446 if not self.vbox.handle:
447 raise Exception("cannot connect to '"+self.url+"' as '"+self.user+"'")
448 return self.vbox
449
450 def disconnect(self):
451 if self.vbox is not None and self.wsmgr is not None:
452 self.wsmgr.logoff(self.vbox)
453 self.vbox = None
454 self.wsmgr = None
455
456 def getType(self):
457 return 'WEBSERVICE'
458
459 def getRemote(self):
460 return True
461
462 def getArray(self, obj, field):
463 return obj.__getattr__(field)
464
465 def initPerThread(self):
466 pass
467
468 def deinitPerThread(self):
469 pass
470
471 def createListener(self, impl, arg):
472 raise Exception("no active listeners for webservices")
473
474 def waitForEvents(self, timeout):
475 # Webservices cannot do that yet
476 return 2;
477
478 def interruptWaitEvents(self, timeout):
479 # Webservices cannot do that yet
480 return False;
481
482 def deinit(self):
483 try:
484 disconnect()
485 except:
486 pass
487
488 def queryInterface(self, obj, klazzName):
489 d = {}
490 d['obj'] = obj
491 str = ""
492 str += "from VirtualBox_wrappers import "+klazzName+"\n"
493 str += "result = "+klazzName+"(obj.mgr,obj.handle)\n"
494 # wrong, need to test if class indeed implements this interface
495 exec (str,d,d)
496 return d['result']
497
498class SessionManager:
499 def __init__(self, mgr):
500 self.mgr = mgr
501
502 def getSessionObject(self, vbox):
503 return self.mgr.platform.getSessionObject(vbox)
504
505class VirtualBoxManager:
506 def __init__(self, style, platparams):
507 if style is None:
508 if sys.platform == 'win32':
509 style = "MSCOM"
510 else:
511 style = "XPCOM"
512
513
514 exec "self.platform = Platform"+style+"(platparams)"
515 # for webservices, enums are symbolic
516 self.constants = VirtualBoxReflectionInfo(style == "WEBSERVICE")
517 self.type = self.platform.getType()
518 self.remote = self.platform.getRemote()
519 self.style = style
520 self.mgr = SessionManager(self)
521
522 try:
523 self.vbox = self.platform.getVirtualBox()
524 except NameError,ne:
525 print "Installation problem: check that appropriate libs in place"
526 traceback.print_exc()
527 raise ne
528 except Exception,e:
529 print "init exception: ",e
530 traceback.print_exc()
531 if self.remote:
532 self.vbox = None
533 else:
534 raise e
535
536 def getArray(self, obj, field):
537 return self.platform.getArray(obj, field)
538
539 def getVirtualBox(self):
540 return self.platform.getVirtualBox()
541
542 def __del__(self):
543 self.deinit()
544
545 def deinit(self):
546 if hasattr(self, "vbox"):
547 del self.vbox
548 self.vbox = None
549 if hasattr(self, "platform"):
550 self.platform.deinit()
551 self.platform = None
552
553 def initPerThread(self):
554 self.platform.initPerThread()
555
556 def openMachineSession(self, mach, permitSharing = True):
557 session = self.mgr.getSessionObject(self.vbox)
558 if permitSharing:
559 type = self.constants.LockType_Shared
560 else:
561 type = self.constants.LockType_Write
562 mach.lockMachine(session, type)
563 return session
564
565 def closeMachineSession(self, session):
566 if session is not None:
567 session.unlockMachine()
568
569 def deinitPerThread(self):
570 self.platform.deinitPerThread()
571
572 def createListener(self, impl, arg = None):
573 return self.platform.createListener(impl, arg)
574
575 def waitForEvents(self, timeout):
576 """
577 Wait for events to arrive and process them.
578
579 The timeout is in milliseconds. A negative value means waiting for
580 ever, while 0 does not wait at all.
581
582 Returns 0 if events was processed.
583 Returns 1 if timed out or interrupted in some way.
584 Returns 2 on error (like not supported for web services).
585
586 Raises an exception if the calling thread is not the main thread (the one
587 that initialized VirtualBoxManager) or if the time isn't an integer.
588 """
589 return self.platform.waitForEvents(timeout)
590
591 def interruptWaitEvents(self):
592 """
593 Interrupt a waitForEvents call.
594 This is normally called from a worker thread.
595
596 Returns True on success, False on failure.
597 """
598 return self.platform.interruptWaitEvents()
599
600 def getPerfCollector(self, vbox):
601 return PerfCollector(self, vbox)
602
603 def getBinDir(self):
604 global VboxBinDir
605 return VboxBinDir
606
607 def getSdkDir(self):
608 global VboxSdkDir
609 return VboxSdkDir
610
611 def queryInterface(self, obj, klazzName):
612 return self.platform.queryInterface(obj, klazzName)
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