Parallels Virtualization SDK Programmer's Guide

Parallels Virtualization SDK
Programmer's Guide
Copyright © 1999-2011 Parallels Holdings, Ltd. and its affiliates. All
ights reserved. r
Parallels Holdings, Ltd. c/o Parallels International GMbH. Parallels International GmbH Vordergasse 49 CH8200 Schaffhausen Switzerland Tel: + 41 526320 411 Fax: + 41 52672 2010 www.parallels.com
Copyright © 1999-2011 Parallels Holdings, Ltd. and its affiliates. All rights reserved.
This product is protected by United States and international copyright laws. The product’s underlying technology, patents, and trademarks are listed at http://www.parallels.com/trademarks.
Microsoft, Windows, Windows Server, Windows NT, Windows Vista, and MS-DOS are registered trademarks of Microsoft Corporation. Linux is a registered trademark of Linus Torvalds. Mac is a registered trademark of Apple, Inc. All other marks and names mentioned herein may be trademarks of their respective owners.
Contents
Getting Started 5
Overview ......................................................................................................................................................5
System Requirements ...................................................................................................................................6
Mac OS X Clients..............................................................................................................................6
Windows Clients ...............................................................................................................................6
Linux Clients.....................................................................................................................................7
Common Network Requirements......................................................................................................7
Parallels C API Concepts 8
Compiling Client Applications.....................................................................................................................8
Mac OS X..........................................................................................................................................8
Windows.......................................................................................................................................... 18
Linux ...............................................................................................................................................19
Handles.......................................................................................................................................................20
Synchronous Functions...............................................................................................................................21
Asynchronous Functions.............................................................................................................................22
Strings as Return Values.............................................................................................................................26
Error Handling............................................................................................................................................28
Parallels C API by Example 30
Obtaining Server Handle and Logging In...................................................................................................31
Host Operations..........................................................................................................................................35
Retrieving Host Configuration Information ....................................................................................36
Managing Parallels Service Preferences..........................................................................................39
Searching for Parallels Servers........................................................................................................42
Managing Parallels Service Users...................................................................................................45
Managing Files In The Host OS......................................................................................................50
Managing Licenses..........................................................................................................................53
Obtaining a Problem Report............................................................................................................56
Virtual Machine Operations........................................................................................................................58
Obtaining the Virtual Machines List ...............................................................................................59
Searching for Virtual Machine by Name.........................................................................................62
Obtaining Virtual Machine Configuration Information...................................................................64
Determining Virtual Machine State.................................................................................................66
Starting, Stopping, Resetting a Virtual Machine.............................................................................69
Suspending and Pausing a Virtual Machine....................................................................................70
Creating a New Virtual Machine.....................................................................................................72
Searching for Virtual Machines.......................................................................................................75
Adding an Existing Virtual Machine...............................................................................................79
Cloning a Virtual Machine..............................................................................................................82
Deleting a Virtual Machine.............................................................................................................84
Modifying Virtual Machine Configuration......................................................................................85
Managing User Access Rights.........................................................................................................99
Working with Virtual Machine Templates....................................................................................101
Events .......................................................................................................................................................110
Receiving and Handling Events.....................................................................................................111
Responding to Parallels Service Questions ...................................................................................114
Performance Statistics...............................................................................................................................121
Obtaining Performance Report......................................................................................................122
Performance Monitoring................................................................................................................125
Contents 4
Encryption Plug-in....................................................................................................................................130
Encryption Plug-in Basics.............................................................................................................130
The Encryption API Reference......................................................................................................131
Implementing a Plug-in.................................................................................................................134
Building the Dynamic Library.......................................................................................................140
Plug-in Installation and Usage.......................................................................................................141
Parallels Python API Concepts 142
Package and Modules...............................................................................................................................143
Classes......................................................................................................................................................144
Class Methods...........................................................................................................................................144
Synchronous Methods...................................................................................................................144
Asynchronous Methods.................................................................................................................145
Error Handling.......................................................................................................................................... 147
Parallels Python API by Example 148
Creating a Basic Application....................................................................................................................149
Connecting to Parallels Service and Logging In.......................................................................................152
Host Operations........................................................................................................................................ 155
Retrieving Host Configuration Info...............................................................................................155
Managing Parallels Service Preferences........................................................................................157
Virtual Machine Operations......................................................................................................................158
Obtaining the Virtual Machine List...............................................................................................159
Searching for a Virtual Machine....................................................................................................161
Performing Power Operations.......................................................................................................162
Creating a New Virtual Machine...................................................................................................163
Obtaining Virtual Machine Configuration Data............................................................................165
Modifying Virtual Machine Configuration....................................................................................168
Adding an Existing Virtual Machine.............................................................................................175
Removing an Existing Virtual Machine........................................................................................176
Cloning a Virtual Machine............................................................................................................177
Remote Desktop Access...........................................................................................................................178
Creating a Simple OS Installation Program...................................................................................179
Index 183
C HAPTER 1

Getting Started

In This Chapter
Overview............................................................................................................................... 5
System Requirements............................................................................................................ 6

Overview

Parallels Virtualization SDK is a development kit used to create and integrate custom software solutions with Parallels virtualization products. The SDK provides cross-platform ANSI C and Python APIs. The SDK can be used to develop software for any hypervisor-based Parallels virtualization product such as Parallels Server, Parallels Workstation, and Parallels Desktop.
The SDK comprises the following components:
C header files. Dynamic libraries. Python package for developing client applications in Python. Parallels command line tools (prlctl, prlsrvctl) -- a command line utility that can
be used to perform a full range of host and virtual machine operations.
Parallels Virtualization SDK Programmer's Guide (this document). Parallels C API Reference Guide. Parallels Python API Reference Guide. Parallels Command Line Reference Guide.
Getting Started 6

System Requirements

Mac OS X Clients

Hardware Requirements
Intel-powered Core™ Duo or Core Solo Mac® Mini, iMac®, MacBook™, MacBook Pro,
MacBook Air, Mac Pro, or Xserve.
Ethernet or WiFi network adapter.
Software Requirements
Mac OS X Tiger 10.4.8 or later. Mac OS X Leopard 10.5.2 or later. Parallels Python API requires Python 2.5. Other versions of Python are not officially
supported.

Windows Clients

Hardware Requirements
Intel-compatible x86 (32-bit) or x64 (64-bit) processor. Ethernet or WiFi network adapter.
Software Requirements
Windows 2000 or higher. The Parallels Python API requires Python 2.5. Other versions of Python are not officially
supported.
Getting Started 7

Linux Clients

Hardware Requirements
Intel-compatible x86 (32-bit) or x64 (64-bit) processor. Ethernet network adapter.
Software Requirements
Red Hat® Enterprise Linux WS4 (x32, x64).  Red Hat Enterprise Linux AS4 (x32, x64). Red Hat Enterprise Linux ES4 (x32, x64). Red Hat Enterprise Linux 5 (x32, x64) CentOS 4.x (x32, x64). CentOS 5.0 (x32, x64). CentOS 5.1 (x32, x64). Ubuntu Server 7.10 (x32, x64).
®
SUSE
Linux Enterprise Server 10 SP1 (x32, x64).

Common Network Requirements

Parallels Server
When creating client applications for Parallels Server, your client computer must be able to establish a network connection with the host computer running the server. The client computer can be connected to a local area network via a wired or a wireless interface. Clients communicate with a server via TCP/IP. The server is listening on port 6400. Please make sure that the port is not blocked by a firewall.
Parallels Desktop and Parallels Workstation
Remote connections to the Parallels Service are not allowed with Parallels Desktop or Parallels Workstation. With these products, you can run your client applications on the host computer only.
C HAPTER 2

Parallels C API Concepts

In This Chapter
Compiling Client Applications ............................................................................................. 8
Handles.................................................................................................................................. 20
Synchronous Functions......................................................................................................... 21
Asynchronous Functions....................................................................................................... 22
Strings as Return Values....................................................................................................... 26
Error Handling ...................................................................................................................... 28

Compiling Client Applications

Mac OS X

Parallels Virtualization SDK for Mac OS X is provided as a framework. The framework is installed in the following directory:
/Library/Frameworks/ParallelsVirtualizationSDK.framework
You can use the framework just like any other Apple framework when creating development projects and compiling applications. Alternately, you can compile and build your applications without using the framework. In such a case, you will have to specify all the necessary paths to the SDK source files manually.
When using the framework, the dynamic library, which is supplied with the SDK, will be directly linked to the application. If you would like to load the dynamic library at runtime, the Parallels Virtualization SDK includes a convenient dlopen wrapper for this purpose called SdkWrap. Using the wrapper, you can load and unload the library symbols at any time with one simple call. Please note that in order to use SdkWrap, you must compile your application without using the framework. The wrapper source files are located in the Helpers/SdkWrap directory, which is located in the main SDK installation directory.
The following subsections describe various compilation scenarios in detail and provide code samples.
Parallels C API Concepts 9
Compiling with SdkWrap
When using SdkWrap, your program must contain the following:
The #include "SdkWrap.h" directive. This header file defines the wrapper functions. The #define SDK_LIB_NAME "libprl_sdk.dylib" directive. This is the name
of the dynamic library included in the SDK.
The SdkWrap_Load(SDK_LIB_NAME) function call that will load the dynamic library
symbols.
The SdkWrap_Unload() function call that will unload the dynamic library when it is no
longer needed.
To compile a program, the following compiler options and instructions must be used:
The DYN_API_WRAP preprocessor macro must be defined. Full paths to the Headers and the Helpers/SdkWrap directories must be specified.
Both directories are located in the main SDK installation directory.
The SdkWrap.cpp file must be included in the project and must be built together with the
main target.
The libdl library must be linked to the application. This is the standard dynamic linking
interface library needed to load the SDK library.
Using Makefile
The following is a sample Makefile that demonstrates the implementation of the requirements described above. To compile a program and to build an executable, type make in the Terminal window. To clean up the project, type make clean. Please note that the SOURCE variable must contain the name of your source file name.
# Source file name. # Substitute the file name with your own. SOURCE = HelloWorld
# Target executable file name. # Here we are using the same name as the source file name. TARGET = $(SOURCE)
# Path to the Parallels Virtualization SDK files. SDK_PATH = /Library/Frameworks/ParallelsVirtualizationSDK.framework
# Relative path to the SdkWrap directory containing # the SDK helper files. The files are used to load # the dynamic library. SDK_WRAP_PATH = Helpers/SdkWrap
OBJS = SdkWrap.o $(SOURCE).o CXX = g++ CXXFLAGS = -DDYN_API_WRAP -I$(SDK_PATH)/Headers -I$(SDK_PATH)/$(SDK_WRAP_PATH) LDFLAGS = -ldl
all : $(TARGET)
$(TARGET) : $(OBJS) $(CXX) -o $@ $(LDFLAGS) $(OBJS)
$(SOURCE).o : $(SOURCE).cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE).cpp
Parallels C API Concepts 10
SdkWrap.o : $(SDK_PATH)/$(SDK_WRAP_PATH)/SdkWrap.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SDK_PATH)/$(SDK_WRAP_PATH)/SdkWrap.cpp
clean: @rm -f $(OBJS) $(TARGET)
.PHONY : all clean
Using Xcode IDE
If you are using the Xcode IDE, follow these steps to set up your project:
1 Add the SdkWrap.h and the SdkWrap.cpp files to your project. 2 In the Search Paths collection, specify:
a full path to the Helpers/SdkWrap directory (contains the wrapper source files) a full path to the Headers directory (contains the SDK header files) a full path to the Libraries directory (contains the dynamic library)
3 In the Preprocessor collection, add the DYN_API_WRAP preprocessor macro.
Example
The following is a complete sample program that demonstrates the usage of the SdkWrap wrapper. The program loads the dynamic library, initializes the API, and then logs in to the local Parallels Service. You can copy the entire program into a file on your Mac and try building and then running it. The program uses a cross-platform approach, so it can also be compiled on Windows and Linux machines.
#include "SdkWrap.h" #include <stdio.h> #include <stdlib.h> #include <string.h>
#ifdef _WIN_ #include <windows.h> #else #include <unistd.h> #endif
PRL_RESULT LoginLocal(PRL_HANDLE &hServer); PRL_RESULT LogOff(PRL_HANDLE &hServer);
/////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) { // Variables for handles. PRL_HANDLE hJob = PRL_INVALID_HANDLE; // job handle PRL_HANDLE hJobResult = PRL_INVALID_HANDLE; // job result PRL_HANDLE hServer = PRL_INVALID_HANDLE; // server handle
// Variables for return codes. PRL_RESULT err = PRL_ERR_UNINITIALIZED; PRL_RESULT nJobReturnCode = PRL_ERR_UNINITIALIZED;
// Log in to Parallels Service. err = LoginLocal(hServer);
// Log off. err = LogOff(hServer);
Parallels C API Concepts 11
printf( "\nEnd of program.\n\n" ); printf("Press Enter to exit..."); getchar();
exit(0); }
// Initializes the SDK library and // logs in to the local Parallels Service. // PRL_RESULT LoginLocal(PRL_HANDLE &hServer) { // Variables for handles. PRL_HANDLE hJob = PRL_INVALID_HANDLE; // job handle PRL_HANDLE hJobResult = PRL_INVALID_HANDLE; // job result
// Variables for return codes. PRL_RESULT err = PRL_ERR_UNINITIALIZED; PRL_RESULT nJobReturnCode = PRL_ERR_UNINITIALIZED;
// Use the correct dynamic library depending on the platform. #ifdef _WIN_ #define SDK_LIB_NAME "prl_sdk.dll" #elif defined(_LIN_) #define SDK_LIB_NAME "libprl_sdk.so" #elif defined(_MAC_) #define SDK_LIB_NAME "libprl_sdk.dylib" #endif
// Load SDK library. if (PRL_FAILED(SdkWrap_Load(SDK_LIB_NAME)) && PRL_FAILED(SdkWrap_Load("./" SDK_LIB_NAME))) { fprintf( stderr, "Failed to load " SDK_LIB_NAME "\n" ); return -1; }
// Initialize the API. In this example, we are initializing the // API for Parallels Desktop. // To initialize in the Parallels Workstation mode, pass PAM_WORKSTATION // as the second parameter. // To initialize for Parallels Server, pass PAM_SERVER. // See the PRL_APPLICATION_MODE enumeration for all possible options. err = PrlApi_InitEx(PARALLELS_API_VER, PAM_DESKTOP, 0, 0);
if (PRL_FAILED(err)) { fprintf(stderr, "PrlApi_InitEx returned with error: %s.\n", prl_result_to_string(err)); PrlApi_Deinit(); SdkWrap_Unload(); return -1; }
// Create a server handle (PHT_SERVER). err = PrlSrv_Create(&hServer); if (PRL_FAILED(err)) { fprintf(stderr, "PrlSvr_Create failed, error: %s", prl_result_to_string(err)); PrlApi_Deinit(); SdkWrap_Unload(); return -1; }
// Log in (asynchronous call).
Parallels C API Concepts 12
hJob = PrlSrv_LoginLocal(hServer, NULL, NULL, PSL_NORMAL_SECURITY);
// Wait for a maximum of 10 seconds for // the job to complete. err = PrlJob_Wait(hJob, 1000); if (PRL_FAILED(err)) { fprintf(stderr, "PrlJob_Wait for PrlSrv_Login returned with error: %s\n", prl_result_to_string(err)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); SdkWrap_Unload(); return -1; }
// Analyze the result of PrlSrv_Login. err = PrlJob_GetRetCode(hJob, &nJobReturnCode);
// First, check PrlJob_GetRetCode success/failure. if (PRL_FAILED(err)) { fprintf(stderr, "PrlJob_GetRetCode returned with error: %s\n", prl_result_to_string(err)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); SdkWrap_Unload(); return -1; }
// Now check the Login operation success/failure. if (PRL_FAILED(nJobReturnCode)) { PrlHandle_Free(hJob); PrlHandle_Free(hServer); printf("Login job returned with error: %s\n", prl_result_to_string(nJobReturnCode)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); SdkWrap_Unload(); return -1; } else { printf( "Login was successful.\n" ); }
return 0; }
// Logs off the Parallels Service and // deinitializes the SDK library. // PRL_RESULT LogOff(PRL_HANDLE &hServer) { PRL_HANDLE hJob = PRL_INVALID_HANDLE; PRL_HANDLE hJobResult = PRL_INVALID_HANDLE;
PRL_RESULT err = PRL_ERR_UNINITIALIZED; PRL_RESULT nJobReturnCode = PRL_ERR_UNINITIALIZED;
// Log off. hJob = PrlSrv_Logoff(hServer); err = PrlJob_Wait(hJob, 1000);
Parallels C API Concepts 13
if (PRL_FAILED(err)) { fprintf(stderr, "PrlJob_Wait for PrlSrv_Logoff returned error: %s\n", prl_result_to_string(err)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); SdkWrap_Unload(); return -1; }
// Get the Logoff operation return code. err = PrlJob_GetRetCode(hJob, &nJobReturnCode);
// Check the PrlJob_GetRetCode success/failure. if (PRL_FAILED(err)) { fprintf(stderr, "PrlJob_GetRetCode failed for PrlSrv_Logoff with error: %s\n", prl_result_to_string(err)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); SdkWrap_Unload(); return -1; }
// Report success or failure of PrlSrv_Logoff. if (PRL_FAILED(nJobReturnCode)) { fprintf(stderr, "PrlSrv_Logoff failed with error: %s\n", prl_result_to_string(nJobReturnCode)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); SdkWrap_Unload(); return -1; } else { printf( "Logoff was successful.\n" ); }
// Free handles that are no longer required. PrlHandle_Free(hJob); PrlHandle_Free(hServer);
// De-initialize the Parallels API, and unload the SDK. PrlApi_Deinit(); SdkWrap_Unload();
return 0; }
Parallels C API Concepts 14
Compiling with Framework
If you are using the ParallelsVirtualizationSDK framework, the program must contain the following include directive:
#include "ParallelsVirtualizationSDK/Parallels.h"
Parallels.h is the main SDK header file. Please note the framework name in front of the
SDK header file name. This is a common requirement when using a framework.
Note: The difference between the SdkWrap scenario (described in the previous subsection) and the framework scenario is that Parallels.h must be included when using the framework, while SdkWrap.h must be included when using SdkWrap. The two files must never be included together. Please also note that you don't have to load the dynamic library manually in your program when using the framework.
The only compiler option that must be specified when using the framework is:
-framework ParallelsVirtualizationSDK
Using Makefile
The following sample Makefile can be used to compile a program using the ParallelsVirtualizationSDK framework:
# Source file name. # Substitute the file name with your own. SOURCE = HelloWorld
# Target executable file name. # Here we are using the same name as the source file name. TARGET = $(SOURCE)
CXX = g++ LDFLAGS = -framework ParallelsVirtualizationSDK
all : $(TARGET)
$(TARGET) : $(OBJS) $(CXX) -o $@ $(LDFLAGS) $(OBJS)
$(SOURCE).o : $(SOURCE).cpp $(CXX) -c -o $@ $(SOURCE).cpp
clean: @rm -f $(OBJS) $(TARGET)
.PHONY : all clean
Using Xcode IDE
When setting up an Xcode project, the only thing that you have to do is add the ParallelsVirtualizationSDK framework to the project. No other project modifications are necessary.
Sample
Parallels C API Concepts 15
The following is a complete sample program that demonstrates the usage of the ParallelsVirtualizationSDK framework.
#include "ParallelsVirtualizationSDK/Parallels.h" #include <stdio.h> #include <stdlib.h> #include <string.h>
#ifdef _WIN_ #include <windows.h> #else #include <unistd.h> #endif
PRL_RESULT LoginLocal(PRL_HANDLE &hServer); PRL_RESULT LogOff(PRL_HANDLE &hServer);
/////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) { // Variables for handles. PRL_HANDLE hServer = PRL_INVALID_HANDLE; // server handle
// Variables for return codes. PRL_RESULT err = PRL_ERR_UNINITIALIZED;
// Log in. err = LoginLocal(hServer);
// Log off err = LogOff(hServer);
printf( "\nEnd of program.\n\n" ); printf("Press Enter to exit..."); getchar();
exit(0); }
// Intializes the SDK library and // logs in to the local Parallels Service. // PRL_RESULT LoginLocal(PRL_HANDLE &hServer) { // Variables for handles. PRL_HANDLE hJob = PRL_INVALID_HANDLE; // job handle
// Variables for return codes. PRL_RESULT err = PRL_ERR_UNINITIALIZED; PRL_RESULT nJobReturnCode = PRL_ERR_UNINITIALIZED;
// Initialize the API. In this example, we are initializing the // API for Parallels Workstation. // To initialize in the Parallels Desktop mode, pass PAM_DESKTOP // as the second parameter. // To initialize for Parallels Server, pass PAM_SERVER. // See the PRL_APPLICATION_MODE enumeration for all possible options. err = PrlApi_InitEx(PARALLELS_API_VER, PAM_DESKTOP, 0, 0);
if (PRL_FAILED(err)) { fprintf(stderr, "PrlApi_InitEx returned with error: %s.\n", prl_result_to_string(err)); PrlApi_Deinit();
Parallels C API Concepts 16
return -1; }
// Create a server handle (PHT_SERVER). err = PrlSrv_Create(&hServer); if (PRL_FAILED(err)) { fprintf(stderr, "PrlSvr_Create failed, error: %s", prl_result_to_string(err)); PrlApi_Deinit(); return -1; }
// Log in (asynchronous call). hJob = PrlSrv_LoginLocal(hServer, NULL, NULL, PSL_NORMAL_SECURITY);
// Wait for a maximum of 10 seconds for // the job to complete. err = PrlJob_Wait(hJob, 1000); if (PRL_FAILED(err)) { fprintf(stderr, "PrlJob_Wait for PrlSrv_Login returned with error: %s\n", prl_result_to_string(err)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); return -1; }
// Analyze the result of PrlSrv_Login. err = PrlJob_GetRetCode(hJob, &nJobReturnCode);
// First, check PrlJob_GetRetCode success/failure. if (PRL_FAILED(err)) { fprintf(stderr, "PrlJob_GetRetCode returned with error: %s\n", prl_result_to_string(err)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); return -1; }
// Now check the Login operation success/failure. if (PRL_FAILED(nJobReturnCode)) { PrlHandle_Free(hJob); PrlHandle_Free(hServer); printf("Login job returned with error: %s\n", prl_result_to_string(nJobReturnCode)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); return -1; } else { printf( "Login was successful.\n" ); }
return 0; }
// Log off the Parallels Service and // deinitializes the SDK library. //
Parallels C API Concepts 17
PRL_RESULT LogOff(PRL_HANDLE &hServer) { PRL_HANDLE hJob = PRL_INVALID_HANDLE;
PRL_RESULT err = PRL_ERR_UNINITIALIZED; PRL_RESULT nJobReturnCode = PRL_ERR_UNINITIALIZED;
// Log off. hJob = PrlSrv_Logoff(hServer); err = PrlJob_Wait(hJob, 1000); if (PRL_FAILED(err)) { fprintf(stderr, "PrlJob_Wait for PrlSrv_Logoff returned error: %s\n", prl_result_to_string(err)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); return -1; }
// Get the Logoff operation return code. err = PrlJob_GetRetCode(hJob, &nJobReturnCode);
// Check the PrlJob_GetRetCode success/failure. if (PRL_FAILED(err)) { fprintf(stderr, "PrlJob_GetRetCode failed for PrlSrv_Logoff with error: %s\n", prl_result_to_string(err)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); return -1; }
// Report success or failure of PrlSrv_Logoff. if (PRL_FAILED(nJobReturnCode)) { fprintf(stderr, "PrlSrv_Logoff failed with error: %s\n", prl_result_to_string(nJobReturnCode)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); return -1; } else { printf( "Logoff was successful.\n" ); }
// Free handles that are no longer required. PrlHandle_Free(hJob); PrlHandle_Free(hServer);
// De-initialize the Parallels API, and unload the SDK. PrlApi_Deinit();
return 0; }
Parallels C API Concepts 18

Windows

The following steps describe how to set up a project in Microsoft Visual Studio: 1 Create a project of your choice in a usual way and open the project Property Pages
windows.
2 In the C/C++ -> General -> Additional Include Directories section, add the path to the
Include and the Helpers\SdkWrap sub-directories located in the main directory where you have the SDK installed.
3 Add the following files from the Helpers\SdkWrap subdirectory to the project:
SdkWrap.h SdkWrap.cpp
These are the helper files that provide a set of methods for loading and unloading dynamic libraries. You can use the included source code file to customize this functionality if you wish.
4 Add the following #include directive to your program:
#include "SdkWrap.h"
The standard libraries used by the samples provided in this guide are:
#include <stdio.h> #include <stdlib.h> #include <string.h>
Parallels C API Concepts 19

Linux

The following is a sample make file that can be used to compile Parallels client applications on Linux:
# set the appropriate path to the SDK headers SDK_INSTALL_PATH=/usr
OBJS = SdkWrap.o main.o CXX = g++ CXXFLAGS = -I$(SDK_INSTALL_PATH)/include/parallels-virtualization-sdk LDFLAGS = -ldl
# Set the current folder name TARGET = Example
all : $(TARGET)
$(TARGET) : $(OBJS) $(CXX) -o $@ $(LDFLAGS) $(OBJS)
main.o : main.cpp $(CXX) -c -o $@ $(CXXFLAGS) main.cpp
SdkWrap.o : $(SDK_INSTALL_PATH)/share/parallels-virtualization­sdk/helpers/SdkWrap/SdkWrap.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SDK_INSTALL_PATH)/share/parallels­virtualization-sdk/helpers/SdkWrap/SdkWrap.cpp
clean: @rm -f $(TARGET) $(OBJS)
.PHONY : all clean
Parallels C API Concepts 20

Handles

The Parallels C API is a set of functions that operate on objects. Objects are not accessed directly. Instead, references to these objects are used. These references are known as handles.
Handle Types
PRL_HANDLE is the only handle type used in the C API. It is a pointer to an integer and it is defined in PrlTypes.h.
PRL_HANDLE can reference any type of object within the API. The type of object that PRL_HANDLE referen ces determines the PRL_HANDLE type. A list of handle types can be
found in the PRL_HANDLE_TYPE enumeration in PrlEnums.h.
A handles' type can be extracted using the PrlHandle_GetType function. A string representation of the handle type can then be obtained using the handle_type_to_string function.
Obtaining a Handle
A handle is usually obtained by calling a function that operates on another (we may call it "parent") handle. For example, a virtual machine handle is obtained by calling a function that operates on the server handle. A virtual device handle is obtained by calling a function that operates on the virtual machine handle, and so forth. The Parallels C API Reference guide contains a description of every available handle and explains how each particular handle type can be obtained. The examples in this guide also demonstrate how to obtain handles of different types.
Freeing a Handle
Parallels API handles are reference counted. Each handle contains a count of the number of references to it held by other objects. A handle stays in memory for as long as the reference count is greater than zero. A client application is responsible for freeing any handles that are no longer needed. A handle can be freed using the PrlHandle_Free function. The function decreases the reference count by one. When the count reaches zero, the object is destroyed. Failing to free a handle after it has been used will result in a memory leak.
Multithreading
Parallels API handles are thread safe. They can be used in multiple threads at the same time. To maintain the proper reference counting, the count should be increased each time a handle is passed to another thread by calling the PrlHandle_AddRef function. If this is not done, freeing a handle in one thread may destroy it while other threads are still using it.
Example
Parallels C API Concepts 21
The following code snippet demonstrates how to obtain a handle, how to determine its type, and how to free it when it's no longer needed. The code is a part of the bigger example that demonstrates how to log in to a Parallels Service (the full example is provided later in this guide).
PRL_HANDLE hServer = PRL_INVALID_HANDLE; PRL_RESULT ret;
ret = PrlSrv_Create(&hServer); if (PRL_FAILED(ret)) { fprintf(stderr, "PrlSvr_Create failed, error: %s", prl_result_to_string(ret)); return PRL_ERR_FAILURE; }
// Determine the type of the hServer handle. PRL_HANDLE_TYPE nHandleType; PrlHandle_GetType(hServer, &nHandleType); printf("Handle type: %s\n", handle_type_to_string(nHandleType));
// Free the handle when it is no longer needed. PrlHandle_Free(hServer);

Synchronous Functions

The Parallels C API provides synchronous and asynchronous functions. Synchronous functions run in the same thread as the caller. When a synchronous function is called it completes executing before returning control to the caller. Synchronous functions return PRL_RESULT, which is a integer indicating success or failure of the operation. Consider the
PrlSrv_Create function. The purpose of this function is to obtain a handle of type PHT_SERVER. The handle is required to access most of the functionality within the Parallels C API. The syntax of PrlSrv_Create is as follows:
PRL_RESULT PrlSrv_Create( PRL_HANDLE_PTR handle );
The following is an example of the PrlSrv_Create function call:
// Declare a handle variable. PRL_HANDLE hServer = PRL_INVALID_HANDLE;
// Call the PrlSrv_Create to obtain the handle. PRL_RESULT res = PrlSrv_Create(&hServer);
// Examine the function return code. // PRL_FAILED is a macro that evaluates a variable of type PRL_RESULT. // A return value of True indicates success; False indicates failure. if (PRL_FAILED(res)) { printf("PrlSrv_Create returned error: %s\n", prl_result_to_string(res)); exit(ret); }
Parallels C API Concepts 22

Asynchronous Functions

An asynchronous operation is executed in its own thread. An asynchronous function that started the operation returns to the caller immediately without waiting for the operation to complete. The results of the operation can be verified later when needed. Asynchronous functions return PRL_HANDLE, which is a pointer to an integer and is a handle of type PHT_JOB. The handle is used as a reference to the asynchronous job executed in the background. The general procedure for calling an asynchronous function is as follows:
1 Register an event handler (callback function). 2 Call an asynchronous function. 3 Analyze the results of events (jobs) within the callback function. 4 Handle the appropriate event in the callback function. 5 Un-register the event handler when it is no longer needed.
The Callback Function (Event Handler)
Asynchronous functions return data to the caller by means of an event handler (or callback function). The callback function could be called at any time, depending on how long the
asynchronous function takes to complete. The callback function must have a specific signature. The prototype can be found in PrlApi.h and is as follows:
typedef PRL_METHOD_PTR(PRL_EVENT_HANDLER_PTR) ( PRL_HANDLE hEvent, PRL_VOID_PTR data );
The following is an example of the callback function implementation:
static PRL_RESULT OurCallback(PRL_HANDLE handle, void *pData) { // Event handler code...
// You must always release the handle before exiting. PrlHandle_Free(handle); }
A handle received by the callback function can be of type PHT_EVENT or PHT_JOB. The type can be determined using the PrlHandle_GetType function. The PHT_EVENT type indicates that the callback was called by a system event. If the type is PHT_JOB then the callback was called by an asynchronous job started by the client.
To handle system events within a callback function:
1 Get the event type using PrlEvent_GetType. 2 Examine the event type. If it is relevant, a handle of type PHT_EVENT_PARAMETER can
be extracted using PrlEvent_GetParam.
3 Convert the PHT_EVENT_PARAMETER handle to the appropriate handle type using
PrlEvtPrm_ToHandle.
To handle jobs within a callback function:
Parallels C API Concepts 23
1 Get the job type using PrlJob_GetType. A job type can be used to identify the function
that started the job and to determine the type of the result it contains. For example, a job of type PJOC_SRV_GET_VM_LIST is started by PrlSrv_GetVmList function call, which returns a list of virtual machines.
2 Examine the job type. If it is relevant, proceed to the next step. 3 Get the job return code using PrlJob_GetRetCode. If it doesn't contain an error,
proceed to the next step.
4 Get the result (a handle of type PHT_RESULT) from the job handle using
PrlJob_GetResult.
5 Get a handle to the result using PrlResult_GetParam. Note that some functions return
a list (ie. there can be more than a single parameter in the result). For example,
PrlSrv_GetVmList returns a list of available virtual machines. In such cases, use PrlResult_GetParamCount and PrlResult_GetParamByIndex.
6 Implement code to use the handle obtained in step 5.
Note: You must always free the handle that was passed to the callback function before exiting, regardless of whether you actually used it or not. Failure to do so will result in a memory leak.
The following skeleton code demonstrates implementation of the above steps. In this example, the objective is to handle events of type PET_DSP_EVT_HOST_STATISTICS_UPDATED that are generated by a call to function PrlSrv_SubscribeToHostStatistics, and to obtain the result from a job of type PJOC_SRV_GET_VM_LIST.
static PRL_RESULT OurCallbackFunction(PRL_HANDLE hHandle, PRL_VOID_PTR pUserData) { PRL_JOB_OPERATION_CODE nJobType = PJOC_UNKNOWN; // job type PRL_HANDLE_TYPE nHandleType = PHT_ERROR; // handle type PRL_HANDLE hVm = PRL_INVALID_HANDLE; // virtual machine handle PRL_HANDLE hParam = PRL_INVALID_HANDLE; // event parameter PRL_HANDLE hJobResult = PRL_INVALID_HANDLE; // job result PRL_UINT32 nParamsCount = -1; // parameter count PRL_UINT32 nParamIndex = -1; // parameter index PRL_RESULT err = PRL_ERR_UNINITIALIZED; // error
// Check the type of the received handle. PrlHandle_GetType(hHandle, &nHandleType);
if (nHandleType == PHT_EVENT) // Event handle { PRL_EVENT_TYPE EventType; PrlEvent_GetType(hHandle, &EventType);
// Check if the event type is a statistics update. if (EventType == PET_DSP_EVT_HOST_STATISTICS_UPDATED) { // Get handle to PHT_EVENT_PARAMETER. PRL_HANDLE hEventParameters = PRL_INVALID_HANDLE; PrlEvent_GetParam(hHandle, 0, &hEventParameters);
// Get handle to PHT_SYSTEM_STATISTICS. PRL_HANDLE hServerStatistics = PRL_INVALID_HANDLE; PrlEvtPrm_ToHandle(hEventParameters, &hServerStatistics);
// Code goes here to extract the statistics data // using hServerStatistics.
Parallels C API Concepts 24
PrlHandle_Free(hServerStatistics); PrlHandle_Free(hEventParameters); } } else if (nHandleType == PHT_JOB) // Job handle { // Get the job type. PrlJob_GetOpCode(hHandle, &nJobType);
// Check if the job type is PJOC_SRV_GET_VM_LIST. if (nJobType == PJOC_SRV_GET_VM_LIST) { // Check the job return code. PRL_RESULT nJobRetCode; PrlJob_GetRetCode(hHandle, &nJobRetCode); if (PRL_FAILED(nJobRetCode)) { fprintf(stderr, "[B]%.8X: %s\n", nJobRetCode, prl_result_to_string(nJobRetCode)); PrlHandle_Free(hHandle); return nJobRetCode; }
err = PrlJob_GetResult(hHandle, &hJobResult);
// if (err != PRL_ERR_SUCCESS), process the error here.
// Determine the number of parameters in the result. PrlResult_GetParamsCount(hJobResult, &nParamsCount);
// Iterate through the parameter list. for(nParamIndex = 0; nParamIndex < nParamsCount ; nParamIndex++) { // Obtain a virtual machine handle (PHT_VIRTUAL_MACHINE). PrlResult_GetParamByIndex(hJobResult, nParamIndex, &hVm);
// Code goes here to obtain virtual machine info from hVm.
// Free the handle when done using it. PrlHandle_Free(hVm); } PrlHandle_Free(hJobResult); } }
PrlHandle_Free(hHandle); return PRL_ERR_SUCCESS; }
Registering / Unregistering an Event Handler
The PrlSrv_RegEventHandler function is used to register an event handler, PrlSrv_UnregEventHandler is used to unregister an event handler.
Note: When an event handler is registered, it will receive all of the events/jobs regardless of their origin. It is the responsibility of the client application to identify the type of the event and to handle each one accordingly.
// Register an event handler. ReturnDataClass rd; // some user-defined class. PrlSrv_RegEventHandler(hServer, OurCallbackFunction, &rd);
// Make a call to an asynchronous function here. // OurCallbackFunction will be called by the background thread
Parallels C API Concepts 25
// as soon as the job is completed, and code within // OurCallbackFunction can populate the ReturnDataClass instance. // For example, we can make the following call here:
hJob = PrlSrv_GetVmList(hServer); PrlHandle_Free(hJob);
// Please note that we still have to obtain the // job object (hJob above) and free it; otherwise // we will have memory leaks.
// Unregister the event handler when it is no longer needed. PrlSrv_UnregEventHandler(hServer, OurCallbackFunction, &rd);
Calling Asynchronous Functions Synchronously
It is possible to call an asynchronous function synchronously by using the PrlJob_Wait function. The function takes two parameters: a PHT_JOB handle and a timeout value in milliseconds. Once you call the function, the main thread will be suspended and the function will wait for the asynchronous job to complete. The function will return when the job is completed or when timeout value is reached, whichever comes first. The following code snippet illustrates how to call an asynchronous function PrlServer_Login synchronously:
// Log in (PrlSrv_Login is asynchronous). PRL_HANDLE hJob = PrlSrv_Login( hServer, szHostnameOrIpAddress, szUsername, szPassword, 0, 0, 0, PSL_LOW_SECURITY);
// Wait for a maximum of 10 seconds for // asynchronous function PrlSrv_Login to complete. ret = PrlJob_Wait(hJob, 10000); if (PRL_FAILED(ret)) { fprintf(stderr, "PrlJob_Wait for PrlSrv_Login returned with error: %s\n", prl_result_to_string(ret)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); return -1; }
// Analyse the result of the PrlServer_Login call. PRL_RESULT nJobResult; ret = PrlJob_GetRetCode(hJob, &nJobResult); if (PRL_FAILED(nJobResult)) { PrlHandle_Free(hJob); PrlHandle_Free(hServer); printf("Login job returned with error: %s\n", prl_result_to_string(nJobResult)); return -1; } else { printf("login successfully performed\n"); }
Parallels C API Concepts 26

Strings as Return Values

Sting values in the Parallels C API are received by passing a char pointer to a function which populates it with data. It is the responsibility of the caller to allocate the memory required to receive the value, and to free it when it is no longer needed. Since in most cases we don't know the string size in advance, we have to either allocate a chunk of memory large enough for any possible value or to determine the exact required size. To determine the required buffer size, the following two approaches can be used:
1 Calling the same function twice: first, to obtain the required buffer size, and second, to
receive the actual string value. To get the required buffer size, call the function passing a null pointer as a value of the output parameter, and pass 0 (zero) as a value of the variable that is used to specify the buffer size. The function will calculate the required size and will populate the variable with the correct value, which you can use to initialize a variable that will receive the string. You can then call the function again to get the actual string value.
2 It is also possible to use a static buffer. If the length of the buffer is large enough, you will
simply receive the result. If the length is too small, a function will fail with the PRL_ERR_BUFFER_OVERRUN error but it will populate the "buffer_size" variable with the required size value. You can then allocate the memory using the received value and call the function again to get the results.
Consider the following function:
PRL_RESULT PrlVmCfg_GetName( PRL_HANDLE hVmCfg, PRL_STR sVmName, PRL_UINT32_PTR pnVmNameBufLength );
The PrlVmCfg_GetName function above is a typical Parallels API function that returns a string value (in this case, the name of a virtual machine). The hVmCfg parameter is a handle to an object containing the virtual machine configuration information. The sVmName parameter is a char pointer. It is used as output that receives the virtual machine name. The variable must be initialized on the client side with enough memory allocated for the expected string. The size of the buffer must be specified using the pnVmNameBufLength variable.
The following example demonstrates how to call the function using the first approach:
PRL_RESULT ret; PRL_UINT32 nBufSize = 0;
// Get the required buffer size. ret = PrlVmCfg_GetName(hVmCfg, 0, &nBufSize);
// Allocate the memory. PRL_STR pBuf = (PRL_STR)malloc(sizeof(PRL_CHAR) * nBufSize);
// Get the virtual machine name. ret = PrlVmCfg_GetName(hVmCfg, pBuf, &nBufSize);
printf("VM name: %s\n", pBuf);
// Deallocate the memory. free(pBuf);
Parallels C API Concepts 27
The following example uses the second approach. To test the buffer-overrun scenario, set the
sVmName array size to some small number.
#define MY_STR_BUF_SIZE 1024
PRL_RESULT ret; char sVmName[MY_STR_BUF_SIZE]; PRL_UINT32 nBufSize = MY_STR_BUF_SIZE;
// Get the virtual machine name. ret = PrlVmCfg_GetName(hVmCfg, sVmName, &nBufSize);
// Check for errors. if (PRL_SUCCEEDED(ret)) { // Everything's OK, print the machine name. printf("VM name: %s\n", sVmName); } else if (ret == PRL_ERR_BUFFER_OVERRUN) { // The sVmName array size is too small. // Get the required size, allocate the memory, // and try getting the VM name again.
PRL_UINT32 nSize = 0; PRL_STR pBuf;
// Get the required buffer size. ret = PrlVmCfg_GetName(hVmCfg, 0, &nSize);
// Allocate the memory. pBuf = (PRL_STR)malloc(sizeof(PRL_CHAR) * nSize);
// Get the virtual machine name. ret = PrlVmCfg_GetName(hVmCfg, pBuf, &nSize);
printf("VM name: %s\n", pBuf);
// Dallocate the memory. free(pBuf); }
Parallels C API Concepts 28

Error Handling

Synchronous Functions
All synchronous Parallels C API functions return PRL_RESULT, which is an integer indicating success or failure of the operation.
Error Codes for Asynchronous Functions
All asynchronous functions return PRL_HANDLE. The error code (return value) in this case can be extracted with PrlJob_GetRetCode after the asynchronous job has finished.
Analyzing Return Values
Parallels C API provides the following macros to work with error codes:
PRL_FAILED
Returns True if the return value indicates failure, or False if the return value indicates success.
PRL_SUCCEEDED
Returns True if the return value indicates success, or False if the return value indicates failure.
prl_result_to_string
Returns a string representation of the error code.
The following code snippet attempts to create a directory on the host and analyzes the return value (error code) of asynchronous function PrlSrv_CreateDir.
// Attempt to create directory /tmp/TestDir on the host. char *szRemoteDir = "/tmp/TestDir"; hJob = PrlSrv_FsCreateDir(hServer, szRemoteDir);
// Wait for a maximum of 5 seconds for asynchronous // function PrlSrv_FsCreateDir to complete. PRL_RESULT resWaitForCreateDir = PrlJob_Wait(hJob, 5000); if (PRL_FAILED(resWaitForCreateDir)) { fprintf(stderr, "PrlJob_Wait for PrlSvr_FsCreateDir failed with error: %s\n", prl_result_to_string(resWaitForCreateDir)); PrlHandle_Free(hJob); return -1; }
// Extract the asynchronous function return code. PrlJob_GetRetCode(hJob, &nJobResult); if (PRL_FAILED(nJobResult)) { fprintf(stderr, "Error creating directory %s. Error returned: %s\n", szRemoteDir, prl_result_to_string(nJobResult)); PrlHandle_Free(hJob); return -1; }
PrlHandle_Free( hJob ); printf( "Remote directory %s was successfully created.\n", szRemoteDir );
Descriptive Error Strings
Parallels C API Concepts 29
Descriptive error messages can sometimes be obtained using the PrlJob_GetError function. This function will return a handle to an object of type PHT_EVENT. In cases where
PrlJob_GetError is unable to return error information, PrlApi_GetResultDescription can be used. Although it is possible to avoid using PrlJob_GetError and use PrlJob_GetResultDescription instead, it is
recommended to first use PrlJob_GetError, and if this doesn't return additional descriptive error information then use PrlApi_GetResultDescription. The reason is that sometimes errors contain dynamic parameters. The following example demonstrates how to obtain descriptive error information:
PrlJob_GetRetCode(hJob, &nJobResult);
PRL_CHAR szErrBuff[1024]; PRL_UINT32 nErrBuffSize = sizeof(szErrBuff); PRL_HANDLE hError = PRL_INVALID_HANDLE; PRL_RESULT ret = PrlJob_GetError(hJob, &hError);
// Check if additional error information is available. if (PRL_SUCCEEDED(ret)) // Additional error information is available. { // Additional error information is available. ret = PrlEvent_GetErrString(hError, PRL_FALSE, PRL_FALSE, szErrBuff, &nErrBuffSize); if (PRL_FAILED(ret)) { printf("PrlEvent_GetErrString returned error: %.8x %s\n", ret, prl_result_to_string(ret)); } else { // Extra error information is available, display it. printf("Error returned: %.8x %s\n", nJobResult, prl_result_to_string(nJobResult)); printf("Descriptive error: %s\n", szErrBuff); } } else { // No additional error information available, so use PrlApi_GetResultDescription. ret = PrlApi_GetResultDescription(nJobResult, PRL_FALSE, PRL_FALSE, szErrBuff, &nErrBuffSize); if (PRL_FAILED(ret)) { printf("PrlApi_GetResultDescription returned error: %s\n", prl_result_to_string(ret)); } else { printf("Error returned: %.8x %s\n", nJobResult, prl_result_to_string(nJobResult)); printf("Descriptive error: %s\n", szErrBuff); } } // Free handles, return the error code. PrlHandle_Free(hJob); PrlHandle_Free(hError); return nJobResult; }
C HAPTER 3

Parallels C API by Example

In This Chapter
Obtaining Server Handle and Logging In............................................................................. 31
Host Operations..................................................................................................................... 35
Virtual Machine Operations.................................................................................................. 58
Events.................................................................................................................................... 110
Performance Statistics........................................................................................................... 121
Encryption Plug-in................................................................................................................ 130
Loading...
+ 154 hidden pages