Code: Select all
#pragma once
#include "VirtualBox.h"
#include <fstream>
#include <vector>
#import "VirtualBox.tlb" rename_namespace("VirtualBox_")
class VB_Manager
{
public:
int countVM; //кол-во зарегестрированных ВМ
int countBMP; //кол-во байт в скриншоте
ULONG width, height, bperp; //ширина\высота\разрешение скриншота
std::string lastError; //содержит сведения о последней возникшей ошибке
//конструктор класса
VB_Manager();
//получить список ВМ
std::string* listVM();
//запуск ВМ
void startVM(std::string machineNama);
//остановка ВМ
void stopVM();
//приостановка\возобновление работы ВМ
void pauseVM();
//получить скриншот в формате BGR
BYTE* getScreenByte();
//получить скриншот в формате PNG
BYTE* getScreenPNG();
//изменить размер оперативной памяти ВМ
int chengeMemory(int newSize);
//ввод с мыши ВМ
void setMouse(int x, int y, int z, int w, int button);
//ввод с клавиатуры ВМ
void setKeyboard(int scancode);
//послать сигнал Ctrl+Alt+Del
void putCAD();
private:
IVirtualBox *virtualBox; // объект сервера VirtualBox'а
IMachine *machine; // объект ВМ
IMouse *mouse; // объект мыши ВМ
IKeyboard *keyboard; // объект клавиатуры ВМ
BSTR machineName; // имя ВМ
ISession *session; // представляет собой процесс клиента
IConsole *console; // интерфейс для управления исполнением виртуальной машины
IProgress *progress; // объект для отслеживания и управления асинхронными задачи в VirtualBox
IDisplay *display; // объект дисплея ВМ
BSTR sessiontype; // тип сессии
BSTR guid; // глобальный идентификатор
SAFEARRAY *buffer; // структура для работы с массивами COM - технологии
LONG xWidth, xHeight; // неиспользуемые параметры
HRESULT rc; // содержит код ошибки исполнения функции
};
Code: Select all
#pragma once
#include "header.h"
#include <atlbase.h>
#define SAFE_RELEASE(x) \
if (x) { \
x->Release(); \
x = NULL; \
}
/**
* Метод преобразования строки OLECHAR *BSTR в std::string
*
* @param in BSTR bstr - исходная строка
* @param out std::string& dst - результирующая строка
* @param in int cp = CP_UTF8 - кодировка строки
* @return тип_данных
*/
std::string& BstrToStdString(const BSTR bstr, std::string& dst, int cp = CP_UTF8)
{
if (!bstr)
{
dst.clear();
return dst;
}
int res = WideCharToMultiByte(cp, 0, bstr, -1, NULL, 0, NULL, NULL);
if (res > 0)
{
dst.resize(res);
WideCharToMultiByte(cp, 0, bstr, -1, &dst[0], res, NULL, NULL);
}
else
{
dst.clear();
}
return dst;
}
VB_Manager::VB_Manager()
{
machine = NULL; //представляет виртуальную машину
session = NULL; /**
* представляет собой процесс клиента и позволяет блокировать
* виртуальную машину (в лице IMachine объектов),
* чтобы предотвратить конфликтующие изменения в машине.
*/
console = NULL; //представляет собой интерфейс для управления исполнением виртуальной машины
progress = NULL; //используется для отслеживания и управления асинхронными задачи в VirtualBox
display = NULL; //представляет собой дисплей виртуальной машины
sessiontype = SysAllocString(L"headless"); //тип сессии
buffer = NULL;
//Инициализирует библиотеку COM в текущем потоке
CoInitialize(NULL);
//Получение объекта IVirtualBox
HRESULT rc = CoCreateInstance(CLSID_VirtualBox, NULL, CLSCTX_LOCAL_SERVER, IID_IVirtualBox, (void**)&virtualBox);
}
/**
* Метод получения списка виртуальных машин.
* Возвращает имена зарегестрированных ВМ
*
* @return std::string*
*/
std::string* VB_Manager::listVM()
{
std::string * result = NULL;
SAFEARRAY *machinesArray = NULL;
//получение данных от сервера VirtualBox
rc = virtualBox->get_Machines(&machinesArray);
//запись списка в массив формата std::string
if (SUCCEEDED(rc))
{
IMachine **machines;
rc = SafeArrayAccessData(machinesArray, (void **)&machines);
if (SUCCEEDED(rc))
{
countVM = machinesArray->rgsabound[0].cElements;
result = new std::string[countVM];
for (int i = 0; i < countVM; ++i)
{
BSTR str;
rc = machines[i]->get_Name(&str);
BstrToStdString(str, result[i]);
SysFreeString(str);
}
SafeArrayUnaccessData(machinesArray);
}
SafeArrayDestroy(machinesArray);
}
return result;
}
/**
* Метод запуска виртуальной машины по её имени.
*
* @param std::string machineName - имя виртуальной машины
*/
void VB_Manager::startVM(std::string machineName)
{
//преобразование формата строки из std::string в OLECHAR BSTR
BSTR s3 = CComBSTR((machineName.c_str())).Detach();
//попытка подключения к виртуальной машине
HRESULT rc = virtualBox->FindMachine(s3, &machine);
//блок обработки ошибки подключения
if (FAILED(rc))
{
IErrorInfo *errorInfo;
rc = GetErrorInfo(0, &errorInfo);
if (FAILED(rc))
{
lastError = "Error getting error info! rc =" ;
lastError += (int)rc;
}
else
{
BSTR errorDescription = NULL;
rc = errorInfo->GetDescription(&errorDescription);
if (FAILED(rc) || !errorDescription)
{
lastError = "Error getting error description! rc = 0x";
lastError += (int)rc;
}
else
{
std::string temp ;
lastError = "Successfully retrieved error description:" + BstrToStdString(errorDescription, temp);
SysFreeString(errorDescription);
}
SAFE_RELEASE(errorInfo);
}
}
//подключение прошло успешно
else
{
MachineState MS;
machine->get_State(&MS);
//проверка на повторный запуск
if (MS != MachineState::MachineState_Running)
{
rc = machine->get_Id(&guid);
if (!SUCCEEDED(rc))
{
lastError = "Error retrieving machine ID! rc = 0x";
lastError += (int)rc;
return;
}
//получение объекта сессии
rc = CoCreateInstance(CLSID_Session, NULL, CLSCTX_INPROC_SERVER, IID_ISession, (void**)&session);
if (!SUCCEEDED(rc))
{
lastError = "Error creating Session instance! rc = 0x";
lastError += (int)rc;
return;
}
else
{
//запуск виртуальной машины
rc = machine->LaunchVMProcess(session, sessiontype, NULL, &progress);
rc = progress->WaitForCompletion(-1);
//получение объекта консоли
rc = session->get_Console(&console);
if (!SUCCEEDED(rc))
{
lastError = "Error creating console! rc = 0x";
lastError += (int)rc;
return;
}
//разблокировка виртуальной машины
rc = session->UnlockMachine();
if (!SUCCEEDED(rc))
{
lastError = "Failed sesion unlock! rc = 0x";
lastError += (int)rc;
return;
}
//получение объекта дисплея
rc = console->get_Display(&display);
if (!SUCCEEDED(rc))
{
lastError = "Error creating display! rc = 0x";
lastError += (int)rc;
}
//получение объекта мыши
rc = console->get_Mouse(&mouse);
if (!SUCCEEDED(rc))
{
lastError = "Error getting mouse! rc = 0x";
lastError += (int)rc;
}
//получение объекта клавиатуры
rc = console->get_Keyboard(&keyboard);
if (!SUCCEEDED(rc))
{
lastError = "Error getting keyboard! rc = 0x";
lastError += (int)rc;
}
}
}
}
}
// останавливает привязанную к данной сессии виртуальную машину.
void VB_Manager::stopVM()
{
//завершение работы виртуальной машины
rc = console->PowerDown(&progress);
if (!SUCCEEDED(rc))
{
lastError = "Error PowerDown! rc = 0x";
lastError += (int)rc;
}
//ожидание выключения виртуальной машины
rc = progress->WaitForCompletion(-1);
if (!SUCCEEDED(rc))
{
lastError = "Error PowerDown WaitForCompletion! rc = 0x";
lastError += (int)rc;
}
//закрытие сессии и освобождение ресурсов
rc = session->UnlockMachine();
SAFE_RELEASE(console);
SAFE_RELEASE(progress);
SAFE_RELEASE(session);
SysFreeString(guid);
SysFreeString(sessiontype);
SAFE_RELEASE(machine);
}
/**
* Метод возвращает массив байт, образующие бутовую карту
* скриншота текущего виртуального дисплея.
*
* @return BYTE*
*/
BYTE* VB_Manager::getScreenByte()
{
BYTE* result = NULL;
//получение информации о дисплеи виртуальной машины
rc = display->GetScreenResolution(0, //номер монитора
&width, //ширина монитора
&height, //высота монитора
&bperp, //количество бит на пиксель
&xWidth, &xHeight);
if (!SUCCEEDED(rc))
{
lastError = "Error GetScreenResolution! rc = 0x";
lastError += (int)rc;
return result;
}
countBMP = width*height*4;
SAFEARRAY *buffer = NULL;
//получение скриншота
rc = display->TakeScreenShotToArray(0, width, height, &buffer);
//блок передачи данных из структуры SAFEARRAY в массив байтов
if (SUCCEEDED(rc))
{
countBMP = buffer->rgsabound[0].cElements;
char *buf = new char[countBMP];
result = new BYTE[countBMP];
rc = SafeArrayAccessData(buffer, (void **)&buf);
if (SUCCEEDED(rc))
{
for (int i = 0; i < countBMP; i++)
{
result[i]=(BYTE)buf[i];
}
SafeArrayUnaccessData(buffer);
}
SafeArrayDestroy(buffer);
}
return result;
}
/**
* Метод возвращает массив байт, который являет собой PNG изображение
* скриншота текущего виртуального дисплея.
*
* @return BYTE*
*/
BYTE* VB_Manager::getScreenPNG()
{
BYTE* result = NULL;
//получение информации о дисплеи виртуальной машины
rc = display->GetScreenResolution(0, //номер монитора
&width, //ширина монитора
&height, //высота монитора
&bperp, //количество бит на пиксель
&xWidth, &xHeight);
if (!SUCCEEDED(rc))
{
lastError = "Error GetScreenResolution! rc = 0x";
lastError += (int)rc;
return result;
}
SAFEARRAY *buffer = NULL;
//получение скриншота
rc = display->TakeScreenShotPNGToArray(0, width, height, &buffer);
//блок передачи данных из структуры SAFEARRAY в массив байтов
if (SUCCEEDED(rc))
{
countBMP = buffer->rgsabound[0].cElements;
char *buf = new char[countBMP];
result = new BYTE[countBMP];
rc = SafeArrayAccessData(buffer, (void **)&buf);
if (SUCCEEDED(rc))
{
for (int i = 0; i < countBMP; i++)
{
result[i] = (BYTE)buf[i];
}
SafeArrayUnaccessData(buffer);
}
SafeArrayDestroy(buffer);
}
return result;
}
/**
* Метод изменяющий объем оперативной памяти виртуальной машины
*
* @param int newSize - новый размер памяти, Мб
* @return int - возвращает newSize в случае успеха и "-1" в случае неудачи
*/
int VB_Manager::chengeMemory(int newSize)
{
//блокировка виртуальной машины
machine->LockMachine(session, LockType::LockType_Write);
IMachine *new_machine;
//создаем еще одну ссылку на объект
rc = session->get_Machine(&new_machine);
if (!SUCCEEDED(rc))
{
lastError = "Error get Machine! rc = 0x";
lastError += (int)rc;
return -1;
}
//изменяем объем оперативной памяти
rc = new_machine->put_MemorySize(newSize);
if (!SUCCEEDED(rc))
{
lastError = "Error put MemorySize! rc = 0x";
lastError += (int)rc;
return -1;
}
//сохраняем изменения
rc = new_machine->SaveSettings();
if (!SUCCEEDED(rc))
{
lastError = "Error Save Settings! rc = 0x";
lastError += (int)rc;
return -1;
}
//снимаем блокировку
rc = session->UnlockMachine();
if (!SUCCEEDED(rc))
{
lastError = "Error Unlock Machine! rc = 0x";
lastError += (int)rc;
return -1;
}
return newSize;
}
/**
* Метод устанавливает указатель мыши, используя абсолютную координаты х и у.
* Эти координаты выражены в пикселях и начинаются с координат [1,1] ,
* которые соответствуют верхнему левому углу виртуального дисплея.
*
* @param int x - Х координата указателя в пикселях, начиная от 1.
* @param int y - У координата указателя в пикселях, начиная от 1.
* @param int z - Смещение колеса мыши по вертикали. Положительные значения
* описывают вращение по часовой стрелке колеса,
* отрицательные значения описывают вращение против часовой стрелки.
* @param int w - Смещение колеса мыши по горизонтали. Положительные значения
* описывают движение влево, отрицательные значения
* описывают движение вправо.
* @param int button - Текущее состояние кнопок мыши. Каждый бит представляет
* собой кнопку мыши следующим образом:
* Бит 0 (0x01) левую кнопку мыши
* Бит 1 (0x02) правая кнопка мыши
* Бит 2 (0x04) средняя кнопка мыши
* Значение 1 означает что соответствующая кнопка нажата.
* В противном случае она будет отпущена.
*/
void VB_Manager::setMouse(int x, int y, int z, int w, int button)
{
if (machine!=NULL)
{
rc = mouse->PutMouseEventAbsolute(x, y, z, w, button);
if (!SUCCEEDED(rc))
{
lastError = "Error put mouse event! rc = 0x";
lastError += (int)rc;
}
}
}
void VB_Manager::setKeyboard(int scancode)
{
rc = keyboard->PutScancode(scancode);
rc = keyboard->PutScancode(scancode);
if (!SUCCEEDED(rc))
{
lastError = "Error put keyboard event! rc = 0x";
lastError += (int)rc;
}
}
void VB_Manager::putCAD()
{
rc = keyboard->PutCAD();
if (!SUCCEEDED(rc))
{
lastError = "Error put ctrl+alt+del event! rc = 0x";
lastError += (int)rc;
}
}
// останавливает/возобновляет работу виртуальной машины
void VB_Manager::pauseVM()
{
// получаем состояние ВМ
MachineState state;
console->get_State(&state);
//если работает - приостанавливаем
if (state == MachineState::MachineState_Running)
{
rc = console->Pause();
}
//если приостановленна - возобновляем работу
if (state == MachineState::MachineState_Paused)
{
rc = console->Resume();
}
}