// aplSocketClient.cpp : implementation file
//
#include "stdafx.h"
#include <AplGuiEx.h>
#include <apl_gui.h>
#include "aplSocketTransport.h"
#include "commands.h"
#include "WaitDlg.h"
#include "ServerStopDlg.h"
//#include <afxpriv.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// При установке в false - во внутренних циклах и т.п. перестает обрабатывать
// сообщения WM_PAINT. Флаг добавлен для ILS.
bool global_process_wm_paint=true;


// Макросы или просто выполняют работу с критическими секциями, или 
// выводят в стандартный лог сообщения о работе с секциями
// в отладочном режиме требует рядом с определением критической секции 
// определения переменной типа long с именем ИМЯ_СЕКЦИИ+"_COUNTER"
// для переключения в отдладочный режим в настройках проекта вкладка C++
// должен быть определен макрос _DEBUG_LOG_CRTITICAL_SECTION

#ifdef _DEBUG_LOG_CRTITICAL_SECTION 

extern long m_IsBlockedInternalBuf_COUNTER;
long m_ManageOperate_COUNTER=0;

extern long m_OperateListClients_COUNTER;
extern long LstenServList_COUNTER;

#endif

#pragma intrinsic( memcpy,memset)
#define _afxSockThreadState AfxGetModuleThreadState()
#define _AFX_SOCK_THREAD_STATE AFX_MODULE_THREAD_STATE

// Функция остаток недоработанного механизма контроля, из нашего ли дистрибутива запущен клиент или из скомпиленного клиентом
void TestListDll()
{
	CString str,str_buf;

	PBYTE pb = NULL; 

	MEMORY_BASIC_INFORMATION mbi; 

	while (VirtualQuery(pb, &mbi, sizeof(mbi)) == sizeof(mbi)) {
		int nLen;
		TCHAR szModName[MAX_PATH];
		if (mbi.State == MEM_FREE)
			mbi.AllocationBase = mbi.BaseAddress;
		if ((mbi.AllocationBase == module_inst) ||
			(mbi.AllocationBase != mbi.BaseAddress) ||
			(mbi.AllocationBase == NULL)) {
				// Имя модуля не включается в список, если
				// истинно хотя бы одно из следующих условий
				// 1 Данный регион содержит нашу DLL
				// 2 Данный блок НЕ является началом региона
				// 3 Адрес равен NULL
				nLen = 0;
		} else {
			nLen = GetModuleFileName((HINSTANCE) mbi.AllocationBase,szModName, MAX_PATH);
		}
		if (nLen > 0) {
			str_buf.Format(_T("\r\n%08X-%s\r\n"), mbi.AllocationBase, szModName);
			str+=str_buf;
		}
		pb += mbi.RegionSize;
	}
	AfxMessageBox(str);
}

////////////////////////////////////////////////////////////////////
/// Список клиентских сокетов, запущенных в рамках текушщего исполняемого файла
/// и функции для работы с ним
/// Используется для периодических попыток дочитать "зависшие" в tcp данные
///

CRITICAL_SECTION m_OperateListClients;
CaplTAggr<CaplSocketClient*,CaplSocketClient*,APLAGGR_LIST> list_existed_clients;
UINT_PTR timer_UnBlock=0;


/// добавить клиентский сокет в список
void Add2List(CaplSocketClient* client)
{
	EnterLogCriticalSection(&m_OperateListClients);
	if(client!=0)
	{
		list_existed_clients.Add(client);
	}
	LeaveLogCriticalSection(&m_OperateListClients);
}

/// удалить клиентский сокет из списка
void RemoveFromList(CaplSocketClient* client)
{
	EnterLogCriticalSection(&m_OperateListClients);
	if(client!=0)
	{
		list_existed_clients.Remove(list_existed_clients.Find(client));
	}
	LeaveLogCriticalSection(&m_OperateListClients);
}

/// попытка дочитать "зависшие" в tcp данные
void CALLBACK TimerProcClient(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
{
	int i;
	CaplSocketClient* client;
	//CString str;
	//DWORD tick=GetTickCount();
	int buf=0, size=4;
	if(nIDEvent==timer_UnBlock)
	{
		EnterLogCriticalSection(&m_OperateListClients);
		for(i=0;i<list_existed_clients.GetSize();i++)
		{
			client=list_existed_clients[i];
			if(client==0)continue;
			if(client->IsReadyData())
			{
				size=client->m_LastReadyData;
				//str.Format("По таймеру блокировки ID_TIMER_BLOCK пытаемся прочитать из канала остаток данных; всего нужно получить %i байт",size);

				//LogDebugMessageIfDef(CString(str));
				/**/
				if(client->Receive(&buf,4,MSG_PEEK)!=-1)
				{
					//LogDebugMessageIfDef(CString(APL_T("Начали получать данные")),(long)0,_T(__FILE__),__LINE__);
				}
				else
				{
					LogDebugMessageIfDefG( APL_T("Не удалось прочитать данные из канала! Возможна потеря данных... Или данные уже кем-то прочитаны"));
				}
				/**/
			}
		}
		LeaveLogCriticalSection(&m_OperateListClients);
	}
}


void SetUnBlockTimer()
{
	CaplEnterCriticalSection ecs(&m_OperateListClients);
	if(timer_UnBlock == 0)
		timer_UnBlock= SetTimer(0,ID_TIMER_BLOCK,2000,TimerProcClient);
}


/////////////////////////////////////////////////////////////////////////////
// CaplSocketClient

CaplSocketClient::CaplSocketClient()
{  
	CaplStackLogger stack_logger(_T("CaplSocketClient::CaplSocketClient()"),true);

	InitVar();
	Add2List(this);

}

CaplSocketClient::CaplSocketClient(LPCTSTR ip, UINT port)
{
	CaplStackLogger stack_logger(_T("CaplSocketClient::CaplSocketClient(LPCTSTR ip, UINT port)"),true);
	
	InitVar();
	Connect(ip,port);
	Add2List(this);
}

CaplSocketClient::~CaplSocketClient()
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	
	RemoveFromList(this);
	if(m_wt_dlg!=0)
	{
		m_wt_dlg->m_pClient=0;
		delete m_wt_dlg;// а вот здесь удалить надо обязательно
	}
	m_wt_dlg=0;

	if(m_server_stop_dlg!=0)
	{
		if(m_server_stop_dlg->m_hWnd!=0)
			m_server_stop_dlg->EndDialog(0);

		delete m_server_stop_dlg;
		m_server_stop_dlg=0;
	}
	ClearInternalData();
	Disconnect();
	DeleteLogCriticalSection(&m_IsBlockedInternalBuf);
	DeleteLogCriticalSection(&m_ManageOperate);
}

void CaplSocketClient::InitVar()
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	InitializeLogCriticalSection(&m_IsBlockedInternalBuf);
	InitializeLogCriticalSection(&m_ManageOperate);
	
	//TestListDll();
	m_isCall = false;

	m_InternalData = 0;
	m_renew_function = 0;
	m_parameter_renew_function = 0;
	m_size_InternalData = 0;
	m_IsConnected = false;
#ifdef _DEBUG
	m_timeout_call = TIMEOUT_WAIT_NODIALOG; //в отладочных целях...
	m_waitdlg_time = TIMEOUT_BEFORE_WAITDIALOG;	// в отладочных целях...
#else
	m_timeout_call = TIMEOUT_WAIT_NODIALOG;
	m_waitdlg_time = TIMEOUT_BEFORE_WAITDIALOG;
#endif
#ifdef _DEBUG
	m_timeout_my_receive = TIMEOUT_RECEIVE;
	// m_timeout_my_receive = TIMEOUT_RECEIVE * 100; // для отладки сетевой части клиента
#else
	//!! не закиыдвать изсменения! m_timeout_my_receive = TIMEOUT_RECEIVE;
	m_timeout_my_receive = TIMEOUT_RECEIVE;
#endif
	m_flag_break = false;
	m_is_buffer_full = false;
	m_operation_in_progress = false;
	m_manage_mode = MANAGE_WAITDLG;
	m_waitdlg_text = _T("");
	m_server_class = 0;

	m_server_name = _T("");
	m_server_port = 0;
	m_num_send = 0;
	external_close_funct = 0;
	external_reconnect_funct = 0;
	m_upper_container = 0;
	m_server_stop_dlg = 0;
	m_NeedAutoDelete = false;
	m_ServerStopping = false;
	m_need_relogin = false;
	m_halt = 0;
	m_wt_dlg = 0;
	m_hide_mode = false;
	m_LastReadyData = 0;
	m_ApplicationLevelLogMessage = 0 ;

#ifdef _UNICODE
	m_ServerAnsi = false;
#else // #ifdef _UNICODE
	m_ServerAnsi = true;
//	m_DenyServerUnicode = true;
#endif // #ifdef _UNICODE

	m_parent_wnd = 0;
	m_thread_id = 0;
	
	m_err_protocol_mess = APL_T("Сервер работает с устаревшей версией транспортного протокола. Обновите сервер приложений!\n");
	m_err_protocol_mess += APL_T(" Дальнейшая работа невозможна");

	m_class_info.Format(_T("CaplSocketClient ") POINTER_FORMAT _T("; create in thread ") THREAD_FORMAT , this, GetCurrentThreadId());

	SetUnBlockTimer();

	LogDebugMessageIfDef(_T("Inited"));
}


// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CaplSocketClient, CSocket)
	//{{AFX_MSG_MAP(CaplSocketClient)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif	// 0

/////////////////////////////////////////////////////////////////////////////
// CaplSocketClient member functions


bool CaplSocketClient::IsOperated()
{
	bool retval;
	LogDebugMessageIfDef(_T("IsOperated"));
	EnterLogCriticalSection(&m_IsBlockedInternalBuf);
	retval=m_operation_in_progress;
	LogDebugMessageIfDef(retval?_T("m_operation_in_progress==true"):_T("m_operation_in_progress==false"));
	LeaveLogCriticalSection(&m_IsBlockedInternalBuf);
	return retval;
}

bool CaplSocketClient::Connect(UINT ip, UINT port, bool prev_ping, LPCTSTR reserved, int num_prev_ping)
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	return Connect(Ip2String(ip), port, prev_ping, reserved, num_prev_ping);
}

bool CaplSocketClient::Connect(LPCTSTR ip, UINT port, bool prev_ping, LPCTSTR reserved, int num_prev_ping)
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	
	m_LastAscError=ASC_NO_ERROR;
	m_LastWsaError=0;
	if(m_IsConnected)
	{
		LogDebugMessageIfDef( APL_T("Connect - уже соединены..."));
		m_LastAscError=ASC_ALREADY_CONNECTED;
		return false;
	}
	LogDebugMessageIfDef( APL_T("Connect - соединяемся..."));

	CSocket::Create();
	CString str;
	DWORD command,command2;
	int nRead;
	// буфер char для заголовка буфера VERSION_INFO который идет в сокет в однобайтном виде!
	char* buf=0;
	int _num_prev_pings = num_prev_ping;

	try{
		if(prev_ping)
		{
// 			HINSTANCE hinst_top=AfxGetApp()->m_hInstance;
// 			TransportPing2(ip,hinst_top);
			while(_num_prev_pings > 0)
			{
				if(TransportPing(ip)==TRUE) break;
				_num_prev_pings--;
				if(_num_prev_pings == 0)
				{
					m_LastWsaError=WSAHOST_NOT_FOUND;
					APL_TRANSPORT_THROW_O(ASC_HOST_INACCESSIBLE);
				}
				Sleep(1000);
			}
		}
		if(CSocket::Connect(ip, port))
		{
			m_halt=0;
			//Sleep(100); - здесь вроде как ждали пока сервре создаст нить и т.п. Пока для проверки убрали, надо посмотреть, вырастет ли число отказов
			m_server_name = ip;
			m_server_port = port;
			// Запрашиваем статус сервера. Фактически серверу идут два нуля
			command = 0;
			command2 = CMDGetServerStatus;

			if(MySend(&command, 4, &command2, 4) == SOCKET_ERROR) APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
			// Получаем подтверждение соединения
			nRead = MyReceive(&command, 4);
			if(nRead == SOCKET_ERROR) APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
			if(nRead!=4 || command!=0)
			{
				APL_TRANSPORT_THROW(ASC_MISSED_RECEIVE_SIZE);
			}
			nRead = MyReceive(&command, 4);

			if(nRead ==SOCKET_ERROR)APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
			if(nRead != 4)
			{
				APL_TRANSPORT_THROW( ASC_MISSED_RECEIVE_SIZE);
			}
			switch (command)
			{
			case CMDConnectionOK:
				if(m_manage_mode != MANAGE_ABSENT) AfxMessageBox(m_err_protocol_mess, MB_OK | MB_ICONERROR);
				APL_TRANSPORT_THROW(ASC_ERROR_MISSED_VERSION);
				
			case CMDConnectionOKNew:
				nRead = MyReceive(&command, 4);// c номером версии
				if(nRead ==SOCKET_ERROR) APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
				nRead = MyReceive(&command2, 4);// с указателем на сокет
				if(nRead ==SOCKET_ERROR) APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);

				if(command < VERSION_NUMBER)
				{
					if(m_manage_mode != MANAGE_ABSENT) AfxMessageBox(m_err_protocol_mess, MB_OK | MB_ICONERROR);
					APL_TRANSPORT_THROW(ASC_ERROR_MISSED_VERSION);
					
				}
				else if(command > VERSION_NUMBER)
				{
					if(m_manage_mode!=MANAGE_ABSENT)
					{
						CString mess;
						mess = APL_T("Версия транспортного протокола сервера приложений более новая, чем версия транспортного протокола клиента.\nОбновите клиента!");
						mess += APL_T(" Дальнейшая работа невозможна");
						AfxMessageBox(mess, MB_OK | MB_ICONERROR);
					}
					APL_TRANSPORT_THROW(ASC_ERROR_MISSED_VERSION);
				}
				m_server_class=command2;
				m_IsConnected=true;
				break;

			default:
				ProcessedCommand(command);
				APL_TRANSPORT_THROW(ASC_ERROR_PROCESSED);
			}
			// посылаем команду...
			command=0;
			// на получение версии
			command2 = CMDGetVersionBuffer;
			if(MySend(&command, 4, &command2, 4) == SOCKET_ERROR) APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);

			// ждем ответа - сначала длина буфера
			nRead = MyReceive(&command, 4);
			if(nRead==SOCKET_ERROR)APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
			if(0 == command  || 0 == nRead)
			{
				APL_TRANSPORT_THROW(ASC_ERROR_MISSED_VERSION);
			}

			if(command>100)APL_TRANSPORT_THROW(ASC_MISSED_RECEIVE_SIZE);// проверка на дурака

			// буфер для заголовка буфера VERSION_INFO который идет в однобайтном виде!
			buf = new char[command + 1];
			nRead = MyReceive(buf,command);
			if(nRead==SOCKET_ERROR)APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
			if((DWORD)nRead!=command)
			{
				APL_TRANSPORT_THROW(ASC_MISSED_RECEIVE_SIZE);
			}
			buf[nRead] = 0;
			// заголовок буфера VERSION_INFO идет в сокет в однобайтном виде!
			nRead = strlen(VERSION_INFO);

#ifdef _UNICODE
			if(memcmp(buf,VERSION_INFO_U,(DWORD)nRead<command?nRead:command)!=0)
			{
				if(memcmp(buf,VERSION_INFO,(DWORD)nRead<command?nRead:command)!=0)
				{
					APL_TRANSPORT_THROW(ASC_ERROR_MISSED_VERSION);
				}
				else
				{
					m_ServerAnsi = true;
				}
			}
#else // #ifdef _UNICODE
			if(memcmp(buf,VERSION_INFO,(DWORD)nRead<command?nRead:command)!=0)
			{
				if(memcmp(buf,VERSION_INFO_U,(DWORD)nRead<command?nRead:command)==0)
				{
// 					if(m_DenyServerUnicode)
// 					{
// 						APL_TRANSPORT_THROW(ASC_ERROR_SERVER_UNICODE);
// 					}
// 					else
					{
						m_ServerAnsi = false;
					}
				}
				else 
				{
					APL_TRANSPORT_THROW(ASC_ERROR_MISSED_VERSION);
				}
				
			}
#endif // #ifdef _UNICODE
			delete[] buf;buf=0;
			
		}
		else
		{
			APL_TRANSPORT_THROW(ASC_ERROR_IN_CONNECT);
		}
	}
	catch(SaplErrorDescription error)
	{
		stack_logger.SetFunctionInfo(error.Print());

		m_LastAscError=(ASC_ERROR_CODES)error.m_err_code;
		if(buf!=0)delete[] buf;buf=0;
		this->Close();

		LogDebugMessageIfDef(_T("Not connected - error ") + error.Print(0, false));
		return false;
	}
	m_thread_id = GetCurrentThreadId();
	LogDebugMessageIfDef( APL_T("Connect - готово"));
	return true;
}


bool CaplSocketClient::IsConnected()
{

	return m_IsConnected;
}

bool CaplSocketClient::IsHalted(){return InterlockedExchangeAdd(&m_halt, 0) > 0;}


void CaplSocketClient::Disconnect()
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	
	// посылаем команду...
	DWORD command=0, command1 = CMDDisconnect;
	try
	{
		if(m_IsConnected)
		{
			MySend(&command, 4, &command1, 4);
		}
	}
	catch(SaplErrorDescription error)
	{
		// Ничего не делаем - главное, ловим исключения
		m_LastAscError=(ASC_ERROR_CODES)error.m_err_code;
	}
	//LogDebugMessageIfDef(_T("Disconnect");
		
	//AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
	m_thread_id = 0;
	this->Close();
	m_IsConnected = false;
	m_renew_function = 0;
	m_parameter_renew_function = 0;
	// чтоюы в дальшейшем можно было переконнектитьсЯ
	m_halt=0;
	
	LogDebugMessageIfDef(_T("Disconnected"));
}


//#define LOG_WARN_TEST(par) LOG_WARN(par)
#define LOG_WARN_TEST(par)

bool CaplSocketClient::Call(void** data, DWORD &length,
							void* lpBuf2, DWORD nBufLen2, bool can_break, bool pause_wait_dlg, bool wait_answer, bool detach_buffer)
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	
	m_LastAscError = ASC_NO_ERROR;
	m_LastWsaError = 0;
	bool ret_val = true;
	
	//DWORD tick_limit=0,call_time_limit=0;
	CaplTimeMeter call_time_limit_timer, wait_dlg_meter;
	DWORD wait_dlg_limit = -100;
	int res_sock;
	DWORD count = 0;

	// указатель нужен, чтобы очистить память, даже когда this удалят вмесье с m_ переменными 
	CTransportWaitDlg* wt_dlg=0;
	
	if(length == 0)return true;
	if(*data == 0)
	{
		m_LastAscError = ASC_MISSED_PARAM;
		return false;
	}

	try
	{
		LogDebugMessageIfDef(_T("\r\n============ Call = begin ========================\r\r"));
		EnterLogCriticalSection(&m_IsBlockedInternalBuf);
		// Отработка таймера в этой же нити критической секцией не ловится
		if(m_operation_in_progress)
		{
			LogDebugMessageIfDef( APL_T("m_operation_in_progress==true, возвращаем ASC_OPERATION_IN_PROGRESS"));
			LeaveLogCriticalSection(&m_IsBlockedInternalBuf);
			m_LastAscError=ASC_OPERATION_IN_PROGRESS;
			// если выйти по исключению, то блок catch прервет процедуру на сервере и покурочит данные
			return false;
		}
		ClearInternalData();
		m_operation_in_progress=true;
		m_num_send++;
	
		LogDebugMessageIfDefFormat2( _T("•Call: Sending to server %i BYTEs (Send N %i)"), length, m_num_send);
		LogDebugMessageIfDefFormat1(_T(" m_manage_mode:%s "),(m_manage_mode==MANAGE_WAITDLG?_T("MANAGE_WAITDLG"):_T("")));
		
		LOG_WARN_TEST(_T("_______________________Send"));

		// отправляем данные серверу по возможности одной пачкой
		res_sock=MySend(&length, 4, *data, length, lpBuf2, nBufLen2);
		if(res_sock==SOCKET_ERROR)
		{
			APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
		}
		if(!wait_answer)
		{
			LogDebugMessageIfDef( APL_T("wait_answer==false, выходим"));
			LeaveLogCriticalSection(&m_IsBlockedInternalBuf);
			return true;
		}

		// чтобы ClearInternalData а) вышла из критиченской секции б) сбросила флаг m_operation_in_progress - m_InternalData не должна быть пустой
		m_InternalData = new BYTE[1];

		// timeout || waitdlg
		if(m_manage_mode == MANAGE_WAITDLG)
		{
			// наш таймер - для определения момента, когда надо показать диалог с бочками
			wait_dlg_meter.Start();
			if(pause_wait_dlg)
			{
				wait_dlg_limit = m_waitdlg_time;	
			}
		}

		// наш таймер - для определения момента, когда уже надежды получить ответ совсем нет
		call_time_limit_timer.Start();

		// чтобы предыдущий мусор не гадил
		m_is_buffer_full = false;
		SetBreak(false);
		count=0;

		LogDebugMessageIfDef(_T("Call - Wait server's answer"));

		while(true)
		{
			if(m_is_buffer_full || m_LastAscError != ASC_NO_ERROR)
			{
				// блин, кто-то уже принял данные с сервера... Или ошибка
				break;
			}
			
			// Пытаемся прочитать из канала
			LOG_WARN_TEST(_T("Receive"));
			res_sock = CAsyncSocket::Receive(&length, 4);
			LogDebugMessageIfDefFormat2(_T(" Call: CAsyncSocket::Receive return %i (Send N %i)"),res_sock,m_num_send);

			if(res_sock == SOCKET_ERROR)
			{
				// опять с сервера ничего не пришло...
				// определяем, нет ли проблем с каналом?
				m_LastWsaError = WSAGetLastError();
				if(0!= m_LastWsaError && WSAEWOULDBLOCK != m_LastWsaError)
				{
					// ага что-то серьезное, ответ мы уже не дождемся
					APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
				}
			}
			else
			{
				LOG_WARN_TEST(_T("4"));
				// так, что-то прочиталось
				LogDebugMessageIfDefFormat2(_T(" CAsyncSocket::Receive get data with length %i (Send N %i)"),length,m_num_send);

				if(res_sock!=4)
				{
					// Тут ошибка, а что делатть?
					APL_TRANSPORT_THROW(ASC_MISSED_RECEIVE_SIZE);
				}
				m_isCall = true;
				if(FullRead(length))
				{
					// это были данные
				}
				m_isCall = false;
				if(m_NeedAutoDelete)
				{
					// вызвана процедура дисконнекта, но удалить класс сокета она не смогла, так как вызывающие функции упадут при обращении к членам класса
					// вызываем удаление здесь
					OnClose(0);
					// и нафиг выходим чтобы не упасть
					LogDebugMessageIfDef(_T("Extra 3!\n"));
					// и бежать отсюда
					return false;
				}
			}

			if(call_time_limit_timer.CheckTimeOut(m_timeout_call))
			{
				// ничего мы не дождемся, времени прошло слишком много
				APL_TRANSPORT_THROW(ASC_TIMEOUT);
				break;
			}

			if(wait_dlg_meter.CheckTimeOut(wait_dlg_limit) && !m_hide_mode)
			{
				CWnd* parent_wnd = 0;
				if(m_parent_wnd !=0)
				{
					if(m_parent_wnd->m_hWnd !=0)
					{
						if(m_parent_wnd->IsWindowVisible())
							parent_wnd = m_parent_wnd;
					}
				}
				if(parent_wnd == 0)parent_wnd = AfxGetMainWnd();

				// пора показывать диалог ожидания с бочками
				if(m_manage_mode == MANAGE_WAITDLG && m_wt_dlg == 0)
				{
					// Диалог "Сервер производит обработку данных" (с "бочками")
					LogDebugMessageIfDef(_T("m_manage_mode==MANAGE_WAITDLG"));
					LogDebugMessageIfDef(APL_T("^%^%^%^%  Создаем окошко CTransportWaitDlg"));

					m_wt_dlg = new CTransportWaitDlg(parent_wnd);
					if(m_waitdlg_text != _T("")) m_wt_dlg->m_txt = m_waitdlg_text;
					m_wt_dlg->m_pClient = this;
					m_wt_dlg->m_can_break = can_break;

					// сохраняем указатель в локальной переменной чтобы спокойно чистить память
					wt_dlg = m_wt_dlg;

					CaplSetResourceHandle res_handle(module_inst);
					//int res=wt_dlg->DoModal();
					wt_dlg->Create(IDD_WAIT_CALL, parent_wnd);
					wt_dlg->ShowWindow(SW_NORMAL);
					res_handle.RestoreHandle();
					LogDebugMessageIfDef(APL_T("^%^%^%^%  Продолжаем обработку"));
				}
			}
			if(wt_dlg != 0)
			{
				if(wt_dlg->IsBreak())
				{
					// при обработке оконной процедуры диалога была вызвана
					// функция OnClose клиента. Класс клиента скорей всего удален, так что
					// надо срочно бежать
					// только диалог удалим
					LogDebugMessageIfDef(APL_T("!!!!! Прерываем по кнопке Break, удаляем диалог и выходим\n"));
					if(wt_dlg!=0){delete wt_dlg; wt_dlg=0;}
					return false;
				}
				if(m_NeedAutoDelete)
				{
					// вызвана процедура дисконнекта, но удалить класс сокета она не смогла - так как здесь было запущенное окно
					// проверяем, работает ли еще это окно
					if(IsWindowVisible(wt_dlg->m_hWnd))
					{
						continue;
					}
					LogDebugMessageIfDef(APL_T("!!!!! Прерываем по m_NeedAutoDelete, удаляем диалог, себя и выходим\n"));
					m_wt_dlg = 0; // чтобы не было повода упасть...
					// удаляем диалог
					delete wt_dlg;
					wt_dlg = 0;
					// удаляем себя
					delete this;
					LogDebugMessageIfDef(_T("Extra 2!\n"));
					// и бежать отсюда
					return false;
				}
			}

			if(m_is_buffer_full)
			{
				// так, пока пользователь ждал, данные получены OnReceive-ом. Выходим из цикла
				break;
			}

			if(IsBreak())
			{
				LogDebugMessageIfDef(_T("flag break"));
				SetBreak(false);
				APL_TRANSPORT_THROW((ASC_ERROR_CODES)ASC_BREAK_CALL);
				break;
			}
			LogDebugMessageIfDef(_T("peek message"));
			
			LOG_WARN_TEST(_T("1"));
			// Тайм аута нет, данные не пришли. Надоть обработать текущие 
			// сообщения из очереди приложения
			if(m_LastWsaError == WSAEWOULDBLOCK)
			{
				LogDebugMessageIfDef(_T("PumpMessage"));
				// Сначала CSocket-ные обработки
				//AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
				//PumpMessages(FD_READ);
				_AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;
				while (true)
				{
					MSG msg;

					if (::PeekMessage(&msg, pState->m_hSocketWindow,
									WM_SOCKET_NOTIFY, WM_SOCKET_DEAD, PM_REMOVE))
					{
						if (msg.message == WM_SOCKET_NOTIFY && (SOCKET)msg.wParam == m_hSocket)
						{
							if (WSAGETSELECTEVENT(msg.lParam) == FD_CLOSE)
							{
								break;
							}
							if (WSAGETSELECTEVENT(msg.lParam) == FD_READ)
							{
								break;
							}
						}
						if (msg.wParam != 0 || msg.lParam != 0)
							CSocket::AuxQueueAdd(msg.message, msg.wParam, msg.lParam);

					}
					else
						break;
				}
				LOG_WARN_TEST(_T("2"));

				if(m_is_buffer_full)
				{
					// при обработке FD_READ  данные получены OnReceive-ом
					LogDebugMessageIfDefFormat1( APL_T("при обработке FD_READ корректно отаботал OnReceive (Send N %i)"),m_num_send);
					break;
				}
			}
			// сообщения таймера и перерисовки
			MSG msg;
			if(wt_dlg != 0)
			{
				LogDebugMessageIfDef(APL_T("Окно диалога - обработка WM_COMMAND"));
				//while (::PeekMessage(&msg, wt_dlg->m_hWnd, WM_COMMAND, WM_COMMAND, PM_REMOVE)) 
				while (::PeekMessage(&msg, wt_dlg->m_hWnd, 0, 0, PM_REMOVE)) 
				{
					DispatchMessage(&msg);
				}
			}

			if(global_process_wm_paint)
			{
				LogDebugMessageIfDef(APL_T("Все окна - обработка WM_PAINT"));
				while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE/*|  PM_NOYIELD*/)) 
					DispatchMessage(&msg);
			}
			LogDebugMessageIfDef(APL_T("Все окна - обработка WM_TIMER"));
			while (::PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE/*|  PM_NOYIELD*/)) 
				DispatchMessage(&msg);
			LogDebugMessageIfDef(APL_T("Все окна - обработка WM_SOCKET_NOTIFY"));
			while (::PeekMessage(&msg, NULL, WM_SOCKET_NOTIFY, WM_SOCKET_NOTIFY, PM_REMOVE|  PM_NOYIELD)) 
				DispatchMessage(&msg);

// 			while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE|  PM_NOYIELD)) 
// 				DispatchMessage(&msg);

			count++;
			LOG_WARN_TEST(_T("3"));

			LogDebugMessageIfDefFormat2(_T(" End cicle %i (Send N %i)"),count,m_num_send);
		}
		LogDebugMessageIfDefFormat1(APL_T(" Закончили циклы приема; всего их было %i "),count);

		if(wt_dlg!=0)
		{
			MSG msg;
			while(IsWindowVisible(wt_dlg->m_hWnd))
			{
				while (::PeekMessage(&msg, wt_dlg->m_hWnd, 0, 0, PM_REMOVE)) 
				{
					DispatchMessage(&msg);
				}
				continue;
			}

			delete wt_dlg;
			m_wt_dlg=0;
			wt_dlg=0;
			while(PeekMessage(&msg,0,WM_COMMAND,WM_COMMAND,PM_REMOVE)) 
			{
				if(msg.message == WM_TIMER) break;
			}
			while(PeekMessage(&msg,0,WM_MOUSEFIRST,WM_NEXTMENU,PM_REMOVE)) 
			{
				if(msg.message == WM_TIMER) break;
			}
			while(PeekMessage(&msg,0,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE)) 
			{
				if(msg.message == WM_TIMER) break;
			}
		}

		LOG_WARN_TEST(_T("_______________________REady+++"));
		// в любом случае длина данных должна быть правильной
		if(m_is_buffer_full)
		{
			*data=m_InternalData;			
			length=m_size_InternalData;
			if(detach_buffer)
			{
				m_InternalData = 0;	
				m_size_InternalData = 0;
				m_operation_in_progress=false;
				LeaveLogCriticalSection(&m_IsBlockedInternalBuf);
			}
		}
		if(m_LastAscError==ASC_OPERATION_IN_PROGRESS)
		{
			m_LastAscError=ASC_NO_ERROR;
		}
	}
	catch(SaplErrorDescription error)
	{
		stack_logger.SetFunctionInfo(error.Print(0, false));

		if(error.m_err_code==ASC_ERROR_IN_SOCKET)
		{
			CString str;
			if(m_LastWsaError != 0)
			{
				GetDescriptionSystemError(m_LastWsaError,str);
			}
			else if(IsHalted())
			{
				str = APL_T("Соединение с сервером разорвано!");
			}
			else
			{
				str = APL_T("Неизвестная ошибка");
			}

			LOG_ERROR( APL_T("При обмене данными с сервером возникла ошибка: ")+str);
		}
		LogDebugMessageIfDefFormat1( APL_T("Call: Исключение! (Send N %i)"),m_num_send);
		if(m_InternalData!=0)
		{
			delete[] m_InternalData;
			m_size_InternalData=0;
			m_InternalData=0;
		}
		m_operation_in_progress=false;
		LeaveLogCriticalSection(&m_IsBlockedInternalBuf);
		ret_val=false;
		m_LastAscError=(ASC_ERROR_CODES)error.m_err_code;


		if(ASC_BREAK_CALL==error.m_err_code && m_server_class!=0)
		{
			LogDebugMessageIfDef(_T("Break on WaitDlg. Send break 2 server with second channel"));
			// пошлем-ка серверу черную метку
			CaplSocketClient black_cli;
			int command, command2, command3;
			int nRead;

			if(black_cli.Connect(m_server_name, m_server_port))
			{
				command = 0;// 0 - признак команды
				command2 = CMDBreakOperation; // код команды
				command3 = m_server_class; // дополнительные данные
				// если сервер подвис - ожидание может затянуться.
				// ставим минимальные таймауты
				black_cli.SetTimeOut(1000, 2000);
				if(black_cli.MySend(&command, 4, &command2, 4, &command3, 4, false) != SOCKET_ERROR)
				{
					// ждем ответ, как прервалось
					nRead = black_cli.MyReceive(&command, 4);
					if(nRead != 4 || command != 0)
					{
						// ошибка при приеме флага команды или пришел не флаг команды!
						command=CMDCriticalError;
					}
					nRead = black_cli.MyReceive(&command, 4);
					if(nRead != 4)
					{
						// ошибка при приеме теперь уже команды!
						command=CMDCriticalError;
					}
				}
				// ну и все
				black_cli.Disconnect();
				switch (command)
				{
				case CMDBreakOk:
					break;
				case CMDCriticalError:
				default:
					LogDebugMessageIfDef(_T("Break work not correctly!"));
					if(m_manage_mode != MANAGE_ABSENT)
					{
						CString mess = APL_T("Прервать операцию не удалось. Возможно,\n пользователь СУБД не имеет необходимых прав.\n");
						mess += APL_T("На сервере поставлен флаг завершения операции,\nно он сработает только после завершения SQL запроса.\n");
						AfxMessageBox(mess);
					}
					break;
				}
			}
		}
		else
		{
			LogDebugMessageIfDefFormat3(_T(" Error in Call! ASC_Error %i WSAErrcode %i (Send N %i)"), error, m_LastWsaError, m_num_send);
		}
		if(error.m_err_code == ASC_ERROR_IN_SOCKET)
		{
			if(TEST_DISCONNECT(m_LastWsaError))
			{
				// или сеть рухнула, или удаленных хост, в общем, кирдык соединению
				error.m_err_code = ASC_ERROR_SOCKET_CLOSE;
			}
		}
	}
	if(m_wt_dlg != 0)
	{
		if(AfxIsValidAddress(m_wt_dlg,FALSE))delete m_wt_dlg;
		m_wt_dlg = 0;
	}
	LogDebugMessageIfDefFormat1(_T("\r\n^^^^^^^^^^^^ Call = end  ^^^^^^^^^^^^^^^^^^^^^^^^^\r\r (Send N %i)"),m_num_send);

	return ret_val;
}


void CaplSocketClient::OnClose(int nErrorCode) 
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	try{
		LogDebugMessageIfDef(_T("OnClose"));

		if(m_server_stop_dlg!=0)
		{
			m_server_stop_dlg->EndDialog(0);
		}
		if(m_wt_dlg!=0)
		{
			m_wt_dlg->m_pClient=0;
		}
		SetHalt();
	//	if(!m_IsConnected)return;

		if(external_close_funct!=0)
		{
			stack_logger.SetFunctionInfo(_T("Call external_close_funct"));

			if(m_wt_dlg!=0)
			{
				m_wt_dlg->SetBreak(true);
				m_wt_dlg->SendMessage(WM_QUIT);
				m_wt_dlg=0;
			}
			external_close_funct(m_upper_container);
			// после вызова этой функции нельзя вызывать переменные-члены класса!
		}
		else
		{
			m_wt_dlg = 0;
		}
	}
	catch(SaplErrorDescription error)
	{
		CString str = error.Print(0, false);
		stack_logger.SetFunctionInfo(str);
		LOG_ERROR(str);
	}
	APL_CATCH_ALL_EXEPTION(;,LOG_ERROR,;);
}


void CaplSocketClient::OnSend(int nErrorCode) 
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	LogDebugMessageIfDef(_T("OnSend"));
}
	
void CaplSocketClient::OnReceive(int nErrorCode) 
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	// TODO: Add your specialized code here and/or call the base class
	
	LogDebugMessageIfDef(_T("OnReceive begin"))
	DWORD length;
	int nRead;
	try
	{
		nRead = MyReceive(&length, 4);

		LogDebugMessageIfDefFormat2(_T(" On receive: length data is %i BYTE (Send N %i)"), length, m_num_send);

		if(SOCKET_ERROR==nRead)
		{
			LogDebugMessageIfDefFormat2(_T(" Error receiving! Errcode %i (Send N %i)") ,m_LastWsaError, m_num_send);
			APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
		}
		if(length > 0x40000000)
		{
			CString str; str.Format(APL_T(" Слишком большой размер порции: %i (Send N %i)") ,length, m_num_send);
			APL_TRANSPORT_THROW_EX(ASC_MISSED_RECEIVE_SIZE, str);
		}
		FullRead(length);
	}
	catch(SaplErrorDescription error)
	{
		CString str = error.Print(0, false);
		stack_logger.SetFunctionInfo(str);

		m_LastAscError=(ASC_ERROR_CODES)error.m_err_code;
		m_LastWsaError=WSAGetLastError();
		if(m_operation_in_progress)
		{
			throw(error);
		}
		LOG_ERROR(str);
	}
	APL_CATCH_ALL_EXEPTION(;,LOG_ERROR,;);

	LogDebugMessageIfDef(_T("OnReceive end"))
}

bool CaplSocketClient::FullRead(DWORD length)
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	
	//LogDebugMessageIfDefFormat1(" Full read getting... %i BYTE",length);

	DWORD position=0;
	DWORD command=0;
	int res_sock;
	DWORD max_num_err=0;

	LogDebugMessageIfDefFormat1(_T(" CAsyncSocket::FullRead (length %i)"),length);
	
	if(length==0)
	{
		// с сервера команда
		res_sock = MyReceive(&command, 4);

		//LogDebugMessageIfDefFormat2(" Full read getting command %i from server! (res_sock %i)",command,res_sock);
		
		if(res_sock==SOCKET_ERROR)
			APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
		if(res_sock!=4)
		{
			// опять ошибка
			APL_TRANSPORT_THROW(ASC_MISSED_RECEIVE_SIZE);
		}
		else
		{
			ProcessedCommand(command);
			LogDebugMessageIfDef( APL_T("Full read : обработали команду. Выходим из FullRead"))
			return false;
		}
	}
	
	if(m_InternalData!=0)
	{
		delete[] m_InternalData;
	}
	m_size_InternalData = 0;
	m_InternalData = new BYTE[length];

	LogDebugMessageIfDefFormat1( APL_T(" Создаем m_InternalData размером %i"), length);
	do
	{
		// приходить может по частям!
		res_sock = MyReceive(m_InternalData + position, length - position);
		
		//LogDebugMessageIfDefFormat1(" Full Read принял %i BYTE",res_sock);
		
		if(res_sock==SOCKET_ERROR)
		{
			LogDebugMessageIfDefFormat2( APL_T(" Ошибка сокета при приеме данныx; errcode %i; N %i"),m_LastWsaError, max_num_err);
			
			if(max_num_err > 100) APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
			max_num_err++;
			continue;
		}
		if(res_sock + position > length) 
			APL_TRANSPORT_THROW(ASC_MISSED_RECEIVE_SIZE);
		if(res_sock + position == length)
			break;

		position += res_sock;
		LogDebugMessageIfDefFormat2( APL_T(" В текущем вызове принято %i байт из %i"), position, length);

	}while(true);

	if(m_operation_in_progress)
	{
		m_is_buffer_full = true;
		m_size_InternalData = length;
	}
	else
	{
		// с сервера пришли непонятные данные. Очищаем буфер
		LogDebugMessageIfDef( APL_T(" !!!!!!!!!!!!!!!!!  Ошибка при приеме данных с сервера!!!!!!!!! Очищаем буфер!!!!! "));
		if(m_InternalData!=0)
		{
			delete[] m_InternalData;
			m_InternalData=0;
			m_size_InternalData=0;
		}
	}
	
	//LogDebugMessageIfDefFormat1(" Full read get %i BYTE",length);
	return true;
}


int CaplSocketClient::MyReceive(void *data, DWORD length)
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	
	CaplTimeMeter timeout_receive;

	int nResult=0;
	if(IsHalted()) return -1;
	if(length == 0) return 0;
	m_LastWsaError = 0;
	
	LogDebugMessageIfDefFormat1(_T(" MyReceive getting %i BYTE..."), length);
	
	// И смиренно ждем ответа
	while ((nResult = CAsyncSocket::Receive(data, length)) == SOCKET_ERROR)
	{
		stack_logger.SetFunctionInfo(_T("CAsyncSocket::Receive..."));

		m_LastWsaError = WSAGetLastError();

		if( WSAEWOULDBLOCK == m_LastWsaError)
		{
			LogDebugMessageIfDef(_T(" MyReceive getting WSAEWOULDBLOCK"));
			//			PumpMessages(FD_READ); Этот вызов здесь может привести к зацикливанию
			if(global_process_wm_paint)
			{
				MSG msg; 
				while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE|  PM_NOYIELD)) 
					DispatchMessage(&msg);
			}
		}
		else if(TEST_DISCONNECT(m_LastWsaError))
		{
			SetHalt();
			LogDebugMessageIfDefFormat2((nResult==SOCKET_ERROR?_T(" Myreceive get %i BYTE with errcode %i"):_T(" Myreceive get %i BYTE (m_LastWsaError %i)")), nResult, m_LastWsaError);
			return nResult;
		}	
		if(timeout_receive.CheckTimeOut(m_timeout_my_receive))
		{
			LogDebugMessageIfDef(_T(" Myreceive - break for timeout"));
			break;
		}
		LogDebugMessageIfDef(_T(" Myreceive - next..."));
	}
	
	LogDebugMessageIfDefFormat2((nResult==SOCKET_ERROR?_T(" Myreceive get %i BYTE with errcode %i"):_T(" Myreceive get %i BYTE (m_LastWsaError %i)")), nResult, m_LastWsaError);
	
	return nResult;
}


void CaplSocketClient::SetApplicationLevelLogMessage(bool (__cdecl *_ApplicationLevelLogMessageDlg)(LPCTSTR message))
{
	m_ApplicationLevelLogMessage = _ApplicationLevelLogMessageDlg;
}

bool CaplSocketClient::ProcessedCommand(DWORD command)
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	
	int percentage=0;
	char* cbuf=0;
	long dead_time=0;
	switch(command)
	{
	case CMDTooManyClients:
		LogDebugMessageIfDef(_T("Command from server - CMDTooManyClients (5)!"));
		APL_TRANSPORT_THROW( ASC_TOO_MANY_CLIENTS_ON_SERVER);
		break;

	case CMDErrorServerProcessed:
		LogDebugMessageIfDef(_T("Command from server - CMDErrorServerProcessed (10)!"));
		APL_TRANSPORT_THROW(ASC_ERROR_PROCESSED_ON_SERVER);
		break;

	case CMDErrorReceiveData:
		LogDebugMessageIfDef(_T("Command from server - CMDErrorReceiveData (11)!"));
		APL_TRANSPORT_THROW(ASC_MISSED_RECEIVE_SIZE_ON_SERVER);
		break;

	case CMDErrorMissedSocketType:
	case CMDErrorInitServer:
		LogDebugMessageIfDef(_T("Command from server - CMDErrorInitServer (12) or CMDErrorMissedSocketType (13)!"));
		APL_TRANSPORT_THROW( ASC_ERROR_INIT_SERVER);
		break;

	case CMDSetProgress:
		LogDebugMessageIfDef(_T("Command from server - CMDSetProgress (21)"));
		// Принимаем 4 байта - процент выполненного
		MyReceive(&percentage,4);
		LogDebugMessageIfDefFormat1( APL_T("Параметр команды %i"),percentage);
		if(m_wt_dlg!=0)
		{
			m_wt_dlg->SetProgressRatio(percentage);
		}
		break;

	case CMDSetProgressText:
		LogDebugMessageIfDef(_T("Command from server - CMDSetProgressText (28)"));
		// Принимаем 4 байта - длинну строчки
		MyReceive(&percentage,4);
		LogDebugMessageIfDefFormat1( APL_T("Длина строчки %i байт"),percentage);
		// длина строчки идет в байтах! Если строка в USC - буфер делаем в два раза короче
		cbuf = new char[percentage + 2];
		MyReceive(cbuf,percentage);
		cbuf[percentage] = 0;
		cbuf[percentage+1] = 0;
		if(m_ApplicationLevelLogMessage!=0)
		{
#ifdef _UNICODE
			if(m_ServerAnsi)
			{
				CaplStringAdapter ad(cbuf);
				m_ApplicationLevelLogMessage((LPCTSTR)ad);
			}
			else
			{
				m_ApplicationLevelLogMessage((LPCTSTR)cbuf);
			}
#else
			if(!m_ServerAnsi) 
			{
				CaplStringAdapter ad((const wchar_t*)cbuf);
				m_ApplicationLevelLogMessage((LPCTSTR)ad);
			}
			else
			{
				m_ApplicationLevelLogMessage(cbuf);
			}
#endif
		}
		delete[] cbuf;
		break;

	case CMDErrorMissedData:
		LogDebugMessageIfDef(_T("Command from server - CMDErrorMissedData (14)"));
		break;

	case CMDRenewClientState:
		LogDebugMessageIfDef(_T("Command from server - CMDRenewClientState (26)"));
		{CaplStackLogger stack_logger(__APL_FUNC__, true); stack_logger.SetFunctionInfo(_T("Command CMDRenewClientState 26"));}
		if(m_renew_function!=0)
		{
			m_renew_function(m_parameter_renew_function);
		}
		break;

	case CMDDeadTime:
		LogDebugMessageIfDef(_T("Command from server - CMDDeadTime (25)"));
		// Принимаем 4 байта - время ожидаемого выключения (в секундах)
		MyReceive(&dead_time,4);
		LogDebugMessageIfDefFormat1( APL_T("Параметр команды %i"),dead_time);
		m_ServerStopping = true;

#ifdef _DEBUG
		{
			CString str;
			str.Format(_T("ProcessedCommand CMDDeadTime - %i"),dead_time);
			_LOG_WARN(str);
		}
#endif

		if(m_hide_mode && dead_time>=0)
		{
			dead_time=0;
			if(m_isCall)
				m_NeedAutoDelete = true;
			else
				OnClose(0);
			return true;
		}
		if(m_server_stop_dlg!=0 && dead_time<0)
		{
			m_server_stop_dlg->CloseWindow();
			delete m_server_stop_dlg;
			m_server_stop_dlg=0;
			m_ServerStopping=false;
			if(!m_hide_mode)AfxMessageBox( APL_T("Сервер приложений не будет остановлен.\nПродолжайте работу в обычном режиме"));
		}
		else if(m_server_stop_dlg==0 && dead_time>0)
		{
			m_server_stop_dlg=new CServerStopDlg();
			m_server_stop_dlg->MakeText(dead_time);
			CaplSetResourceHandle res_handle(module_inst);
			m_server_stop_dlg->Create(IDD_SERVER_STOP_DIALOG,0);
		}
		if(m_server_stop_dlg!=0)
		{
			if(m_server_stop_dlg->m_hWnd!=0)
			{
				m_server_stop_dlg->SetStoppingTime(dead_time);
				m_server_stop_dlg->ShowWindow(SW_SHOW);
				m_server_stop_dlg->SetForegroundWindow();
			}
		}
		break;

	case CMDCriticalError:
		LogDebugMessageIfDef(_T("Command from server - CMDCriticalError (102)"));
		// Принимаем 4 байта - дополнительный код ошибки
		MyReceive(&dead_time,4);
		APL_TRANSPORT_THROW( dead_time);
		break;

	case CMDNeedReconnect:
		if(IsOperated())break;
		if(external_reconnect_funct!=0)
		{
			if(m_wt_dlg!=0)
			{
				m_wt_dlg->SetBreak(true);
				m_wt_dlg->SendMessage(WM_QUIT);
				m_wt_dlg = 0;
			}
			external_reconnect_funct(m_upper_container);
			// после вызова этой функции нельзя вызывать переменные-члены класса!
		}
		break;
	case CMDNeedRelogin:
		if(IsOperated())break;
		if(m_wt_dlg!=0)
		{
			m_wt_dlg->SetBreak(true);
			m_wt_dlg->SendMessage(WM_QUIT);
			m_wt_dlg = 0;
		}
		m_need_relogin = true;
		
		break;

	default:
		break;
	}
	return true;
}


int CaplSocketClient::MySend(const void* lpBuf1, DWORD nBufLen1, const void* lpBuf2, DWORD nBufLen2, const void* lpBuf3, DWORD nBufLen3, bool is_throw)
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	u_long portion_size = MAX_PORTION_SIZE;
	u_long iterator_data = 0, iterator_buf = 0, length;
	BYTE* buf=0;
	int i=0;
	int ret;

	int num_buf=0;
	DWORD sent=0;
	WSABUF data_bufs[3];
	if(lpBuf1==0 || nBufLen1==0)
	{
		return -1;
	}
	if(IsHalted())
	{
		return -1;
	}
	// структура из недр винды, в ней используется char*
	data_bufs[0].buf = (char*)lpBuf1;
	data_bufs[0].len = nBufLen1;
	if(lpBuf2 == 0 || nBufLen2 == 0)
	{
		num_buf=1;
		data_bufs[1].buf = NULL;
		data_bufs[1].len = 0;
		data_bufs[2].buf = NULL;
		data_bufs[2].len = 0;
	}
	else
	{
		data_bufs[1].buf = (char*)lpBuf2;
		data_bufs[1].len = nBufLen2;
		if(lpBuf3 == 0 || nBufLen3 == 0)
		{
			num_buf=2;
			data_bufs[2].buf = (char*)0;
			data_bufs[2].len = 0;
		}
		else
		{
			data_bufs[2].buf = (char*)lpBuf3;
			data_bufs[2].len = nBufLen3;
			num_buf = 3;
		}
	}
	ret = WSASend(m_hSocket, data_bufs, num_buf, &sent, 0, 0, 0);
	if(SOCKET_ERROR == ret)
	{
		m_LastWsaError = WSAGetLastError();
		if(WSAEWOULDBLOCK == m_LastWsaError)
		{
			return 0;
		}
		else if(TEST_DISCONNECT(m_LastWsaError))
		{
			SetHalt();
			LogDebugMessageIfDefFormat1(_T(" MySend don't post because errcode %i"),m_LastWsaError);
			return ret;
		}	
		else
		{
			if(WSAENOBUFS == m_LastWsaError)
			{
				LogDebugMessageIfDefFormat2( APL_T(" MySend: разбиваем %i буферов суммарной длиной %i на части"), num_buf, nBufLen1 + nBufLen2 + nBufLen3);
				do
				{
					try
					{
						// Разбиваем на части и посылаем маленькими порциями
						sent=0;
						BYTE* buf = 0;
						buf = new BYTE[portion_size];
						if(buf == 0)
						{
							// вот блин памяти совсем нет, даже на такой буфер...
							m_LastWsaError = WSAENOBUFS;
							APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
						}
						for(i = 0; i < num_buf; i++)
						{
							iterator_data = 0;
							if(data_bufs[i].len == 0)
							{
								break;
							}
							do
							{
								length = (data_bufs[i].len - iterator_data) < (portion_size-iterator_buf)?
															(data_bufs[i].len-iterator_data):(portion_size-iterator_buf);

								memcpy((BYTE*)(buf+iterator_buf), (BYTE*)(data_bufs[i].buf+iterator_data), length);
								iterator_buf += length;
								iterator_data += length;
								if(iterator_buf == portion_size)
								{
									// буфер полон. посылаем
									ret = Send(buf, iterator_buf);
									// буфер после посылки заполняем c начала
									iterator_buf=0;
									if(SOCKET_ERROR == ret)
									{
										delete buf;
										APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
									}
									sent += ret;
									if(iterator_data < data_bufs[i].len)
									{
										// этот буфер данных еще не кончился
										continue;
									}
								}
								if(i == num_buf-1)
								{
									// Этот буфер входных данных - последний
									ret = Send(buf, iterator_buf);
									if(SOCKET_ERROR == ret)
									{
										delete buf;
										APL_TRANSPORT_THROW(ASC_ERROR_IN_SOCKET);
									}
									sent += ret;
								}
								break;
							}while(true);
						}
						delete buf;				
					}
					catch(SaplErrorDescription err)
					{
						LogDebugMessageIfDef( APL_T("MySend: Ошибка передачи буфера."));
						if(m_LastWsaError != WSAENOBUFS)
						{
							// пересылаем дальше
							throw(err);
						}
						LogDebugMessageIfDef( APL_T("MySend: Уменьшаем размер передачи!"));
						portion_size /= 2;
						if(portion_size < MIN_PORTION_SIZE)
						{
							// дальше уж дробить некуда. Совсем ошибка однако
							LogDebugMessageIfDef( APL_T("MySend: Размер передачи слишком мал!"));
							// пересылаем дальше
							throw(err);
						}
						if(sent > 0)
						{
							// начать передачу по новой мы не могем - часть данных уже была отослана
							LogDebugMessageIfDef( APL_T("MySend: Часть данных уже была отослана!"));
							// пересылаем дальше
							throw(err);
						}
						continue;
					}
				}while(false);
				m_LastWsaError = 0;
				LogDebugMessageIfDefFormat1( APL_T("MySend: В результате размер порции %i"),portion_size);
			}
		}
	}
	if(sent != nBufLen1 + nBufLen2 + nBufLen3)
	{
		LogDebugMessageIfDefFormat2(_T("MySend: sent(%i)!=nBufLen1+nBufLen2+nBufLen3 (%i)"),sent, nBufLen1 + nBufLen2 + nBufLen3);
		if(is_throw)
			APL_TRANSPORT_THROW(ASC_MISSED_SENT_SIZE);
	}
	return ret;
}

void CaplSocketClient::ClearInternalData()
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	
	LogDebugMessageIfDef(_T("ClearInternalData"));
	if(m_InternalData!=0)
	{
		delete[] m_InternalData;
		m_InternalData = 0;
		m_size_InternalData = 0;
		m_operation_in_progress = false;
		LeaveLogCriticalSection(&m_IsBlockedInternalBuf);
	}
}

bool CaplSocketClient::IsWaitDlg()
{
	bool res;
	LogDebugMessageIfDef(_T("IsWaitDlg"));
	EnterLogCriticalSection(&m_ManageOperate);
	res=m_manage_mode==MANAGE_WAITDLG;
	LogDebugMessageIfDef(res ? _T("m_manage_mode==MANAGE_WAITDLG"):_T("m_manage_mode!=MANAGE_WAITDLG"));
	LeaveLogCriticalSection(&m_ManageOperate);
	return res;
}

bool CaplSocketClient::IsActiveWaitDlg()
{
	
	bool res;
	LogDebugMessageIfDef(_T("IsActiveWaitDlg"));
	EnterLogCriticalSection(&m_ManageOperate);
	res=m_wt_dlg!=0;
	LogDebugMessageIfDef(res ? _T("m_wt_dlg!=0"):_T("m_wt_dlg==0"));
	LeaveLogCriticalSection(&m_ManageOperate);
	return res;
}

void CaplSocketClient::SetManageMode(long manage_mode)
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	
	LogDebugMessageIfDef(_T("SetManageMode"));
	EnterLogCriticalSection(&m_ManageOperate);
	m_manage_mode=manage_mode;
	LogDebugMessageIfDef(m_manage_mode ? _T("m_manage_mode==true"):_T("m_manage_mode==false"));
	LeaveLogCriticalSection(&m_ManageOperate);
}

bool CaplSocketClient::IsBreak()
{

	bool res;
	LogDebugMessageIfDef(_T("IsBreak"));
	EnterLogCriticalSection(&m_ManageOperate);
	res=m_flag_break;
	LogDebugMessageIfDef(m_flag_break ? _T("m_flag_break==true") : _T("m_flag_break==false"));
	LeaveLogCriticalSection(&m_ManageOperate);
	return res;
}

void CaplSocketClient::SetBreak(bool state)
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	
	LogDebugMessageIfDef(_T("SetBreak"));
	EnterLogCriticalSection(&m_ManageOperate);
	m_flag_break=state;
	LogDebugMessageIfDef(m_flag_break ? _T("m_flag_break==true"):_T("m_flag_break==false"));
	LeaveLogCriticalSection(&m_ManageOperate);
	if(state)
		m_LastAscError=ASC_BREAK_CALL;
}

bool CaplSocketClient::IsBreakWaitData()
{
	
	bool ret;
	LogDebugMessageIfDef(_T("IsBufferFull"));
	EnterLogCriticalSection(&m_IsBlockedInternalBuf);
	ret=m_is_buffer_full || m_LastAscError != ASC_NO_ERROR;
	LogDebugMessageIfDef(m_is_buffer_full ? _T("m_is_buffer_full==true"):_T("m_is_buffer_full==false"));
	LeaveLogCriticalSection(&m_IsBlockedInternalBuf);
	return ret;
}

void CaplSocketClient::SetWaitDlgText(LPCTSTR waitdlg_text)
{
	
	m_waitdlg_text=waitdlg_text;
}


CString CaplSocketClient::GetDescriptionLastError()
{
	
	CString str;
	::GetDescriptionTransportError(m_LastAscError, m_LastWsaError, str);
	return str;
}

ASC_ERROR_CODES CaplSocketClient::GetLastAscError()
{
	return m_LastAscError;
}

int CaplSocketClient::GetLastWsaError()
{
	return m_LastWsaError;
}


bool CaplSocketClient::SetTimeOut(DWORD timeout_call, DWORD timeout_my_receive)
{
	m_LastAscError = ASC_NO_ERROR;
	m_timeout_call = (timeout_call == 0) ? TIMEOUT_WAIT_NODIALOG : timeout_call;
	m_timeout_my_receive = (timeout_my_receive==0) ? TIMEOUT_RECEIVE : timeout_my_receive;
	return true;
}

bool CaplSocketClient::IsReadyData()
{
	if(IsHalted()) return false;

	if(IOCtl(FIONREAD, &m_LastReadyData))
	{
		return (m_LastReadyData != 0);
	}
	m_LastWsaError = WSAGetLastError();

	LogDebugMessageIfDefFormat1( APL_T(" IsReadyData - Ошибка (%i) определения готовности данных"),m_LastWsaError);
	m_LastReadyData=0;
	return false;
}


void CaplSocketClient::SetRenewFunction(AFX_THREADPROC renew_function, LPVOID parameter_renew_function)
{
	m_renew_function = renew_function;
	m_parameter_renew_function = parameter_renew_function;
}

bool CaplSocketClient::GetHostName(CString &name)
{
	bool ret=true;
	name = _T("");
	// функция gethostname только однобайтная
	char buf[1024];
	if(gethostname(buf, 1024) == SOCKET_ERROR)
	{
		m_LastAscError = ASC_ERROR_IN_SOCKET;
		m_LastWsaError = WSAGetLastError();
		ret = false;
	}
	else
	{
#ifdef _UNICODE
		CaplStringAdapter str_ad(buf);
		name = (LPCTSTR)str_ad;
#else // #ifdef _UNICODE
		name = buf;
#endif // #ifdef _UNICODE

	}
	return ret;
}

UINT32 CaplSocketClient::GetCompIp()
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	
	UINT32 id=0;
// 	char name[512];
// 	int res = gethostname (name, 512);
	SOCKADDR_IN contact_sin;
	//  Старый код - возвращает первый попавшийся ip компа
// 	PHOSTENT phe =gethostbyname(name);
// 	//Копируем адрес узла
// 	memcpy((char FAR *)&(contact_sin.sin_addr),phe->h_addr,phe->h_length);

	// Код возвращает сразу строку с ip и номер порта. Но нам уже много гже нужне ip  в виде 4-байтного числа, так что код - только для примера
// 	CString rSocketAddress;
// 	UINT rSocketPort;
// 	GetSockName(rSocketAddress, rSocketPort);
	// Определяем ip установленного соединения
	int SockAddrLen = sizeof(SOCKADDR); 
	GetSockName((struct sockaddr*)&contact_sin, &SockAddrLen);
	memcpy(&id, &contact_sin.sin_addr, 4);
	//  CString str;
	//	str=inet_ntoa(contact_sin.sin_addr);
	return id;
}

CaplSocketClientH::CaplSocketClientH()
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	m_http_reader = 0;
}

CaplSocketClientH::~CaplSocketClientH()
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	if(m_http_reader != 0)
	{
		delete m_http_reader;
	}
	m_http_reader = 0;
}

bool CaplSocketClientH::Connect(UINT ip, UINT port, bool prev_ping, LPCTSTR proxy, int num_prev_ping)
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	return Connect(Ip2String(ip), port, prev_ping, proxy, num_prev_ping);
}


bool CaplSocketClientH::Connect(LPCTSTR ip, UINT port, bool prev_ping, LPCTSTR proxy, int num_prev_ping)
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	m_LastAscError=ASC_NO_ERROR;
	m_LastWsaError=0;
	if(m_IsConnected)
	{
		LogDebugMessageIfDef( APL_T("Connect - уже соединены..."));
		m_LastAscError=ASC_ALREADY_CONNECTED;return false;
	}
	LogDebugMessageIfDef( APL_T("Connect - соединяемся..."));
	

	CString str;

	try{
		int _num_prev_pings = num_prev_ping;

		if(prev_ping)
		{
			while(_num_prev_pings > 0)
			{
				if(!InternetCheckConnection(ip, FLAG_ICC_FORCE_CONNECTION, 0)) break;
				_num_prev_pings--;
				if(_num_prev_pings == 0)
				{
					m_LastWsaError=WSAHOST_NOT_FOUND;
					APL_TRANSPORT_THROW_O(ASC_HOST_INACCESSIBLE);
				}
				Sleep(1000);
			}
		}

		m_http_reader = new CHTTPReader(ip, port, false, proxy);
		if(m_http_reader == 0)
		{
			APL_TRANSPORT_THROW(ASC_ERROR_IN_CONNECT);
		}
		if(!m_http_reader->OpenInternet(HTTP_NAME_APPLICATION_BASE HTTP_NAME_APPLICATION_VER))
		{
			APL_TRANSPORT_THROW(ASC_ERROR_IN_CONNECT);
		}

		if(m_http_reader->OpenConnection())
		{
			m_halt=0;
			m_server_name = ip;
			m_server_port = port;

			///////////////////////////////////////////////////////////////////////////
			// Запрашиваем статус сервера. 
			// Запрос очень простой - наш сервер должен понять какой клиент по строке приложения
			// А обычный http сервер вернет главную страничку и все.
			m_http_reader->Get(_T(""));

			if(m_http_reader->m_asc_code != ASC_NO_ERROR)
			{
				APL_TRANSPORT_THROW(m_http_reader->m_asc_code);
			}
			
			if(m_http_reader->m_hdr_server.Find(_T("PSS Server "))==-1)
			{
				APL_TRANSPORT_THROW(ASC_MISSED_SERVER);
			}
			if(m_http_reader->m_hdr_version_num > VERSION_PSS_OVER_HTTP)
			{
				if(m_manage_mode != MANAGE_ABSENT)
				{
					CString strt = APL_T("Версия транспортного протокола сервера приложений более новая, чем версия транспортного протокола клиента.\n");
					str += APL_T("Обновите клиента! Дальнейшая работа невозможна");
					AfxMessageBox( str, MB_OK | MB_ICONERROR);
				}
				APL_TRANSPORT_THROW(ASC_ERROR_MISSED_VERSION);
			}
			
			m_LastAscError = m_http_reader->GetAscErrorCode();
			if(m_LastAscError != ASC_NO_ERROR)
			{
				APL_TRANSPORT_THROW(m_LastAscError);
			}

			m_server_class = m_http_reader->m_ClientId;
			if(m_server_class == 0)
			{
				APL_TRANSPORT_THROW(ASC_ERROR_PROCESSED);
			}
			m_IsConnected=true;

		}
		else
		{
			APL_TRANSPORT_THROW(ASC_ERROR_IN_CONNECT);
		}
	}
	catch(SaplErrorDescription error)
	{
		m_LastAscError = (ASC_ERROR_CODES)error.m_err_code;
		if(m_http_reader!=0)
		{
			if(error.m_err_code == ASC_ERROR_IN_WININET)
			{
				m_LastWsaError = m_http_reader->GetError();
				LOG_ERROR_ED( error);
			}
			else if(error.m_err_code == ASC_ERROR_IN_HTTP_REQ)
			{
				m_LastWsaError = m_http_reader->m_dwStatus;
				LOG_ERROR_ED( error);
			}

			delete m_http_reader;
			m_http_reader=0;
		}

		LogDebugMessageIfDefFormat1(_T("Not connected - error %i"), error);
		return false;
	}
	LogDebugMessageIfDef( APL_T("Connect - готово"));
	return true;
}

void CaplSocketClientH::Disconnect()
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);
	
	// посылаем команду...
	DWORD command=0, command1=CMDDisconnect;
	try
	{
		if(m_IsConnected)
		{
			MySend(&command, 4, &command1, 4);
		}
	}
	catch(SaplErrorDescription error)
	{
		// Ничего не делаем - главное, ловим исключения
		m_LastAscError=(ASC_ERROR_CODES)error.m_err_code;
	}
	//LogDebugMessageIfDef(_T("Disconnect"));
		
	//AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
	this->Close();
	m_IsConnected = false;
	m_renew_function = 0;
	m_parameter_renew_function = 0;
	// чтоюы в дальшейшем можно было переконнектитьсЯ
	m_halt = 0;
	
	LogDebugMessageIfDef(_T("Disconnected"));
}


bool CaplSocketClientH::Call(void** data, DWORD &length, void* lpBuf2, DWORD nBufLen2, 
										bool can_break, bool pause_wait_dlg, bool wait_answer, bool detach_buffer)
{
	CaplStackLogger stack_logger(__APL_FUNC__,true);

	m_LastAscError=ASC_NO_ERROR;
	m_LastWsaError=0;
	bool ret_val= true;

	DWORD tick_limit=0, call_time_limit = 0;
//	int res_sock;
	DWORD count=0;
	CaplDataBuf dbuf_internal;
	CString data_encoded;
	CString server;
	DWORD data_size_readed;

	if(m_http_reader == 0)
	{
		APL_TRANSPORT_THROW(ASC_ERROR_IN_CONNECT);
		return false;
	}

	if(length==0)return true;
	if(*data==0)
	{
		m_LastAscError=ASC_MISSED_PARAM;
		return false;
	}

	try
	{
		LogDebugMessageIfDef(_T("Call"));
		EnterLogCriticalSection(&m_IsBlockedInternalBuf);
		// Отработка таймера в этой же нити критической секцией не ловится
		if(m_operation_in_progress)
		{
			LogDebugMessageIfDef( APL_T("m_operation_in_progress==true, возвращаем ASC_OPERATION_IN_PROGRESS"));
			LeaveLogCriticalSection(&m_IsBlockedInternalBuf);
			m_LastAscError=ASC_OPERATION_IN_PROGRESS;
			// если выйти по исключению, то блок catch прервет процедуру на сервере и покурочит данные
			return false;
		}
		ClearInternalData();
		m_operation_in_progress = true;
		m_num_send++;

		LogDebugMessageIfDefFormat2( _T("•Call: Sending to server %i BYTEs (Send N %i)"),length,m_num_send);
		LogDebugMessageIfDefFormat1(_T(" m_manage_mode:%s "),( (m_manage_mode==MANAGE_WAITDLG) ? _T("MANAGE_WAITDLG"):_T("")));

		LOG_WARN_TEST(_T("_______________________Send"));
		// отправляем данные серверу по возможности одной пачкой
		dbuf_internal.Add(&length,4);
		dbuf_internal.Add(*data,length);
		dbuf_internal.Add(lpBuf2,nBufLen2);

		data_encoded = EncodeToBase64(dbuf_internal);
		//UUUU здесь явно неправильно, надо смотреть по факту что передается
		m_http_reader->Post(_T(""), (LPVOID)(LPCTSTR)data_encoded, data_encoded.GetLength(), _T(""));
//AB		m_http_reader->Post("",dbuf_internal.m_data,dbuf_internal.m_Size,"");

		if(m_http_reader->m_hdr_server.Find(_T("PSS Server "))==-1)
		{
			APL_TRANSPORT_THROW(ASC_MISSED_SERVER);
		}
		if(m_http_reader->m_hdr_version_num > VERSION_PSS_OVER_HTTP)
		{
			if(m_manage_mode!=MANAGE_ABSENT)
			{
				CString str = APL_T("Версия транспортного протокола сервера приложений более новая, чем версия транспортного протокола клиента.\n");
				str += APL_T("Обновите клиента! Дальнейшая работа невозможна");
				AfxMessageBox( str, MB_OK | MB_ICONERROR);
			}
			APL_TRANSPORT_THROW(ASC_ERROR_MISSED_VERSION);
		}

		m_LastAscError = m_http_reader->GetAscErrorCode();
		if(m_LastAscError!=ASC_NO_ERROR)
		{
			APL_TRANSPORT_THROW(m_LastAscError);
		}
		
		m_size_InternalData = m_http_reader->GetDataSize();
		if(m_size_InternalData>0)
		{
			m_InternalData = new BYTE[m_size_InternalData+1];
			m_http_reader->GetData(m_InternalData,m_size_InternalData,&data_size_readed);
			m_InternalData[m_size_InternalData]=0;
			
			//UUUU надо проверить как оно работает
			long crc_local_encoded = GetCRC32((char*)m_InternalData,data_size_readed);

			//UUUU надо проверить как оно работает
			DecodeFromBase64((char*)m_InternalData, m_size_InternalData+1, dbuf_internal);

			if(dbuf_internal.m_Size != m_http_reader->m_hdr_spec_original_data_size)
			{
				APL_TRANSPORT_THROW_EX(ASC_MISSED_RECEIVE_SIZE, APL_T("Ошибка! Размер после декодирования неправильный!"));
			}
			
			long crc_local_original = GetCRC32((char*)dbuf_internal.m_data,dbuf_internal.m_Size);

// 			CString str;
// 			str.Format(	"================= CRC: ====================="
// 				"\nEncoded - данные		%x;"
// 				"\nEncoded - с сервера	%x"
// 				"\nOriginal - данные	%x;"
// 				"\nOriginal - с сервера	%x"
// 				,crc_local_encoded,m_http_reader->m_hdr_spec_answer_crc_encoded
// 				,crc_local_original,m_http_reader->m_hdr_spec_answer_crc_original);
// 			LOG_WARN(str);

			if(m_http_reader->m_hdr_spec_answer_crc_encoded!=0)
			{
				if(crc_local_encoded != m_http_reader->m_hdr_spec_answer_crc_encoded || 
					crc_local_original != m_http_reader->m_hdr_spec_answer_crc_original)
				{
					APL_TRANSPORT_THROW_EX(ASC_MISSED_RECEIVE_SIZE, APL_T("Ошибка! Контрольные суммы не совпадают!"));
				}
			}

		}
		else
		{
			dbuf_internal.Clear();
		}

 		m_size_InternalData = dbuf_internal.m_Size;
		delete[] m_InternalData;
		m_InternalData = new BYTE[m_size_InternalData];
 		memcpy(m_InternalData,dbuf_internal.m_data,m_size_InternalData);


		// в любом случае длина данных должна быть правильной
		*data=m_InternalData;			
		length=m_size_InternalData;
		if(detach_buffer)
		{
			m_InternalData = 0;	
			m_size_InternalData = 0;
			m_operation_in_progress=false;
			LeaveLogCriticalSection(&m_IsBlockedInternalBuf);
		}

		if(m_LastAscError==ASC_OPERATION_IN_PROGRESS)
		{
			m_LastAscError=ASC_NO_ERROR;
		}
	}
	catch(SaplErrorDescription error)
	{

		if(error.m_err_code==ASC_ERROR_IN_WININET)
		{
			m_LastWsaError = m_http_reader->GetError();
			LOG_ERROR_ED( error);
		}
		else if(error.m_err_code==ASC_ERROR_IN_HTTP_REQ)
		{
			m_LastWsaError = m_http_reader->m_dwStatus;
			LOG_ERROR_ED( error);
		}
		else
		{
			CString str;
			GetDescriptionSystemError(m_LastWsaError,str);
			LOG_ERROR( APL_T("При обмене данными с сервером возникла ошибка: ")+str);
		}

		LogDebugMessageIfDef( APL_T("Call: Исключение! "));
		if(m_InternalData!=0)
		{
			delete[] m_InternalData;
			m_size_InternalData=0;
			m_InternalData=0;
		}
		m_operation_in_progress=false;
		LeaveLogCriticalSection(&m_IsBlockedInternalBuf);
		ret_val=false;
		m_LastAscError=(ASC_ERROR_CODES)error.m_err_code;


		if(ASC_BREAK_CALL==error.m_err_code && m_server_class!=0)
		{
/*
			LogDebugMessageIfDef(_T("Break on WaitDlg. Send break 2 server with second channel");
			// пошлем-ка серверу черную метку
			CaplSocketClient black_cli;
			int command,command2,command3;
			int nRead;
			if(black_cli.Connect(m_server_ip,m_server_port))
			{
				command=0;// 0 - признак команды
				command2=CMDBreakOperation; // код команды
				command3=m_server_class; // дополнительные данные
				// если сервер подвис - ожидание может затянуться.
				// ставим минимальные таймауты
				black_cli.SetTimeOut(1000,2000);
				if(black_cli.MySend(&command,4,&command2,4,&command3,4,false)!= SOCKET_ERROR)
				{
					// ждем ответ, как прервалось
					nRead=black_cli.MyReceive(&command,4);
					if(nRead!=4 || command!=0)
					{
						// ошибка при приеме флага команды или пришел не флаг команды!
						command=CMDCriticalError;
					}
					nRead=black_cli.MyReceive(&command,4);
					if(nRead!=4)
					{
						// ошибка при приеме теперь уже команды!
						command=CMDCriticalError;
					}
				}
				// ну и все
				black_cli.Disconnect();
				switch (command)
				{
				case CMDBreakOk:
					break;
				case CMDCriticalError:
				default:
					LogDebugMessageIfDef(_T("Break work not correctly!"));
					if(m_manage_mode!=MANAGE_ABSENT)
					{
						AfxMessageBox(	"Прервать операцию не удалось. Возможно,\n"
							"пользователь ORACLE не имеет необходимых прав\n"
							"На сервере поставлен флаг завершения операции,\n"
							"но он сработает только после завершения SQL запроса\n"
							);
					}
					break;
				}
			}
*/
		}
		else
		{
			LogDebugMessageIfDefFormat3(_T(" Error in Call! ASC_Error %i WSAErrcode %i (Send N %i)"), error, m_LastWsaError, m_num_send);
		}
		if(error.m_err_code==ASC_ERROR_IN_SOCKET)
		{
			if(TEST_DISCONNECT(m_LastWsaError))
			{
				// или сеть рухнула, или удаленных хост, в общем, кирдык соединению
				error.m_err_code = ASC_ERROR_SOCKET_CLOSE;
			}
		}
	}
	if(m_wt_dlg!=0)
	{
		delete m_wt_dlg;
		m_wt_dlg=0;
	}

	return ret_val;
}


bool CaplSocketClient::SetGlobalProcessWmPaint(bool is_process)
{
	bool prev_val = global_process_wm_paint;
	global_process_wm_paint=is_process;
	return prev_val;
}

