VirtualBox

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

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

Main, Python glue: Windows updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.3 KB
Line 
1#
2# Copyright (C) 2009 Sun Microsystems, Inc.
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#
12# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
13# Clara, CA 95054 USA or visit http://www.sun.com if you need
14# additional information or have any questions.
15#
16import sys,os
17import traceback
18
19VboxBinDir = os.environ.get("VBOX_PROGRAM_PATH", None)
20VboxSdkDir = os.environ.get("VBOX_SDK_PATH", None)
21
22if VboxBinDir is None:
23 # Will be set by the installer
24 VboxBinDir = "%VBOX_INSTALL_PATH%"
25
26if VboxSdkDir is None:
27 VboxSdkDir = os.path.join(VboxBinDir,"sdk")
28
29os.environ["VBOX_PROGRAM_PATH"] = VboxBinDir
30os.environ["VBOX_SDK_PATH"] = VboxSdkDir
31sys.path.append(VboxBinDir)
32
33from VirtualBox_constants import VirtualBoxReflectionInfo
34
35class PerfCollector:
36 """ This class provides a wrapper over IPerformanceCollector in order to
37 get more 'pythonic' interface.
38
39 To begin collection of metrics use setup() method.
40
41 To get collected data use query() method.
42
43 It is possible to disable metric collection without changing collection
44 parameters with disable() method. The enable() method resumes metric
45 collection.
46 """
47
48 def __init__(self, mgr, vbox):
49 """ Initializes the instance.
50
51 """
52 self.mgr = mgr
53 self.isMscom = (mgr.type == 'MSCOM')
54 self.collector = vbox.performanceCollector
55
56 def setup(self, names, objects, period, nsamples):
57 """ Discards all previously collected values for the specified
58 metrics, sets the period of collection and the number of retained
59 samples, enables collection.
60 """
61 self.collector.setupMetrics(names, objects, period, nsamples)
62
63 def enable(self, names, objects):
64 """ Resumes metric collection for the specified metrics.
65 """
66 self.collector.enableMetrics(names, objects)
67
68 def disable(self, names, objects):
69 """ Suspends metric collection for the specified metrics.
70 """
71 self.collector.disableMetrics(names, objects)
72
73 def query(self, names, objects):
74 """ Retrieves collected metric values as well as some auxiliary
75 information. Returns an array of dictionaries, one dictionary per
76 metric. Each dictionary contains the following entries:
77 'name': metric name
78 'object': managed object this metric associated with
79 'unit': unit of measurement
80 'scale': divide 'values' by this number to get float numbers
81 'values': collected data
82 'values_as_string': pre-processed values ready for 'print' statement
83 """
84 # Get around the problem with input arrays returned in output
85 # parameters (see #3953) for MSCOM.
86 if self.isMscom:
87 (values, names, objects, names_out, objects_out, units, scales, sequence_numbers,
88 indices, lengths) = self.collector.queryMetricsData(names, objects)
89 else:
90 (values, names_out, objects_out, units, scales, sequence_numbers,
91 indices, lengths) = self.collector.queryMetricsData(names, objects)
92 out = []
93 for i in xrange(0, len(names_out)):
94 scale = int(scales[i])
95 if scale != 1:
96 fmt = '%.2f%s'
97 else:
98 fmt = '%d %s'
99 out.append({
100 'name':str(names_out[i]),
101 'object':str(objects_out[i]),
102 'unit':str(units[i]),
103 'scale':scale,
104 'values':[int(values[j]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))],
105 'values_as_string':'['+', '.join([fmt % (int(values[j])/scale, units[i]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))])+']'
106 })
107 return out
108
109def ComifyName(name):
110 return name[0].capitalize()+name[1:]
111
112_COMForward = { 'getattr' : None,
113 'setattr' : None}
114
115def CustomGetAttr(self, attr):
116 # fastpath
117 if self.__class__.__dict__.get(attr) != None:
118 return self.__class__.__dict__.get(attr)
119
120 # try case-insensitivity workaround for class attributes (COM methods)
121 for k in self.__class__.__dict__.keys():
122 if k.lower() == attr.lower():
123 self.__class__.__dict__[attr] = self.__class__.__dict__[k]
124 return getattr(self, k)
125 try:
126 return _COMForward['getattr'](self,ComifyName(attr))
127 except AttributeError:
128 return _COMForward['getattr'](self,attr)
129
130def CustomSetAttr(self, attr, value):
131 try:
132 return _COMForward['setattr'](self, ComifyName(attr), value)
133 except AttributeError:
134 return _COMForward['setattr'](self, attr, value)
135
136class PlatformMSCOM:
137 # Class to fake access to constants in style of foo.bar.boo
138 class ConstantFake:
139 def __init__(self, parent, name):
140 self.__dict__['_parent'] = parent
141 self.__dict__['_name'] = name
142 self.__dict__['_consts'] = {}
143 try:
144 self.__dict__['_depth']=parent.__dict__['_depth']+1
145 except:
146 self.__dict__['_depth']=0
147 if self.__dict__['_depth'] > 4:
148 raise AttributeError
149
150 def __getattr__(self, attr):
151 import win32com
152 from win32com.client import constants
153
154 if attr.startswith("__"):
155 raise AttributeError
156
157 consts = self.__dict__['_consts']
158
159 fake = consts.get(attr, None)
160 if fake != None:
161 return fake
162 try:
163 name = self.__dict__['_name']
164 parent = self.__dict__['_parent']
165 while parent != None:
166 if parent._name is not None:
167 name = parent._name+'_'+name
168 parent = parent._parent
169
170 if name is not None:
171 name += "_" + attr
172 else:
173 name = attr
174 return win32com.client.constants.__getattr__(name)
175 except AttributeError,e:
176 fake = PlatformMSCOM.ConstantFake(self, attr)
177 consts[attr] = fake
178 return fake
179
180
181 class InterfacesWrapper:
182 def __init__(self):
183 self.__dict__['_rootFake'] = PlatformMSCOM.ConstantFake(None, None)
184
185 def __getattr__(self, a):
186 import win32com
187 from win32com.client import constants
188 if a.startswith("__"):
189 raise AttributeError
190 try:
191 return win32com.client.constants.__getattr__(a)
192 except AttributeError,e:
193 return self.__dict__['_rootFake'].__getattr__(a)
194
195 VBOX_TLB_GUID = '{46137EEC-703B-4FE5-AFD4-7C9BBBBA0259}'
196 VBOX_TLB_LCID = 0
197 VBOX_TLB_MAJOR = 1
198 VBOX_TLB_MINOR = 0
199
200 def __init__(self, params):
201 from win32com import universal
202 from win32com.client import gencache, DispatchBaseClass
203 from win32com.client import constants, getevents
204 import win32com
205 import pythoncom
206 import win32api
207 from win32con import DUPLICATE_SAME_ACCESS
208 from win32api import GetCurrentThread,GetCurrentThreadId,DuplicateHandle,GetCurrentProcess
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 win32com.client.gencache.EnsureDispatch('VirtualBox.CallbackWrapper')
221
222 def getSessionObject(self, vbox):
223 import win32com
224 from win32com.client import Dispatch
225 return win32com.client.Dispatch("VirtualBox.Session")
226
227 def getVirtualBox(self):
228 import win32com
229 from win32com.client import Dispatch
230 return win32com.client.Dispatch("VirtualBox.VirtualBox")
231
232 def getType(self):
233 return 'MSCOM'
234
235 def getRemote(self):
236 return False
237
238 def getArray(self, obj, field):
239 return obj.__getattr__(field)
240
241 def initPerThread(self):
242 import pythoncom
243 pythoncom.CoInitializeEx(0)
244
245 def deinitPerThread(self):
246 import pythoncom
247 pythoncom.CoUninitialize()
248
249 def createCallback(self, iface, impl, arg):
250 d = {}
251 d['BaseClass'] = impl
252 d['arg'] = arg
253 d['tlb_guid'] = PlatformMSCOM.VBOX_TLB_GUID
254 str = ""
255 str += "import win32com.server.util\n"
256 str += "import pythoncom\n"
257
258 str += "class "+iface+"Impl(BaseClass):\n"
259 str += " _com_interfaces_ = ['"+iface+"']\n"
260 str += " _typelib_guid_ = tlb_guid\n"
261 str += " _typelib_version_ = 1, 0\n"
262 str += " _reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER\n"
263 # Maybe we'd better implement Dynamic invoke policy, to be more flexible here
264 str += " _reg_policy_spec_ = 'win32com.server.policy.EventHandlerPolicy'\n"
265
266 # generate capitalized version of callback methods -
267 # that's how Python COM looks them up
268 for m in dir(impl):
269 if m.startswith("on"):
270 str += " "+ComifyName(m)+"=BaseClass."+m+"\n"
271
272 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
273 str += "result = win32com.client.Dispatch('VirtualBox.CallbackWrapper')\n"
274 str += "result.SetLocalObject(win32com.server.util.wrap("+iface+"Impl()))\n"
275 exec (str,d,d)
276 return d['result']
277
278 def waitForEvents(self, timeout):
279 from win32api import GetCurrentThreadId
280 from win32event import MsgWaitForMultipleObjects, \
281 QS_ALLINPUT, WAIT_TIMEOUT, WAIT_OBJECT_0
282 from pythoncom import PumpWaitingMessages
283
284 if (self.tid != GetCurrentThreadId()):
285 raise Exception("wait for events from the same thread you inited!")
286
287 rc = MsgWaitForMultipleObjects(self.handles, 0, timeout, QS_ALLINPUT)
288 if rc >= WAIT_OBJECT_0 and rc < WAIT_OBJECT_0+len(self.handles):
289 # is it possible?
290 pass
291 elif rc==WAIT_OBJECT_0 + len(self.handles):
292 # Waiting messages
293 PumpWaitingMessages()
294 else:
295 # Timeout
296 pass
297
298 def deinit(self):
299 import pythoncom
300 from win32file import CloseHandle
301
302 for h in self.handles:
303 if h is not None:
304 CloseHandle(h)
305 self.handles = None
306 pythoncom.CoUninitialize()
307 pass
308
309
310class PlatformXPCOM:
311 def __init__(self, params):
312 sys.path.append(VboxSdkDir+'/bindings/xpcom/python/')
313 import xpcom.vboxxpcom
314 import xpcom
315 import xpcom.components
316
317 def getSessionObject(self, vbox):
318 import xpcom.components
319 return xpcom.components.classes["@virtualbox.org/Session;1"].createInstance()
320
321 def getVirtualBox(self):
322 import xpcom.components
323 return xpcom.components.classes["@virtualbox.org/VirtualBox;1"].createInstance()
324
325 def getType(self):
326 return 'XPCOM'
327
328 def getRemote(self):
329 return False
330
331 def getArray(self, obj, field):
332 return obj.__getattr__('get'+ComifyName(field))()
333
334 def initPerThread(self):
335 import xpcom
336 xpcom._xpcom.AttachThread()
337
338 def deinitPerThread(self):
339 import xpcom
340 xpcom._xpcom.DetachThread()
341
342 def createCallback(self, iface, impl, arg):
343 d = {}
344 d['BaseClass'] = impl
345 d['arg'] = arg
346 str = ""
347 str += "import xpcom.components\n"
348 str += "class "+iface+"Impl(BaseClass):\n"
349 str += " _com_interfaces_ = xpcom.components.interfaces."+iface+"\n"
350 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
351 str += "result = xpcom.components.classes['@virtualbox.org/CallbackWrapper;1'].createInstance()\n"
352 # This wrapping is not entirely correct - we shall create a local object
353 str += "result.setLocalObject(win32com.server.util.wrap("+iface+"Impl()))\n"
354 exec (str,d,d)
355 return d['result']
356
357 def waitForEvents(self, timeout):
358 import xpcom
359 xpcom._xpcom.WaitForEvents(timeout)
360
361 def deinit(self):
362 import xpcom
363 xpcom._xpcom.DeinitCOM()
364
365class PlatformWEBSERVICE:
366 def __init__(self, params):
367 sys.path.append(os.path.join(VboxSdkDir,'bindings', 'webservice', 'python', 'lib'))
368 # not really needed, but just fail early if misconfigured
369 import VirtualBox_services
370 import VirtualBox_wrappers
371 from VirtualBox_wrappers import IWebsessionManager2
372
373 if params is not None:
374 self.user = params.get("user", "")
375 self.password = params.get("password", "")
376 self.url = params.get("url", "")
377 else:
378 self.user = ""
379 self.password = ""
380 self.url = None
381 self.vbox = None
382
383 def getSessionObject(self, vbox):
384 return self.wsmgr.getSessionObject(vbox)
385
386 def getVirtualBox(self):
387 return self.connect(self.url, self.user, self.password)
388
389 def connect(self, url, user, passwd):
390 if self.vbox is not None:
391 self.disconnect()
392 from VirtualBox_wrappers import IWebsessionManager2
393 if url is None:
394 url = ""
395 self.url = url
396 if user is None:
397 user = ""
398 self.user = user
399 if passwd is None:
400 passwd = ""
401 self.password = passwd
402 self.wsmgr = IWebsessionManager2(self.url)
403 self.vbox = self.wsmgr.logon(self.user, self.password)
404 if not self.vbox.handle:
405 raise Exception("cannot connect to '"+self.url+"' as '"+self.user+"'")
406 return self.vbox
407
408 def disconnect(self):
409 if self.vbox is not None and self.wsmgr is not None:
410 self.wsmgr.logoff(self.vbox)
411 self.vbox = None
412 self.wsmgr = None
413
414 def getType(self):
415 return 'WEBSERVICE'
416
417 def getRemote(self):
418 return True
419
420 def getArray(self, obj, field):
421 return obj.__getattr__(field)
422
423 def initPerThread(self):
424 pass
425
426 def deinitPerThread(self):
427 pass
428
429 def createCallback(self, iface, impl, arg):
430 raise Exception("no callbacks for webservices")
431
432 def waitForEvents(self, timeout):
433 # Webservices cannot do that yet
434 pass
435
436 def deinit(self):
437 try:
438 disconnect()
439 except:
440 pass
441
442class SessionManager:
443 def __init__(self, mgr):
444 self.mgr = mgr
445
446 def getSessionObject(self, vbox):
447 return self.mgr.platform.getSessionObject(vbox)
448
449class VirtualBoxManager:
450 def __init__(self, style, platparams):
451 if style is None:
452 if sys.platform == 'win32':
453 style = "MSCOM"
454 else:
455 style = "XPCOM"
456
457
458 exec "self.platform = Platform"+style+"(platparams)"
459 # for webservices, enums are symbolic
460 self.constants = VirtualBoxReflectionInfo(style == "WEBSERVICE")
461 self.type = self.platform.getType()
462 self.remote = self.platform.getRemote()
463 self.style = style
464 self.mgr = SessionManager(self)
465
466 try:
467 self.vbox = self.platform.getVirtualBox()
468 except NameError,ne:
469 print "Installation problem: check that appropriate libs in place"
470 traceback.print_exc()
471 raise ne
472 except Exception,e:
473 print "init exception: ",e
474 traceback.print_exc()
475 if self.remote:
476 self.vbox = None
477 else:
478 raise e
479
480 def getArray(self, obj, field):
481 return self.platform.getArray(obj, field)
482
483 def getVirtualBox(self):
484 return self.platform.getVirtualBox()
485
486 def __del__(self):
487 self.deinit()
488
489 def deinit(self):
490 if hasattr(self, "vbox"):
491 del self.vbox
492 self.vbox = None
493 if hasattr(self, "platform"):
494 self.platform.deinit()
495 self.platform = None
496
497 def initPerThread(self):
498 self.platform.initPerThread()
499
500 def openMachineSession(self, machineId):
501 session = self.mgr.getSessionObject(self.vbox)
502 self.vbox.openSession(session, machineId)
503 return session
504
505 def closeMachineSession(self, session):
506 session.close()
507
508 def deinitPerThread(self):
509 self.platform.deinitPerThread()
510
511 def createCallback(self, iface, impl, arg):
512 return self.platform.createCallback(iface, impl, arg)
513
514 def waitForEvents(self, timeout):
515 return self.platform.waitForEvents(timeout)
516
517 def getPerfCollector(self, vbox):
518 return PerfCollector(self, vbox)
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