// ComponentClass.cpp: implementation of the CComponentClass class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "addin.h"
#include "ComponentClass.h"
#include "BLModuleWrapper.h"
#include "Preprocessor.h"

extern CMetaDataCont * pMetaDataCont;
extern CBkEndUI * pBkEndUI;

class CObjID CComponentClass::ObjID;

class CMapDefMethod CComponentClass::MapDef;

CComponentClass* CComponentClass::m_CurDebugObject = NULL;

bool CComponentClass::isExceptionStatus = false;
CString CComponentClass::strTextException;
CValue* CComponentClass::ExceptionValue = NULL;


IMPLEMENT_DYNCREATE(CComponentClass, CBLContext)
		
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//CStdOleBLContext(1)
CComponentClass::CComponentClass() : CBLContext(1)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	m_pModule = NULL;
	m_pHostModule = CBLModule::GetExecutedModule();
	m_pDebugContext = NULL;
	defFnNames = NULL;
	m_MethParamsDef.nNumberOfMeth = -1;
	m_MethParamsDef.nRealNumberOfMeth = -1;
	m_MethParamsDef.pContext = NULL;
	m_isCreateOptimizeMode = pMainAddIn->m_EnableOptimizate==0 ? false : true;
#ifdef _DEBUG
	//pBkEndUI->DoMessageLine("Активизация класса CComponentClass!", mmExclamation);	
#endif
}

CComponentClass::~CComponentClass()
{
//	Msg("Destructor: %s", m_NameOfInstance);
	if (m_pDebugContext != NULL)
	{    
		int n = m_pDebugContext->FindProp("Form");
		if (n != -1)
		{            
			CValue cont1;
			m_pDebugContext->GetPropVal(n, cont1);
			CBLContext *pCont = cont1.GetContext();
			if (pCont)
			{
				n = pCont->FindMethod("Close");
				if (n != -1)
				{
					CValue par1(1);
					CValue *massPar[1];
					massPar[0] = &par1;
					pCont->CallAsProc(n, massPar);
					
				}
			}  
		}
		m_pDebugContext->DecrRef();
	}
	
	POSITION pos;
	CString pkey;
	CSetOfHierarchy::InfoUnlimitsParams *pInfo = NULL;
	
	for( pos = m_BindInstaceValueList.GetStartPosition(); pos != NULL; )
	{
		m_BindInstaceValueList.GetNextAssoc(pos, pkey, (void*&)pInfo );
		pInfo->cont_ValueList->DecrRef();
		delete pInfo;    
	}
	
	
	if (m_pModule)
	{
		/*if (pMainAddIn->m_EnableOptimizate)
		{
		int nStaticVars = m_pModule->GetNStaticVars();
		for (int i = 0; i < nStaticVars; i ++)
		{        
		CValue val;                
		m_pModule->GetStaticVarValue(i, val, 0);
		
		  CBLContext *p = val.GetContext();
		  if (p != NULL)
		  p->DecrRef();
		  }
		}*/
		
		CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();
		pHierarchy->DeInitInstanceComp(m_pModule);
		
		if (!m_pDebugContext)
		{      
			if (!pMainAddIn->m_EnableOptimizate && NULL != MapDef.GetModule(m_NameOfInstance))      
				MapDef.DelModule(m_NameOfInstance);                      
			
			delete m_pModule;
			
		}
		
//		pBkEndUI->DoMessageLine("CComponentClass::~CComponentClass delete m_pModule;", mmBlackErr);	
	}
	
	if(!pMainAddIn->m_EnableOptimizate && defFnNames) 
	{        
		if (NULL != MapDef.GetDefs(m_NameOfInstance))
		{
			MapDef.DelDefParam(m_NameOfInstance);
			//delete defFnNames;
		}
		else
			if (!m_isCreateOptimizeMode)
				delete defFnNames;
	}  
  
#ifdef _DEBUG
  //pBkEndUI->DoMessageLine("Деактивизация класса CComponentClass!", mmExclamation);	
#endif
}

inline int CComponentClass::CallAsMethod(int iMethNum, CValue **ppValue, bool bHasRetVal, CValue *pRetValue)
{
  int res = 0;  
  int iMet = defFnNames->Size();

  if (iMethNum >= iMet)
  {    
	  for (ITER_CONT iter = vecOfBaseCont.begin(); iter != vecOfBaseCont.end(); ++iter)
    {
      CBLContext *pCont = *iter;
      
      int nNMethods = pCont->GetNMethods();

      if (iMethNum <= iMet+nNMethods) 
      {
        int nMeth = iMethNum - iMet;        

        if (bHasRetVal)        
          res = pCont->CallAsFunc(nMeth, *pRetValue, ppValue);          
        else        
          res = pCont->CallAsProc(nMeth, ppValue);                   
        break;
      }
      iMet += nNMethods;
    }	
  }
  else
  {
    if (m_pModule)
    {            
      int iProc = (*defFnNames)[iMethNum].nProcPos; 
  
      CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();        
      assert(pHierarchy!=NULL);
      assert(pMainAddIn!=NULL);
      
      if (pMainAddIn->m_EnabledCheckType)
      {
        // Проверим сначала параметры метода
        CBLProcInfo ProcInfo;
        m_pModule->GetProcInfo(iProc, ProcInfo);
        CString strTemp = pHierarchy->m_strClassAndMethCurrent;          
        pHierarchy->CheckTypeOfParam(this, iMethNum, ppValue, &ProcInfo);
        pHierarchy->m_strClassAndMethCurrent = strTemp;
      }
  

      bool bResOfImpParam = false;
      bool result = false;
          
      // Массив с параметрами переданными по значению в метод для последующего восстановления
      CArray<CValue*, CValue*> arrParamValOfMeth;        
  
      CString strClassAndMeth;
      bool isUnLimParMethod = (*defFnNames)[iMethNum].isUnLimParMethod;

      if (iMethNum >= lastMethod)
      {
        if (isUnLimParMethod)
        {
          bResOfImpParam = pHierarchy->GetImplicitParams(this, ppValue, iMethNum);
          if (bResOfImpParam)
            strClassAndMeth = pHierarchy->m_strClassAndMethImplicit;
        }

        if ((*defFnNames)[iMethNum].bMethHaveVal)
          pHierarchy->SaveValParam(this, iMethNum, ppValue, &arrParamValOfMeth);
      }
      int nCountParams = pHierarchy->m_CountParametersInCallMethod;
          
      if (bHasRetVal)
      {
        CValue locVal;
			  res = m_pModule->CallAsFunc(iProc, locVal, (*defFnNames)[iMethNum].NumberOfParams, ppValue);                        
        *pRetValue = locVal;                
      }
      else
      {
        //CTrapModule* pTrap=(CTrapModule*)m_pModule;
		    //res=pTrap->CallAsProcReal(iProc, (*defFnNames)[iMethNum].NumberOfParams, ppValue);
        res = m_pModule->CallAsProc(iProc, (*defFnNames)[iMethNum].NumberOfParams, ppValue);
      }
       
      pHierarchy->m_CountParametersInCallMethod = nCountParams;

      if (bResOfImpParam)
        pHierarchy->m_strClassAndMethImplicit = strClassAndMeth;

      if ((*defFnNames)[iMethNum].bMethHaveVal) 
        pHierarchy->RestoreValParam(this, iMethNum, ppValue, &arrParamValOfMeth);        
         
      if (isExceptionStatus)
        ThrowException();

      if (bHasRetVal && pMainAddIn && pMainAddIn->m_EnabledCheckType && res == 1)
      {
        // Затем проверим возвращенный тип метода
        CBLProcInfo ProcInfo;
        m_pModule->GetProcInfo(iProc, ProcInfo);          
        pHierarchy->CheckTypeOfParam(this, iMethNum, ppValue, &ProcInfo, pRetValue);
      }
    
    }
  }  
  return res;      
}

// artbear
void CComponentClass::GetFullTypeName(CBLContext *pCont, CString& rus, CString& eng, 
		CString& rusKind, bool bAddKind)
{
  
  CString strClassName(pCont->GetRuntimeClass()->m_lpszClassName);  
  rus.Empty();
  eng.Empty();
  rusKind.Empty();

  rus = pCont->GetTypeString();
  
  if (rus.IsEmpty() || strClassName == "CRegActContext" || strClassName == "CAllRegsContext") 
  {     
    // Здесь агрегатные объекты 1С только такие как "Справочник" и "Документ"    
    int meth = pCont->FindMethod("Kind");
    if (meth != -1) // Нашли номер метода
    {
      //Вызываем данный метод
      CValue value;
      CValue ValueParam;
      CValue *pMassVal[1] = {&ValueParam};
    
      pCont->CallAsFunc(meth, value, pMassVal);
    
      if (strClassName == "CDocContext")
      {
        rus = "Документ";
        eng = "Document";
      }
      else if (strClassName == "CSubcContext")
      {
        rus = "Справочник";
        eng = "Reference";
      }
      else if (strClassName == "CRegActContext")
      {
        rus = "Регистр";  
        eng = "Register";
      }

      CString sKind = value.GetString();
      if (!sKind.IsEmpty() && bAddKind)
		  rusKind = sKind;
    }
    else
    {
      if (strClassName == "CAllRegsContext")
      {
        rus = "Регистры";
        eng = "Registers";
      }
    }
  }
  else
  {
    eng = rus;
  }
  if (rus.IsEmpty())
  {
    CString info;
    info.Format("Имя класса: %s для которого не удалось сформировать имя в методе CComponentClass::GetFullTypeName! Обратитесь за консультацией к разработчику.", strClassName);
    CBLModule::RaiseExtRuntimeError(info,0);    
  }  
}

void CComponentClass::GetFullTypeName(CBLContext *pCont, CString& rus, CString& eng, bool bAddKind)
{
	CString rusKind;  
	GetFullTypeName(pCont, rus, eng, rusKind,bAddKind);
	if (!rusKind.IsEmpty())
	{
		rus += "."+rusKind;
		eng += "."+rusKind;
	}
}

int CComponentClass::GetBaseClass(const CValue &NameClass, CValue &rValue) const
{
  int res = 0;
  rValue = CNumeric(0);

  CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();
  assert(pHierarchy!=NULL);
  
  if (NameClass.IsEmpty())
  {
    CComponentClass* pCompClass = pHierarchy->GetComponentClassCurExModule();
    
    if (pCompClass != NULL && pCompClass != this 
      && CBLModuleWrapper::GetContextFromModule(CBLModule::GetExecutedModule()) == (CBLContext*)this)
    {      
      res = pCompClass->GetBaseClass(NameClass, rValue);
    }
    else
    {
      if (!vecOfBaseCont.empty())
      {
        CBLContext *p = *vecOfBaseCont.begin();
        rValue.AssignContext(p);
      }
      else          
        rValue = CNumeric(0);          
      res = 1;
    }        
  }
  else
  {    
//Msg("%s %s - <%s>", "CComponentClass::GetBaseClass", "NameClass", NameClass);		  
    if (!m_NameOfInstance.CompareNoCase(NameClass.GetString()))
    {
      rValue.AssignContext(const_cast<CComponentClass*>(this));
      res = 1;
    }
    else
    {
      CComponentClass* pCompClass = pHierarchy->GetComponentClassCurExModule();
      if (pCompClass != NULL && pCompClass != this && 
          CBLModuleWrapper::GetContextFromModule(CBLModule::GetExecutedModule()) == (CBLContext*)this)
      {
//Msg("%s %s", "CComponentClass::GetBaseClass", "10");		  
        if (pCompClass->GetBaseClass(NameClass, rValue) == 1)
        {
          res = 1;          
        }         
      }
      else
      {
        for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != vecOfBaseCont.end(); ++iter)
        {
          CBLContext *pCBLContext = *iter;
          CString strRus;
          CString strEng;
          GetFullTypeName(pCBLContext, strRus, strEng);

          if (strRus.CompareNoCase(NameClass.GetString()) == 0 || strEng.CompareNoCase(NameClass.GetString()) == 0)
          {
            rValue.AssignContext(pCBLContext);
            res = 1;
            break;
          }
		  // artbear если у базы тип Справочник.ВидСправочника, а запрашиваем Справочник
		  else
		  {
			  CString strRus;
			  CString strEng;
			  GetFullTypeName(pCBLContext, strRus, strEng, false);
			  if (strRus.CompareNoCase(NameClass.GetString()) == 0 || strEng.CompareNoCase(NameClass.GetString()) == 0)
			  {
				rValue.AssignContext(pCBLContext);
				res = 1;
				break;
			  }
			  else if(pCBLContext->GetRuntimeClass()==&classCComponentClass)
			  {
				CValue* params[1] = {const_cast<CValue*>(&NameClass)};
            
				if (pCBLContext->CallAsFunc(fuctGetBaseClass, rValue, params) == 1)
				{
				  res = 1;
				  break;
				}         
			  }
		  }
        }
      }
    }    
  }
  return res;
}

int CComponentClass::ReplaceInstBaseClasses(const CValue &NameClass, const CValue &Instance, CValue &rValue)
{
  int res = 0;
  rValue = CNumeric(0);
  if (Instance.GetContext() == NULL)
  {
    CBLModule::RaiseExtRuntimeError("Заменить экземпляр базового класса можно только объектом созданным функцией СоздатьОбъект или контекстом модуля!",0);    
  }
  if (NameClass.GetString().GetLength() == 0)
  {
    CBLModule::RaiseExtRuntimeError("Первым параметром должна быть не пустая строка!",0);    
  }
  /*if (!m_NameOfInstance.CompareNoCase(NameClass.GetString()))
  {
    // Сами себя мы не можем заменить    
    res = 1; // artbear здесь будет ошибка для кода Потомок.ЗаменитьБазовыйОбъект("Предок", СовсемДругойОбъект);
	return res;
  }
  else*/
  {
    CString strNameClass(NameClass.GetString());
    CString strRusInstance;
    CString strEngInstance;
    CString strRusInstanceKind;
	 
	// последний параметр true - чтобы правильно обрабатывал ситуацию наследования 
	// от универсального "Справочник"
	// описание бага http://cvs.alterplast.ru/bugs/show_bug.cgi?id=2513
    GetFullTypeName(Instance.GetContext(), strRusInstance, strEngInstance, 
		strRusInstanceKind);

    CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();
    assert(pHierarchy!=NULL);

    CComponentClass* pCompClass = pHierarchy->GetComponentClassCurExModule();
    if (!m_NameOfInstance.CompareNoCase(NameClass.GetString()))
	{
    // artbear Сами себя мы можем заменить, если только передаваемый объект того же типа
    // иначе здесь будет ошибка для кода Потомок.ЗаменитьБазовыйОбъект("Предок", СовсемДругойОбъект);
	// тест "Тест_ЗаменитьБазовыйОбъект_НаНеверныйКласс" - здесь очень-очень старая ошибка с первых релизов 1С++ :( !!
		if (NULL == pCompClass)
			return 0;
        CString strRus;
        CString strEng;
        CString strRusKind;

        GetFullTypeName(this, strRus, strEng, strRusKind);
		bool bNeedReplace = false;
		if (strRusKind.IsEmpty())
		{
			bNeedReplace = !strRus.CompareNoCase(strRusInstance) || 
				!strEng.CompareNoCase(strEngInstance);
		}
		else
		{
			bNeedReplace = !strRusKind.CompareNoCase(strRusInstanceKind) &&
				(!strRus.CompareNoCase(strRusInstance) || !strEng.CompareNoCase(strEngInstance));
		}

		if (bNeedReplace)
			return 1;
		else
			return 0;
	}
	else
    if (pCompClass != NULL && pCompClass != this && 
        CBLModuleWrapper::GetContextFromModule(CBLModule::GetExecutedModule()) == (CBLContext*)this)
    {        
      if (pCompClass->ReplaceInstBaseClasses(NameClass, Instance, rValue) == 1)
      {
        res = 1;
		return res;
      }         
    }
    else
    {
      for (ITER_CONT iter = vecOfBaseCont.begin(); iter != vecOfBaseCont.end(); ++iter)
      {
        CBLContext* pCBLContext = *iter;
        CString strRus;
        CString strEng;
        CString strRusKind;

        GetFullTypeName(pCBLContext, strRus, strEng, strRusKind);

		// описание бага http://cvs.alterplast.ru/bugs/show_bug.cgi?id=2513

		bool bNeedReplace = false;
		if (strRusKind.IsEmpty())
		{
			bNeedReplace = !strRus.CompareNoCase(strNameClass) || 
				strEng.CompareNoCase(strNameClass);
			if (bNeedReplace)
			{
				bNeedReplace = CSetOfHierarchy::GetHierarchy()->IsObject(strRus, strRusInstance) ||
					CSetOfHierarchy::GetHierarchy()->IsObject(strEng, strEngInstance);
			}
		}
		else
		{
			bNeedReplace = !(strRus+"."+strRusKind).CompareNoCase(strNameClass) || 
				(strEng+"."+strRusKind).CompareNoCase(strNameClass);
			if (bNeedReplace)
				bNeedReplace = !strRusKind.CompareNoCase(strRusInstanceKind) &&
					(!strRus.CompareNoCase(strRusInstance) || !strEng.CompareNoCase(strEngInstance));
		}

		if (bNeedReplace)
        {
			*iter = Instance.GetContext();
			(*iter).IncrRef();

			rValue = CNumeric(1);
			res = 1;
			return res;
			break;
        }
        else if(pCBLContext->GetRuntimeClass()==&classCComponentClass)
        {
          CValue* params[2] = {const_cast<CValue*>(&NameClass), const_cast<CValue*>(&Instance)};
          if (pCBLContext->CallAsFunc(funcReplaceInstBaseClasses, rValue, params) == 1)
          {            
            rValue = CNumeric(1);
            res = 1;
			return res;
            break;
          }                
        }      
      }      
    }
  }
  return res;
}

int CComponentClass::IsObject(const CValue &NameClass, CValue &rValue) const
{

	/*if (!m_NameOfInstance.CompareNoCase(NameClass.GetString()))
		rValue = CNumeric(1);
	else
		if (CSetOfHierarchy::GetHierarchy()->TheClassIsDerive(m_NameOfInstance, NameClass.GetString()))
			rValue = CNumeric(1);
		else
			rValue = CNumeric(0);*/
	if (CSetOfHierarchy::GetHierarchy()->IsObject(m_NameOfInstance, NameClass.GetString()))
		rValue = CNumeric(1);
	else
		rValue = CNumeric(0);
	
	return 1;
}

int  CComponentClass::CallAsFunc(int iMethNum,class CValue & rValue,class CValue * *ppValue)
{
  int res = 0;
  switch(iMethNum)
	{    
    

    case fuctGetBaseClass: // ПолучитьБазовыйКласс(<Название класса>) : возврат ссылка на базовый класс
    {
      res = GetBaseClass(*ppValue[0], rValue); 
    }
    break;   
    

    case funcReplaceInstBaseClasses:
    case funcReplaceInstBaseClasses_SYN1:
    {      
      res = ReplaceInstBaseClasses(*ppValue[0], *ppValue[1], rValue);
    }
    break;

	case funcIsObject: // ЯвляетсяОбъектом(<Название объекта>) : возвращает 1 или 0
	{
	  res = IsObject(*ppValue[0], rValue); 
	}
	break;

    case funcSendMessageOwnMod:
    {
      /*ULONG first = CBLContext::GetFirstLoadedContextID();      
      for (ULONG ind = first; ind != 0; ind = CBLContext::GetNextLoadedContextID(ind))
      {
        CBLContext* pContLoaded = CBLContext::GetLoadedContext(ind);
        int nContMeth = pContLoaded->GetNMethods();
        for (int nM = 0; nM < nContMeth; nM++)
        {
          CString strMethodName = pContLoaded->GetPresentMethodName(nM);
          pBkEndUI->DoMessageLine(strMethodName, mmExclamation);	
        }
      }*/
      if (m_pHostModule)
      {
        int iProc = m_pHostModule->FindProc("ОбработкаСобытияОтКласса", 1);
        if (iProc != -1)
        { 
			CValue retValue; // если в функцию передавать напрямую rValue, будет баг с возвращаемым значением
			res = m_pHostModule->CallAsFunc(iProc, retValue, (*defFnNames)[iMethNum].NumberOfParams, ppValue);
			rValue = retValue;
        }        
        else
//          pBkEndUI->DoMessageLine("Не найдена функция обратного вызова ОбработкаСобытияОтКласса()", mmBlackErr);	
          RuntimeError("Не найдена функция обратного вызова ОбработкаСобытияОтКласса()", mmBlackErr); // удобнее исключение artbear
      }
      break;
    }
    case funcGetPathName:
      {
        CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();        
        CString str = pHierarchy->GetNameOfFile(m_NameOfInstance);
        CSetOfHierarchy::MakeFullFileName(&str);        
        rValue = str;
        res = 1;
      }
      break;
    case funcGetEnvContext:
      { 
		  try{
			CBLContext *pCont  = CBLModuleWrapper::GetContextFromModule(m_pHostModule);        
			if (pCont)
			  rValue.AssignContext(pCont);
			else
			  rValue = CNumeric(0);
			res = 1;
			}
		  catch(...)
			  // для kms - хотя это и "не наш метод", но он работает :)
			  // эх! // kms //
		  {
			  RuntimeError("Неизвестное исключение при вызове метода 'ПолучитьКонтекстОкружения'");
		  }
      }
      break;
    case funcGetParamsList:
      {
        CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();

        CBLContext *pContOfList = pHierarchy->GetImplicitParamsList(this, ppValue[0]->GetString());
        if (pContOfList)
          rValue.AssignContext(pContOfList);
        else
          CBLModule::RaiseExtRuntimeError("Нельзя вызывать функцию GetParamsList в методе с отсутсвующими неявными параметрами (...)!",0);
        res = 1;
      }
      break;
    case funcSetOnIndexParams:
      {        
        CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();
        res = pHierarchy->SetImplicitParamOfInd(this, ppValue[0]->GetString(), ppValue[1]->GetNumeric().operator long(), ppValue[2]);
        rValue = CNumeric(res);        
      }
      break;

	default:   
	  res = CallAsMethod(iMethNum, ppValue, true, &rValue);	
	};

	return res; 
}

int  CComponentClass::CallAsProc(int iMethNum,class CValue * * ppValue)
{
  
  int res = 0;
  switch(iMethNum)
	{		
  /*
  case procAssignFriendModule:
    {
      if (m_pModule)
        m_pModule->AssignFriendModule(CBLModule::GetExecutedModule());
    }
    break;
  */

/*// этот функционал закрыт общее решение artbear 
// TODO возможно, в дальнейшем он должен быть открыт внутри класса, а снаружи невидим
//
  case procAddBaseClass:
    {
      CBLContext *pCont = NULL;
      if (strlen(ppValue[0]->GetString()) != 0)
        pCont = CBLContext::CreateInstance(ppValue[0]->GetString());
      else
      {
        pCont = ppValue[0]->GetContext();
        if (pCont) 
        {
          pCont->IncrRef();          
        }
      }
      
      if (pCont) 
      {
// artbear в этом случае массив базовых классов нужно очистить !!
// TODO а не хотел ли Deb здесь специально делать возможность добавления на лету нескольких базовых классов ??
//
		  ITER_CONT iEnd(vecOfBaseCont.end());
		  for (ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd;)
		  {                         
			(*iter)->DecrRef();
			//delete *iter;
			*iter = NULL;        
			vecOfBaseCont.erase(iter++);
		  }      
// end
        CBLContext *pBase = pCont;
        SetNestedObj(pBase);
      }
      res = 1;
    }
    break;*/
  case procOnOpen: // оставлен для совместимости
	res = 1;
    break;  
  case procThrow:
    {
      *ExceptionValue = *ppValue[0];
      CBLModule7::RaiseExtRuntimeError(strTextException, 0);      
    }
    break;
  default:
	res = CallAsMethod(iMethNum, ppValue);	
  };
  return res;
}

int  CComponentClass::FindMethod(char const * lpMethodName)const
{
  int res = defFnNames->GetIndexByName(lpMethodName);	  

  if (-1 != res)
  {
    if ((*defFnNames)[res].isUnLimParMethod || (*defFnNames)[res].bMethHaveVal)
    {
      CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();
      pHierarchy->m_strClassAndMethCurrent = m_NameOfInstance;
      pHierarchy->m_strClassAndMethCurrent += ":";  
      pHierarchy->m_strClassAndMethCurrent += lpMethodName;
    }    
  }
  else
  {    
    int nMethCount = defFnNames->Size();
    for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != vecOfBaseCont.end(); ++iter)
    {  
      CBLContext *pCont = *iter;
    
      res = pCont->FindMethod(lpMethodName);

      if (res != -1)
      {
        res += nMethCount;
        break;
      }
      nMethCount += pCont->GetNMethods();
    }
  }
  return res;
}


char const *  CComponentClass::GetMethodName(int iMethodNum,int iMethodAlias)const
{
	if (iMethodNum < defFnNames->Size())
		return (*defFnNames)[iMethodNum].Names[iMethodAlias];

	int iMet = defFnNames->Size();
	CONST_ITER_CONT iEnd(vecOfBaseCont.end());
	for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd; ++iter)
	{
		CBLContext *pCont = *iter;
		int nNMethods = pCont->GetNMethods();      
		if (iMethodNum < iMet + nNMethods) 
		{
			int nMeth = iMethodNum - iMet;
			return pCont->GetMethodName(nMeth, iMethodAlias);
		}
		iMet += nNMethods;
	}	
	return NULL;
}

int  CComponentClass::GetNMethods(void)const
{
	int nMethCount = defFnNames ? defFnNames->Size() : 0;
	
	CONST_ITER_CONT iEnd(vecOfBaseCont.end());
	for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd; ++iter)
	{  
		CBLContext *pCont = *iter;
		nMethCount += pCont->GetNMethods();
	}
	return nMethCount;
}

int  CComponentClass::HasRetVal(int iMethodNum)const
{
	if (iMethodNum < defFnNames->Size()) 
		return (*defFnNames)[iMethodNum].HasReturnValue;

	int iMet = defFnNames->Size();
	CONST_ITER_CONT iEnd(vecOfBaseCont.end());
	for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd; ++iter)
	{
		CBLContext *pCont = *iter;
		int nNMethods = pCont->GetNMethods();
		if (iMethodNum < iMet+nNMethods) 
		{
			int nMeth = iMethodNum - iMet;
			return pCont->HasRetVal(nMeth);
		}
		iMet += nNMethods;
	}	
	return 0;
}
/*int  CComponentClass::HasRetVal(int iMethodNum)const
{
  int iMet = 0;
  if (iMethodNum >= defFnNames->Size())
  {
    iMet = defFnNames->Size();
    CONST_ITER_CONT iEnd(vecOfBaseCont.end());
	  for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd; ++iter)
    {
      CBLContext *pCont = *iter;
      int nNMethods = pCont->GetNMethods();
      if (iMethodNum < iMet+nNMethods)
      {
        int nMeth = iMethodNum - iMet;
        return pCont->HasRetVal(nMeth);
      }
      iMet += nNMethods;
    }
    return 0;
  }
  else
    return (*defFnNames)[iMethodNum].HasReturnValue;
}*/

int CComponentClass::GetNParams(int iMethodNum)const
{
  int iMet = 0;
  if (iMethodNum >= defFnNames->Size()) 
  {
    iMet = defFnNames->Size();
    CONST_ITER_CONT iEnd(vecOfBaseCont.end());
	  for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd; ++iter)
    {
      CBLContext *pCont = *iter;
      int nNMethods = pCont->GetNMethods();
      if (iMethodNum < iMet+nNMethods) 
      {
        int nMeth = iMethodNum - iMet;
        return pCont->GetNParams(nMeth);
      }
      iMet += nNMethods;
    }	
    return 0;
  }
  else
  {
        
    CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();
    if (pHierarchy && iMethodNum >= lastMethod)
    {
      if ((*defFnNames)[iMethodNum].isUnLimParMethod)
        return pHierarchy->GetNParams(this, iMethodNum, (*defFnNames)[iMethodNum].NumberOfParams);
      else
        return (*defFnNames)[iMethodNum].NumberOfParams;
    }
    else if (iMethodNum <= lastMethod)
      return (*defFnNames)[iMethodNum].NumberOfParams;
    else
      return -1;
    //return (*defFnNames)[iMethodNum].NumberOfParams;
  }  
}

int  CComponentClass::GetParamDefValue(int iMethodNum,int iParamNum,class CValue * pDefValue)const
{
  // Данная функция вызывается перед вызовом CallAsFunc или CallAsProc для 
  // назначения типа и значения переменной pDefValue  

	if (iMethodNum >= defFnNames->Size())
  {    
    bool bFind = false;
    int  nMeth = -1;
    CBLContext *pCont = NULL;
    if (m_MethParamsDef.nNumberOfMeth == iMethodNum && m_MethParamsDef.pContext != NULL)
    {
      nMeth = m_MethParamsDef.nRealNumberOfMeth; 
      pCont = m_MethParamsDef.pContext;
      bFind = true;
    }
    else
    {
      int  iMet = defFnNames->Size();
      CONST_ITER_CONT iEnd(vecOfBaseCont.end());
      for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd; ++iter)
      {
        pCont = *iter;
        int nNMethods = pCont->GetNMethods();
    
        if (iMethodNum < iMet + nNMethods) 
        {
          nMeth = iMethodNum - iMet;
          bFind = true;

          break;
        }
        iMet += nNMethods;
      }	
    }
    if (bFind && pCont)
    {      
      m_MethParamsDef.nNumberOfMeth = iMethodNum;
      m_MethParamsDef.nRealNumberOfMeth = nMeth;
      m_MethParamsDef.pContext = pCont;
      //return 1;
      return pCont->GetParamDefValue(nMeth, iParamNum, pDefValue);
    }
		return 0;
  }
  else
  {
    if (fuctGetBaseClass == iMethodNum && iParamNum == 0)
    {
      pDefValue->Reset();
      return 1;
    }
    else if (fuctGetBaseClass == procThrow)
    {
      if      (iParamNum == 0)
        pDefValue->Reset();
      else if (iParamNum == 1)
        *pDefValue = "";
      else
        return 0;

      return 1;
    }
    else
    {      
      CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();        
      return pHierarchy->GetParamDefValue(iMethodNum, iParamNum, pDefValue, this);            
    }
  }  
	return 0; // Значит параметры по умолчанию не обрабатываются
}


void  CComponentClass::IncrRef(void)
{
	++m_RefCount;
}

void  CComponentClass::DecrRef(void)
{  
	if (m_RefCount == 1)
	{
		if (m_pModule)
		{          
			if (defFnNames->nPosDestructor != -1)
			{
				CValue ValueParam;
				CValue *pMassVal[1] = {0};
				pMassVal[0] = &ValueParam;
				int res = m_pModule->CallAsProc(defFnNames->nPosDestructor, 0, pMassVal);        
			}      
		}
		if (!vecOfBaseCont.empty())
		{
/*
			CONST_ITER_CONT iEnd(vecOfBaseCont.end());
			for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd; ++iter)    
				((CSafeBLContext&)*iter).DecrRef();
*/			
			vecOfBaseCont.clear();
		}    
	}
	
	if(--m_RefCount == 0)
		delete this;  
}

// данная функция используется при вызове Строка(ОбъектКласса) в 1С
// разрешаю наследование функции _ПолучитьКод для КОП,
// если в КОП предке данный метод описан с модификатором Экспорт 
// если же данного модификатора нет, значит, этот метод не будет наследоваться
//
char const *  CComponentClass::GetCode(void) const
{  
  int nPosCode = -1;
  const char * pRet = NULL;
  if (m_pModule)
  {
	  // разрешаю наследование функции _ПолучитьКод
	  // сначала пытаюсь найти метод _ПолучитьКод в текущем модуле,
	  // если не нашел, тогда в базовых классах
	nPosCode = FindMethod(m_pModule, "_ПолучитьКод", "_GetCode");
	
    if (nPosCode != -1)
    {
      CValue ret;
	  // разрешаю наследование функции _ПолучитьКод
	  const_cast<CComponentClass*>(this)->CallAsMethod(nPosCode, NULL, true, &ret);
      pRet = ret.GetString().operator LPCTSTR();
    }
  }  
  return pRet;
}

int  CComponentClass::GetDestroyUnRefd(void)const
{
	return CBLContext::GetDestroyUnRefd();
}

void  CComponentClass::GetExactValue(class CValue & vParam)
{   
	CBLContext::GetExactValue(vParam);
}

class CObjID   CComponentClass::GetID(void)const
{ 
	return ObjID;
}

class CBLContextInternalData *  CComponentClass::GetInternalData(void)
{ 
	return CBLContext::GetInternalData();
}

long  CComponentClass::GetTypeID(void)const
{ 
	return 100;
}

char const *  CComponentClass::GetTypeString(void)const
{ 
	return m_NameOfInstance;
/*// artbear TODO если еще возникнут проблемы с неверным написанием, можно убрать комментарии
	// чтобы название класса писалось не как пользователь напишет, 
	// а бралось из файла описания 
	CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();
	LPSTR strResult = pHierarchy->GetClassNameFromDefinition(m_NameOfInstance);
//Msg("%s %s -<%s>", "CComponentClass::InitObject", "GetClassNameFromDefinition", strResult);
	if (strResult && *strResult)
	{
		return strResult; 
//Msg("%s %s -<%s>", "CComponentClass::InitObject", "m_NameOfInstance", m_NameOfInstance);
	}
// end
	return m_NameOfInstance;*/
}

class CType   CComponentClass::GetValueType(void)const
{
	CType tType(100);
	return tType;
}

void  CComponentClass::InitObject(char const * strName)
{  
	m_NameOfInstance = strName; 
//	Msg("InitObject: %s", m_NameOfInstance);
	CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();
	
	// чтобы название класса писалось не как пользователь напишет, 
	// а бралось из файла описания artbear
	CString strResult = pHierarchy->GetClassNameFromDefinition(CString(strName));
//Msg("%s %s -<%s>", "CComponentClass::InitObject", "GetClassNameFromDefinition", strResult);
	//if (strResult && *strResult)
	if (!strResult.IsEmpty())
	{
		m_NameOfInstance = strResult; 
		//Msg("%s %s -<%s>", "CComponentClass::InitObject", "m_NameOfInstance", m_NameOfInstance);
	}
	
	// end
	
	if (!pHierarchy->InitInstanceComp(this))
	{
/*
		CONST_ITER_CONT iEnd(vecOfBaseCont.end());
		for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd; ++iter)    
			((CSafeBLContext&)*iter).DecrRef();
*/		
		vecOfBaseCont.clear();
	}
}

int  CComponentClass::IsExactValue(void)const
{    
	return 1;
}

int  CComponentClass::IsOleContext(void)const
{  
  int regEBX = 0;
  __asm {
    mov regEBX, ebx // В этом регистре 1С хранит количество параметров при вызове метода
  }
  CSetOfHierarchy::GetHierarchy()->m_CountParametersInCallMethod = regEBX; // сохраним это значение  
	return 0;
}

int  CComponentClass::IsPropReadable(int iPropNum)const
{
	return 1;
}

int  CComponentClass::IsPropWritable(int iPropNum)const
{  
	return 1;
}

int  CComponentClass::IsSerializable(void)
{
	int iProc = m_pModule->FindFunc("КлассСохраняемый");
	if (-1 == iProc)
		iProc = m_pModule->FindFunc("IsSerializable");
	if (-1 == iProc)
		return 0;
	
	CValue ValueParam;
	CValue *pMassVal[1] = {0};
	pMassVal[0] = &ValueParam;
	CValue retVal;
	int res = m_pModule->CallAsFunc(iProc, retVal, 0, pMassVal);
	if (isExceptionStatus)
		ThrowException();
	return retVal.GetNumeric();
}

int  CComponentClass::SaveToString(class CString & csStr)
{     
#ifndef _DEBUG
  if (m_pModule)
  {
    int iProc = m_pModule->FindFunc("СохранитьКлассВСтроку");
    iProc = iProc == -1 ? m_pModule->FindFunc("SaveToString") : iProc;
    if (iProc != -1)
    {
      CValue ValueParam;
      CValue *pMassVal[1] = {0};
      pMassVal[0] = &ValueParam;
      CValue retVal;
      int res = m_pModule->CallAsFunc(iProc, retVal, 0,pMassVal);
      if (isExceptionStatus)
        ThrowException();
      csStr = retVal.GetString();            
    }
  }
#else
  pBkEndUI->DoMessageLine("В _DEBUG режиме с методом SaveToString работать нельзя, если его вызывает 1С движок!!!",mmInformation);
#endif
	return 1;
}

void  CComponentClass::SelectByID(class CObjID cID,long lNum)
{ 
	//CBLContext::SelectByID(cID,lNum);
}

int  CComponentClass::GetNProps(void)const
{
  if (defFnNames->nPosOnReadFreeProp != -1 && defFnNames->nPosOnWriteFreeProp != -1)
  {
    static int nPosNProps = -1;
	nPosNProps = m_pModule->FindFunc("_ПолучитьКолвоДСвойств");
    if (-1 == nPosNProps)
      nPosNProps = m_pModule->FindFunc("_GetNDynamicProps");
    if (nPosNProps != -1)
    {
      CValue rValue;
      //CComponentClass *pClass = const_cast<CComponentClass *>(this);
      m_pModule->CallAsFunc(nPosNProps, rValue, 0, NULL);
      if (isExceptionStatus)
        ThrowException();
      return rValue.GetNumeric();
    }    
  }
  else
  {
    int nCountProps = m_pModule->GetNStaticVars();
    for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != vecOfBaseCont.end(); ++iter)
    {      
      CBLContext *pCont = *iter;
      nCountProps += pCont->GetNProps();
    }
	  return nCountProps;
  }
  return 0;
}

char const *  CComponentClass::GetPropName(int A,int B)const
{  
  if (defFnNames->nPosOnReadFreeProp != -1 && defFnNames->nPosOnWriteFreeProp != -1)
  {
    static int nPosGetPropName = -1;
	nPosGetPropName = m_pModule->FindFunc("_ПолучитьИмяДСвойства");
    if (-1 == nPosGetPropName)
      nPosGetPropName = m_pModule->FindFunc("_GetPropDynamicName");
    if (nPosGetPropName != -1)
    { 
      CValue par1 = A+1;
      CValue* mas[1] = {&par1};
      CValue rValue;
      //CComponentClass *pClass = const_cast<CComponentClass *>(this);
      m_pModule->CallAsFunc(nPosGetPropName, rValue, 1, mas);
      if (isExceptionStatus)
        ThrowException();
      return rValue.GetString();
    }
  }
  else
  {
    int nCountProps = m_pModule->GetNStaticVars();
    if (nCountProps > A)
    {
      CBLVarInfo VarInfo;
	    m_pModule->GetStaticVarDescr(A,VarInfo);
	    return VarInfo.GetName();
    }
    else
    {
      CONST_ITER_CONT iEnd(vecOfBaseCont.end());
      for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd; ++iter)
      {  
        CBLContext *pCont = *iter;
        int nNProps = pCont->GetNProps();
        if (A < nCountProps + nNProps)
        {
          return pCont->GetPropName(A-nCountProps , B);
        }
        else
          nCountProps += nNProps;
      }    
    }    
  }
  return NULL;
}

int  CComponentClass::GetPropVal(int iPropNum,class CValue & rValue)const
{
  if (iPropNum > 65536)
  {
    POSITION pos;
    CString key;
    int *val = NULL;
    for (pos = defFnNames->mapNamesFreeProp.GetStartPosition(); pos != NULL;)
    {
      defFnNames->mapNamesFreeProp.GetNextAssoc( pos, key, (void*&)val );
      if ((int)val == iPropNum - 65536)
      {
        CValue* pParams[1] = {0};
        CValue par0(key);
        pParams[0] = &par0;
        int ret = m_pModule->CallAsFunc(defFnNames->nPosOnReadFreeProp, rValue, 1, pParams);    
        if (isExceptionStatus)
          ThrowException();
        return ret;
      }
    }    
    
  }

  int nCountProps = m_pModule->GetNStaticVars();
  
  if (nCountProps > iPropNum)
  {
    int res = m_pModule->GetStaticVarValue(iPropNum, rValue, 0);
    /*    
    CString strNameProp = GetPropName(iPropNum, 0);
    CString strNamePropRus = "ПриПолучении_";
    strNamePropRus += strNameProp;    

    int iProc = m_pModule->FindProc(strNamePropRus, 0);    
    if (iProc == -1)
    {
      CString strNamePropEng = "OnGet_";
      strNamePropEng += strNameProp;
      iProc = m_pModule->FindProc(strNamePropEng, 1);
    }*/
    int iProc = -1;
    if (defFnNames)
      iProc = defFnNames->GetIndexPropetry(GetPropName(iPropNum, 0), m_pModule, false);    
    
    if (iProc != -1)
    {      
      CValue *pMassVal[1] = {0};
      pMassVal[0] = &rValue;      
      int res = m_pModule->CallAsProc(iProc, 1, pMassVal);
      if (isExceptionStatus)
          ThrowException();
      return res;
    }    
    return res;
  }
	else
  {
    CONST_ITER_CONT iEnd(vecOfBaseCont.end());
    for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd; ++iter)
    {  
      CBLContext *pCont = *iter;
      int nNProps = pCont->GetNProps();
      if (iPropNum < nCountProps + nNProps)
      {
        return pCont->GetPropVal(iPropNum - nCountProps, rValue);
      }
      else
        nCountProps += nNProps;
    }
    return 0;
  }  
}

int  CComponentClass::SetPropVal(int iPropNum, class CValue const & vValue)
{  
  if (iPropNum > 65536)
  {
    POSITION pos;
    CString key;
    int *val = NULL;
    for (pos = defFnNames->mapNamesFreeProp.GetStartPosition(); pos != NULL;)
    {
      defFnNames->mapNamesFreeProp.GetNextAssoc( pos, key, (void*&)val );
      if ((int)val == iPropNum - 65536)
      {
        CValue* pParams[2] = {0};
        CValue par0(key);
        CValue par1(vValue);
        pParams[0] = &par0;
        pParams[1] = &par1;
        //pBkEndUI->DoMessageLine(key, mmBlueTriangle);    
        int ret = m_pModule->CallAsProc(defFnNames->nPosOnWriteFreeProp, 2, &pParams[0]);        
        if (isExceptionStatus)
          ThrowException();
        return ret;
      }
    }    
  }

  int nCountProps = m_pModule->GetNStaticVars();

  if (nCountProps > iPropNum)
  {                
    /*CString strNameProp = GetPropName(iPropNum, 0);
    CString strNamePropRus = "ПриЗаписи_";    
    strNamePropRus += strNameProp;
    
    
    int iProc = m_pModule->FindProc(strNamePropRus, 0);
    if (iProc == -1)
    {
      CString strNamePropEng = "OnWrite_";
      strNamePropEng += strNameProp;
      iProc = m_pModule->FindProc(strNamePropEng, 1);
    }*/
    
    int iProc = -1;
    if (defFnNames)
      iProc = defFnNames->GetIndexPropetry(GetPropName(iPropNum, 0), m_pModule, true);    

    if (iProc != -1)
    {
      CValue par(vValue);
      CValue *pMassVal[1] = {0};
      pMassVal[0] = &par;      
      int ret = m_pModule->CallAsProc(iProc, 1, pMassVal);            
      if (isExceptionStatus)
          ThrowException();
      return ret;      
    }    
    return m_pModule->SetStaticVarValue(iPropNum,vValue,0);    
  }
	else
  {   
    CONST_ITER_CONT iEnd(vecOfBaseCont.end());
    for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd; ++iter)
    {  
      CBLContext *pCont = *iter;
      if (iPropNum >= nCountProps && iPropNum < nCountProps + pCont->GetNProps())
      {
        return pCont->SetPropVal(iPropNum - nCountProps, vValue);
      }
      else
        nCountProps += pCont->GetNProps();
    }
    return 0;
  }
}

int  CComponentClass::FindProp(char const * Name)const
{
  if (defFnNames->nPosOnReadFreeProp != -1 && defFnNames->nPosOnWriteFreeProp != -1)
  {
    int *i = NULL;
    int nCount = 0;
    if (!defFnNames->mapNamesFreeProp.Lookup(Name, (void*&)i))
    {
      nCount = defFnNames->mapNamesFreeProp.GetCount() + 1;
      defFnNames->mapNamesFreeProp[Name] = (int *)nCount;            
    }    
    else
      nCount = (int)i;
    return 65536 + nCount;
  }
    
  int nNumProp = m_pModule->FindStaticVar(Name);
  if (nNumProp == -1)
  {
    int nCountProps = m_pModule->GetNStaticVars();
    
    CONST_ITER_CONT iEnd(vecOfBaseCont.end());
    for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd; ++iter)
    {  
      CBLContext *pCont = *iter;
      int res = pCont->FindProp(Name);
      if (res != -1)
        return nCountProps + res;
      nCountProps += pCont->GetNProps();
    }
  }
  else
  {
    CBLVarInfo VarInfo;
	  m_pModule->GetStaticVarDescr(nNumProp,VarInfo);
    if (VarInfo.IsExported() == 0)      
      nNumProp = -1;
  }
  
	return nNumProp;
}

void CComponentClass::ShowError(const char *err)
{
	if (m_pHostModule) {
		CString str(32,500);
		char buf[100];
		int nLine = m_pHostModule->GetExecutedLineNum();
		m_pHostModule->GetCurSourceLine(nLine, str);
		sprintf(buf, "Ошибка в модуле строка: %d", nLine);
		pBkEndUI->DoMessageLine(buf, mmExclamation);
		str.TrimLeft();
		pBkEndUI->DoMessageLine(str, mmExclamation);
	}
	pBkEndUI->DoMessageLine((LPCTSTR)err, mmExclamation);
}

void  CComponentClass::InitObject(class CType const & tType)
{  
  CBLContext::InitObject(tType);
}

void CComponentClass::OpenDebugForm()
{
	CBLContext* pContLoaded = NULL;
	
	CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();        
	CString str = pHierarchy->GetNameOfFile(m_NameOfInstance);            
	CSetOfHierarchy::MakeFullFileName(&str);          
	
	CString strPar1;
	if (0 == str.Right(4).CompareNoCase(".ert"))
		strPar1 = "Отчет#";
	else if (0 == str.Right(3).CompareNoCase("@md"))
	{
		strPar1 = "Обработка.";
		strPar1 += str.Left(str.GetLength() - 3);
		strPar1 += "#";
	}
	else
		// artbear отладка возможна только для внешних/встроенных отчетов/обработок
		// иначе выдается дурацкое, неудобное предупреждение
		return;
	
	CValue retval;
	CValue Par1 = strPar1, Par2, Par3 = str;
	
	Par2.SetValTypeID(100);
	Par2.AssignContext(this);                          
	
	CValue* MasPar[6] = {&Par1, &Par2, &Par3, 0, 0, 0};
	
	// artbear - при открытии формы класса в виде группового контекста директива _NOW_PREPARE_CLASS выключена
	// http://cvs.alterplast.ru/bugs/show_bug.cgi?id=2505
	const char* cstr_NOW_PREPARE_CLASS = "_NOW_PREPARE_CLASS";
	void *pV = NULL;
	
	CMapStringToPtr &m_RefMap = pHierarchy->m_SymbolOfPreprocessor;
	
	bool bEnable_NOW_PREPARE_CLASS_Prev = m_RefMap.Lookup(cstr_NOW_PREPARE_CLASS, (void*&)pV) > 0 ? true : false;
	//m_RefMap.RemoveKey(cstr_NOW_PREPARE_CLASS);
	m_RefMap[cstr_NOW_PREPARE_CLASS] = NULL;
	pHierarchy->SetIsOpenCompForm(true);
	//end
	
	int bFormOpen;
	int nMethNum = ::FindMethodOfGlobalContexts("OpenForm", pContLoaded);
	if (-1 == nMethNum)
		return;
	try
	{              
		pContLoaded->CallAsFunc(nMethNum, retval, &MasPar[0]);            
		bFormOpen = (retval == 1);
	}
	catch(...)
	{
		bFormOpen = 0;
	}
	
	pHierarchy->SetIsOpenCompForm(false);
	
	if (bEnable_NOW_PREPARE_CLASS_Prev)
		m_RefMap.SetAt(cstr_NOW_PREPARE_CLASS, pV);
	else
		m_RefMap.RemoveKey(cstr_NOW_PREPARE_CLASS);
	
	if (!bFormOpen)	{
		ShowMsg("Класс <%s>. Не удалось открыть форму отладки класса, форма должна содержать хотя бы один элемент.", mmBlackErr, m_NameOfInstance);
		return;
	}

	m_pDebugContext = Par2.GetContext();
	m_pDebugContext->IncrRef();
	m_pModule = GetModuleByContext((CGroupContext*)m_pDebugContext);
	m_pModule->AssignContext(m_CurDebugObject);

	DecrRef();
}

//CBLModuleWrapper* CComponentClass::Init(const char *file, CComponentClass* pCreatedCompModule)
CBLModule* CComponentClass::Init(const char *file, CComponentClass* pCreatedCompModule)
{  
	// file - имя файла, где расположен текст модуля компоненты
	
	// Попробуем получить из общего пула класса MapDef список методов и 
	// откомпилированный модуль относящийся к данному экземпляру класса,
	// т.к. модули и его команды (процедуры, функции, общие переменные) 
	// общие для всех экзепляров дочернего класса. Выполнять компиляцию,
	// теперь необходимо только один раз при первом создании данного класса.
	// Последующие обращения будут располагать готовыми данными  
	try {        
		CBLModule* pNewModule = NULL;
		
		CParamDefs *pParDefs = NULL;
		if (pMainAddIn->m_EnableOptimizate)
			pParDefs = MapDef.GetDefs(m_NameOfInstance);
		
		if (NULL != pParDefs) {
			defFnNames = pParDefs; 
			pNewModule = MapDef.GetModule(m_NameOfInstance);      
		}
		else {
			//pBkEndUI->DoMessageLine("Из файла", mmExclamation);	
			// это первое обращение, необходимо заполнить команды и скомпилировать модуль
			
			CString FullFileName(file);
			CSetOfHierarchy::MakeFullFileName(&FullFileName);
			
			CSetOfHierarchy* pHierarchy = CSetOfHierarchy::GetHierarchy();
			
			CModuleString str;
			if (!str.LoadModule(FullFileName, m_NameOfInstance)) {
				ShowMsg(FullFileName, mmBlackErr);	
				return NULL;
			}
			try 
			{
				// Содержит имена загруженных файлов директивой include в качестве ключей          
				CMapStringToString mapLoadedIncludeFiles;
				CPreprocessor::Preprocess(true, str, pHierarchy->m_SymbolOfPreprocessor, mapLoadedIncludeFiles, FullFileName);        
			}
			catch (CPreprocessor::ExceptionPreprocessor &ex)
			{
				CString strErr;
				strErr.Format("В модуле класса: %s (%s)", m_NameOfInstance, FullFileName);
				pBkEndUI->DoMessageLine(strErr, mmBlackErr);	
				strErr = ex.GetErrorString();        
				pBkEndUI->DoMessageLine(strErr, mmBlackErr);	
				strErr.Empty();
				if (!ex.GetCodeString().IsEmpty()) {
					strErr.Format("(%d) %s", ex.GetNumString(), ex.GetCodeString());
					pBkEndUI->DoMessageLine(strErr, mmBlackErr);
				}
				pHierarchy->m_SymbolOfPreprocessor.RemoveKey("_NOW_PREPARE_CLASS");
				return NULL;
			}
			
			if (str.IsEmpty()) {
				ShowMsg("Класс <%s>. Из программного файла (%s) не получен модуль!", mmBlackErr, m_NameOfInstance, FullFileName);
				return NULL;
			}
			
			pNewModule = new CBLModuleWrapper(NULL, str, FullFileName);
			
			if (pNewModule->Compile() != 1) {
				ShowMsg("Класс <%s>. Файл: %s компиляция не выполнена!", mmRedErr, m_NameOfInstance, FullFileName);
				return NULL;
			}
			
			//int nExec = pNewModule->Execute();
			
			//////////////////////////////////////////////////////////////////////
			// Описание методов и функций класса для 1С языка
			// {{<"English_description">,<"Русское_название">},<0-это процедура, 1-это функция>,<Количество параметров>}
			//////////////////////////////////////////////////////////////////////
			defFnNames = new CParamDefs();
			
			int iProc = pNewModule->FindProc("Конструктор", 0);
			iProc = (iProc == -1) ? pNewModule->FindProc("Constructor", 1) : iProc;
			defFnNames->nPosConstructor = iProc;
			iProc = pNewModule->FindProc("Деструктор", 0);            
			iProc = (iProc == -1) ? pNewModule->FindProc("Destructor", 1) : iProc;                  
			defFnNames->nPosDestructor = iProc;
			
			//_ПриЧтенииСвойства(стрИмяСвойства) возврат "Значение свойства"
			//_OnReadProperty()
			//_ПриЗаписиСвойства(стрИмяСвойства, НовоеЗначениеСв_ва)
			//_OnWriteProperty()
			int nReadPos = pNewModule->FindFunc("_ПриЧтенииСвойства");
			nReadPos = (nReadPos != -1) ? nReadPos : pNewModule->FindFunc("_OnReadProperty");
			if (nReadPos != -1)
			{
				int nWritePos = pNewModule->FindProc("_ПриЗаписиСвойства", 0);
				nWritePos = (nWritePos != -1) ? nWritePos :pNewModule->FindProc("_OnWriteProperty", 1);
				if (nWritePos != -1)
				{
					defFnNames->nPosOnReadFreeProp  = nReadPos;
					defFnNames->nPosOnWriteFreeProp = nWritePos;
				}
			}
			
			if(pMainAddIn->m_EnableOptimizate)  // добавим модуль в банк модулей для данного класса
				MapDef.AddModule(m_NameOfInstance, pNewModule, defFnNames);
			
			int nProc = pNewModule->GetNProcs(); // Получим общее количество процедур и фукций
			
			if (pHierarchy) // Инициализируем описание класса дополнительной информацией полученной из описания класса, по его методам
				pHierarchy->InitParamDefsClass(defFnNames, m_NameOfInstance);
			
			
			
			defFnNames->SetPoolSize(nProc + lastMethod + 1, pNewModule->GetNStaticVars());
			
			defFnNames->AddParam("GetBaseClass", "ПолучитьБазовыйКласс", fuctGetBaseClass, 1, 1);
			defFnNames->AddParam("AssignFriendModule", "ПрисоединитьТекущийМодуль",procAssignFriendModule, 0, 0);
			
			// этот функционал закрыт общее решение artbear 
			// TODO возможно, в дальнейшем он должен быть открыт внутри класса, а снаружи невидим
			//
			//defFnNames->AddParam("AssignBaseClass", "НазначитьБазовыйКласс", procAddBaseClass, 0, 1);
			
			defFnNames->AddParam("SendMessageOwnMod", "ОтправитьСообщениеМодулюХоз", funcSendMessageOwnMod, 1, 3);
			defFnNames->AddParam("GetPathName", "ПолучитьПуть", funcGetPathName, 1, 0);
			defFnNames->AddParam("GetEnvContext", "ПолучитьКонтекстОкружения", funcGetEnvContext, 1, 0);
			defFnNames->AddParam("GetParamsList", "ПолучитьСписокПараметров", funcGetParamsList, 1, 1);
			
			defFnNames->AddParam("ReplaсeBaseObject", "ЗаменитьБазовыйОбъект", funcReplaceInstBaseClasses, 1, 2);  //recommended
			defFnNames->AddParam("ReplaceInstBaseClasses", "ЗаменитьЭксзБазовогоКласса", funcReplaceInstBaseClasses_SYN1, 1, 2);  //deprecated
			
			defFnNames->AddParam("SetOnIndexParams", "УстановитьПараметрПоИндексу", funcSetOnIndexParams, 1, 3);
			defFnNames->AddParam("_OnOpen", "_ПриОткрытии", procOnOpen, 0, 0);
			defFnNames->AddParam("_Throw", "_ВыброситьИскл", procThrow, 0, 1);
			
			defFnNames->AddParam("IsObject", "ЯвляетсяОбъектом", funcIsObject, 1, 1);
			
			for (int count = 1; count < nProc; count++) 
			{
				char nameProc[255] = {0};
				CBLProcInfo procInfo;
				pNewModule->GetProcInfo(count, procInfo); // Получим расширенную инф. по процедурам и функциям
				strcpy(nameProc, procInfo.GetName());
				int nParamas   = procInfo.GetNParams();
				int nVars      = procInfo.GetNVars();
				int hasRetVal  = procInfo.HasRetVal();
				int procPos    = procInfo.GetProcPos();  
				
				if (procInfo.IsExported() == 1)
				{
					CString strNamesClassAndMeth = m_NameOfInstance;
					strNamesClassAndMeth +=":";
					strNamesClassAndMeth +=nameProc;            
					defFnNames->AddParam(NULL,nameProc, procPos, hasRetVal, nParamas, 
						pHierarchy->ThisIsUnLimMethod(strNamesClassAndMeth), //узнаем имеет ли метод неявные параметры
						pHierarchy->isMethHaveParVal(strNamesClassAndMeth)); //узнаем имеет ли метод параметры передаваемые по значению
				}
			}       
		}

		if (pNewModule) {
			if (m_pModule) 
			{
				// pBkEndUI->DoMessageLine("CComponentClass::Init delete m_pModule;", mmBlackErr);	
				delete m_pModule;
				m_pModule = NULL;
			}
			// pBkEndUI->DoMessageLine("CComponentClass::Init m_pModule = new CBLModuleWrapper(this, NULL);", mmBlackErr);	      
			if(pMainAddIn->m_EnableDebugging) 
				OpenDebugForm();
			
			if (!m_pModule)       		    
				m_pModule = new CBLModuleWrapper(pCreatedCompModule, NULL);
			
			m_pModule->AssignCompiled(*pNewModule);      
			
			if(!pMainAddIn->m_EnableOptimizate) 
			{
				MapDef.DelDefs(m_NameOfInstance);
				delete pNewModule;
				// pBkEndUI->DoMessageLine("CComponentClass::Init delete pNewModule;", mmBlackErr);	2A049C00
			}      
			
			if (m_pHostModule != NULL)
				m_pModule->AssignFriendModule(m_pHostModule);
			
			int res = m_pModule->Execute();
			if (res != 1)
			{
				ShowMsg("Класс <%s>. Не удалось выполнить модуль класса!", mmBlackErr, m_NameOfInstance);
				return NULL;
			}      
		}    
		return m_pModule;
	}
	catch (...)
	{
		ShowMsg("Класс <%s>. Неизвестное исключение при инициализации класса!", mmBlackErr, m_NameOfInstance);
		return NULL;
	}
}

void CComponentClass::SetNestedObj(CBLContext* pCont)
{
	/*
	Установка переданного контекста в список 
	контекстов для реализации моделирования 
	наследования 
	*/

	if (pCont)
	{
		vecOfBaseCont.push_back(CSafeContext(TRUE));
		vecOfBaseCont.back() = pCont;
	}

}

void CComponentClass::InvokeConstructor()
{  
	CONST_ITER_CONT iEnd(vecOfBaseCont.end());
	for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != iEnd; ++iter)
	{
		CBLContext *pCBLContext = *iter;
		CString strClassName(pCBLContext->GetRuntimeClass()->m_lpszClassName);
		if (strClassName == "CComponentClass")
		{
			static_cast<CComponentClass*>(pCBLContext)->InvokeConstructor();
		}
	}
	if (m_pModule)
	{            
		if (defFnNames->nPosConstructor != -1)
		{
			CValue ValueParam;
			CValue *pMassVal[1] = {0};
			pMassVal[0] = &ValueParam;
			int res = m_pModule->CallAsProc(defFnNames->nPosConstructor, 0, pMassVal);
			if (isExceptionStatus)
				ThrowException();
		}        
	}     
}

CBLModule * CComponentClass::GetHostModule() const
{
	return m_pHostModule;
}

CBLModule * CComponentClass::GetModule() const
{
	return m_pModule;
}

void CComponentClass::ThrowException(bool isThrow)
{
	//pBkEndUI->DoMessageLine("void CComponentClass::ThrowException(bool isThrow)", mmRedErr);	
	isExceptionStatus = false;
	CString copy(strTextException);
	strTextException.Empty();        
	if (isThrow)
		CBLModule7::RaiseExtRuntimeError(copy, 0) ;        
	else
		pBkEndUI->DoMessageLine(copy, mmExclamation);	
}

void CComponentClass::ClearDebugInfo()
{
	m_CurDebugObject = NULL;
}

void CComponentClass::SetDebugInfo(CComponentClass *pComp)
{
	if (pMainAddIn->m_EnableDebugging)
		m_CurDebugObject = pComp;
}

BOOL CComponentClass::GetBaseClass(const CRuntimeClass* pRTClass, CBLContext** ppBaseObj) const
{
    for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != vecOfBaseCont.end(); ++iter)
    {
		CBLContext *pCont = *iter;
        if (pCont->GetRuntimeClass() == pRTClass)
        {
            *ppBaseObj = *iter;
            return TRUE;
        }
        else if (pCont->GetRuntimeClass() == RUNTIME_CLASS(CComponentClass))
        {
            if ((static_cast<CComponentClass*>(pCont))->GetBaseClass(pRTClass, ppBaseObj))
                return TRUE;
        }
    }
    return FALSE;
}


// найти метод класса по названию
// сначала ищется в модуле класса на случай, если задан без Экспорт
// а затем в экспортируемых методах класса, затем в наследниках 
//
// сначала ищется русское имя, а затем английское
//
inline int CComponentClass::FindMethod(CBLContext* pContext, CBLModule *pMod, LPCTSTR sNameRus, LPCTSTR sNameEng)
{
	int nPosCode = -1;
	
	// пытаюсь в модуле текущего класса найти
	// нужный метод , заданнный без "Экспорт" или с Экспорт
    if (-1 == nPosCode)
		nPosCode = pMod->FindFunc(sNameRus);
	
	// далее пройдусь по наследникам
    if (-1 == nPosCode)
		nPosCode = pContext->FindMethod(sNameRus);

	// пытаюсь в модуле текущего класса найти
	// нужный метод , заданнный без "Экспорт" или с Экспорт
    if (-1 == nPosCode)
		nPosCode = pMod->FindFunc(sNameEng);

	// далее пройдусь по наследникам
    if (-1 == nPosCode)
	      nPosCode = pContext->FindMethod(sNameEng);
	
	return nPosCode;
}
