Automating VirtualBox screenshots with Python
Following on from last week's post, this post is going to look at using the VirtualBox API to take screenshots.
There are two ways the VirtualBox API can be called, either via a Component
Object Model (COM), or using a web service built using
SOAP, so long as the
vboxwebsrv process is started. This post is
going to look at using the COM interface, however the calls should be very
similar to the web service interface.
Setting up Python
The Python's standard library doesn't have any way to use COM interfaces, however the pywin32 module can be used to create COM objects. This can be installed using pip:
$ python -m venv vbox_venv $ source vbox_venv/Scripts/activate $ pip install pywin32 Collecting pywin32 Using cached https://files.pythonhosted.org/packages/d4/2d/b927e61c4a2b0aaaab72c8cb97cf748c319c399d804293164b0c43380d5f/pywin32-223-cp36-cp36m-win32.whl Installing collected packages: pywin32 Successfully installed pywin32-223
pywin32 is installed, you should be able to import
$ python Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 16:07:46) [MSC v.1900 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import win32com.client >>> win32com.client.__name__ 'win32com.client'
Using the API
pywin32 is setup, the next thing to do is start a new session. This can
be done using
import win32com.client from win32com.client import constants vbox = win32com.client.Dispatch("VirtualBox.VirtualBox") session = win32com.client.Dispatch("VirtualBox.Session")
findMachine function can then be used to find the virtual machine we want
machine = vbox.FindMachine("example_vm")
Note: you can either search for machines by name or UUID.
The VirtualBox API uses a locking mechanism to control access to virtual
machines. Before calling the screenshot function, we need to create a lock
This function takes two parameters, the session to create the lock with, and
the type of lock to create. The VirtualBox COM interface uses several
enumerations to store constants, like the lock type, these can be accessed from
After successfully creating a lock it should be possible to use the
TakeScreenShotToArray functions to work out the
require resolution and grab a screenshot:
display = session.Console.Display width, height, _, _, _, _= display.GetScreenResolution(0) screenshot = display.TakeScreenShotToArray(0, width, height, constants.BitmapFormat_PNG)
At this point we can now release our machine lock:
Finally the screenshot data can be written out to a file:
with open('screenshot.png', 'wb') as output_png: output_png.write(screenshot.tobytes())
If everything goes well, this should create a new screenshot:
$ file screenshot.png screenshot.png: PNG image data, 720 x 400, 8-bit/color RGB, non-interlaced
Note: the lines above can obviously be put together into a short script.
COM interfaces tips
I've not previously done much with COM interfaces, below are a few points I wish I knew at the start:
The VirtualBox SDK docs are very comprehensive, and cover all available functions in detail, although they can be a bit tricky to navigate.
You can inspect available constants by calling
win32com.client.constants.__dict__["__dicts__"]after you've called the
pywin32 comes with a simple object browser which can be used to browse available COM interface functions. You can access this by running:
$ python vbox_venv/Lib/site-packages/win32com/client/combrowse.py