#pragma once


/** Класс для передачи между процессами текстовых команд. Ограничения:
	*) Команда представляет собой строку, заканчивающуюся нулем (при необходимости - легко переделать на 
массив произвольных байтов)
	*) Максимальный размер команды - 1 килобайт
	*) Наличие команды проверяется каждые 200 милисекунд
	*) Обработка команды производится в том же потоке, в котором была вызвана функция InitListen
	
	Для приема команд надо:
	1) Определить класс-наследник CaplMPC
	2) Перегрузить функцию ProcessingCommand - в нее передаются принятые команды. Функция базового класса при 
приеме команды выводит ее в MessageBox.
	3) Вызвать функцию InitListen
	При вызове функции InitListen создаются три именованных объекта: область памяти, мутекс и евент. Имена этих 
объектов включают id процесса; т.е. чтобы послать команду определенному процессу - надо знать его идентификатор.
	Если при приеме команд возникают обрабатываемые ошибки - сообщения об этих ошибках записываются в строковый 
массив m_ReceveErrors (максимум 20 сообщений). Для получения сообщений об ошибках надо вызвать функцию 
GetLastReceiveErrors; если в массиве есть сообщения об ошибках - она возвращает true, если нет - то false. После 
каждого вызова она очищает массив сообщений об ошибках приема. Функцию получения сообщений можно вызывать из 
любого потока, работа с массивом ошибок защищена критической секцией.

	Для отправки команды процессу, надо объявить экземпляр класса CaplMPC (или наследника от него; можно отправлять 
команды через экземпляр класса, который используется для приема команд) и вызвать функцию SendCommand. В случае 
ошибки - описание ошибки можно получить функцией GetLastSendError.
	При передаче команды возможны две ошибочные ситуации:
	1) В вызываемом процессе не была вызвана функция InitListen. В таком случае функция не сможет получить управляющие
объекты и сразу же вернет false.
	2) Вызываемый процесс уже обрабатывает команду. В этом случает функция SendCommand будет пытаться в течение 10 секунд
передать команду (100 попыток с ожиданием 100 милисекунд в каждой), и только после этого вернет false.
*/

typedef void (*CaplMPC_ext_function)(const TCHAR*);

class AFX_EXT_CLASS CaplMPC
{
public:
	CaplMPC(void);
	~CaplMPC(void);
	/** Запускает прием команд
		Если func!=0 - эта функция будет вызываться при обработке комманды
		@return <b>true</b> при удачном выполнении и false в случае ошибки. Для получения сообщения об ошибках - GetLastReceiveErrors */
	bool InitListen(CaplMPC_ext_function func=0);

	/** Вызывается при приеме команды. Для выполнения осмысленных действий надо переопределить эту функцию в классе-наследнике
		В базовом классе выводит MessageBox с текстом команды. Возвращаемое значение может быть любым*/
	virtual bool ProcessingCommand(const TCHAR* command);

	/** Посылает команду процессу
	@param process_id идентификатор процесса
	@param command текст команды
	@return <b>true</b> при удачном выполнении и false в случае ошибки. Для получения сообщения об ошибке - GetLastSendError*/
	bool SendCommand(DWORD process_id,const TCHAR* command);

	/** Возвращает текст сообщения об ошибке передачи
	@return текст сообщения об ошибке*/
	CString GetLastSendError(){return m_LastSendError;};

	/** Возвращает текст 20ти последних сообщений об ошибке приема. После копирования сообщений - очищает массив последних ошибок
	@param ReceiveErrors массив строк, в который помещаются сообщания
	@return <b>true</b> если в массиве есть сообщения и <b>false</b> если сообщений об ошиюках нет.*/
	bool GetLastReceiveErrors(CStringArray &ReceiveErrors);

	// служебная функция - вызывается из таймера
	void ProcessTimer();

	// запускает процесс exe_name (если указан без пути, то берется путь к текущему exe)
	static DWORD StartProcess(LPCTSTR exe_name, LPCTSTR cmdline);

	// Читает параметр из строки cmd_line  !!! с учетом регистра
	// по факту ищет подстроку param и возвращает то, что после нее до пробела или ""
	// лучше всего задавать параметры в стиле param=value
	static bool GetParam(LPCTSTR cmd_line, LPCTSTR param, CString &value); 

	// Определяет не завершен ли процесс по PID
	static bool IsPpocessActive(DWORD pid);


protected:
	static CaplMPC_ext_function st_function;
	static bool st_InitializeCriticalSection;

	// Дескрипторы буфера для приема команд
	HANDLE m_hFile;
	HANDLE m_hFileCommandMapping;
	PVOID m_CommandPregion;
	// Управляющие структуры
	HANDLE m_event_command_set;
	HANDLE m_mutex_command_buffer_processed;

	// указатель на первые 4 байта буфера - в них размер команды
	DWORD *m_p_command_size;
	// указатель на тело команды
	BYTE *m_p_command_data;

	// Описание ошибки передачи
	CString m_LastSendError;

	// Добавление описания ошибки приема
	void AddReceiveErrorMessage(const TCHAR *LastReсeiveMessage);
	// Массив описаний ошибок приема
	CStringArray m_ReceveErrors;

};