I have used the VirtualBox COM interface for a while with VirtualBox 6.0. Now I am having troubles with 6.1.
The following code works well on 6.0.
* I start a VM in "headless"
* When the state is Running I stop it
* Then I wait until the session state is unlocked again
* I redo the previous steps 10 times.
Code: Select all
#include "VirtualBox.h"
#include <chrono>
#include <string>
#include <thread>
#define SAFE_RELEASE(x) \
if (x) \
{ \
x->Release(); \
x = NULL; \
}
void printErrorInfo()
{
IErrorInfo *errorInfo;
HRESULT rc = GetErrorInfo(0, &errorInfo);
if (FAILED(rc))
{
printf("Failed to get error info! rc = 0x%x\n", rc);
return;
}
BSTR errorDescription = NULL;
rc = errorInfo->GetDescription(&errorDescription);
if (FAILED(rc) || !errorDescription)
{
printf("Error getting error description! rc = 0x%x\n", rc);
return;
}
printf("Successfully retrieved error description: %S\n", errorDescription);
SysFreeString(errorDescription);
SAFE_RELEASE(errorInfo);
}
int testStartVM(IVirtualBox *virtualBox, const wchar_t *name, const wchar_t *sessionTypeName)
{
HRESULT rc;
/* Try to start a VM called "WinXP SP2". */
IMachine *machine = NULL;
BSTR machineName = SysAllocString(name);
rc = virtualBox->FindMachine(machineName, &machine);
if (FAILED(rc))
{
printErrorInfo();
}
else
{
ISession *session = NULL;
IConsole *console = NULL;
IProgress *progress = NULL;
BSTR sessiontype = SysAllocString(sessionTypeName);
BSTR guid;
do
{
rc = machine->get_Id(&guid); /* Get the GUID of the machine. */
if (!SUCCEEDED(rc))
{
printf("Error retrieving machine ID! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
/* Create the session object. */
rc = CoCreateInstance(CLSID_Session, /* the VirtualBox base object */
NULL, /* no aggregation */
CLSCTX_INPROC_SERVER, /* the object lives in the current process */
IID_ISession, /* IID of the interface */
(void **)&session);
if (!SUCCEEDED(rc))
{
printf("Error creating Session instance! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
/* Start a VM session using the delivered VBox GUI. */
rc = machine->LaunchVMProcess(session, sessiontype, NULL, &progress);
if (!SUCCEEDED(rc))
{
printf("Could not open remote session! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
/* Wait until VM is running. */
printf("Starting VM, please wait ...\n");
rc = progress->WaitForCompletion(-1);
if (!SUCCEEDED(rc))
{
printf("Progress wait for LaunchVMProcess completion fail! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
/* Get console object. */
session->get_Console(&console);
/* Bring console window to front. */
machine->ShowConsoleWindow(0);
while (true)
{
MachineState state;
rc = machine->get_State(&state);
if (FAILED(rc))
{
printf("Faile to get machine state! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
printf("Machine state == %d\n", state);
if (state == MachineState_Running)
{
break;
}
}
/* Power down the machine. */
rc = console->PowerDown(&progress);
if (!SUCCEEDED(rc))
{
printf("Console PowerDown fail! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
/* Wait until VM is powered down. */
printf("Powering off VM, please wait ...\n");
rc = progress->WaitForCompletion(-1);
if (!SUCCEEDED(rc))
{
printf("Progress wait for PowerDown fail! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
/* Close the session. */
rc = session->UnlockMachine();
if (!SUCCEEDED(rc))
{
printf("Cannot unlock machine! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
} while (0);
SAFE_RELEASE(console);
SAFE_RELEASE(progress);
SAFE_RELEASE(session);
SysFreeString(guid);
SysFreeString(sessiontype);
// wait for unlocked
printf("Wait for machine unlocked ...\n");
while (true)
{
SessionState sessionState;
rc = machine->get_SessionState(&sessionState);
if (FAILED(rc))
{
printf("Cannot get session state! rc = 0x%x\n", rc);
printErrorInfo();
break;
}
if (sessionState == SessionState_Unlocked)
{
break;
}
}
SAFE_RELEASE(machine);
}
SysFreeString(machineName);
return 0;
}
int main(int argc, char **argv)
{
/* Initialize the COM subsystem. */
CoInitialize(NULL);
/* Instantiate the VirtualBox root object. */
IVirtualBoxClient *virtualBoxClient;
HRESULT rc = CoCreateInstance(CLSID_VirtualBoxClient, /* the VirtualBoxClient object */
NULL, /* no aggregation */
CLSCTX_INPROC_SERVER, /* the object lives in the current process */
IID_IVirtualBoxClient, /* IID of the interface */
(void **)&virtualBoxClient);
if (SUCCEEDED(rc))
{
IVirtualBox *virtualBox;
rc = virtualBoxClient->get_VirtualBox(&virtualBox);
if (SUCCEEDED(rc))
{
for (int i = 0; i < 10; ++i)
{
printf("Test run %d\n", i);
testStartVM(virtualBox, L"TESTING", L"headless");
}
/* Release the VirtualBox object. */
virtualBox->Release();
virtualBoxClient->Release();
}
else
{
printf("Error creating VirtualBox instance! rc = 0x%x\n", rc);
printErrorInfo();
}
}
CoUninitialize();
return 0;
}
If I use a "gui" session type than all works as exepected also in 6.1.
I think that the problem is caused by the event loop of VBoxHeadless because I see that it is started after I triggrer PowerDown command from the console.
Code: Select all
00:00:01.819978 Changing the VM state from 'DESTROYING' to 'TERMINATED'
00:00:01.824010 Console: Machine state changed to 'PoweredOff'
00:00:01.937393 VBoxHeadless: starting event loop
Attached the code and the log.
Thanks.