I need fast help!

Discussion about using the VirtualBox API, Tutorials, Samples.
Wulfiks
Posts: 13
Joined: 13. Jun 2015, 09:10

Re: I need fast help!

Post by Wulfiks »

Here's a piece of my code, is responsible for receiving the screenshot:

Code: Select all

machine->LockMachine(session, LockType::LockType_Shared);
				rc = console->get_Display(&display);
				
				rc = display->GetScreenResolution(0, &width, &height, &bperp, &xWidth, &xHeight);
				
				SAFEARRAY *buffer = NULL;
				rc = display->TakeScreenShotToArray(0, width, height, &buffer);

				if (SUCCEEDED(rc))
				{
					char *buf = new char[height*width * 4];
					BYTE *rebuf = new BYTE[height*width * 4];
					rc = SafeArrayAccessData(buffer, (void **)&buf);
					if (SUCCEEDED(rc))
					{
						for (ULONG i = 0; i < height; i++)
						{				
							for (ULONG j = 0; j < width * 4; j++)
							{
								rebuf[i * width * 4 + j] = (BYTE)buf[(height - i-1) * width * 4 + j];
							}
						}

						hBitmap = CreateBitmap(width, height, 1, 32, rebuf);
						pBitmapInfo = CreateBitmapInfoStruct(hBitmap);
				
						BITMAPFILEHEADER bmph;
						bmph.bfType = 0x4D42;
						bmph.bfSize = sizeof(BITMAPFILEHEADER)+ sizeof(BITMAPINFO)+height*width * 4;
						bmph.bfReserved1 = 0;
						bmph.bfReserved2 = 0;
						bmph.bfOffBits = sizeof(BITMAPFILEHEADER)+ sizeof(BITMAPINFO);
						FILE * pFile;
						  pFile = fopen ("D:\\myfile.bmp","w");
						  if (pFile!=NULL)
						  {
							fwrite (&bmph , sizeof(BITMAPFILEHEADER), 1, pFile);
							fwrite (pBitmapInfo , sizeof(BITMAPINFO), 1, pFile);
							fwrite (rebuf , sizeof(BYTE), height*width * 4, pFile);
							fclose (pFile);
						  } 
						SafeArrayUnaccessData(buffer);
					}
					SafeArrayDestroy(buffer);
				}
				rc = session->UnlockMachine();
				
Screenshot received through the VBoxManage:
Image

Screenshot received through the my programm:
Image

The image received through my program to boot Windows:
Image
noteirak
Site Moderator
Posts: 5229
Joined: 13. Jan 2012, 11:14
Primary OS: Debian other
VBox Version: OSE Debian
Guest OSses: Debian, Win 2k8, Win 7
Contact:

Re: I need fast help!

Post by noteirak »

Few things you should try :
- Check the VBoxManage code for screenshotpng and see how it's done. They use more arguments than you on TakeScreenShotToArray().
- Disable 2D & 3D accelleration if they are on.
- Try with the latest version of VirtualBox (4.3.28). Make sure you update virtualbox and the SDK code you're using.
- Try using takeScreenShotPNGToArray().
Hyperbox - Virtual Infrastructure Manager - https://apps.kamax.lu/hyperbox/
Manage your VirtualBox infrastructure the free way!
Wulfiks
Posts: 13
Joined: 13. Jun 2015, 09:10

Re: I need fast help!

Post by Wulfiks »

Thank you very much!
Earned when using TakeScreenShotPNGToArray
Below is working code, can anyone help.

Code: Select all

machine->LockMachine(session, LockType::LockType_Shared);
				rc = console->get_Display(&display);
								
				rc = display->GetScreenResolution(0, &width, &height, &bperp, &xWidth, &xHeight);
								
				SAFEARRAY *buffer = NULL;
				rc = display->TakeScreenShotPNGToArray(0, width, height, &buffer);
				if (SUCCEEDED(rc))
				{
                                        ULONG size = buffer->rgsabound[0].cElements;
					char *buf = new char[size];
					BYTE *rebuf = new BYTE[size];
					rc = SafeArrayAccessData(buffer, (void **)&buf);
					ofstream  pFile.open("D:\\myfile.png", ios::binary);
					if (SUCCEEDED(rc))
					{
						for (ULONG i = 0; i < size; i++)
						{		
							rebuf[i] = (BYTE)buf[i];
							pFile << rebuf[i];
						}
						
						pFile.close();
						
						SafeArrayUnaccessData(buffer);
					}
					SafeArrayDestroy(buffer);
				}
				rc = session->UnlockMachine();
				
noteirak
Site Moderator
Posts: 5229
Joined: 13. Jan 2012, 11:14
Primary OS: Debian other
VBox Version: OSE Debian
Guest OSses: Debian, Win 2k8, Win 7
Contact:

Re: I need fast help!

Post by noteirak »

So it's working, yes?
Hyperbox - Virtual Infrastructure Manager - https://apps.kamax.lu/hyperbox/
Manage your VirtualBox infrastructure the free way!
Wulfiks
Posts: 13
Joined: 13. Jun 2015, 09:10

Re: I need fast help!

Post by Wulfiks »

Sorry for not having posted.
Yes, it is a working code for version 4.3.12
Wulfiks
Posts: 13
Joined: 13. Jun 2015, 09:10

It works!!! (C++)

Post by Wulfiks »

VirtualBox - 4.3.12
Host OS - Windows 7x64

header.h

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;				// содержит код ошибки исполнения функции
	
};
body.cpp

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();
	}
}
noteirak
Site Moderator
Posts: 5229
Joined: 13. Jan 2012, 11:14
Primary OS: Debian other
VBox Version: OSE Debian
Guest OSses: Debian, Win 2k8, Win 7
Contact:

Re: It works!!! (C++)

Post by noteirak »

Is this related to your previous topic?
Hyperbox - Virtual Infrastructure Manager - https://apps.kamax.lu/hyperbox/
Manage your VirtualBox infrastructure the free way!
Wulfiks
Posts: 13
Joined: 13. Jun 2015, 09:10

Re: It works!!! (C++)

Post by Wulfiks »

Yes. This is a turnkey solution. Next I use this functionality to create a class library.
noteirak
Site Moderator
Posts: 5229
Joined: 13. Jan 2012, 11:14
Primary OS: Debian other
VBox Version: OSE Debian
Guest OSses: Debian, Win 2k8, Win 7
Contact:

Re: I need fast help!

Post by noteirak »

I've merged the topic with your old one then. It will be easier for people to find the full history and the solution you offer.
Hyperbox - Virtual Infrastructure Manager - https://apps.kamax.lu/hyperbox/
Manage your VirtualBox infrastructure the free way!
Post Reply