diff options
Diffstat (limited to 'doc/manual/en_US/SDKRef.xml')
-rw-r--r-- | doc/manual/en_US/SDKRef.xml | 776 |
1 files changed, 599 insertions, 177 deletions
diff --git a/doc/manual/en_US/SDKRef.xml b/doc/manual/en_US/SDKRef.xml index 40e1559f..e8c63cc3 100644 --- a/doc/manual/en_US/SDKRef.xml +++ b/doc/manual/en_US/SDKRef.xml @@ -308,7 +308,7 @@ <computeroutput>user1</computeroutput>, it will see and manipulate the virtual machines and other data represented by the VirtualBox data of that user (for example, on a Linux machine, under - <computeroutput>/home/user1/.VirtualBox</computeroutput>; see the + <computeroutput>/home/user1/.config/VirtualBox</computeroutput>; see the VirtualBox User Manual for details on where this data is stored).</para> <sect2 id="vboxwebsrv-ref"> @@ -1542,7 +1542,7 @@ for m in mgr.getArray(vbox, 'machines'): print "Machine '%s' logs in '%s'" %(m.name, m.logFolder) </screen> - <para>Code above demonstartes cross-platform access to array properties + <para>Code above demonstrates cross-platform access to array properties (certain limitations prevent one from using <computeroutput>vbox.machines</computeroutput> to access a list of available virtual machines in case of XPCOM), and a mechanism of @@ -1718,157 +1718,210 @@ print "Machine '%s' logs in '%s'" %(m.name, m.logFolder) </sect2> <sect2 id="cbinding"> - <title>C binding to XPCOM API</title> + <title>C binding to VirtualBox API</title> - <note> - <para>This section currently applies to Linux hosts only.</para> - </note> + <para>The VirtualBox API originally is designed as object oriented, + using XPCOM or COM as the middleware, which translates natively to C++. + This means that in order to use it from C there needs to be some + helper code to bridge the language differences and reduce the + differences between platforms.</para> - <para>Starting with version 2.2, VirtualBox offers a C binding for the - XPCOM API.</para> + <sect3 id="capi_glue"> + <title>Cross-platform C binding to VirtualBox API</title> - <para>The C binding provides a layer enabling object creation, method - invocation and attribute access from C.</para> + <para>Starting with version 4.3, VirtualBox offers a C binding + which allows using the same C client sources for all platforms, + covering Windows, Linux, Mac OS X and Solaris. It is the + preferred way to write API clients, even though the old style + is still available.</para> + + </sect3> <sect3 id="c-gettingstarted"> <title>Getting started</title> - <para>The following sections describe how to use the C binding in a - C program.</para> - - <para>For Linux, a sample program is provided which demonstrates use - of the C binding to initialize XPCOM, get handles for VirtualBox and - Session objects, make calls to list and start virtual machines, and - uninitialize resources when done. The program uses the VBoxGlue - library to open the C binding layer during runtime.</para> - - <para>The sample program - <computeroutput>tstXPCOMCGlue</computeroutput> is located in the bin - directory and can be run without arguments. It lists registered - machines on the host along with some additional information and ask - for a machine to start. The source for this program is available in - <computeroutput>sdk/bindings/xpcom/cbinding/samples/</computeroutput> - directory. The source for the VBoxGlue library is available in the - <computeroutput>sdk/bindings/xpcom/cbinding/</computeroutput> - directory.</para> + <para>The following sections describe how to use the VirtualBox API + in a C program. The necessary files are included in the SDK, in the + directories <computeroutput>sdk/bindings/c/include</computeroutput> + and <computeroutput>sdk/bindings/c/glue</computeroutput>.</para> + + <para>As part of the SDK, a sample program + <computeroutput>tstCAPIGlue.c</computeroutput> is provided in the + directory <computeroutput>sdk/bindings/c/samples</computeroutput> + which demonstrates + using the C binding to initialize the API, get handles for + VirtualBox and Session objects, make calls to list and start virtual + machines, monitor events, and uninitialize resources when done. The + sample program is trying to illustrate all relevant concepts, so it + is a great source of detail information. Among many other generally + useful code sequences it contains a function which shows how to + retrieve error details in C code if they are available from the API + call.</para> + + <para>The sample program <computeroutput>tstCAPIGlue</computeroutput> + can be built using the provided <computeroutput>Makefile</computeroutput> + and can be run without arguments.</para> + + <para>It uses the VBoxCAPIGlue library (source code is in directory + <computeroutput>sdk/bindings/c/glue</computeroutput>, to be used in + your API client code) to open the C binding layer during runtime, + which is preferred to other means as it isolates the code which + locates the necessary dynamic library, using a known working way + which works on all platforms. If you encounter problems with this + glue code in <computeroutput>VBoxCAPIGlue.c</computeroutput>, let the + VirtualBox developers know, rather than inventing incompatible + solutions.</para> + + <para>The following sections document the important concepts needed + to correctly use the C binding, as it is vital for developing API + client code which manages memory correctly, updates the reference + counters correctly, avoiding crashes and memory leaks. Often API + clients need to handle events, so the C API specifics are also + described below.</para> </sect3> <sect3 id="c-initialization"> - <title>XPCOM initialization</title> - - <para>Just like in C++, XPCOM needs to be initialized before it can - be used. The <computeroutput>VBoxCAPI_v2_5.h</computeroutput> header - provides the interface to the C binding. Here's how to initialize - XPCOM:</para> - - <screen>#include "VBoxCAPI_v2_5.h" + <title>VirtualBox C API initialization</title> + + <para>Just like in C++, the API and the underlying middleware needs + to be initialized before it can be used. The + <computeroutput>VBoxCAPI_v4_3.h</computeroutput> header provides the + interface to the C binding, but you can alternatively and more + conveniently also include <computeroutput>VBoxCAPIGlue.h</computeroutput>, + as this avoids the VirtualBox version dependent header file name and + makes sure the global variable <code>g_pVBoxFuncs</code> contains a + pointer to the structure which contains the helper function pointers. + Here's how to initialize the C API:<screen>#include "VBoxCAPIGlue.h" ... -PCVBOXXPCOM g_pVBoxFuncs = NULL; -IVirtualBox *vbox = NULL; -ISession *session = NULL; +IVirtualBoxClient *vboxclient = NULL; +IVirtualBox *vbox = NULL; +ISession *session = NULL; +HRESULT rc; +ULONG revision; /* - * VBoxGetXPCOMCFunctions() is the only function exported by - * VBoxXPCOMC.so and the only one needed to make virtualbox - * work with C. This functions gives you the pointer to the - * function table (g_pVBoxFuncs). + * VBoxCGlueInit() loads the necessary dynamic library, handles errors + * (producing an error message hinting what went wrong) and gives you + * the pointer to the function table (g_pVBoxFuncs). * * Once you get the function table, then how and which functions * to use is explained below. * - * g_pVBoxFuncs->pfnComInitialize does all the necessary startup - * action and provides us with pointers to vbox and session handles. - * It should be matched by a call to g_pVBoxFuncs->pfnComUninitialize() + * g_pVBoxFuncs->pfnClientInitialize does all the necessary startup + * action and provides us with pointers to an IVirtualBoxClient instance. + * It should be matched by a call to g_pVBoxFuncs->pfnClientUninitialize() * when done. */ -g_pVBoxFuncs = VBoxGetXPCOMCFunctions(VBOX_XPCOMC_VERSION); -g_pVBoxFuncs->pfnComInitialize(&vbox, &session);</screen> - - <para>If either <computeroutput>vbox</computeroutput> or - <computeroutput>session</computeroutput> is still - <computeroutput>NULL</computeroutput>, initialization failed and the - XPCOM API cannot be used.</para> +if (VBoxCGlueInit()) +{ + fprintf(stderr, "s: FATAL: VBoxCGlueInit failed: %s\n", + argv[0], g_szVBoxErrMsg); + return EXIT_FAILURE; +} + +g_pVBoxFuncs->pfnClientInitialize(NULL, &vboxclient); +if (!vboxclient) +{ + fprintf(stderr, "%s: FATAL: could not get VirtualBoxClient reference\n", + argv[0]); + return EXIT_FAILURE; +}</screen></para> + + <para>If <computeroutput>vboxclient</computeroutput> is still + <computeroutput>NULL</computeroutput> this means the initializationi + failed and the VirtualBox C API cannot be used.</para> + + <para>It is possible to write C applications using multiple threads + which all use the VirtualBox API, as long as you're initializing + the C API in each thread which your application creates. This is done + with <code>g_pVBoxFuncs->pfnClientThreadInitialize()</code> and + likewise before the thread is terminated the API must be + uninitialized with + <code>g_pVBoxFuncs->pfnClientThreadUninitialize()</code>. You don't + have to use these functions in worker threads created by COM/XPCOM + (which you might observe if your code uses active event handling), + everything is initialized correctly already. On Windows the C + bindings create a marshaller which supports a wide range of COM + threading models, from STA to MTA, so you don't have to worry about + these details unless you plan to use active event handlers. See + the sample code how to get this to work reliably (in other words + think twice if passive event handling isn't the better solution after + you looked at the sample code).</para> </sect3> <sect3 id="c-invocation"> - <title>XPCOM method invocation</title> + <title>C API attribute and method invocation</title> <para>Method invocation is straightforward. It looks pretty much - like the C++ way, augmented with an extra indirection due to - accessing the vtable and passing a pointer to the object as the - first argument to serve as the <computeroutput>this</computeroutput> - pointer.</para> + like the C++ way, by using a macro which internally accesses the + vtable, and additionally needs to be passed a pointer to the objecti + as the first argument to serve as the + <computeroutput>this</computeroutput> pointer.</para> <para>Using the C binding, all method invocations return a numeric - result code.</para> + result code of type <code>HRESULT</code> (with a few exceptions + which normally are not relevant).</para> <para>If an interface is specified as returning an object, a pointer to a pointer to the appropriate object must be passed as the last argument. The method will then store an object pointer in that location.</para> - <para>In other words, to call an object's method what you need - is</para> + <para>Likewise, attributes (properties) can be queried or set using + method invocations, using specially named methods. For each + attribute there exists a getter method, the name of which is composed + of <computeroutput>get_</computeroutput> followed by the capitalized + attribute name. Unless the attribute is read-only, an analogous + <computeroutput>set_</computeroutput> method exists. Let's apply + these rules to get the <computeroutput>IVirtualBox</computeroutput> + reference, an <computeroutput>ISession</computeroutput> instance + reference and read the <xref linkend="IVirtualBox__revision" + xreflabel="IVirtualBox::revision" /> attribute:<screen>rc = IVirtualBoxClient_get_VirtualBox(vboxclient, &vbox); +if (FAILED(rc) || !vbox) +{ + PrintErrorInfo(argv[0], "FATAL: could not get VirtualBox reference", rc); + return EXIT_FAILURE; +} +rc = IVirtualBoxClient_get_Session(vboxclient, &session); +if (FAILED(rc) || !session) +{ + PrintErrorInfo(argv[0], "FATAL: could not get Session reference", rc); + return EXIT_FAILURE; +} - <screen>IObject *object; -nsresult rc; -... -/* - * Calling void IObject::method(arg, ...) - */ -rc = object->vtbl->Method(object, arg, ...); +rc = IVirtualBox_get_Revision(vbox, &revision); +if (SUCCEEDED(rc)) +{ + printf("Revision: %u\n", revision); +}</screen></para> + <para>The convenience macros for calling a method are named by + prepending the method name with the interface name (using + <code>_</code>as the separator).</para> + + <para>So far only attribute getters were illustrated, but generic + method calls are straightforward, too:<screen>IMachine *machine = NULL; +BSTR vmname = ...; ... -IFoo *foo; /* - * Calling IFoo IObject::method(arg, ...) + * Calling IMachine::findMachine(...) */ -rc = object->vtbl->Method(object, args, ..., &foo);</screen> +rc = IVirtualBox_FindMachine(vbox, vmname, &machine);</screen></para> - <para>As a real-world example of a method invocation, let's call - <xref linkend="IMachine__launchVMProcess" + <para>As a more complicated example of a method invocation, let's + call <xref linkend="IMachine__launchVMProcess" xreflabel="IMachine::launchVMProcess" /> which returns an IProgress object. Note again that the method name is - capitalized.</para> - - <screen>IProgress *progress; + capitalized:<screen>IProgress *progress; ... -rc = vbox->vtbl->LaunchVMProcess( +rc = IMachine_LaunchVMProcess( machine, /* this */ session, /* arg 1 */ sessionType, /* arg 2 */ env, /* arg 3 */ &progress /* Out */ -); -</screen> - </sect3> - - <sect3 id="c-attributes"> - <title>XPCOM attribute access</title> - - <para>A construct similar to calling non-void methods is used to - access object attributes. For each attribute there exists a getter - method, the name of which is composed of - <computeroutput>Get</computeroutput> followed by the capitalized - attribute name. Unless the attribute is read-only, an analogous - <computeroutput>Set</computeroutput> method exists. Let's apply - these rules to read the <xref linkend="IVirtualBox__revision" - xreflabel="IVirtualBox::revision" /> attribute.</para> - - <para>Using the <computeroutput>IVirtualBox</computeroutput> handle - <computeroutput>vbox</computeroutput> obtained above, calling its - <computeroutput>GetRevision</computeroutput> method looks like - this:</para> - - <screen>PRUint32 rev; - -rc = vbox->vtbl->GetRevision(vbox, &rev); -if (NS_SUCCEEDED(rc)) -{ - printf("Revision: %u\n", (unsigned)rev); -} -</screen> +);</screen></para> <para>All objects with their methods and attributes are documented in <xref linkend="sdkref_classes" />.</para> @@ -1880,65 +1933,173 @@ if (NS_SUCCEEDED(rc)) <para>When dealing with strings you have to be aware of a string's encoding and ownership.</para> - <para>Internally, XPCOM uses UTF-16 encoded strings. A set of + <para>Internally, the API uses UTF-16 encoded strings. A set of conversion functions is provided to convert other encodings to and from UTF-16. The type of a UTF-16 character is - <computeroutput>PRUnichar</computeroutput>. Strings of UTF-16 - characters are arrays of that type. Most string handling functions - take pointers to that type. Prototypes for the following conversion - functions are declared in - <computeroutput>VBoxCAPI_v2_5.h</computeroutput>.</para> - - <sect4> - <title>Conversion of UTF-16 to and from UTF-8</title> - - <screen>int (*pfnUtf16ToUtf8)(const PRUnichar *pwszString, char **ppszString); -int (*pfnUtf8ToUtf16)(const char *pszString, PRUnichar **ppwszString); -</screen> - </sect4> + <computeroutput>BSTR</computeroutput> (or its constant counterpart + <computeroutput>CBSTR</computeroutput>), which is an array type, + represented by a pointer to the start of the zero-terminated string. + There are functions for converting between UTF-8 and UTF-16 strings + available through <code>g_pVBoxFuncs</code>:<screen>int (*pfnUtf16ToUtf8)(CBSTR pwszString, char **ppszString); +int (*pfnUtf8ToUtf16)(const char *pszString, BSTR *ppwszString);</screen></para> + + <para>The ownership of a string determines who is responsible for + releasing resources associated with the string. Whenever the API + creates a string (essentially for output parameters), ownership is + transferred to the caller. To avoid resource leaks, the caller + should release resources once the string is no longer needed. + There are plenty of examples in the sample code.</para> + </sect3> + + <sect3 id="c-safearray"> + <title>Array handling</title> + + <para>Arrays are handled somewhat similarly to strings, with the + additional information of the number of elements in the array. The + exact details of string passing depends on the platform middleware + (COM/XPCOM), and therefore the C binding offers helper functions to + gloss over these differences.</para> + + <para>Passing arrays as input parameters to API methods is usually + done by the following sequence, calling a hypothetical + <code>IArrayDemo_PassArray</code> API method:<screen>static const ULONG aElements[] = { 1, 2, 3, 4 }; +ULONG cElements = sizeof(aElements) / sizeof(aElements[0]); +SAFEARRAY *psa = NULL; +psa = g_pVBoxFuncs->pfnSafeArrayCreateVector(VT_I4, 0, cElements); +g_pVBoxFuncs->pfnSafeArrayCopyInParamHelper(psa, aElements, sizeof(aElements)); +IArrayDemo_PassArray(pThis, ComSafeArrayAsInParam(psa)); +g_pVBoxFuncs->pfnSafeArrayDestroy(psa);</screen></para> + + <para>Likewise, getting arrays results from output parameters is done + using helper functions which manage memory allocations as part of + their other functionality:<screen>SAFEARRAY *psa = g_pVBoxFuncs->pfnSafeArrayOutParamAlloc(); +ULONG *pData; +ULONG cElements; +IArrayDemo_ReturnArray(pThis, ComSafeArrayAsOutParam(psa)); +g_pVBoxFuncs->pfnSafeArrayCopyOutParamHelper((void **)&pData, &cElements, VT_I4, psa); +g_pVBoxFuncs->pfnSafeArrayDestroy(psa);</screen></para> + + <para>This covers the necessary functionality for all array element + types except interface references. These need special helpers to + manage the reference counting correctly. The following code snippet + gets the list of VMs, and passes the first IMachine reference to + another API function (assuming that there is at least one element + in the array, to simplify the example):<screen>SAFEARRAY psa = g_pVBoxFuncs->pfnSafeArrayOutParamAlloc(); +IMachine **machines = NULL; +ULONG machineCnt = 0; +ULONG i; +IVirtualBox_get_Machines(virtualBox, ComSafeArrayAsOutIfaceParam(machinesSA, IMachine *)); +g_pVBoxFuncs->pfnSafeArrayCopyOutIfaceParamHelper((IUnknown ***)&machines, &machineCnt, machinesSA); +g_pVBoxFuncs->pfnSafeArrayDestroy(machinesSA); +/* Now "machines" contains the IMachine references, and machineCnt the + * number of elements in the array. */ +... +SAFEARRAY *psa = g_pVBoxFuncs->pfnSafeArrayCreateVector(VT_IUNKNOWN, 0, 1); +g_pVBoxFuncs->pfnSafeArrayCopyInParamHelper(psa, (void *)&machines[0], sizeof(machines[0])); +IVirtualBox_GetMachineStates(ComSafeArrayAsInParam(psa), ...); +... +g_pVBoxFuncs->pfnSafeArrayDestroy(psa); +for (i = 0; i < machineCnt; ++i) +{ + IMachine *machine = machines[i]; + IMachine_Release(machine); +} +free(machines);</screen></para> - <sect4> - <title>Ownership</title> + <para>Handling output parameters needs more special effort than + input parameters, thus only for the former there are special helpers, + and the latter is handled through the generic array support.</para> + </sect3> - <para>The ownership of a string determines who is responsible for - releasing resources associated with the string. Whenever XPCOM - creates a string, ownership is transferred to the caller. To avoid - resource leaks, the caller should release resources once the - string is no longer needed.</para> - </sect4> + <sect3 id="c-eventhandling"> + <title>Event handling</title> + + <para>The VirtualBox API offers two types of event handling, active + and passive, and consequently there is support for both with the + C API binding. Active event handling (based on asynchronous + callback invocation for event delivery) is more difficult, as it + requires the construction of valid C++ objects in C, which is + inherently platform and compiler dependent. Passive event handling + is much simpler, it relies on an event loop, fetching events and + triggering the necessary handlers explicitly in the API client code. + Both approaches depend on an event loop to make sure that events + get delivered in a timely manner, with differences what exactly needs + to be done.</para> + + <para>The C API sample contains code for both event handling styles, + and one has to modify the appropriate <code>#define</code> to select + which style is actually used by the compiled program. It allows a + good comparison between the two variants, and the code sequences are + probably worth reusing without much change in other API clients + with only minor adaptions.</para> + + <para>Active event handling needs to ensure that the following helper + function is called frequently enough in the primary thread: + <screen>g_pVBoxFuncs->pfnProcessEventQueue(cTimeoutMS);</screen></para> + + <para>The actual event handler implementation is quite tedious, as + it has to implement a complete API interface. Especially on Windows + it is a lot of work to implement the complicated <code>IDispatch</code> + interface, requiring to load COM type information and using it + in the <code>IDispatch</code> method implementation. Overall this is + quite tedious compared to passive event handling.</para> + + <para>Passive event handling uses a similar event loop structure, + which requires calling the following function in a loop, and + processing the returned event appropriately: + <screen>rc = IEventSource_GetEvent(pEventSource, pListener, cTimeoutMS, &pEvent);</screen></para> + + <para>After processing the event it needs to be marked as processed + with the following method call: + <screen>rc = IEventSource_EventProcessed(pEventSource, pListener, pEvent);</screen></para> + + <para>This is vital for vetoable events, as they would be stuck + otherwise, waiting whether the veto comes or not. It does not do any + harm for other event types, and in the end is cheaper than checking + if the event at hand is vetoable or not.</para> + + <para>The general event handling concepts are described in the API + specification (see <xref linkend="events" />), including how to + aggregate multiple event sources for processing in one event loop. + As mentioned, the sample illustrates the practical aspects of how to + use both types of event handling, active and passive, from a C + application. Additional hints are in the comments documenting + the helper methods in <computeroutput>VBoxCAPI_v4_3.h</computeroutput>. + The code complexity of active event handling (and its inherenly + platform/compiler specific aspects) should be motivation to use + passive event handling whereever possible.</para> </sect3> <sect3 id="c-uninitialization"> - <title>XPCOM uninitialization</title> + <title>C API uninitialization</title> <para>Uninitialization is performed by - <computeroutput>g_pVBoxFuncs->pfnComUninitialize().</computeroutput> + <computeroutput>g_pVBoxFuncs->pfnClientUninitialize().</computeroutput> If your program can exit from more than one place, it is a good idea to install this function as an exit handler with Standard C's <computeroutput>atexit()</computeroutput> just after calling - <computeroutput>g_pVBoxFuncs->pfnComInitialize()</computeroutput> + <computeroutput>g_pVBoxFuncs->pfnClientInitialize()</computeroutput> , e.g. <screen>#include <stdlib.h> #include <stdio.h> ... /* - * Make sure g_pVBoxFuncs->pfnComUninitialize() is called at exit, no + * Make sure g_pVBoxFuncs->pfnClientUninitialize() is called at exit, no * matter if we return from the initial call to main or call exit() * somewhere else. Note that atexit registered functions are not * called upon abnormal termination, i.e. when calling abort() or - * signal(). Separate provisions must be taken for these cases. + * signal(). */ -if (atexit(g_pVBoxFuncs->pfnComUninitialize()) != 0) { - fprintf(stderr, "failed to register g_pVBoxFuncs->pfnComUninitialize()\n"); +if (atexit(g_pVBoxFuncs->pfnClientUninitialize()) != 0) { + fprintf(stderr, "failed to register g_pVBoxFuncs->pfnClientUninitialize()\n"); exit(EXIT_FAILURE); -} -</screen></para> +}</screen></para> <para>Another idea would be to write your own <computeroutput>void myexit(int status)</computeroutput> function, calling - <computeroutput>g_pVBoxFuncs->pfnComUninitialize()</computeroutput> + <computeroutput>g_pVBoxFuncs->pfnClientUninitialize()</computeroutput> followed by the real <computeroutput>exit()</computeroutput>, and use it instead of <computeroutput>exit()</computeroutput> throughout your program and at the end of @@ -1948,15 +2109,14 @@ if (atexit(g_pVBoxFuncs->pfnComUninitialize()) != 0) { user types CTRL-C sending SIGINT) you might want to install a signal handler setting a flag noting that a signal was sent and then calling - <computeroutput>g_pVBoxFuncs->pfnComUninitialize()</computeroutput> - later on (usually <emphasis>not</emphasis> from the handler itself - .)</para> + <computeroutput>g_pVBoxFuncs->pfnClientUninitialize()</computeroutput> + later on, <emphasis>not</emphasis> from the handler itself.</para> <para>That said, if a client program forgets to call - <computeroutput>g_pVBoxFuncs->pfnComUninitialize()</computeroutput> + <computeroutput>g_pVBoxFuncs->pfnClientUninitialize()</computeroutput> before it terminates, there is a mechanism in place which will - eventually release references held by the client. You should not - rely on this, however.</para> + eventually release references held by the client. On Windows it can + take quite a while, in the order of 6-7 minutes.</para> </sect3> <sect3 id="c-linking"> @@ -1964,27 +2124,101 @@ if (atexit(g_pVBoxFuncs->pfnComUninitialize()) != 0) { <para>A program using the C binding has to open the library during runtime using the help of glue code provided and as shown in the - example <computeroutput>tstXPCOMCGlue.c</computeroutput>. - Compilation and linking can be achieved, e.g., with a makefile - fragment similar to</para> - - <screen># Where is the XPCOM include directory? -INCS_XPCOM = -I../../include -# Where is the glue code directory? -GLUE_DIR = .. -GLUE_INC = -I.. - -#Compile Glue Library -VBoxXPCOMCGlue.o: $(GLUE_DIR)/VBoxXPCOMCGlue.c - $(CC) $(CFLAGS) $(INCS_XPCOM) $(GLUE_INC) -o $@ -c $< - -# Compile. -program.o: program.c VBoxCAPI_v2_5.h - $(CC) $(CFLAGS) $(INCS_XPCOM) $(GLUE_INC) -o $@ -c $< - -# Link. -program: program.o VBoxXPCOMCGlue.o - $(CC) -o $@ $^ -ldl</screen> + example <computeroutput>tstCAPIGlue.c</computeroutput>. + Compilation and linking can be achieved with a makefile fragment + similar to:<screen># Where is the SDK directory? +PATH_SDK = ../../.. +CAPI_INC = -I$(PATH_SDK)/bindings/c/include +ifeq ($(BUILD_PLATFORM),win) +PLATFORM_INC = -I$(PATH_SDK)/bindings/mscom/include +PLATFORM_LIB = $(PATH_SDK)/bindings/mscom/lib +else +PLATFORM_INC = -I$(PATH_SDK)/bindings/xpcom/include +PLATFORM_LIB = $(PATH_SDK)/bindings/xpcom/lib +endif +GLUE_DIR = $(PATH_SDK)/bindings/c/glue +GLUE_INC = -I$(GLUE_DIR) + +# Compile Glue Library +VBoxCAPIGlue.o: $(GLUE_DIR)/VBoxCAPIGlue.c + $(CC) $(CFLAGS) $(CAPI_INC) $(PLATFORM_INC) $(GLUE_INC) -o $@ -c $< + +# Compile interface ID list +VirtualBox_i.o: $(PLATFORM_LIB)/VirtualBox_i.c + $(CC) $(CFLAGS) $(CAPI_INC) $(PLATFORM_INC) $(GLUE_INC) -o $@ -c $< + +# Compile program code +program.o: program.c + $(CC) $(CFLAGS) $(CAPI_INC) $(PLATFORM_INC) $(GLUE_INC) -o $@ -c $< + +# Link program. +program: program.o VBoxCAPICGlue.o VirtualBox_i.o + $(CC) -o $@ $^ -ldl -lpthread</screen></para> + </sect3> + + <sect3 id="capi_conversion"> + <title>Conversion of code using legacy C binding</title> + + <para>This section aims to make the task of converting code using + the legacy C binding to the new style a breeze, by pointing out some + key steps.</para> + + <para>One necessary change is adjusting your Makefile to reflect the + different include paths. See above. There are now 3 relevant include + directories, and most of it is pointing to the C binding directory. + The XPCOM include directory is still relevant for platforms where + the XPCOM middleware is used, but most of the include files live + elsewhere now, so it's good to have it last. Additionally the + <computeroutput>VirtualBox_i.c</computeroutput> file needs to be + compiled and linked to the program, it contains the IIDs relevant + for the VirtualBox API, making sure they are not replicated endlessly + if the code refers to them frequently.</para> + + <para>The C API client code should include <computeroutput>VBoxCAPIGlue.h</computeroutput> + instead of <computeroutput>VBoxXPCOMCGlue.h</computeroutput> or + <computeroutput>VBoxCAPI_v4_3.h</computeroutput>, as this makes sure + the correct macros and internal translations are selected.</para> + + <para>All API method calls (anything mentioning <code>vtbl</code>) + should be rewritten using the convenience macros for calling methods, + as these hide the internal details, are generally easier to use and + shorter to type. You should remove as many as possible + <code>(nsISupports **)</code> or similar typecasts, as the new style + should use the correct type in most places, increasing the type + safety in case of an error in the source code.</para> + + <para>To gloss over the platform differences, API client code should + no longer rely on XPCOM specific interface names such as + <code>nsISupports</code>, <code>nsIException</code> and + <code>nsIEventQueue</code>, and replace them by the platform + independent interface names <code>IUnknown</code> and + <code>IErrorInfo</code> for the first two respectively. Event queue + handling should be replaced by using the platform independent way + described in <xref linkend="c-eventhandling" />.</para> + + <para>Finally adjust the string and array handling to use the new + helpers, as these make sure the code works without changes with + both COM and XPCOM, which are significantly different in this area. + The code should be double checked if it uses the correct way to + manage memory, and is freeing it only after the last use.</para> + </sect3> + + <sect3 id="xpcom_cbinding"> + <title>Legacy C binding to VirtualBox API for XPCOM</title> + + <note> + <para>This section applies to Linux, Mac OS X and Solaris + hosts only and describes deprecated use of the API from C.</para> + </note> + + <para>Starting with version 2.2, VirtualBox offers a C binding for + its API which works only on platforms using XPCOM. Refer to the + old SDK documentation (included in the SDK packages for version 4.3.6 + or earlier), it still applies unchanged. The fundamental concepts are + similar (but the syntactical details are quite different) to the + newer cross-platform C binding which should be used for all new code, + as the support for the old C binding will go away in a major release + after version 4.3.</para> </sect3> </sect2> </sect1> @@ -2133,7 +2367,7 @@ if (prog.getResultCode() != 0) // check success stopped, snapshotted or other things.</para> </sect1> - <sect1> + <sect1 id="events"> <title>VirtualBox events</title> <para>In VirtualBox, "events" provide a uniform mechanism to register @@ -2216,8 +2450,8 @@ es.unregisterListener(listener); </screen></para> three COM/XPCOM/WS styles of the API.</para> <para>You can easily extend this shell with your own commands. Create a - subdirectory named <computeroutput>.VirtualBox/shexts</computeroutput> - below your home directory and put a Python file implementing your shell + subdirectory named <computeroutput>.config/VirtualBox/shexts</computeroutput> + below your home directory (respectively <computeroutput>.VirtualBox/shexts</computeroutput> on a Windows system and <computeroutput>Library/VirtualBox/shexts</computeroutput> on OS X) and put a Python file implementing your shell extension commands in this directory. This file must contain an array named <computeroutput>commands</computeroutput> containing your command definitions: <screen> @@ -2245,7 +2479,7 @@ es.unregisterListener(listener); </screen></para> # Call VirtualBox API, using context's fields hdd = ctx['vb'].createHardDisk(format, loc) # Access constants using ctx['global'].constants - progress = hdd.createBaseStorage(size, ctx['global'].constants.HardDiskVariant_Standard) + progress = hdd.createBaseStorage(size, (ctx['global'].constants.MediumVariant_Standard, )) # use standard progress bar mechanism ctx['progressBar'](progress) @@ -2266,7 +2500,7 @@ es.unregisterListener(listener); </screen></para> } </screen> Just store the above text in the file <computeroutput>createHdd</computeroutput> (or any other meaningful name) - in <computeroutput>.VirtualBox/shexts/</computeroutput>. Start the + in <computeroutput>.config/VirtualBox/shexts/</computeroutput>. Start the VirtualBox shell, or just issue the <computeroutput>reloadExts</computeroutput> command, if the shell is already running. Your new command will now be available.</para> @@ -3447,7 +3681,7 @@ AuthResult AUTHCALL AuthEntry( setup phase (see <computeroutput>ws</computeroutput> variable). In the SOAP case it's possible to create several VirtualBoxManager instances to communicate with multiple VirtualBox hosts. <programlisting> - import org.virtualbox_3_3.*; + import org.virtualbox_4_3.*; .... VirtualBoxManager mgr = VirtualBoxManager.createInstance(null); boolean ws = false; // or true, if we need the SOAP version @@ -3472,7 +3706,8 @@ AuthResult AUTHCALL AuthEntry( mgr.cleanup(); </programlisting> For more a complete example, see <computeroutput>TestVBox.java</computeroutput>, shipped with the - SDK.</para> + SDK. It contains exception handling and error printing code, which + is important for reliable larger scale projects.</para> </sect1> </chapter> @@ -3525,6 +3760,194 @@ AuthResult AUTHCALL AuthEntry( existing client code.</para> <sect1> + <title>Incompatible API changes with version 4.3</title> + + <itemizedlist> + <listitem> + <para>The explicit medium locking methods + <xref linkend="IMedium__lockRead" xreflabel="IMedium::lockRead()" /> + and <xref linkend="IMedium__lockWrite" xreflabel="IMedium::lockWrite()" /> + have been redesigned. They return a lock token object reference + now, and calling the <xref linkend="IToken__abandon" + xreflabel="IToken::abandon()" /> method (or letting the reference + count to this object drop to 0) will unlock it. This eliminates + the rather common problem that an API client crash left behind + locks, and also improves the safety (API clients can't release + locks they didn't obtain).</para> + </listitem> + + <listitem> + <para>The parameter list of <xref linkend="IAppliance__write" + xreflabel="IAppliance::write()" /> has been changed slightly, to + allow multiple flags to be passed.</para> + </listitem> + + <listitem> + <para><computeroutput>IMachine::delete</computeroutput> + has been renamed to <xref linkend="IMachine__deleteConfig" + xreflabel="IMachine::deleteConfig()" />, to improve API client + binding compatibility.</para> + </listitem> + + <listitem> + <para><computeroutput>IMachine::export</computeroutput> + has been renamed to <xref linkend="IMachine__exportTo" + xreflabel="IMachine::exportTo()" />, to improve API client binding + compatibility.</para> + </listitem> + + <listitem> + <para>For <xref linkend="IMachine__launchVMProcess" + xreflabel="IMachine::launchVMProcess()"/> the meaning of the + <computeroutput>type</computeroutput> parameter has changed slightly. + Empty string now means that the per-VM or global default frontend + is launched. Most callers of this method should use the empty string + now, unless they really want to override the default and launch a + particular frontend.</para> + </listitem> + + <listitem> + <para>Medium management APIs were changed as follows:<itemizedlist> + + <listitem> + <para>The type of attribute + <xref linkend="IMedium__variant" xreflabel="IMedium::variant()"/> + changed from <computeroutput>unsigned long</computeroutput> + to <computeroutput>safe-array MediumVariant</computeroutput>. + It is an array of flags instead of a set of flags which were stored inside one variable. + </para> + </listitem> + + <listitem> + <para>The parameter list for <xref + linkend="IMedium__cloneTo" + xreflabel="IMedium::cloneTo()" /> was modified.</para> + The type of parameter variant was changed from unsigned long to safe-array MediumVariant. + </listitem> + + <listitem> + <para>The parameter list for <xref + linkend="IMedium__createBaseStorage" + xreflabel="IMedium::createBaseStorage()" /> was modified.</para> + The type of parameter variant was changed from unsigned long to safe-array MediumVariant. + </listitem> + + <listitem> + <para>The parameter list for <xref + linkend="IMedium__createDiffStorage" + xreflabel="IMedium::createDiffStorage()" /> was modified.</para> + The type of parameter variant was changed from unsigned long to safe-array MediumVariant. + </listitem> + + <listitem> + <para>The parameter list for <xref + linkend="IMedium__cloneToBase" + xreflabel="IMedium::cloneToBase()" /> was modified.</para> + The type of parameter variant was changed from unsigned long to safe-array MediumVariant. + </listitem> + </itemizedlist></para> + </listitem> + + <listitem> + <para>The type of attribute + <xref linkend="IMediumFormat__capabilities" + xreflabel="IMediumFormat::capabilities()"/> + changed from <computeroutput>unsigned long</computeroutput> + to <computeroutput>safe-array MediumFormatCapabilities</computeroutput>. + It is an array of flags instead of a set of flags which were stored inside one variable. + </para> + </listitem> + + <listitem> + <para>The attribute <xref linkend="IMedium__logicalSize" + xreflabel="IMedium::logicalSize()" /> now returns the logical + size of exactly this medium object (whether it is a base or diff + image). The old behavior was no longer acceptable, as each image + can have a different capacity.</para> + </listitem> + + <listitem> + <para>Guest control APIs - such as <xref linkend="IGuest" + xreflabel="IGuest" />, <xref linkend="IGuestSession" + xreflabel="IGuestSession" />, <xref linkend="IGuestProcess" + xreflabel="IGuestProcess" /> and so on - now emit own events to provide + clients much finer control and the ability to write own frontends for + guest operations. The event <xref linkend="IGuestSessionEvent" + xreflabel="IGuestSessionEvent" /> acts as an abstract base class + for all guest control events. Certain guest events contain a + <xref linkend="IVirtualBoxErrorInfo" xreflabel="IVirtualBoxErrorInfo" /> member + to provide more information in case of an error happened on the + guest side.</para> + </listitem> + + <listitem> + <para>Guest control sessions on the guest started by <xref + linkend="IGuest__createSession" xreflabel="IGuest::createSession()" /> + now are dedicated guest processes to provide more safety and performance + for certain operations. Also, the <xref linkend="IGuest__createSession" + xreflabel="IGuest::createSession()" /> call does not wait for the + guest session being created anymore due to the dedicated guest session + processes just mentioned. This also will enable webservice clients to + handle guest session creation more gracefully. To wait for a guest + session being started, use the newly added attribute <xref + linkend="IGuestSession__status" xreflabel="IGuestSession::status()" /> + to query the current guest session status.</para> + </listitem> + + <listitem> + <para>The <xref linkend="IGuestFile" xreflabel="IGuestFile" /> + APIs are now implemented to provide native guest file access from + the host.</para> + </listitem> + + <listitem> + <para>The parameter list for <xref + linkend="IGuest__updateGuestAdditions" + xreflabel="IMedium::updateGuestAdditions()" /> was modified.</para> + It now supports specifying optional command line arguments for the + Guest Additions installer performing the actual update on the guest. + </listitem> + + <listitem> + <para>A new event <xref linkend="IGuestUserStateChangedEvent" + xreflabel="IGuestUserStateChangedEvent" /> was introduced to provide + guest user status updates to the host via event listeners. To use this + event there needs to be at least the 4.3 Guest Additions installed on + the guest. At the moment only the states "Idle" and "InUse" of the + <xref linkend="GuestUserState" + xreflabel="GuestUserState" /> enum are supported on + Windows guests, starting at Windows 2000 SP2.</para> + </listitem> + + <listitem> + <para> + The attribute <xref linkend="IGuestSession__protocolVersion" + xreflabel="IGuestSession::protocolVersion"/> was added to provide a + convenient way to lookup the guest session's protocol version it + uses to communicate with the installed Guest Additions on the guest. + Older Guest Additions will set the protocol version to 1, whereas + Guest Additions 4.3 will set the protocol version to 2. This might + change in the future as new features arise.</para> + </listitem> + + <listitem> + <para><computeroutput>IDisplay::getScreenResolution</computeroutput> + has been extended to return the display position in the guest.</para> + </listitem> + + <listitem> + <para> + The <xref linkend="IUSBController" xreflabel="IUSBController"/> + class is not a singleton of <xref linkend="IMachine" xreflabel="IMachine"/> + anymore but <xref linkend="IMachine" xreflabel="IMachine"/> contains + a list of USB controllers present in the VM. The USB device filter + handling was moved to <xref linkend="IUSBDeviceFilters" xreflabel="IUSBDeviceFilters"/>. + </para> + </listitem> + </itemizedlist> + </sect1> + + <sect1> <title>Incompatible API changes with version 4.2</title> <itemizedlist> @@ -3785,7 +4208,7 @@ AuthResult AUTHCALL AuthEntry( </row> <row> <entry>IUSBController::enabledEhci</entry> - <entry><xref linkend="IUSBController__enabledEHCI" xreflabel="IUSBController::enabledEHCI"/></entry> + <entry>IUSBController::enabledEHCI"</entry> </row> <row> <entry>INATEngine::tftpPrefix</entry> @@ -3837,7 +4260,6 @@ AuthResult AUTHCALL AuthEntry( </itemizedlist> </sect1> - <sect1> <title>Incompatible API changes with version 4.1</title> @@ -4156,8 +4578,8 @@ AuthResult AUTHCALL AuthEntry( <para>The appliance (OVF) APIs were enhanced as follows:<itemizedlist> <listitem> - <para><xref linkend="IMachine__export" - xreflabel="IMachine::export()" /> received an extra parameter + <para><computeroutput>IMachine::export</computeroutput> + received an extra parameter <computeroutput>location</computeroutput>, which is used to decide for the disk naming.</para> </listitem> @@ -4466,7 +4888,7 @@ AuthResult AUTHCALL AuthEntry( <listitem> <para>Reading the <xref linkend="IMedium__state" - xreflabel="IMedium::state" xrefstyle="" /> attribute no longer + xreflabel="IMedium::state" /> attribute no longer automatically performs an accessibility check; a new method <xref linkend="IMedium__refreshState" xreflabel="IMedium::refreshState()" /> does this. The attribute only |