Learn how to evaluate and integrate the VNC SDK

We're here if you need help.

Python API

The VNC SDK provides Python bindings, enabling you to create a VNC Viewer or a VNC Server app from a Python script.

When using the Python bindings, the Python method calls used to invoke the SDK are implemented using calls into the lower-level C API. Therefore, to distribute your application which uses the Python bindings, you will need to include not only the bindings themselves, vncsdk.py, but also the SDK’s native bindings (the SDK shared library, or DLL).

The Python bindings support Python 2.6, 2.7, and 3.x, using a Python runtime with support for ctypes (such as CPython or PyPy). The bindings are provided as a single file, vncsdk.py, which has no external dependencies that are not part of the default Python runtime.

How to import the bindings

The VNC SDK is imported using the standard Python mechanism:

import vncsdk

In order for the Python runtime to locate the SDK, you may need to append the location of the bindings to the sys.path variable before importing the bindings. Alternatively, you can install the bindings in a global location such as /usr/lib/python2.7/site-packages/ or C:\Python27\lib\site-packages (depending on your system and Python version).

When the bindings are imported, the SDK shared library (DLL) must also be located. By default, the bindings look in the system paths (/usr/lib or C:\Windows\system32). In order to specify a search location, set the VNCSDK_LIBRARY environment variable to point to the library, using either the exact name of the shared object, or the directory it is located in. If a directory is specified, the bindings search for the shared object using its default name (vncsdk.dll, libvncsdk.x.x.so, or libvncsdk.x.x.dylib depending on the platform), and also search in subdirectories matching the platform name.

# Example: Search for the library in the app's "resources" directory:
os.environ['VNCSDK_LIBRARY'] = os.path.join(os.path.dirname(__file__), 'resources')
import vncsdk
print('SDK library found at: ' + vncsdk.VNCSDK_LIBRARY)

Finally, if you are using the bindings to create a Server application, the capture agent must also be located (vncagent.exe). The Server’s constructor vncsdk.Server.__init__() has a parameter which allows the location to be specified; if this is passed as None then the bindings will search for the agent in the main module’s directory (the C API searches for the agent in the directory of the running binary if the path is not specified).

How to use the documentation

The primary source for documentation on the VNC SDK is provided by the C API reference. Most methods provided through the Python bindings are documented with a brief summary only, since the full behaviour and description of each method and argument is contained in the C API reference. This documentation for the Python bindings fully describes only the behaviour which is unique to the Python bindings.

Methods and their types are mapped into Python as follows:

  • Each structure in the C API is mapped to a corresponding Python class. For example, vnc_DataBuffer corresponds to vncsdk.DataBuffer. Each function operating on a C type is mapped to a method on the Python class, such as DataBuffer.get_data for vnc_DataBuffer_getData. The constructors of Python classes correspond to the “create” methods in the C API. Method names in the Python bindings are separated with underscores, rather than the camel-case used in the C API.
  • Arguments are mapped to their native Python types. Pass in a Python string where the C API uses a const char*, Python lists for C-style arrays, and Python integers for C integers. The SDK coerces any arguments you pass in to the expected type. See below for more information on how to use callback and enumeration objects.
  • Many functions in the VNC SDK return return an error if an unexpected condition occurred or the arguments were invalid. In the C API, this is indicated by functions returning vnc_failure or NULL, and the error condition can be found by calling vnc_getLastError. In the Python bindings, this function is not available, as all errors are indicated by throwing exceptions. For all cases where C API returns an error, the Python bindings throw a vncsdk.VncException, whose errorCode member contains the strings described in the C API reference. Many methods can also throw standard Python errors such as TypeError if incorrect values are passed into the API.
  • The vncsdk module contains global functions from the C API which are not associated with any particular class.

Memory management

Although Python is a garbage-collected language, every object created by the VNC SDK must be explicitly destroyed by the user with its destroy() method. This is because the Python garbage collector does not reliably reclaim objects; for most objects this is not a problem, but for some resources such as files or open network connections, proper cleanup is important. As the CPython’s documentation says:

Do not depend on immediate finalization of objects when they become unreachable (ex: always close files).

Since most SDK objects hold references to shared long-running tasks such as network connections, it is not appropriate to expect the garbage collector to reclaim SDK objects: they must all be closed with their destroy() method, or network connections may not be cleanly closed.

As an alternative to calling destroy(), Python’s with statement may be used for cleaning up local objects:

with vncsdk.CloudConnector(address, password) as connector:
    connector.connect(peer_address, viewer.get_connection_handler())

How to use the SDK with threading

The VNC SDK can be used in a multi-threaded application. For most applications, this is unnecessary and it is simpler to run the SDK in the main thread, and the SDK is able to run in the same thread as third-party event loops such as Qt and wxWidgets. If you decide to use only one Python thread, see the documentation on event loops for information on how to integrate the SDK’s event loop with your application’s.

However, for GUI applications the extra flexibility of running the SDK in a background thread can be useful, so you may choose to run the SDK’s event loop in its own thread.

In this case, the SDK’s threading rule is simple: the SDK can only be called from one thread. So, you must decide which thread in your application uses the SDK, then call all SDK methods from that thread.

The Python bindings provides a helper method to make it easier to interact with the SDK thread. If you run vncsdk.EventLoop.run() in a background thread, then in any other thread you can call vncsdk.EventLoop.run_on_loop() to pass a Python callable object to be invoked on the SDK thread. The other method which can be called from a non-SDK thread is vncsdk.EventLoop.stop(), which causes the event loop in the SDK thread to stop.

How to use SDK callbacks

Each callback is represented by a class in the Python API. There are two ways of constructing a callback, using an instance of the callback object constructed with Python functions, or secondly deriving from the callback class and implementing the callback’s methods.

  • When you construct an instance of the callback class directly, pass in your functions as named arguments to the constructor:

    # Example 1: Using an instance of the callback object
    def log_fn(level, message):
        print('SDK message: ' + level + ', ' + message)
    
    vncsdk.Logger.create_custom_logger(vncsdk.Logger.Callback(
        log_message = log_fn
    ))
    vncsdk.Logger.create_custom_logger(vncsdk.Logger.Callback(
        log_message = lambda _, message: sys.stdout.write(message)
    ))
    
  • When you derive from the callback class, override the methods you choose to implement:

    # Example 2: Deriving from the callback object
    class MyCustomLogger(vncsdk.Logger.Callback):
        def log_message(self, level, message):
            print('SDK message: ' + level + ', ' + message)
    vncsdk.Logger.create_custom_logger(MyCustomLogger())
    

    If your class implements __init__(), remember that you must call the base class’s __init__() method.

Finally, note that the Python bindings do not allow callback objects to be garbage-collected. Therefore, if you create a large number of callback objects, they will be leaked. This is not a problem if you set up callback objects once at the start of the application, rather than recreating them repeatedly while the application is running.

How to use SDK enumerations

Enumerations are represented in the Python API by an object with an attribute for each item. The items can be printed using str() or their name member. Functions accepting an enum argument must be passed an instance of the required enum. Functions accepting a bitmask of enums take a Python iterable of enum items. Callbacks returning an SDK enum always return the same item as the SDK exports, so you can test for equality using == or is.

viewer = vncsdk.Viewer()

# Example: passing in an enum
viewer.send_scroll_event(
    5, vncsdk.Viewer.MouseWheel.MOUSE_WHEEL_VERTICAL)

# Example: passing in a bitmask of enums, using a Python set
buttons = {vncsdk.Viewer.MouseButton.MOUSE_BUTTON_LEFT}
viewer.send_pointer_event(100, 100, buttons, False)

# Example: receiving an enum in a callback, printing items using
# 'name', and checking for specific enum values
class MyConnectionCallback(vncsdk.Viewer.ConnectionCallback):
   def disconnected(self, viewer, reason, flags):
      for flag in flags:
          if flag == vncsdk.Viewer.DisconnectFlags.CAN_RECONNECT:
              print("Viewer disconnected, reconnecting...")
          else
              print("Viewer disconnected, got flag " + flag.name)
   def connected(self, viewer):
       pass
   def connecting(self, viewer):
       pass
viewer.set_connection_callback(MyConnectionCallback())
×