/*
 * Base-routines for OOPS system
 *
 * Copyright 1999 Antonio Linares <alinares@fivetech.com>
 * Copyright 1999 Eddie Runia <eddie@runia.com>
 *    :CLASSSEL()
 *    __clsDelMsg()
 *    __clsModMsg()
 *    __clsInstSuper()
 *    __cls_CntClsData()
 *    __cls_CntData()
 *    __cls_DecData()
 *    __cls_IncData()
 *    __objClone()
 *    __objHasMsg()
 *    __objSendMsg()
 *
 * Copyright 1999-2001 Viktor Szakats (vszakats.net/harbour)
 *    __classNew()
 *    __classInstance()
 *    __classAdd()
 *    __className()
 *    __classSel() (based on hb___msgClsSel())
 *
 * Copyright 1999 Janica Lubos <janica@fornax.elf.stuba.sk>
 *    hb_clsDictRealloc()
 *
 * Copyright 2000-2007 JF. Lefebvre <jfl@mafact.com> & RA. Cuylen <cakiral@altern.org
 *    Multiple inheritance fully implemented
 *    Forwarding, delegating
 *    Data initialization & Autoinit for Bool and Numeric
 *    Scoping: PROTECTED / EXPORTED
 *
 * Copyright 2008- JF. Lefebvre <jfl@mafact.com>
 *    hb_clsDictRealloc()   New version
 *    Now support of shared and not shared class data
 *    Multiple data declarations fully supported
 *
 * Copyright 2000 Ryszard Glab <rglab@imid.med.pl>
 *    Garbage collector fixes
 *
 * Copyright 2001 JF. Lefebvre <jfl@mafact.com>
 *    Super msg corrected
 *    Scoping: working for PROTECTED, HIDDEN and READONLY
 *    To Many enhancement and correction to give a full list :-)
 *    Improved Class(y) compatibility
 *    Improved TopClass compatibility
 *    __CLS_PAR00() (Allow the creation of class which not autoinherit of the default HBObject())
 *    Adding HB_CLS_ENFORCERO FLAG to disable Write access to RO VAR
 *    outside of Constructors /!\ Could be related to some incompatibility
 *    Added hb_objGetRealClsName() to keep a full class tree (for 99% cases)
 *    Fixed hb_clsIsParent()
 *    hb_objGetMthd() & __clsAddMsg() modified to translate operators
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file LICENSE.txt.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
 *
 * As a special exception, the Harbour Project gives permission for
 * additional uses of the text contained in its release of Harbour.
 *
 * The exception is that, if you link the Harbour libraries with other
 * files to produce an executable, this does not by itself cause the
 * resulting executable to be covered by the GNU General Public License.
 * Your use of that executable is in no way restricted on account of
 * linking the Harbour library code into it.
 *
 * This exception does not however invalidate any other reasons why
 * the executable file might be covered by the GNU General Public License.
 *
 * This exception applies only to the code released by the Harbour
 * Project under the name Harbour.  If you copy code from other
 * Harbour Project or Free Software Foundation releases into a copy of
 * Harbour, as the General Public License permits, the exception does
 * not apply to the code that you add in this way.  To avoid misleading
 * anyone as to the status of such modified files, you must delete
 * this exception notice from them.
 *
 * If you write modifications of your own for Harbour, it is your choice
 * whether to permit this exception to apply to your modifications.
 * If you do not wish that, delete this exception notice.
 *
 */

#include "hbvmopt.h"
#include "hbapi.h"
#include "hbapicls.h"
#include "hbstack.h"
#include "hbapierr.h"
#include "hbapiitm.h"
#include "hbvm.h"
#include "hbthread.h"
#include "hboo.ch"

typedef struct
{
   HB_USHORT   uiClass;
   HB_USHORT   uiOffset;
} HB_CLSCAST, * PHB_CLSCAST;

typedef struct
{
   PHB_ITEM    pInitValue;       /* Init Value for data */
   HB_USHORT   uiType;           /* HB_OO_MSG_DATA, HB_OO_MSG_CLASSDATA or HB_OO_MSG_INITIALIZED */
   HB_USHORT   uiData;           /* Item position in instance area or class data */
   HB_USHORT   uiOffset;         /* Super cast instance area offset for HB_OO_MSG_DATA or real class item position */
   HB_USHORT   uiSprClass;       /* The real class where method were defined */
} INITDATA, * PINITDATA;

typedef struct
{
   PHB_DYNS    pMessage;         /* Method symbolic name */
   PHB_DYNS    pAccMsg;          /* Corresponding access method symbolic name */
   PHB_SYMB    pFuncSym;         /* Function symbol */
   PHB_SYMB    pRealSym;         /* Real function symbol when wrapper is used */
   HB_TYPE     itemType;         /* Type of item in restricted assignment */
   HB_USHORT   uiSprClass;       /* Original class handle (super or current class handle if not inherited). [RAC&JF] */
   HB_USHORT   uiScope;          /* Scoping value */
   HB_USHORT   uiData;           /* Item position for instance data, class data and shared data (Harbour like, begin from 1), supercast class or delegated message index object */
   HB_USHORT   uiOffset;         /* position in pInitData for class datas (from 1) or offset to instance area in inherited instance data and supercast messages (from 0) */
   HB_USHORT   uiPrevCls;
   HB_USHORT   uiPrevMth;
#ifndef HB_NO_PROFILER
   HB_ULONG    ulCalls;          /* profiler support */
   HB_ULONG    ulTime;           /* profiler support */
   HB_ULONG    ulRecurse;        /* profiler support */
#endif
} METHOD, * PMETHOD;


#define HB_MSG_POOL
typedef struct
{
   char *      szName;           /* Class name */
   PHB_DYNS    pClassSym;        /* Class symbolic name */
   PMETHOD     pMethods;         /* Class methods */
   PHB_SYMB    pClassFuncSym;    /* Class function symbol */
   PHB_SYMB    pFriendModule;    /* Class friend symbols */
   PINITDATA   pInitData;        /* Class/instance Initialization data */
   PHB_ITEM    pClassDatas;      /* Harbour Array for Class Datas */
   PHB_ITEM    pSharedDatas;     /* Harbour Array for Class Shared Datas */
   PHB_ITEM    pInlines;         /* Array for inline codeblocks */
   PHB_ITEM    pMutex;           /* Class sync method mutex */
   PHB_SYMB *  pFriendSyms;      /* Friend functions' symbols */
   PHB_CLSCAST pSuperClasses;    /* Super classes */
   HB_U32      nOpFlags;         /* Flags for overloaded operators */
   HB_USHORT   uiClass;          /* This class handle */
   HB_USHORT   fHasDestructor;   /* has the class destructor message? */
   HB_USHORT   fHasOnError;      /* has the class OnError message? */
   HB_USHORT   fLocked;          /* Class is locked against modifications */
   HB_USHORT   uiMethods;        /* Total Method initialized Counter */
   HB_USHORT   uiInitDatas;      /* Total Method initialized Counter */
   HB_USHORT   uiDatas;          /* Total Data Counter */
   HB_USHORT   uiDataFirst;      /* First instance item from this class */
   HB_USHORT   uiSuperClasses;   /* Number of super classes */
   HB_USHORT   uiFriendSyms;     /* Number of friend function's symbols */
   HB_USHORT   uiFriendModule;   /* Number of friend symbols in pFriendModule */
   HB_USHORT   uiMutexOffset;    /* Offset in instance area to SYNC method mutex */
   HB_SIZE     nHashKey;
#ifdef HB_MSG_POOL
   HB_USHORT   uiMethodCount;
   HB_USHORT * puiMsgIdx;
#endif
} CLASS, * PCLASS;

#define BUCKETBITS      2
#define BUCKETSIZE      ( 1 << BUCKETBITS )
#define BUCKETMASK      ( BUCKETSIZE - 1 )
#define HASHBITS        3
#define HASH_KEY        ( ( 1 << HASHBITS ) - 1 )
#define HASH_KEYMAX     ( 1 << ( 32 - BUCKETBITS ) )
#define hb_clsInited(p) ( (p)->pMethods != NULL )
#define hb_clsBucketPos( p, m )  ( ( ( HB_SIZE ) (p)->uiSymNum & (m) ) << BUCKETBITS )

#ifdef HB_MSG_POOL
#  define hb_clsMthNum( p )      ( ( HB_SIZE ) ( p )->uiMethodCount )
#else
#  define hb_clsMthNum( p )      ( ( ( p )->nHashKey + 1 ) << BUCKETBITS )
#endif

#if defined( HB_REAL_BLOCK_SCOPE )
#  undef HB_CLASSY_BLOCK_SCOPE
#elif ! defined( HB_CLASSY_BLOCK_SCOPE )
#  define HB_REAL_BLOCK_SCOPE
#endif

#if ! defined( HB_CLASSY_BLOCK_SCOPE )
#  define hb_clsSenderOffset()   hb_stackBaseProcOffset( 1 )
#endif


HB_FUNC_STATIC( msgGetData );
HB_FUNC_STATIC( msgSetData );
HB_FUNC_STATIC( msgGetClsData );
HB_FUNC_STATIC( msgSetClsData );
HB_FUNC_STATIC( msgGetShrData );
HB_FUNC_STATIC( msgSetShrData );
HB_FUNC_STATIC( msgEvalInline );
HB_FUNC_STATIC( msgVirtual );
HB_FUNC_STATIC( msgSuper );
HB_FUNC_STATIC( msgRealClass );
HB_FUNC_STATIC( msgPerform );
HB_FUNC_STATIC( msgDelegate );
HB_FUNC_STATIC( msgSync );
HB_FUNC_STATIC( msgSyncClass );
HB_FUNC_STATIC( msgNoMethod );
HB_FUNC_STATIC( msgScopeErr );
HB_FUNC_STATIC( msgTypeErr );
HB_FUNC_STATIC( msgNull );

HB_FUNC_STATIC( msgClassH );
HB_FUNC_STATIC( msgClassName );
HB_FUNC_STATIC( msgClassSel );
#if 0
HB_FUNC_STATIC( msgClass );
HB_FUNC_STATIC( msgClassParent );
#endif

/* --- */

/* static variables and structures initialized at HVM startup which
 * do not need any synchronization mechanism in MT mode, [druzus]
 */

/* The positions of items in symbol table below have to correspond
 * to HB_OO_OP_* constants in hbapicls.h, [druzus]
 */
static HB_SYMB s_opSymbols[ HB_OO_MAX_OPERATOR + 1 ] = {
   { "__OPPLUS",              {HB_FS_MESSAGE}, {NULL}, NULL },  /* 00 */
   { "__OPMINUS",             {HB_FS_MESSAGE}, {NULL}, NULL },  /* 01 */
   { "__OPMULT",              {HB_FS_MESSAGE}, {NULL}, NULL },  /* 02 */
   { "__OPDIVIDE",            {HB_FS_MESSAGE}, {NULL}, NULL },  /* 03 */
   { "__OPMOD",               {HB_FS_MESSAGE}, {NULL}, NULL },  /* 04 */
   { "__OPPOWER",             {HB_FS_MESSAGE}, {NULL}, NULL },  /* 05 */
   { "__OPINC",               {HB_FS_MESSAGE}, {NULL}, NULL },  /* 06 */
   { "__OPDEC",               {HB_FS_MESSAGE}, {NULL}, NULL },  /* 07 */
   { "__OPEQUAL",             {HB_FS_MESSAGE}, {NULL}, NULL },  /* 08 */
   { "__OPEXACTEQUAL",        {HB_FS_MESSAGE}, {NULL}, NULL },  /* 09 */
   { "__OPNOTEQUAL",          {HB_FS_MESSAGE}, {NULL}, NULL },  /* 10 */
   { "__OPLESS",              {HB_FS_MESSAGE}, {NULL}, NULL },  /* 11 */
   { "__OPLESSEQUAL",         {HB_FS_MESSAGE}, {NULL}, NULL },  /* 12 */
   { "__OPGREATER",           {HB_FS_MESSAGE}, {NULL}, NULL },  /* 13 */
   { "__OPGREATEREQUAL",      {HB_FS_MESSAGE}, {NULL}, NULL },  /* 14 */
   { "__OPASSIGN",            {HB_FS_MESSAGE}, {NULL}, NULL },  /* 15 */
   { "__OPINSTRING",          {HB_FS_MESSAGE}, {NULL}, NULL },  /* 16 */
   { "__OPINCLUDE",           {HB_FS_MESSAGE}, {NULL}, NULL },  /* 17 */
   { "__OPNOT",               {HB_FS_MESSAGE}, {NULL}, NULL },  /* 18 */
   { "__OPAND",               {HB_FS_MESSAGE}, {NULL}, NULL },  /* 19 */
   { "__OPOR",                {HB_FS_MESSAGE}, {NULL}, NULL },  /* 20 */
   { "__OPARRAYINDEX",        {HB_FS_MESSAGE}, {NULL}, NULL },  /* 21 */
   { "__ENUMINDEX",           {HB_FS_MESSAGE}, {NULL}, NULL },  /* 22 */
   { "__ENUMBASE",            {HB_FS_MESSAGE}, {NULL}, NULL },  /* 23 */
   { "__ENUMVALUE",           {HB_FS_MESSAGE}, {NULL}, NULL },  /* 24 */
   { "__ENUMSTART",           {HB_FS_MESSAGE}, {NULL}, NULL },  /* 25 */
   { "__ENUMSKIP",            {HB_FS_MESSAGE}, {NULL}, NULL },  /* 26 */
   { "__ENUMSTOP",            {HB_FS_MESSAGE}, {NULL}, NULL },  /* 27 */
   { "__ENUMISFIRST",         {HB_FS_MESSAGE}, {NULL}, NULL },  /* 28 */
   { "__ENUMISLAST",          {HB_FS_MESSAGE}, {NULL}, NULL },  /* 29 */
};

static HB_SYMB s___msgDestructor  = { "__msgDestructor", {HB_FS_MESSAGE}, {NULL},               NULL };
static HB_SYMB s___msgOnError     = { "__msgOnError",    {HB_FS_MESSAGE}, {NULL},               NULL };

static HB_SYMB s___msgSetData     = { "__msgSetData",    {HB_FS_MESSAGE}, {HB_FUNCNAME( msgSetData )},    NULL };
static HB_SYMB s___msgGetData     = { "__msgGetData",    {HB_FS_MESSAGE}, {HB_FUNCNAME( msgGetData )},    NULL };
static HB_SYMB s___msgSetClsData  = { "__msgSetClsData", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgSetClsData )}, NULL };
static HB_SYMB s___msgGetClsData  = { "__msgGetClsData", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgGetClsData )}, NULL };
static HB_SYMB s___msgSetShrData  = { "__msgSetShrData", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgSetShrData )}, NULL };
static HB_SYMB s___msgGetShrData  = { "__msgGetShrData", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgGetShrData )}, NULL };
static HB_SYMB s___msgEvalInline  = { "__msgEvalInline", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgEvalInline )}, NULL };
static HB_SYMB s___msgVirtual     = { "__msgVirtual",    {HB_FS_MESSAGE}, {HB_FUNCNAME( msgVirtual )},    NULL };
static HB_SYMB s___msgSuper       = { "__msgSuper",      {HB_FS_MESSAGE}, {HB_FUNCNAME( msgSuper )},      NULL };
static HB_SYMB s___msgRealClass   = { "__msgRealClass",  {HB_FS_MESSAGE}, {HB_FUNCNAME( msgRealClass )},  NULL };
static HB_SYMB s___msgPerform     = { "__msgPerform",    {HB_FS_MESSAGE}, {HB_FUNCNAME( msgPerform )},    NULL };
static HB_SYMB s___msgDelegate    = { "__msgDelegate",   {HB_FS_MESSAGE}, {HB_FUNCNAME( msgDelegate )},   NULL };
static HB_SYMB s___msgSync        = { "__msgSync",       {HB_FS_MESSAGE}, {HB_FUNCNAME( msgSync )},       NULL };
static HB_SYMB s___msgSyncClass   = { "__msgSyncClass",  {HB_FS_MESSAGE}, {HB_FUNCNAME( msgSyncClass )},  NULL };
static HB_SYMB s___msgNoMethod    = { "__msgNoMethod",   {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNoMethod )},   NULL };
static HB_SYMB s___msgScopeErr    = { "__msgScopeErr",   {HB_FS_MESSAGE}, {HB_FUNCNAME( msgScopeErr )},   NULL };
static HB_SYMB s___msgTypeErr     = { "__msgTypeErr",    {HB_FS_MESSAGE}, {HB_FUNCNAME( msgTypeErr )},    NULL };

static HB_SYMB s___msgNew         = { "NEW",             {HB_FS_MESSAGE}, {NULL},               NULL };
static HB_SYMB s___msgSymbol      = { "SYMBOL",          {HB_FS_MESSAGE}, {NULL},               NULL };

static HB_SYMB s___msgClassName   = { "CLASSNAME",       {HB_FS_MESSAGE}, {HB_FUNCNAME( msgClassName )},  NULL };
static HB_SYMB s___msgClassH      = { "CLASSH",          {HB_FS_MESSAGE}, {HB_FUNCNAME( msgClassH )},     NULL };
static HB_SYMB s___msgClassSel    = { "CLASSSEL",        {HB_FS_MESSAGE}, {HB_FUNCNAME( msgClassSel )},   NULL };
static HB_SYMB s___msgExec        = { "EXEC",            {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )},       NULL };
static HB_SYMB s___msgName        = { "NAME",            {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )},       NULL };
/*
static HB_SYMB s___msgClsParent   = { "ISDERIVEDFROM",   {HB_FS_MESSAGE}, {HB_FUNCNAME( msgClassParent )},NULL };
static HB_SYMB s___msgClass       = { "CLASS",           {HB_FS_MESSAGE}, {HB_FUNCNAME( msgClass )},      NULL };
*/
static HB_SYMB s___msgKeys        = { "KEYS",            {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )},       NULL };
static HB_SYMB s___msgValues      = { "VALUES",          {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )},       NULL };

/* Default enumerator methods (FOR EACH) */
static HB_SYMB s___msgEnumIndex   = { "__ENUMINDEX",     {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )},       NULL };
static HB_SYMB s___msgEnumBase    = { "__ENUMBASE",      {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )},       NULL };
static HB_SYMB s___msgEnumKey     = { "__ENUMKEY",       {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )},       NULL };
static HB_SYMB s___msgEnumValue   = { "__ENUMVALUE",     {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )},       NULL };
static HB_SYMB s___msgEnumIsFirst = { "__ENUMISFIRST",   {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )},       NULL };
static HB_SYMB s___msgEnumIsLast  = { "__ENUMISLAST",    {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )},       NULL };

/* WITH OBJECT base value access/assign methods (:__withobject) */
static HB_SYMB s___msgWithObjectPush = { "__WITHOBJECT",  {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )},       NULL };
static HB_SYMB s___msgWithObjectPop  = { "___WITHOBJECT", {HB_FS_MESSAGE}, {HB_FUNCNAME( msgNull )},       NULL };

/* --- */

/* Scalar classes' handles */

/* If user wants to change scalar classes at runtime in MT mode then
 * he must resolve thread synchronization problem himself, [druzus]
 */
static HB_USHORT s_uiArrayClass     = 0;
static HB_USHORT s_uiBlockClass     = 0;
static HB_USHORT s_uiCharacterClass = 0;
static HB_USHORT s_uiDateClass      = 0;
static HB_USHORT s_uiTimeStampClass = 0;
static HB_USHORT s_uiHashClass      = 0;
static HB_USHORT s_uiLogicalClass   = 0;
static HB_USHORT s_uiNilClass       = 0;
static HB_USHORT s_uiNumericClass   = 0;
static HB_USHORT s_uiSymbolClass    = 0;
static HB_USHORT s_uiPointerClass   = 0;

static HB_USHORT s_uiObjectClass    = 0;

/* --- */

/* Class definition holder */

/* In MT mode we are allocating array big enough to hold all
 * class definitions so we do not have to worry about runtime
 * s_pClasses reallocation, [druzus]
 */
#if defined( HB_MT_VM )

#  include "hbthread.h"

#  define HB_CLASS_POOL_SIZE  16382
#  define HB_CLASS_LOCK()     hb_threadEnterCriticalSection( &s_clsMtx )
#  define HB_CLASS_UNLOCK()   hb_threadLeaveCriticalSection( &s_clsMtx )
   static HB_CRITICAL_NEW( s_clsMtx );

#else

#  define HB_CLASS_POOL_SIZE  0
#  define HB_CLASS_LOCK()     do {} while( 0 )
#  define HB_CLASS_UNLOCK()   do {} while( 0 )

#endif

#define HB_CLASS_POOL_RESIZE  64

static PCLASS *  s_pClasses  = NULL;
static HB_USHORT s_uiClsSize = 0;
static HB_USHORT s_uiClasses = 0;

static PHB_ITEM s_pClassMtx = NULL;

/* --- */

#if 0
static HB_SIZE hb_clsBucketPos( PHB_DYNS pMsg, HB_SIZE uiMask )
{
   /* we can use PHB_DYNS address as base for hash key.
    * This value is perfectly unique and we do not need anything more
    * but it's not continuous so we will have to add dynamic BUCKETSIZE
    * modification to be 100% sure that we can resolve all symbol name
    * conflicts (though even without it it's rather theoretical problem).
    * [druzus]
    */

   /* Safely divide it by 16 - it's minimum memory allocated for single
    * HB_DYNS structure
    */
   /*
      return ( ( HB_USHORT ) ( ( HB_PTRUINT ) pMsg >> 4 ) & uiMask ) << BUCKETBITS;
    */

   /* Using continuous symbol numbers we are 100% sure that we will cover
    * the whole 16-bit area and we will never have any problems until number
    * of symbols is limited to 2^16. [druzus]
    */
   return ( pMsg->uiSymNum & uiMask ) << BUCKETBITS;
}
#endif

/* hb_clsDictRealloc( PCLASS )
 *
 * Realloc (widen) class
 */
static HB_BOOL hb_clsDictRealloc( PCLASS pClass )
{
   HB_SIZE nNewHashKey, nLimit, n;

#ifdef HB_MSG_POOL
   HB_USHORT * puiMsgIdx;
#else
   PMETHOD pNewMethods;
#endif

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsDictRealloc(%p)", ( void * ) pClass ) );

   nNewHashKey = pClass->nHashKey + 1;
   nLimit = nNewHashKey << BUCKETBITS;

   do
   {
      nNewHashKey <<= 1;
      if( nNewHashKey > HASH_KEYMAX )
         hb_errInternal( 6002, "Could not realloc class message in __clsDictRealloc()", NULL, NULL );

#ifdef HB_MSG_POOL
      puiMsgIdx = ( HB_USHORT * ) hb_xgrabz( ( nNewHashKey << BUCKETBITS ) * sizeof( HB_USHORT ) );

      for( n = 0; n < nLimit; n++ )
      {
         HB_USHORT uiMsg = pClass->puiMsgIdx[ n ];
         if( pClass->puiMsgIdx[ n ] )
         {
            HB_USHORT uiBucket = BUCKETSIZE;
            HB_USHORT * puiIdx = puiMsgIdx + hb_clsBucketPos(
                        pClass->pMethods[ uiMsg ].pMessage, nNewHashKey - 1 );
            do
            {
               if( *puiIdx == 0 )  /* this message position is empty */
               {
                  *puiIdx = uiMsg;
                  break;
               }
               ++puiIdx;
            }
            while( --uiBucket );

            /* Not enough go back to the beginning */
            if( ! uiBucket )
            {
               hb_xfree( puiMsgIdx );
               break;
            }
         }
      }
   }
   while( n < nLimit );

   pClass->nHashKey = nNewHashKey - 1;
   hb_xfree( pClass->puiMsgIdx );
   pClass->puiMsgIdx = puiMsgIdx;

#else

      pNewMethods = ( PMETHOD ) hb_xgrabz( ( nNewHashKey << BUCKETBITS ) * sizeof( METHOD ) );

      for( n = 0; n < nLimit; n++ )
      {
         PHB_DYNS pMessage = ( PHB_DYNS ) pClass->pMethods[ n ].pMessage;

         if( pMessage )
         {
            PMETHOD pMethod = pNewMethods + hb_clsBucketPos( pMessage, nNewHashKey - 1 );
            HB_USHORT uiBucket = BUCKETSIZE;

            do
            {
               if( ! pMethod->pMessage ) /* this message position is empty */
               {
                  memcpy( pMethod, pClass->pMethods + n, sizeof( METHOD ) );
                  break;
               }
               ++pMethod;
            }
            while( --uiBucket );

            /* Not enough go back to the beginning */
            if( ! uiBucket )
            {
               hb_xfree( pNewMethods );
               break;
            }
         }
      }
   }
   while( n < nLimit );

   pClass->nHashKey = nNewHashKey - 1;
   hb_xfree( pClass->pMethods );
   pClass->pMethods = pNewMethods;
#endif

   return HB_TRUE;
}

static void hb_clsDictInit( PCLASS pClass, HB_SIZE nHashKey )
{
   HB_SIZE nSize;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsDictInit(%p,%" HB_PFS "u)", ( void * ) pClass, nHashKey ) );

   pClass->nHashKey = nHashKey;
#ifdef HB_MSG_POOL
   nSize = ( ( nHashKey + 1 ) << BUCKETBITS ) * sizeof( HB_USHORT );
   pClass->puiMsgIdx = ( HB_USHORT * ) hb_xgrabz( nSize );

   pClass->uiMethodCount = 1;
   pClass->pMethods = ( PMETHOD ) hb_xgrabz( sizeof( METHOD ) );
#else
   nSize = ( ( nHashKey + 1 ) << BUCKETBITS ) * sizeof( METHOD );
   pClass->pMethods = ( PMETHOD ) hb_xgrabz( nSize );
#endif
}

static PMETHOD hb_clsFindMsg( PCLASS pClass, PHB_DYNS pMsg )
{
#ifdef HB_MSG_POOL

   HB_USHORT uiBucket, * puiMsgIdx;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsFindMsg(%p,%p)", ( void * ) pClass, ( void * ) pMsg ) );

   puiMsgIdx = pClass->puiMsgIdx + hb_clsBucketPos( pMsg, pClass->nHashKey );
   uiBucket = BUCKETSIZE;

   do
   {
      PMETHOD pMethod = &pClass->pMethods[ *puiMsgIdx ];

      if( pMethod->pMessage == pMsg )
         return pMethod;
      ++puiMsgIdx;
   }
   while( --uiBucket );

#else

   PMETHOD pMethod;
   HB_USHORT uiBucket;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsFindMsg(%p,%p)", ( void * ) pClass, ( void * ) pMsg ) );

   pMethod = pClass->pMethods + hb_clsBucketPos( pMsg, pClass->nHashKey );
   uiBucket = BUCKETSIZE;

   do
   {
      if( pMethod->pMessage == pMsg )
         return pMethod;
      ++pMethod;
   }
   while( --uiBucket );

#endif

   return NULL;
}

static PMETHOD hb_clsAllocMsg( PCLASS pClass, PHB_DYNS pMsg )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_clsAllocMsg(%p,%p)", ( void * ) pClass, ( void * ) pMsg ) );

   do
   {

#ifdef HB_MSG_POOL

      HB_USHORT uiBucket = BUCKETSIZE, * puiMsgIdx = pClass->puiMsgIdx +
                                    hb_clsBucketPos( pMsg, pClass->nHashKey );

      do
      {
         if( *puiMsgIdx == 0 )
         {
            pClass->pMethods = ( PMETHOD ) hb_xrealloc( pClass->pMethods,
                           sizeof( METHOD ) * ( pClass->uiMethodCount + 1 ) );
            memset( &pClass->pMethods[ pClass->uiMethodCount ], 0, sizeof( METHOD ) );
            *puiMsgIdx = pClass->uiMethodCount++;
            return &pClass->pMethods[ *puiMsgIdx ];
         }
         else if( pClass->pMethods[ *puiMsgIdx ].pMessage == pMsg )
            return &pClass->pMethods[ *puiMsgIdx ];
         ++puiMsgIdx;
      }
      while( --uiBucket );

#else

      PMETHOD pMethod = pClass->pMethods + hb_clsBucketPos( pMsg, pClass->nHashKey );
      HB_USHORT uiBucket = BUCKETSIZE;

      do
      {
         if( ! pMethod->pMessage || pMethod->pMessage == pMsg )
            return pMethod;
         ++pMethod;
      }
      while( --uiBucket );

#endif

   }
   while( hb_clsDictRealloc( pClass ) );

   hb_errInternal( 6001, "Could not allocate new message", NULL, NULL );

   return NULL;
}

static HB_BOOL hb_clsCanClearMethod( PMETHOD pMethod, HB_BOOL fError )
{
   HB_SYMBOL_UNUSED( pMethod );
   HB_SYMBOL_UNUSED( fError );
#if 0
   if( pMethod->pFuncSym == &s___msgSuper )
   {
      if( fError )
         hb_errRT_BASE( EG_ARG, 3000, "Cannot delete supercast messages", HB_ERR_FUNCNAME, 0 );
      return HB_FALSE;
   }
#endif
   return HB_TRUE;
}

static void hb_clsFreeMsg( PCLASS pClass, PHB_DYNS pMsg )
{
#ifdef HB_MSG_POOL

   HB_USHORT uiBucket, * puiMsgIdx;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsFreeMsg(%p,%p)", ( void * ) pClass, ( void * ) pMsg ) );


   puiMsgIdx = pClass->puiMsgIdx + hb_clsBucketPos( pMsg, pClass->nHashKey );
   uiBucket = BUCKETSIZE;

   do
   {
      if( *puiMsgIdx && pClass->pMethods[ *puiMsgIdx ].pMessage == pMsg )
      {
         if( hb_clsCanClearMethod( &pClass->pMethods[ *puiMsgIdx ], HB_TRUE ) )
         {
            memset( &pClass->pMethods[ *puiMsgIdx ], 0, sizeof( METHOD ) );
            *puiMsgIdx = 0;
            pClass->uiMethods--;       /* Decrease number of messages */
         }
         return;
      }
      ++puiMsgIdx;
   }
   while( --uiBucket );

#else

   PMETHOD pMethod;
   HB_USHORT uiBucket;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsFreeMsg(%p,%p)", ( void * ) pClass, ( void * ) pMsg ) );

   pMethod = pClass->pMethods + hb_clsBucketPos( pMsg, pClass->nHashKey );
   HB_USHORT = BUCKETSIZE;

   do
   {
      if( pMethod->pMessage == pMsg )
      {
         if( hb_clsCanClearMethod( pMethod, HB_TRUE ) )
         {
            /* Move messages */
            while( --uiBucket )
            {
               memcpy( pMethod, pMethod + 1, sizeof( METHOD ) );
               pMethod++;
            }
            memset( pMethod, 0, sizeof( METHOD ) );
            pClass->uiMethods--;       /* Decrease number of messages */
         }
         return;
      }
      ++pMethod;
   }
   while( --uiBucket );

#endif
}

static HB_BOOL hb_clsHasParentClass( PCLASS pClass, HB_USHORT uiParentCls )
{
   HB_USHORT uiCount = pClass->uiSuperClasses;

   while( uiCount )
   {
      if( pClass->pSuperClasses[ --uiCount ].uiClass == uiParentCls )
         return HB_TRUE;
   }
   return HB_FALSE;

   /* alternative method but can give wrong results
    * if user overloads super casting method, [druzus].
    */
   /*
   PMETHOD pMethod = hb_clsFindMsg( pClass, s_pClasses[ uiParentCls ]->pClassSym );
   return pMethod && pMethod->pFuncSym == &s___msgSuper;
   */
}

static HB_USHORT hb_clsGetParent( PCLASS pClass, PHB_DYNS pParentSym )
{
   HB_USHORT uiCount = pClass->uiSuperClasses;

   while( uiCount )
   {
      HB_USHORT uiClass = pClass->pSuperClasses[ --uiCount ].uiClass;
      if( s_pClasses[ uiClass ]->pClassSym == pParentSym )
         return uiClass;
   }
   return 0;

   /* alternative method but can give wrong results
    * if user overloads super casting method, [druzus].
    */
   /*
   PMETHOD pMethod = hb_clsFindMsg( pClass, pParentSym );
   return pMethod && pMethod->pFuncSym == &s___msgSuper;
   */
}

static HB_USHORT hb_clsParentInstanceOffset( PCLASS pClass, HB_USHORT uiParentCls )
{
   HB_USHORT uiCount = pClass->uiSuperClasses;

   while( uiCount )
   {
      if( pClass->pSuperClasses[ --uiCount ].uiClass == uiParentCls )
         return pClass->pSuperClasses[ uiCount ].uiOffset;
   }
   return 0;
}

#if 0
static HB_USHORT hb_clsParentInstanceOffset( PCLASS pClass, HB_USHORT uiParentCls )
{
   PMETHOD pMethod = hb_clsFindMsg( pClass, s_pClasses[ uiParentCls ]->pClassSym );

   return ( pMethod && pMethod->pFuncSym == &s___msgSuper ) ? pMethod->uiOffset : 0;
}
#endif

static HB_USHORT hb_clsAddInitValue( PCLASS pClass, PHB_ITEM pItem,
                                     HB_USHORT uiType, HB_USHORT uiData,
                                     HB_USHORT uiOffset, HB_USHORT uiSprClass )
{
   PINITDATA pInitData;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsAddInitValue(%p,%p,%hu,%hu,%hu,%hu)", ( void * ) pClass, ( void * ) pItem, uiType, uiData, uiOffset, uiSprClass ) );

   if( ! pItem || HB_IS_NIL( pItem ) )
      return 0;

   if( ! pClass->uiInitDatas )
   {
      pClass->pInitData = ( PINITDATA ) hb_xgrab( sizeof( INITDATA ) );
      pInitData = pClass->pInitData + pClass->uiInitDatas++;
   }
   else
   {
      HB_USHORT ui = pClass->uiInitDatas;
      pInitData = pClass->pInitData;
      do
      {
         if( pInitData->uiType == uiType &&
             pInitData->uiData + pInitData->uiOffset == uiData + uiOffset )
         {
            hb_itemRelease( pInitData->pInitValue );
            break;
         }
         ++pInitData;
      }
      while( --ui );

      if( ui == 0 )
      {
         pClass->pInitData = ( PINITDATA ) hb_xrealloc( pClass->pInitData,
                  ( HB_SIZE ) ( pClass->uiInitDatas + 1 ) * sizeof( INITDATA ) );
         pInitData = pClass->pInitData + pClass->uiInitDatas++;
      }
   }

   pInitData->pInitValue = hb_itemClone( pItem );
   pInitData->uiType = uiType;
   pInitData->uiData = uiData;
   pInitData->uiOffset = uiOffset;
   pInitData->uiSprClass = uiSprClass;

   return pClass->uiInitDatas;
}

static HB_USHORT hb_clsFindRealClassDataOffset( PMETHOD pMethod )
{
   PMETHOD pRealMth;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsFindRealClassDataOffset(%p)", ( void * ) pMethod ) );

   pRealMth = hb_clsFindMsg( s_pClasses[ pMethod->uiSprClass ],
                             pMethod->pMessage );
   if( pRealMth && pRealMth->uiSprClass == pMethod->uiSprClass &&
       ( pRealMth->pFuncSym == &s___msgSetClsData ||
         pRealMth->pFuncSym == &s___msgGetClsData ) )
   {
      return pRealMth->uiData;
   }
   return 0;
}

static HB_USHORT hb_clsFindClassDataOffset( PCLASS pClass, PMETHOD pNewMethod )
{
   HB_USHORT uiData;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsFindClassDataOffset(%p,%p)", ( void * ) pClass, ( void * ) pNewMethod ) );

   uiData = hb_clsFindRealClassDataOffset( pNewMethod );
   if( uiData )
   {
      HB_SIZE nLimit = hb_clsMthNum( pClass );
      PMETHOD pMethod = pClass->pMethods;
      do
      {
         if( pMethod->pMessage && pMethod != pNewMethod &&
             pMethod->uiSprClass == pNewMethod->uiSprClass &&
             ( pMethod->pFuncSym == &s___msgSetClsData ||
               pMethod->pFuncSym == &s___msgGetClsData ) &&
             uiData == hb_clsFindRealClassDataOffset( pMethod ) )
         {
            return pMethod->uiData;
         }
         ++pMethod;
      }
      while( --nLimit );
   }

   return 0;
}

static HB_BOOL hb_clsUpdateHiddenMessages( PMETHOD pSrcMethod, PMETHOD pDstMethod,
                                           PCLASS pDstClass )
{
   PMETHOD pNewMethod = pSrcMethod;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsUpdateHiddenMessages(%p,%p,%p)", ( void * ) pSrcMethod, ( void * ) pDstMethod, ( void * ) pDstClass ) );

   if( ! pDstMethod->pMessage ||
       ( hb_clsCanClearMethod( pDstMethod, HB_FALSE ) &&
         pDstMethod->uiPrevCls != pDstMethod->uiSprClass &&
         ( pDstMethod->uiScope & HB_OO_CLSTP_HIDDEN ) &&
         ( pDstMethod->uiScope & HB_OO_CLSTP_NONVIRTUAL ) ) )
   {
      while( pNewMethod &&
             pNewMethod->uiPrevCls != pNewMethod->uiSprClass &&
             ( pNewMethod->uiScope & HB_OO_CLSTP_HIDDEN ) &&
             ( pNewMethod->uiScope & HB_OO_CLSTP_NONVIRTUAL ) )
      {
         pNewMethod = hb_clsFindMsg( s_pClasses[ pNewMethod->uiPrevCls ],
                                     pNewMethod->pMessage );
      }
      if( pNewMethod && pNewMethod != pSrcMethod &&
          ! ( pNewMethod->uiScope & HB_OO_CLSTP_HIDDEN ) &&
          hb_clsCanClearMethod( pDstMethod, HB_FALSE ) )
      {
         HB_USHORT uiPrevCls = pDstMethod->uiPrevCls,
                   uiPrevMth = pDstMethod->uiPrevMth;
         PHB_SYMB pFuncSym;

         memcpy( pDstMethod, pNewMethod, sizeof( METHOD ) );
         pDstMethod->uiPrevCls = uiPrevCls;
         pDstMethod->uiPrevMth = uiPrevMth;
         pDstMethod->uiScope |= HB_OO_CLSTP_OVERLOADED | HB_OO_CLSTP_SUPER;
         pFuncSym = pDstMethod->pFuncSym;
         if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass )
            pFuncSym = pDstMethod->pRealSym;
         if( pFuncSym == &s___msgSetData ||
             pFuncSym == &s___msgGetData )
         {
            pDstMethod->uiOffset = hb_clsParentInstanceOffset( pDstClass,
                                                   pDstMethod->uiSprClass );
         }
         else if( pFuncSym == &s___msgSetClsData ||
                  pFuncSym == &s___msgGetClsData )
         {
            PCLASS pSrcClass = s_pClasses[ pDstMethod->uiSprClass ];
            HB_USHORT uiData;

            /* check if we already have corresponding access or assign
             * message for this class var to reuse its index
             */
            uiData = hb_clsFindClassDataOffset( pDstClass, pDstMethod );

            if( uiData == 0 )
            {
               uiData = ( HB_USHORT ) hb_arrayLen( pDstClass->pClassDatas ) + 1;
               hb_arraySize( pDstClass->pClassDatas, uiData );
            }
            if( pDstMethod->uiOffset )
            {
               pDstMethod->uiOffset = hb_clsAddInitValue( pDstClass,
                  pSrcClass->pInitData[ pDstMethod->uiOffset - 1 ].pInitValue,
                  HB_OO_MSG_CLASSDATA, uiData, 0, pDstMethod->uiSprClass );
            }
            pDstMethod->uiData = uiData;
         }
         return HB_TRUE;
      }
   }

   return HB_FALSE;
}

static void hb_clsAddSuperClass( PCLASS pClass, HB_USHORT uiSuperCls, HB_USHORT uiOffset )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_clsAddSuperClass(%p,%hu,%hu)", ( void * ) pClass, uiSuperCls, uiOffset ) );

   pClass->pSuperClasses = ( PHB_CLSCAST ) hb_xrealloc( pClass->pSuperClasses,
                     ( pClass->uiSuperClasses + 1 ) * sizeof( HB_CLSCAST ) );
   pClass->pSuperClasses[ pClass->uiSuperClasses ].uiClass = uiSuperCls;
   pClass->pSuperClasses[ pClass->uiSuperClasses++ ].uiOffset = uiOffset;
}

static void hb_clsDefineSuperClass( PCLASS pClass, HB_USHORT uiSuperCls, HB_BOOL fNew )
{
   PMETHOD pMethod;
   PCLASS pSprCls;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsDefineSuperClass(%p,%hu,%d)", ( void * ) pClass, uiSuperCls, fNew ) );

   pSprCls = s_pClasses[ uiSuperCls ];

   if( ! hb_clsHasParentClass( pClass, uiSuperCls ) )
   {
      if( fNew )
      {
         hb_clsAddSuperClass( pClass, uiSuperCls, pClass->uiDatas );
         pClass->uiDatas += pSprCls->uiDatas - pSprCls->uiDataFirst;
      }
      else
         hb_clsAddSuperClass( pClass, uiSuperCls, pSprCls->uiDataFirst );
   }

   pMethod = hb_clsAllocMsg( pClass, pSprCls->pClassSym );
   if( pMethod->pMessage == NULL )
   {
      pClass->uiMethods++;
      pMethod->pMessage = pSprCls->pClassSym;
      pMethod->uiSprClass = pClass->uiClass;
      pMethod->uiData = uiSuperCls;
      pMethod->uiScope = HB_OO_CLSTP_EXPORTED;
      pMethod->pFuncSym = &s___msgSuper;
      pMethod->uiOffset = hb_clsParentInstanceOffset( pClass, uiSuperCls );
   }
   else
   {
      PHB_SYMB pFuncSym = pMethod->pFuncSym;

      if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass )
         pFuncSym = pMethod->pRealSym;
      if( pFuncSym == &s___msgSuper && pMethod->uiData == uiSuperCls )
         pMethod->uiOffset = hb_clsParentInstanceOffset( pClass, uiSuperCls );
   }
}

static void hb_clsCopyClass( PCLASS pClsDst, PCLASS pClsSrc )
{
   PMETHOD pMethod;
   HB_SIZE nLimit;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsCopyClass(%p,%p)", ( void * ) pClsDst, ( void * ) pClsSrc ) );

   hb_clsDictInit( pClsDst, pClsSrc->nHashKey );
   pClsDst->fHasOnError = pClsSrc->fHasOnError;
   pClsDst->fHasDestructor = pClsSrc->fHasDestructor;

   /* CLASS DATA Not Shared ( new array, new value ) */
#if 0
   /* enable this code if you want to inherit class variables values
    * from ancestor classes when new class is dynamically created.
    * (compatibility with older [x]Harbour versions)
    */
   pClsDst->pClassDatas = hb_arrayClone( pClsSrc->pClassDatas );
#else
   pClsDst->pClassDatas = hb_itemArrayNew( hb_arrayLen( pClsSrc->pClassDatas ) );
#endif
   /* do not copy shared data array - just simply create new one */
   pClsDst->pSharedDatas = hb_itemArrayNew( 0 );
   pClsDst->pInlines = hb_arrayClone( pClsSrc->pInlines );
   pClsDst->uiDatas = pClsSrc->uiDatas;
   pClsDst->uiMutexOffset = pClsSrc->uiMutexOffset;
   pClsDst->nOpFlags = pClsSrc->nOpFlags;
   if( pClsSrc->pMutex )
      pClsDst->pMutex = hb_threadMutexCreate();

   if( pClsSrc->uiInitDatas )
   {
      HB_SIZE nSize = ( HB_SIZE ) pClsSrc->uiInitDatas * sizeof( INITDATA );
      HB_USHORT uiData;

      pClsDst->uiInitDatas = pClsSrc->uiInitDatas;
      pClsDst->pInitData = ( PINITDATA ) hb_xgrab( nSize );
      memcpy( pClsDst->pInitData, pClsSrc->pInitData, nSize );
      for( uiData = 0; uiData < pClsDst->uiInitDatas; ++uiData )
      {
         if( pClsDst->pInitData[ uiData ].uiType == HB_OO_MSG_INITIALIZED )
            pClsDst->pInitData[ uiData ].uiType = HB_OO_MSG_CLASSDATA;
         pClsDst->pInitData[ uiData ].pInitValue =
                        hb_itemNew( pClsDst->pInitData[ uiData ].pInitValue );
      }
   }

   nLimit = hb_clsMthNum( pClsSrc );
#ifdef HB_MSG_POOL
   memcpy( pClsDst->puiMsgIdx, pClsSrc->puiMsgIdx,
      ( ( pClsSrc->nHashKey + 1 ) << BUCKETBITS ) * sizeof( HB_USHORT ) );
   pClsDst->uiMethodCount = pClsSrc->uiMethodCount;
   pClsDst->pMethods = ( PMETHOD ) hb_xrealloc( pClsDst->pMethods,
                                                nLimit * sizeof( METHOD ) );
#endif
   memcpy( pClsDst->pMethods, pClsSrc->pMethods, nLimit * sizeof( METHOD ) );
   pClsDst->uiMethods = pClsSrc->uiMethods;

   if( pClsSrc->uiSuperClasses )
   {
      pClsDst->uiSuperClasses = pClsSrc->uiSuperClasses;
      pClsDst->pSuperClasses = ( PHB_CLSCAST )
                     hb_xgrab( pClsSrc->uiSuperClasses * sizeof( HB_CLSCAST ) );
      memcpy( pClsDst->pSuperClasses, pClsSrc->pSuperClasses,
              pClsSrc->uiSuperClasses * sizeof( HB_CLSCAST ) );
   }
   hb_clsDefineSuperClass( pClsDst, pClsSrc->uiClass, HB_FALSE );

   pMethod = pClsDst->pMethods;
   do
   {
      if( pMethod->pMessage )
      {
         hb_clsUpdateHiddenMessages( pMethod, pMethod, pClsDst );
         pMethod->uiScope |= HB_OO_CLSTP_SUPER;
      }
      ++pMethod;
   }
   while( --nLimit );
}

static HB_BOOL hb_clsIsFriendSymbol( PCLASS pClass, PHB_SYMB pSym )
{
   HB_USHORT uiCount;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsIsFriendSymbol(%p,%p)", ( void * ) pClass, ( void * ) pSym ) );

   if( pClass->pFriendModule && pSym >= pClass->pFriendModule &&
       pSym < pClass->pFriendModule + pClass->uiFriendModule )
      return HB_TRUE;

   for( uiCount = 0; uiCount < pClass->uiFriendSyms; ++uiCount )
   {
      if( pClass->pFriendSyms[ uiCount ] == pSym )
         return HB_TRUE;
   }

   return HB_FALSE;
}

static void hb_clsAddFriendSymbol( PCLASS pClass, PHB_SYMB pSym )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_clsAddFriendSymbol(%p,%p)", ( void * ) pClass, ( void * ) pSym ) );

   if( ! hb_clsIsFriendSymbol( pClass, pSym ) )
   {
      if( pClass->uiFriendSyms == 0 )
      {
         pClass->pFriendSyms = ( PHB_SYMB * ) hb_xgrab( sizeof( PHB_SYMB ) );
         pClass->pFriendSyms[ 0 ] = pSym;
         pClass->uiFriendSyms++;
      }
      else
      {
         pClass->pFriendSyms = ( PHB_SYMB * ) hb_xrealloc( pClass->pFriendSyms,
                           ( pClass->uiFriendSyms + 1 ) * sizeof( PHB_SYMB ) );
         pClass->pFriendSyms[ pClass->uiFriendSyms++ ] = pSym;
      }
   }
}

/* initialize Classy/OO system at HVM startup */
void hb_clsInit( void )
{
   PHB_SYMB pOpSym;
   HB_USHORT uiOperator;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsInit()" ) );

   for( uiOperator = 0, pOpSym = s_opSymbols; uiOperator <= HB_OO_MAX_OPERATOR;
        ++uiOperator, ++pOpSym )
   {
      pOpSym->pDynSym = hb_dynsymGetCase( pOpSym->szName );
   }

   s___msgDestructor.pDynSym  = hb_dynsymGetCase( s___msgDestructor.szName );
   s___msgOnError.pDynSym     = hb_dynsymGetCase( s___msgOnError.szName );

   s___msgClassName.pDynSym   = hb_dynsymGetCase( s___msgClassName.szName );  /* Standard messages */
   s___msgClassH.pDynSym      = hb_dynsymGetCase( s___msgClassH.szName );     /* Not present in classdef. */
   s___msgClassSel.pDynSym    = hb_dynsymGetCase( s___msgClassSel.szName );
   s___msgExec.pDynSym        = hb_dynsymGetCase( s___msgExec.szName );
   s___msgName.pDynSym        = hb_dynsymGetCase( s___msgName.szName );
   s___msgNew.pDynSym         = hb_dynsymGetCase( s___msgNew.szName );
   s___msgSymbol.pDynSym      = hb_dynsymGetCase( s___msgSymbol.szName );
   s___msgKeys.pDynSym        = hb_dynsymGetCase( s___msgKeys.szName );
   s___msgValues.pDynSym      = hb_dynsymGetCase( s___msgValues.szName );
/*
   s___msgClsParent.pDynSym   = hb_dynsymGetCase( s___msgClsParent.szName );
   s___msgClass.pDynSym       = hb_dynsymGetCase( s___msgClass.szName );
*/
   s___msgEnumIndex.pDynSym   = hb_dynsymGetCase( s___msgEnumIndex.szName );
   s___msgEnumBase.pDynSym    = hb_dynsymGetCase( s___msgEnumBase.szName );
   s___msgEnumKey.pDynSym     = hb_dynsymGetCase( s___msgEnumKey.szName );
   s___msgEnumValue.pDynSym   = hb_dynsymGetCase( s___msgEnumValue.szName );
   s___msgEnumIsFirst.pDynSym = hb_dynsymGetCase( s___msgEnumIsFirst.szName );
   s___msgEnumIsLast.pDynSym  = hb_dynsymGetCase( s___msgEnumIsLast.szName );

   s___msgWithObjectPush.pDynSym = hb_dynsymGetCase( s___msgWithObjectPush.szName );
   s___msgWithObjectPop.pDynSym  = hb_dynsymGetCase( s___msgWithObjectPop.szName );


   s_uiClsSize = HB_CLASS_POOL_SIZE;
   s_uiClasses = 0;
   s_pClasses = ( PCLASS * ) hb_xgrab( ( ( HB_SIZE ) s_uiClsSize + 1 ) * sizeof( PCLASS ) );
   s_pClasses[ 0 ] = NULL;

#if defined( HB_MT_VM )
   s_pClassMtx = hb_threadMutexCreate();
#endif
}

/* initialize Classy/OO system .prg functions */
void hb_clsDoInit( void )
{
   static const char * s_pszFuncNames[] =
      { "HBARRAY", "HBBLOCK", "HBCHARACTER",
        "HBDATE", "HBTIMESTAMP",
        "HBHASH", "HBLOGICAL", "HBNIL", "HBNUMERIC",
        "HBSYMBOL", "HBPOINTER",
        "HBOBJECT" };
   static HB_USHORT * s_puiHandles[] =
      { &s_uiArrayClass, &s_uiBlockClass, &s_uiCharacterClass,
        &s_uiDateClass, &s_uiTimeStampClass,
        &s_uiHashClass, &s_uiLogicalClass, &s_uiNilClass, &s_uiNumericClass,
        &s_uiSymbolClass, &s_uiPointerClass,
        &s_uiObjectClass };

   HB_STACK_TLS_PRELOAD
   int i;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsDoInit()" ) );

   for( i = 0; i < ( int ) HB_SIZEOFARRAY( s_puiHandles ); ++i )
   {
      PHB_DYNS pFuncSym = hb_dynsymFindName( s_pszFuncNames[i] );
      if( pFuncSym && hb_dynsymIsFunction( pFuncSym ) )
      {
         PHB_ITEM pReturn = hb_stackReturnItem();
         hb_itemSetNil( pReturn );
         hb_vmPushDynSym( pFuncSym );
         hb_vmPushNil();
         hb_vmProc( 0 );
         if( HB_IS_OBJECT( pReturn ) )
            *( s_puiHandles[ i ] ) = pReturn->item.asArray.value->uiClass;
      }
   }
}

/* hb_clsRelease( <pClass> )
 *
 * Release a class from memory
 */
static void hb_clsRelease( PCLASS pClass )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_clsRelease(%p)", ( void * ) pClass ) );

   if( pClass->uiInitDatas )
   {
      HB_USHORT ui = pClass->uiInitDatas;
      PINITDATA pInitData = pClass->pInitData;

      do
      {
         hb_itemRelease( pInitData->pInitValue );
         ++pInitData;
      }
      while( --ui );
      hb_xfree( pClass->pInitData );
   }

   if( pClass->szName )
      hb_xfree( pClass->szName );
   if( pClass->pMethods )
      hb_xfree( pClass->pMethods );
   if( pClass->uiFriendSyms )
      hb_xfree( pClass->pFriendSyms );
   if( pClass->pSuperClasses )
      hb_xfree( pClass->pSuperClasses );
#ifdef HB_MSG_POOL
   if( pClass->puiMsgIdx )
      hb_xfree( pClass->puiMsgIdx );
#endif
   if( pClass->pClassDatas )
      hb_itemRelease( pClass->pClassDatas );
   if( pClass->pSharedDatas )
      hb_itemRelease( pClass->pSharedDatas );
   if( pClass->pInlines )
      hb_itemRelease( pClass->pInlines );

   hb_xfree( pClass );
}


/* hb_clsReleaseAll()
 *
 * Release all classes
 */
void hb_clsReleaseAll( void )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_clsReleaseAll()" ) );

   if( s_uiClasses )
   {
      HB_USHORT uiClass = s_uiClasses;

      /* It blocks destructor execution - don't move. [druzus] */
      s_uiClasses = 0;

      do
      {
         hb_clsRelease( s_pClasses[ uiClass ] );
      }
      while( --uiClass );

   }

   if( s_pClasses )
   {
      hb_xfree( s_pClasses );
      s_pClasses = NULL;
      s_uiClsSize = 0;
   }

   if( s_pClassMtx )
   {
      hb_itemRelease( s_pClassMtx );
      s_pClassMtx = NULL;
   }
}

/* Mark all internal data as used so it will not be released by the
 * garbage collector
 */
void hb_clsIsClassRef( void )
{
   /* All internal items are allocated with hb_itemNew()
    * GC knows them and scan itself so it's not necessary
    * to repeat scanning here [druzus].
    */
#if 0
   HB_USHORT uiClass = s_uiClasses;

   HB_TRACE( HB_TR_DEBUG, ( "hb_clsIsClassRef()" ) );

   while( uiClass )
   {
      PCLASS pClass = s_pClasses[ uiClass-- ];

      if( pClass->pInlines )
         hb_gcItemRef( pClass->pInlines );

      if( pClass->pClassDatas )
         hb_gcItemRef( pClass->pClassDatas );

      if( pClass->pSharedDatas )
         hb_gcItemRef( pClass->pSharedDatas );

      if( pClass->uiInitDatas )
      {
         HB_USHORT ui = pClass->uiInitDatas;
         PINITDATA pInitData = pClass->pInitData;

         do
         {
            if( HB_IS_GCITEM( pInitData->pInitValue ) )
               hb_gcItemRef( pInitData->pInitValue );
            ++pInitData;
         }
         while( --ui );
      }
   }
#endif
}

HB_BOOL hb_clsIsParent( HB_USHORT uiClass, const char * szParentName )
{
   if( uiClass && uiClass <= s_uiClasses )
   {
      PCLASS pClass = s_pClasses[ uiClass ];

      if( strcmp( pClass->szName, szParentName ) == 0 )
         return HB_TRUE;
      else
      {
         PHB_DYNS pMsg = hb_dynsymFindName( szParentName );

         if( pMsg )
            return hb_clsGetParent( pClass, pMsg ) != 0;
      }
   }

   return HB_FALSE;
}

HB_USHORT hb_objGetClass( PHB_ITEM pItem )
{
   if( pItem && HB_IS_ARRAY( pItem ) )
      return pItem->item.asArray.value->uiClass;
   else
      return 0;
}

/* get object class handle using class name and class function name */
HB_USHORT hb_objSetClass( PHB_ITEM pItem, const char * szClass, const char * szFunc )
{
   HB_USHORT uiClass = 0;

   if( pItem && HB_IS_ARRAY( pItem ) &&
       pItem->item.asArray.value->uiClass == 0 )
   {
      uiClass = pItem->item.asArray.value->uiClass =
                                          hb_clsFindClass( szClass, szFunc );
   }
   return uiClass;
}

/* --- */

/* Get the class handle */
static HB_USHORT hb_objGetClassH( PHB_ITEM pObject )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_objGetClassH(%p)", ( void * ) pObject ) );

   if( HB_IS_ARRAY( pObject ) )
   {
      if( pObject->item.asArray.value->uiClass != 0 )
         return pObject->item.asArray.value->uiClass;
      else
         return s_uiArrayClass;
   }
   /* built in types */
   else if( HB_IS_NIL( pObject ) )
      return s_uiNilClass;

   else if( HB_IS_STRING( pObject ) )
      return s_uiCharacterClass;

   else if( HB_IS_NUMERIC( pObject ) )
      return s_uiNumericClass;

   else if( HB_IS_DATE( pObject ) )
      return s_uiDateClass;

   else if( HB_IS_TIMESTAMP( pObject ) )
      return s_uiTimeStampClass;

   else if( HB_IS_LOGICAL( pObject ) )
      return s_uiLogicalClass;

   else if( HB_IS_BLOCK( pObject ) )
      return s_uiBlockClass;

   else if( HB_IS_HASH( pObject ) )
      return s_uiHashClass;

   else if( HB_IS_POINTER( pObject ) )
      return s_uiPointerClass;

   else if( HB_IS_SYMBOL( pObject ) )
      return s_uiSymbolClass;

   return 0;
}

/* Get the class name of an object */
const char * hb_objGetClsName( PHB_ITEM pObject )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_objGetClsName(%p)", ( void * ) pObject ) );

   if( HB_IS_ARRAY( pObject ) )
   {
      if( pObject->item.asArray.value->uiClass != 0 )
         return s_pClasses[ pObject->item.asArray.value->uiClass ]->szName;
      else
         return "ARRAY";
   }
   /* built in types */
   else if( HB_IS_NIL( pObject ) )
      return "NIL";

   else if( HB_IS_STRING( pObject ) )
      return "CHARACTER";

   else if( HB_IS_NUMERIC( pObject ) )
      return "NUMERIC";

   else if( HB_IS_DATE( pObject ) )
      return "DATE";

   else if( HB_IS_TIMESTAMP( pObject ) )
      return "TIMESTAMP";

   else if( HB_IS_LOGICAL( pObject ) )
      return "LOGICAL";

   else if( HB_IS_BLOCK( pObject ) )
      return "BLOCK";

   else if( HB_IS_HASH( pObject ) )
      return "HASH";

   else if( HB_IS_POINTER( pObject ) )
      return "POINTER";

   else if( HB_IS_SYMBOL( pObject ) )
      return "SYMBOL";

   else
      return "UNKNOWN";
}

const char * hb_clsName( HB_USHORT uiClass )
{
   if( uiClass && uiClass <= s_uiClasses )
      return s_pClasses[ uiClass ]->szName;
   else
      return NULL;
}

const char * hb_clsFuncName( HB_USHORT uiClass )
{
   if( uiClass && uiClass <= s_uiClasses )
      return s_pClasses[ uiClass ]->pClassFuncSym ?
             s_pClasses[ uiClass ]->pClassFuncSym->szName :
             "";
   else
      return NULL;
}

PHB_SYMB hb_clsFuncSym( HB_USHORT uiClass )
{
   if( uiClass && uiClass <= s_uiClasses )
      return s_pClasses[ uiClass ]->pClassFuncSym;
   else
      return NULL;
}

const char * hb_clsMethodName( HB_USHORT uiClass, HB_USHORT uiMethod )
{
   if( uiClass && uiClass <= s_uiClasses &&
       ( HB_UINT ) uiMethod < ( HB_UINT ) hb_clsMthNum( s_pClasses[ uiClass ] ) )
   {
      PMETHOD pMethod = s_pClasses[ uiClass ]->pMethods + uiMethod;
      if( pMethod->pMessage )
         return pMethod->pMessage->pSymbol->szName;
   }
   return NULL;
}

static HB_SIZE hb_clsGetVarIndexEx( HB_USHORT uiClass, PHB_DYNS pVarSym,
                                    HB_USHORT uiSuper )
{
   PMETHOD pMethod = hb_clsFindMsg( s_pClasses[ uiSuper ], pVarSym );
   if( pMethod )
   {
      PHB_SYMB pFuncSym = pMethod->pFuncSym;

      if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass )
         pFuncSym = pMethod->pRealSym;

      if( pFuncSym == &s___msgSetData || pFuncSym == &s___msgGetData )
      {
         return ( HB_SIZE ) pMethod->uiData + ( uiClass != uiSuper ?
                hb_clsParentInstanceOffset( s_pClasses[ uiClass ], uiSuper ) :
                pMethod->uiOffset );
      }
   }
   return 0;
}

HB_SIZE hb_clsGetVarIndex( HB_USHORT uiClass, PHB_DYNS pVarSym )
{
   if( uiClass && uiClass <= s_uiClasses )
      return hb_clsGetVarIndexEx( uiClass, pVarSym, uiClass );
   else
      return 0;
}

HB_USHORT hb_clsFindClass( const char * szClass, const char * szClassFunc )
{
   HB_USHORT uiClass;

   for( uiClass = 1; uiClass <= s_uiClasses; uiClass++ )
   {
      if( strcmp( szClass, s_pClasses[ uiClass ]->szName ) == 0 &&
          ( ! szClassFunc || ( ! s_pClasses[ uiClass ]->pClassFuncSym ? ! *szClassFunc :
            strcmp( szClassFunc, s_pClasses[ uiClass ]->pClassFuncSym->szName ) == 0 ) ) )
      {
         return uiClass;
      }
   }
   return 0;
}

static HB_USHORT hb_clsFindClassByFunc( PHB_SYMB pClassFuncSym )
{
   HB_USHORT uiClass;

   for( uiClass = 1; uiClass <= s_uiClasses; uiClass++ )
   {
      if( s_pClasses[ uiClass ]->pClassFuncSym == pClassFuncSym )
      {
         return uiClass;
      }
   }
   return 0;
}

/* Get the real method symbol for given stack symbol */
PHB_SYMB hb_clsMethodSym( PHB_ITEM pBaseSymbol )
{
   PHB_STACK_STATE pStack = pBaseSymbol->item.asSymbol.stackstate;

   if( pStack->uiClass )
   {
      PMETHOD pMethod = s_pClasses[ pStack->uiClass ]->pMethods + pStack->uiMethod;
      PHB_SYMB pFuncSym = pMethod->pFuncSym;

      if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass )
         pFuncSym = pMethod->pRealSym;

      if( pFuncSym == &s___msgEvalInline )
      {
         PHB_ITEM pItem = hb_arrayGetItemPtr( s_pClasses[ pMethod->uiSprClass ]->pInlines,
                                              pMethod->uiData );
         return pItem ? pItem->item.asBlock.value->pDefSymb : NULL;
      }
/*
      else if( pFuncSym == &s___msgPerform )
 */
      else if( pFuncSym == &s___msgDelegate )
         return s_pClasses[ pStack->uiClass ]->pMethods[ pMethod->uiData ].pFuncSym;
      else
         return pFuncSym;
   }

   return pBaseSymbol->item.asSymbol.value;
}

/* Get the real class name of an object message
 * Will return the class name from wich the message is inherited in case
 * of inheritance.
 */
const char * hb_objGetRealClsName( PHB_ITEM pObject, const char * szName )
{
   HB_USHORT uiClass;

   HB_TRACE( HB_TR_DEBUG, ( "hb_objGetrealClsName(%p,%s)", ( void * ) pObject, szName ) );

   uiClass = hb_objGetClassH( pObject );
   if( uiClass && uiClass <= s_uiClasses )
   {
      PHB_DYNS pMsg = hb_dynsymFindName( szName );

      if( pMsg )
      {
         PMETHOD pMethod = hb_clsFindMsg( s_pClasses[ uiClass ], pMsg );
         if( pMethod )
            uiClass = pMethod->uiSprClass;
      }
      if( uiClass && uiClass <= s_uiClasses )
         return s_pClasses[ uiClass ]->szName;
   }

   return hb_objGetClsName( pObject );
}

#if defined( HB_CLASSY_BLOCK_SCOPE )
static HB_ISIZ hb_clsSenderOffset( void )
{
   HB_ISIZ nOffset = hb_stackBaseProcOffset( 1 );

   if( nOffset > 0 )
   {
      /* Is it inline method? */
      if( nOffset > 0 && HB_IS_BLOCK( hb_stackItem( nOffset + 1 ) ) &&
          ( hb_stackItem( nOffset )->item.asSymbol.value == &hb_symEval ||
            hb_stackItem( nOffset )->item.asSymbol.value->pDynSym ==
            hb_symEval.pDynSym ) )
      {
         nOffset = hb_stackItem( nOffset )->item.asSymbol.stackstate->nBaseItem;

         /* I do not like it but Class(y) makes something like that. [druzus] */
         while( nOffset > 0 &&
                hb_stackItem( nOffset )->item.asSymbol.stackstate->uiClass == 0 )
            nOffset = hb_stackItem( nOffset )->item.asSymbol.stackstate->nBaseItem;
      }
      return nOffset;
   }
   return -1;
}
#endif

#if 0
static HB_USHORT hb_clsSenderClass( void )
{
   HB_ISIZ nOffset = hb_clsSenderOffset();

   if( nOffset > 0 )
      return hb_stackItem( nOffset )->item.asSymbol.stackstate->uiClass;
   else
      return 0;
}
#endif

static HB_USHORT hb_clsSenderMethodClass( void )
{
   HB_ISIZ nOffset = hb_clsSenderOffset();

   if( nOffset > 0 )
   {
      HB_STACK_TLS_PRELOAD
      PHB_STACK_STATE pStack = hb_stackItem( nOffset )->item.asSymbol.stackstate;

      if( pStack->uiClass )
         return ( s_pClasses[ pStack->uiClass ]->pMethods +
                  pStack->uiMethod )->uiSprClass;
   }
   return 0;
}

static PHB_SYMB hb_clsSenderSymbol( void )
{
   PHB_SYMB pSym = NULL;
   HB_ISIZ nOffset = hb_clsSenderOffset();

   if( nOffset > 0 )
   {
      HB_STACK_TLS_PRELOAD
      pSym = hb_stackItem( nOffset )->item.asSymbol.value;

      if( pSym == &hb_symEval || pSym->pDynSym == hb_symEval.pDynSym )
      {
         PHB_ITEM pBlock = hb_stackItem( nOffset + 1 );

         if( HB_IS_BLOCK( pBlock ) )
            pSym = pBlock->item.asBlock.value->pDefSymb;
      }
   }

   return hb_vmGetRealFuncSym( pSym );
}

static HB_USHORT hb_clsSenderObjectClass( void )
{
   HB_ISIZ nOffset = hb_clsSenderOffset();

   if( nOffset > 0 )
   {
      HB_STACK_TLS_PRELOAD
      PHB_ITEM pSender = hb_stackItem( nOffset + 1 );

      if( HB_IS_ARRAY( pSender ) )
         return pSender->item.asArray.value->uiClass;
   }
   return 0;
}

static PHB_SYMB hb_clsValidScope( PMETHOD pMethod, PHB_STACK_STATE pStack )
{
   if( pMethod->uiScope & ( HB_OO_CLSTP_HIDDEN | HB_OO_CLSTP_PROTECTED |
                            HB_OO_CLSTP_OVERLOADED ) )
   {
      HB_USHORT uiSenderClass = hb_clsSenderMethodClass();

      if( uiSenderClass == pMethod->uiSprClass )
         return pMethod->pFuncSym;
      else if( uiSenderClass )
      {
         /* Warning!!! Friends cannot access overloaded non virtual methods.
          * This feature is available _ONLY_ for real class members, [druzus]
          */
         if( pMethod->uiScope & HB_OO_CLSTP_OVERLOADED &&
             hb_clsHasParentClass( s_pClasses[ pStack->uiClass ], uiSenderClass ) )
         {
            PCLASS pClass = s_pClasses[ uiSenderClass ];
            PMETHOD pHiddenMthd = hb_clsFindMsg( pClass, pMethod->pMessage );

            if( pHiddenMthd && ( pHiddenMthd->uiScope & HB_OO_CLSTP_NONVIRTUAL ) &&
                pHiddenMthd->uiSprClass == uiSenderClass )
            {
               pStack->uiClass = uiSenderClass;
               pStack->uiMethod = ( HB_USHORT ) ( pHiddenMthd - pClass->pMethods );
               return pHiddenMthd->pFuncSym;
            }
         }

         if( pMethod->uiScope & HB_OO_CLSTP_HIDDEN )
         {
            if( ! hb_clsIsFriendSymbol( s_pClasses[ pMethod->uiSprClass ],
                              s_pClasses[ uiSenderClass ]->pClassFuncSym ) )
               return &s___msgScopeErr;
         }
         else if( pMethod->uiScope & HB_OO_CLSTP_PROTECTED &&
             ! hb_clsHasParentClass( s_pClasses[ pStack->uiClass ],
                                     uiSenderClass ) &&
             ! hb_clsHasParentClass( s_pClasses[ uiSenderClass ],
                                     pStack->uiClass ) &&
             ! hb_clsIsFriendSymbol( s_pClasses[ pMethod->uiSprClass ],
                                     s_pClasses[ uiSenderClass ]->pClassFuncSym ) &&
             ( pStack->uiClass == pMethod->uiSprClass ||
               ! hb_clsIsFriendSymbol( s_pClasses[ pStack->uiClass ],
                              s_pClasses[ uiSenderClass ]->pClassFuncSym ) ) )
            return &s___msgScopeErr;
      }
      else if( pMethod->uiScope & ( HB_OO_CLSTP_HIDDEN | HB_OO_CLSTP_PROTECTED ) )
      {
         PHB_SYMB pSym = hb_clsSenderSymbol();

         if( ! hb_clsIsFriendSymbol( s_pClasses[ pMethod->uiSprClass ], pSym ) )
         {
            if( ( pMethod->uiScope & HB_OO_CLSTP_HIDDEN ) ||
                ! hb_clsIsFriendSymbol( s_pClasses[ pStack->uiClass ], pSym ) )
               return &s___msgScopeErr;
         }
      }
   }

   return pMethod->pFuncSym;
}

static PHB_SYMB hb_clsScalarMethod( PCLASS pClass, PHB_DYNS pMsg,
                                    PHB_STACK_STATE pStack )
{
   PMETHOD pMethod = hb_clsFindMsg( pClass, pMsg );

   if( pStack )
   {
      pStack->uiClass = pClass->uiClass;
      if( pMethod )
      {
         pStack->uiMethod = ( HB_USHORT ) ( pMethod - pClass->pMethods );
         return hb_clsValidScope( pMethod, pStack );
      }
   }
   else if( pMethod )
      return pMethod->pFuncSym;

   return NULL;
}

static void hb_clsMakeSuperObject( PHB_ITEM pDest, PHB_ITEM pObject,
                                   HB_USHORT uiSuperClass )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_clsMakeSuperObject(%p, %p, %hu)", ( void * ) pDest, ( void * ) pObject, uiSuperClass ) );

   /* create a fake object array */
   hb_arrayNew( pDest, 1 );
   /* Now save the Self object as the 1st elem. */
   hb_arraySet( pDest, 1, pObject );
   /* And transform it into a fake object */
   /* backup of actual handle */
   pDest->item.asArray.value->uiPrevCls = hb_objGetClassH( pObject );
   /* superclass handle casting */
   pDest->item.asArray.value->uiClass = uiSuperClass;
}

/* <pFuncSym> = hb_objGetMethod( <pObject>, <pMessage>, <pStackState> )
 *
 * Internal function to the function pointer of a message of an object
 */
PHB_SYMB hb_objGetMethod( PHB_ITEM pObject, PHB_SYMB pMessage,
                          PHB_STACK_STATE pStack )
{
   HB_STACK_TLS_PRELOAD
   PCLASS pClass = NULL;
   PHB_DYNS pMsg;

   HB_TRACE( HB_TR_DEBUG, ( "hb_objGetMethod(%p, %p, %p)", ( void * ) pObject, ( void * ) pMessage, ( void * ) pStack ) );

   pMsg = pMessage->pDynSym;

   if( HB_IS_ARRAY( pObject ) )
   {
      if( pObject->item.asArray.value->uiClass )
      {
         pClass = s_pClasses[ pObject->item.asArray.value->uiClass ];
         if( pStack )
         {
            pStack->uiClass = pObject->item.asArray.value->uiClass;
            if( pObject->item.asArray.value->uiPrevCls )
            {
               if( pObject->item.asArray.value->nLen )
               {
                  /* Copy real object - do not move! the same super casted
                   * object can be used more then once and we mustn't
                   * destroy it. We can safely use hb_stackReturnItem() here.
                   */
                  hb_itemCopy( hb_stackReturnItem(), pObject->item.asArray.value->pItems );
                  /* move real object back to the stack */
                  hb_itemMove( pObject, hb_stackReturnItem() );
               }
               else
                  /* Someone tried to manipulate with supercast array */
                  hb_itemClear( pObject );
            }
#ifdef HB_MSG_POOL
            {
               HB_USHORT uiBucket = BUCKETSIZE, * puiMsgIdx =
                  pClass->puiMsgIdx + hb_clsBucketPos( pMsg, pClass->nHashKey );

               do
               {
                  PMETHOD pMethod = &pClass->pMethods[ *puiMsgIdx ];
                  if( pMethod->pMessage == pMsg )
                  {
                     pStack->uiMethod = *puiMsgIdx;
                     return hb_clsValidScope( pMethod, pStack );
                  }
                  ++puiMsgIdx;
               }
               while( --uiBucket );
            }
#else
            {
               PMETHOD pMethod = hb_clsFindMsg( pClass, pMsg );
               if( pMethod )
               {
                  pStack->uiMethod = ( HB_USHORT ) ( pMethod - pClass->pMethods );
                  return hb_clsValidScope( pMethod, pStack );
               }
            }
#endif
         }
         else
         {
            PMETHOD pMethod = hb_clsFindMsg( pClass, pMsg );
            if( pMethod )
               return pMethod->pFuncSym;
         }
      }
      else if( s_uiArrayClass )
      {
         pClass = s_pClasses[ s_uiArrayClass ];
         {
            PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack );
            if( pExecSym )
               return pExecSym;
         }
      }
   }
   else if( HB_IS_BLOCK( pObject ) )
   {
      if( pMsg == hb_symEval.pDynSym )
         return &hb_symEval;
      else if( s_uiBlockClass )
      {
         pClass = s_pClasses[ s_uiBlockClass ];
         {
            PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack );
            if( pExecSym )
               return pExecSym;
         }
      }
   }
   else if( HB_IS_BYREF( pObject ) )
   {
      if( pStack )
      {
         /* method of enumerator variable from FOR EACH statement
          */
         PHB_ITEM pEnum = hb_itemUnRefOnce( pObject );

         if( HB_IS_ENUM( pEnum ) )
         {
            /* Do actions here - we already have unreferenced pEnum so
             * it will be a little bit faster but in the future it's
             * possible that I'll move it to separate function when
             * I'll add enumerators overloading. [druzus]
             */
            if( pMsg == s___msgEnumIndex.pDynSym )
            {
               hb_itemPutNS( hb_stackReturnItem(), pEnum->item.asEnum.offset );
               if( hb_pcount() > 0 && HB_ISNUM( 1 ) )
                  pEnum->item.asEnum.offset = hb_itemGetNS( hb_param( 1, HB_IT_ANY ) );
               return &s___msgEnumIndex;
            }
            else if( pMsg == s___msgEnumKey.pDynSym )
            {
               PHB_ITEM pBase = HB_IS_BYREF( pEnum->item.asEnum.basePtr ) ?
                                hb_itemUnRef( pEnum->item.asEnum.basePtr ) :
                                pEnum->item.asEnum.basePtr;
               if( HB_IS_HASH( pBase ) )
               {
                  pBase = hb_hashGetKeyAt( pBase, pEnum->item.asEnum.offset );
                  if( pBase )
                     hb_itemCopy( hb_stackReturnItem(), pBase );
               }
               return &s___msgEnumKey;
            }
            else if( pMsg == s___msgEnumBase.pDynSym )
            {
               if( HB_IS_BYREF( pEnum->item.asEnum.basePtr ) )
                  hb_itemCopy( hb_stackReturnItem(),
                               hb_itemUnRef( pEnum->item.asEnum.basePtr ) );
               else
                  hb_itemCopy( hb_stackReturnItem(),
                               pEnum->item.asEnum.basePtr );
               if( hb_pcount() > 0 )
                  hb_itemCopy( pEnum->item.asEnum.basePtr,
                               hb_itemUnRef( hb_stackItemFromBase( 1 ) ) );
               return &s___msgEnumBase;
            }
            else if( pMsg == s___msgEnumValue.pDynSym )
            {
               pEnum = hb_itemUnRef( pEnum );
               hb_itemCopy( hb_stackReturnItem(), pEnum );
               if( hb_pcount() > 0 )
                  hb_itemCopy( pEnum, hb_itemUnRef( hb_stackItemFromBase( 1 ) ) );
               return &s___msgEnumValue;
            }
            else if( pMsg == s___msgEnumIsFirst.pDynSym )
            {
               PHB_ITEM pBase = HB_IS_BYREF( pEnum->item.asEnum.basePtr ) ?
                                hb_itemUnRef( pEnum->item.asEnum.basePtr ) :
                                pEnum->item.asEnum.basePtr;
               if( HB_IS_OBJECT( pBase ) &&
                   hb_objHasOperator( pBase, HB_OO_OP_ENUMISFIRST ) )
                  return hb_objGetMethod( pBase, pMessage, pStack );
               hb_itemPutL( hb_stackReturnItem(), ( HB_SIZE ) pEnum->item.asEnum.offset <= 1 );
               return &s___msgEnumIsFirst;
            }
            else if( pMsg == s___msgEnumIsLast.pDynSym )
            {
               PHB_ITEM pBase = HB_IS_BYREF( pEnum->item.asEnum.basePtr ) ?
                                hb_itemUnRef( pEnum->item.asEnum.basePtr ) :
                                pEnum->item.asEnum.basePtr;
               if( HB_IS_ARRAY( pBase ) )
               {
                  if( HB_IS_OBJECT( pBase ) &&
                      hb_objHasOperator( pBase, HB_OO_OP_ENUMISLAST ) )
                     return hb_objGetMethod( pBase, pMessage, pStack );
                  else
                     hb_itemPutL( hb_stackReturnItem(), ( HB_SIZE ) pEnum->item.asEnum.offset >= hb_arrayLen( pBase ) );
               }
               else if( HB_IS_HASH( pBase ) )
                  hb_itemPutL( hb_stackReturnItem(), ( HB_SIZE ) pEnum->item.asEnum.offset >= hb_hashLen( pBase ) );
               else if( HB_IS_STRING( pBase ) )
                  hb_itemPutL( hb_stackReturnItem(), ( HB_SIZE ) pEnum->item.asEnum.offset >= hb_itemGetCLen( pBase ) );

               return &s___msgEnumIsLast;
            }
         }
      }
   }
   else if( HB_IS_SYMBOL( pObject ) )
   {
      if( s_uiSymbolClass )
      {
         pClass = s_pClasses[ s_uiSymbolClass ];
         {
            PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack );
            if( pExecSym )
               return pExecSym;
         }
      }
      if( pMsg == s___msgExec.pDynSym || pMsg == hb_symEval.pDynSym )
      {
         if( ! pObject->item.asSymbol.value->value.pFunPtr &&
               pObject->item.asSymbol.value->pDynSym )
            return pObject->item.asSymbol.value->pDynSym->pSymbol;
         else
            return pObject->item.asSymbol.value;
      }
      else if( pMsg == s___msgName.pDynSym )
      {
         hb_itemPutC( hb_stackReturnItem(),
                      pObject->item.asSymbol.value->szName );
         return &s___msgName;
      }
   }
   else if( HB_IS_HASH( pObject ) )
   {
      if( s_uiHashClass )
      {
         pClass = s_pClasses[ s_uiHashClass ];
         {
            PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack );
            if( pExecSym )
               return pExecSym;
         }
      }

      if( pMsg == s___msgKeys.pDynSym )
      {
         hb_itemReturnRelease( hb_hashGetKeys( pObject ) );
         return &s___msgKeys;
      }
      else if( pMsg == s___msgValues.pDynSym )
      {
         hb_itemReturnRelease( hb_hashGetValues( pObject ) );
         return &s___msgValues;
      }
#if defined( HB_HASH_MSG_ITEMS )
      else
      {
         if( hb_pcount() == 1 && pMessage->szName[ 0 ] == '_' ) /* ASSIGN */
         {
            PHB_ITEM pIndex = hb_itemPutCConst( hb_stackAllocItem(), pMessage->szName + 1 );
            PHB_ITEM pDest = hb_hashGetItemPtr( pObject, pIndex, HB_HASH_AUTOADD_ASSIGN );
            hb_stackPop();
            if( pDest )
            {
               PHB_ITEM pValue = hb_param( 1, HB_IT_ANY );
               hb_itemCopyFromRef( pDest, pValue );
               hb_itemReturn( pValue );
               return &s___msgVirtual;
            }
         }
         else if( hb_pcount() == 0 ) /* ACCESS */
         {
            PHB_ITEM pIndex = hb_itemPutCConst( hb_stackAllocItem(), pMessage->szName );
            PHB_ITEM pValue = hb_hashGetItemPtr( pObject, pIndex, HB_HASH_AUTOADD_ACCESS );
            hb_stackPop();
            if( pValue )
            {
               hb_itemReturn( pValue );
               return &s___msgVirtual;
            }
         }
      }
#endif
   }
   else if( HB_IS_STRING( pObject ) )
   {
      if( s_uiCharacterClass )
      {
         pClass = s_pClasses[ s_uiCharacterClass ];
         {
            PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack );
            if( pExecSym )
               return pExecSym;
         }
      }
   }
   else if( HB_IS_DATE( pObject ) )
   {
      if( s_uiDateClass )
      {
         pClass = s_pClasses[ s_uiDateClass ];
         {
            PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack );
            if( pExecSym )
               return pExecSym;
         }
      }
   }
   else if( HB_IS_TIMESTAMP( pObject ) )
   {
      if( s_uiTimeStampClass )
      {
         pClass = s_pClasses[ s_uiTimeStampClass ];
         {
            PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack );
            if( pExecSym )
               return pExecSym;
         }
      }
   }
   else if( HB_IS_NUMERIC( pObject ) )
   {
      if( s_uiNumericClass )
      {
         pClass = s_pClasses[ s_uiNumericClass ];
         {
            PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack );
            if( pExecSym )
               return pExecSym;
         }
      }
   }
   else if( HB_IS_LOGICAL( pObject ) )
   {
      if( s_uiLogicalClass )
      {
         pClass = s_pClasses[ s_uiLogicalClass ];
         {
            PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack );
            if( pExecSym )
               return pExecSym;
         }
      }
   }
   else if( HB_IS_POINTER( pObject ) )
   {
      if( s_uiPointerClass )
      {
         pClass = s_pClasses[ s_uiPointerClass ];
         {
            PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack );
            if( pExecSym )
               return pExecSym;
         }
      }
   }
   else if( HB_IS_NIL( pObject ) )
   {
      if( s_uiNilClass )
      {
         pClass = s_pClasses[ s_uiNilClass ];
         {
            PHB_SYMB pExecSym = hb_clsScalarMethod( pClass, pMsg, pStack );
            if( pExecSym )
               return pExecSym;
         }
      }
   }

   /* Default messages here */
   if( pMsg == s___msgWithObjectPush.pDynSym )
   {
      if( pStack )
      {
         PHB_ITEM pItem = hb_stackWithObjectItem();
         if( pItem )
         {
            /* push current WITH OBJECT object */
            hb_itemCopy( hb_stackReturnItem(), pItem );
            return &s___msgWithObjectPush;
         }
      }
   }
   else if( pMsg == s___msgWithObjectPop.pDynSym )
   {
      if( pStack )
      {
         PHB_ITEM pItem = hb_stackWithObjectItem();
         if( pItem )
         {
            /* replace current WITH OBJECT object */
            hb_itemCopy( pItem, hb_stackItemFromBase( 1 ) );
            hb_itemCopy( hb_stackReturnItem(), pItem );
            return &s___msgWithObjectPop;
         }
      }
   }
   else if( pMsg == s___msgClassName.pDynSym )
      return &s___msgClassName;

   else if( pMsg == s___msgClassH.pDynSym )
      return &s___msgClassH;

   else if( pMsg == s___msgClassSel.pDynSym )
      return &s___msgClassSel;

/*
   else if( pMsg == s___msgClsParent.pDynSym )
      return &s___msgClsParent;

   else if( pMsg == s___msgClass.pDynSym )
      return &s___msgClass;
 */
   if( pStack )
   {
      if( pClass && pClass->fHasOnError )
      {
         PMETHOD pMethod = hb_clsFindMsg( pClass, s___msgOnError.pDynSym );
         if( pMethod )
         {
            pStack->uiMethod = ( HB_USHORT ) ( pMethod - pClass->pMethods );
            return pMethod->pFuncSym;
         }
      }

      /* remove this line if you want default HVM error message */
      return &s___msgNoMethod;
   }
   return NULL;
}

HB_BOOL hb_objGetVarRef( PHB_ITEM pObject, PHB_SYMB pMessage,
                         PHB_STACK_STATE pStack )
{
   PHB_SYMB pExecSym;

#if defined( HB_HASH_MSG_ITEMS )
   if( HB_IS_HASH( pObject ) )
   {
      HB_STACK_TLS_PRELOAD
      PHB_ITEM pIndex = hb_itemPutCConst( hb_stackAllocItem(), pMessage->szName + 1 );
      PHB_ITEM pValue = hb_hashGetItemRefPtr( pObject, pIndex );
      hb_stackPop();
      if( pValue )
         hb_itemReturn( pValue );
      return pValue != NULL;
   }
#endif

   pExecSym = hb_objGetMethod( pObject, pMessage, pStack );
   if( pExecSym )
   {
      HB_STACK_TLS_PRELOAD
      if( pExecSym == &s___msgSetData )
      {
         HB_USHORT uiObjClass = pObject->item.asArray.value->uiClass;
         PCLASS pClass        = s_pClasses[ pStack->uiClass ];
         PMETHOD pMethod      = pClass->pMethods + pStack->uiMethod;
         HB_SIZE nIndex       = pMethod->uiData;

         if( pStack->uiClass != uiObjClass )
            nIndex += hb_clsParentInstanceOffset( s_pClasses[ uiObjClass ],
                                                  pMethod->uiSprClass );
         else
            nIndex += pMethod->uiOffset;

         /* will arise only if the class has been modified after first instance */
         if( nIndex > hb_arrayLen( pObject ) ) /* Resize needed */
            hb_arraySize( pObject, nIndex );   /* Make large enough */

         return hb_arrayGetItemRef( pObject, nIndex, hb_stackReturnItem() );
      }
      else if( pExecSym == &s___msgSetClsData )
      {
         PCLASS pClass   = s_pClasses[ pStack->uiClass ];
         PMETHOD pMethod = pClass->pMethods + pStack->uiMethod;

         return hb_arrayGetItemRef( pClass->pClassDatas, pMethod->uiData,
                                    hb_stackReturnItem() );
      }
      else if( pExecSym == &s___msgSetShrData )
      {
         PCLASS pClass   = s_pClasses[ pStack->uiClass ];
         PMETHOD pMethod = pClass->pMethods + pStack->uiMethod;

         return hb_arrayGetItemRef( s_pClasses[ pMethod->uiSprClass ]->pSharedDatas,
                                    pMethod->uiData, hb_stackReturnItem() );
      }
      else if( pExecSym == &s___msgScopeErr )
      {
         pExecSym->value.pFunPtr();
      }
      else if( pStack->uiClass )
      {
         PCLASS pClass   = s_pClasses[ pStack->uiClass ];
         PMETHOD pMethod = pClass->pMethods + pStack->uiMethod;

         if( pMethod->pMessage == s___msgOnError.pDynSym )
            return hb_vmMsgReference( pObject, pMessage->pDynSym, NULL );

         if( ! pMethod->pAccMsg )
            pMethod->pAccMsg = hb_dynsymGetCase( pMessage->szName + 1 );

         return hb_vmMsgReference( pObject, pMessage->pDynSym, pMethod->pAccMsg );
      }
   }

   return HB_FALSE;
}

/* Check if class has object destructors */
HB_BOOL hb_clsHasDestructor( HB_USHORT uiClass )
{
   if( uiClass && uiClass <= s_uiClasses )
      return s_pClasses[ uiClass ]->fHasDestructor;
   else
      return HB_FALSE;
}

/* Call all known super destructors */
static void hb_objSuperDestructorCall( PHB_ITEM pObject, PCLASS pClass )
{
#if 0
   HB_STACK_TLS_PRELOAD
   PMETHOD pMethod = pClass->pMethods;
   HB_SIZE nLimit = hb_clsMthNum( pClass );
   char * pcClasses;
   HB_USHORT uiClass;

   pcClasses = ( char * ) hb_xgrabz( ( HB_SIZE ) s_uiClasses + 1 );

   do
   {
      if( pMethod->pMessage )
      {
         if( pMethod->pFuncSym == &s___msgSuper )
         {
            PCLASS pSuperClass = s_pClasses[ pMethod->uiData ];
            if( pSuperClass->fHasDestructor && pSuperClass != pClass )
               pcClasses[ pMethod->uiData ] |= 1;
         }
         else if( pMethod->pMessage == s___msgDestructor.pDynSym )
            pcClasses[ pMethod->uiSprClass ] |= 2;
      }
      ++pMethod;
   }
   while( --nLimit );

   for( uiClass = s_uiClasses; uiClass; --uiClass )
   {
      if( pcClasses[ uiClass ] == 1 )
      {
         PMETHOD pDestructor = hb_clsFindMsg( s_pClasses[ uiClass ],
                                              s___msgDestructor.pDynSym );
         if( pDestructor )
         {
            if( pcClasses[ pDestructor->uiSprClass ] == 1 )
            {
               hb_vmPushSymbol( &s___msgDestructor );
               hb_clsMakeSuperObject( hb_stackAllocItem(), pObject, uiClass );
               hb_vmSend( 0 );
               if( hb_vmRequestQuery() != 0 )
                  break;
               pcClasses[ pDestructor->uiSprClass ] |= 2;
            }
         }
      }
   }

   hb_xfree( pcClasses );
#else
   HB_STACK_TLS_PRELOAD
   HB_USHORT uiCount, uiDtorClass;

   uiDtorClass = hb_clsFindMsg( pClass, s___msgDestructor.pDynSym )->uiSprClass;
   uiCount = pClass->uiSuperClasses;
   while( uiCount-- )
   {
      HB_USHORT uiParentCls = pClass->pSuperClasses[ uiCount ].uiClass;

      if( uiParentCls != uiDtorClass && uiParentCls != pClass->uiClass )
      {
         PCLASS pSuperClass = s_pClasses[ uiParentCls ];

         if( pSuperClass->fHasDestructor )
         {
            PMETHOD pDestructor = hb_clsFindMsg( s_pClasses[ uiParentCls ],
                                                 s___msgDestructor.pDynSym );
            if( pDestructor && pDestructor->uiSprClass == uiParentCls )
            {
               hb_vmPushSymbol( &s___msgDestructor );
               hb_clsMakeSuperObject( hb_stackAllocItem(), pObject, uiParentCls );
               hb_vmSend( 0 );
               if( hb_vmRequestQuery() != 0 )
                  break;
            }
         }
      }
   }
#endif
}

/* Call object destructor */
void hb_objDestructorCall( PHB_ITEM pObject )
{
   if( HB_IS_OBJECT( pObject ) &&
       pObject->item.asArray.value->uiClass <= s_uiClasses )
   {
      PCLASS pClass = s_pClasses[ pObject->item.asArray.value->uiClass ];

      if( pClass->fHasDestructor )
      {
         if( hb_vmRequestReenter() )
         {
            hb_vmPushSymbol( &s___msgDestructor );
            hb_vmPush( pObject );
            hb_vmSend( 0 );
            if( hb_vmRequestQuery() == 0 )
               hb_objSuperDestructorCall( pObject, pClass );
            hb_vmRequestRestore();
         }
      }
   }
}

/* Check if object has a given operator */
HB_BOOL hb_objHasOperator( PHB_ITEM pObject, HB_USHORT uiOperator )
{
   HB_USHORT uiClass;

   HB_TRACE( HB_TR_DEBUG, ( "hb_objHasOperator(%p,%hu)", ( void * ) pObject, uiOperator ) );

   uiClass = hb_objGetClassH( pObject );
   if( uiClass && uiClass <= s_uiClasses )
   {
      return ( s_pClasses[ uiClass ]->nOpFlags & ( 1 << uiOperator ) ) != 0;
   }

   return HB_FALSE;
}

/* Call object operator. If pMsgArg is NULL then operator is unary.
 * Function return HB_TRUE when object class overloads given operator
 * and HB_FALSE otherwise. [druzus]
 */
HB_BOOL hb_objOperatorCall( HB_USHORT uiOperator, PHB_ITEM pResult, PHB_ITEM pObject,
                            PHB_ITEM pMsgArg1, PHB_ITEM pMsgArg2 )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_objOperatorCall(%hu,%p,%p,%p,%p)", uiOperator, ( void * ) pResult, ( void * ) pObject, ( void * ) pMsgArg1, ( void * ) pMsgArg2 ) );

   if( hb_objHasOperator( pObject, uiOperator ) )
   {
      HB_STACK_TLS_PRELOAD
      hb_vmPushSymbol( s_opSymbols + uiOperator );
      hb_vmPush( pObject );
      hb_itemSetNil( hb_stackReturnItem() );
      if( pMsgArg1 )
      {
         hb_vmPush( pMsgArg1 );
         if( pMsgArg2 )
         {
            hb_vmPush( pMsgArg2 );
            hb_vmSend( 2 );
         }
         else
            hb_vmSend( 1 );
      }
      else
         hb_vmSend( 0 );

      /* store the return value */
      hb_itemMove( pResult, hb_stackReturnItem() );
      return HB_TRUE;
   }
   return HB_FALSE;
}

/* return HB_TRUE if object has a given message */
HB_BOOL hb_objHasMessage( PHB_ITEM pObject, PHB_DYNS pMessage )
{
   return hb_objGetMethod( pObject, pMessage->pSymbol, NULL ) != NULL;
}

/* <bool> = hb_objHasMsg( <pObject>, <szString> )
 *
 * Check whether <szString> is an existing message for object.
 *
 * <uPtr> should be read as a boolean
 */
HB_BOOL hb_objHasMsg( PHB_ITEM pObject, const char * szString )
{
   PHB_DYNS pDynSym;

   HB_TRACE( HB_TR_DEBUG, ( "hb_objHasMsg(%p, %s)", ( void * ) pObject, szString ) );

   pDynSym = hb_dynsymFindName( szString );
   if( pDynSym )
      return hb_objGetMethod( pObject, pDynSym->pSymbol, NULL ) != NULL;
   else
      return HB_FALSE;
}

PHB_ITEM hb_objSendMessage( PHB_ITEM pObject, PHB_DYNS pMsgSym, HB_ULONG ulArg, ... )
{
   if( pObject && pMsgSym )
   {
      hb_vmPushSymbol( pMsgSym->pSymbol );
      hb_vmPush( pObject );

      if( ulArg )
      {
         HB_ULONG i;
         va_list ap;

         va_start( ap, ulArg );
         for( i = 0; i < ulArg; i++ )
         {
            hb_vmPush( va_arg( ap, PHB_ITEM ) );
         }
         va_end( ap );
      }
      hb_vmSend( ( HB_USHORT ) ulArg );
   }
   else
      hb_errRT_BASE( EG_ARG, 3000, NULL, "__objSendMessage()", 0 );

   {
      HB_STACK_TLS_PRELOAD
      return hb_stackReturnItem();
   }
}

PHB_ITEM hb_objSendMsg( PHB_ITEM pObject, const char * szMsg, HB_ULONG ulArg, ... )
{
   hb_vmPushSymbol( hb_dynsymGet( szMsg )->pSymbol );
   hb_vmPush( pObject );
   if( ulArg )
   {
      HB_ULONG i;
      va_list ap;

      va_start( ap, ulArg );
      for( i = 0; i < ulArg; i++ )
      {
         hb_vmPush( va_arg( ap, PHB_ITEM ) );
      }
      va_end( ap );
   }
   hb_vmSend( ( HB_USHORT ) ulArg );

   {
      HB_STACK_TLS_PRELOAD
      return hb_stackReturnItem();
   }
}

PHB_ITEM hb_objGetVarPtr( PHB_ITEM pObject, PHB_DYNS pVarMsg )
{
   if( pObject && HB_IS_OBJECT( pObject ) && pVarMsg )
   {
      HB_USHORT uiClass = pObject->item.asArray.value->uiClass;
      PCLASS pClass = s_pClasses[ uiClass ];
      PMETHOD pMethod = hb_clsFindMsg( pClass, pVarMsg );

      if( pMethod )
      {
         PHB_SYMB pFuncSym = pMethod->pFuncSym;

         if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass )
            pFuncSym = pMethod->pRealSym;

         if( pFuncSym == &s___msgSetData || pFuncSym == &s___msgGetData )
         {
            HB_SIZE nIndex = pMethod->uiData + pMethod->uiOffset;
            if( pObject->item.asArray.value->uiPrevCls )
            {
               pObject = hb_arrayGetItemPtr( pObject, 1 );
               if( ! pObject )
                  return NULL;
               if( uiClass != pObject->item.asArray.value->uiClass )
                  nIndex = pMethod->uiData +
                           hb_clsParentInstanceOffset( s_pClasses[ pObject->item.asArray.value->uiClass ],
                                                       pMethod->uiSprClass );
            }
            return hb_arrayGetItemPtr( pObject, nIndex );
         }
      }
   }
   return NULL;
}

static PHB_DYNS hb_objGetMsgSym( PHB_ITEM pMessage )
{
   PHB_DYNS pDynSym = NULL;

   if( pMessage )
   {
      const char * szMsg = NULL;

      if( HB_IS_STRING( pMessage ) )
         szMsg = pMessage->item.asString.value;
      else if( HB_IS_SYMBOL( pMessage ) )
      {
         pDynSym = pMessage->item.asSymbol.value->pDynSym;
         if( ! pDynSym )
            szMsg = pMessage->item.asSymbol.value->szName;
      }

      if( szMsg && *szMsg )
         pDynSym = hb_dynsymGet( szMsg );
   }

   return pDynSym;
}

static PHB_SYMB hb_objGetFuncSym( PHB_ITEM pItem )
{
   if( pItem )
   {
      if( HB_IS_SYMBOL( pItem ) )
         return pItem->item.asSymbol.value;
      else if( HB_IS_STRING( pItem ) )
      {
         PHB_DYNS pDynSym = hb_dynsymFindName( hb_itemGetCPtr( pItem ) );

         if( pDynSym && pDynSym->pSymbol->value.pFunPtr )
            return pDynSym->pSymbol;
      }
   }

   return NULL;
}

/* clone object if user defined clone method or copy it */
void hb_objCloneBody( PHB_ITEM pDest, PHB_ITEM pObject, PHB_NESTED_CLONED pClonedList )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_objCloneBody(%p,%p,%p)", ( void * ) pDest, ( void * ) pObject, ( void * ) pClonedList ) );

   HB_SYMBOL_UNUSED( pClonedList );

   /* TODO: add support for user defined clone operation */

   hb_itemCopy( pDest, pObject );
}

/* clone object if user defined clone method or copy it */
PHB_ITEM hb_objCloneTo( PHB_ITEM pDest, PHB_ITEM pObject )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_objCloneTo(%p,%p)", ( void * ) pDest, ( void * ) pObject ) );

   hb_objCloneBody( pDest, pObject, NULL );

   return pDest;
}

/* send message which allows to set execution context for debugger */
void hb_dbg_objSendMessage( int iProcLevel, PHB_ITEM pObject, PHB_ITEM pMessage, int iParamOffset )
{
   HB_STACK_TLS_PRELOAD
   PHB_DYNS pMsgSym;

   pMsgSym = hb_objGetMsgSym( pMessage );
   if( pObject && pMsgSym )
   {
      HB_USHORT uiParams = 0;

      /* set requested sender class and method id for scope verification */
      if( iProcLevel > 0 )
      {
         int iLevel = hb_stackCallDepth();
         if( iProcLevel < iLevel )
         {
            HB_ISIZ nOffset = hb_stackBaseProcOffset( iLevel - iProcLevel );
            if( nOffset > 0 )
            {
               PHB_ITEM pItem = hb_stackItem( nOffset );
               PHB_ITEM pBase = hb_stackBaseItem();
               pBase->item.asSymbol.stackstate->uiClass =
                                    pItem->item.asSymbol.stackstate->uiClass;
               pBase->item.asSymbol.stackstate->uiMethod =
                                    pItem->item.asSymbol.stackstate->uiMethod;
            }
         }
      }
      else if( iProcLevel == 0 )
      {
         /* set scope like for internal object messages to any visible
            method without respecting overloaded methods */
         HB_USHORT uiClass = hb_objGetClassH( pObject );

         if( uiClass && uiClass <= s_uiClasses )
         {
            PMETHOD pMethod = hb_clsFindMsg( s_pClasses[ uiClass ], pMsgSym );
            if( pMethod )
            {
               PHB_ITEM pBase = hb_stackBaseItem();

               pBase->item.asSymbol.stackstate->uiClass = uiClass;
               pBase->item.asSymbol.stackstate->uiMethod =
                     ( HB_USHORT ) ( pMethod - s_pClasses[ uiClass ]->pMethods );
            }
         }
      }

      hb_vmPushSymbol( pMsgSym->pSymbol );
      hb_vmPush( pObject );

      if( iParamOffset > 0 )
      {
         int iPCount = hb_pcount();

         while( iParamOffset <= iPCount )
         {
            hb_vmPush( hb_stackItemFromBase( iParamOffset ) );
            ++uiParams;
            ++iParamOffset;
         }
      }
      hb_vmSend( uiParams );
   }
   else
      hb_errRT_BASE( EG_ARG, 3000, NULL, "hb_dbg_objSendMessage()", 2, pObject, pMsgSym );
}

static HB_USHORT hb_clsUpdateScope( HB_USHORT uiScope, HB_BOOL fAssign )
{
   if( ! fAssign )
      uiScope &= ~HB_OO_CLSTP_READONLY;
   else
   {
      uiScope &= ~HB_OO_CLSTP_PERSIST;

      if( ( uiScope & HB_OO_CLSTP_READONLY ) &&
         !( uiScope & HB_OO_CLSTP_HIDDEN ) )
      {
         /* Class(y) does not allow to write to HIDDEN+READONLY
            instance variables, [druzus] */

         uiScope &= ~HB_OO_CLSTP_READONLY;
         uiScope |= ( uiScope & HB_OO_CLSTP_PROTECTED ) ?
                       HB_OO_CLSTP_HIDDEN : HB_OO_CLSTP_PROTECTED;
      }
   }
   return uiScope;
}

static HB_TYPE hb_clsGetItemType( PHB_ITEM pItem, HB_TYPE nDefault )
{
   if( pItem )
   {
      if( HB_IS_STRING( pItem ) )
      {
         switch( hb_itemGetCPtr( pItem )[ 0 ] )
         {
            case 'C':
            case 'c':
               if( hb_strnicmp( hb_itemGetCPtr( pItem ), "code", 4 ) == 0 )
                  return HB_IT_BLOCK;
               /* fallthrough */
            case '\0':
               return HB_IT_STRING;

            case 'S':
            case 's':
               if( hb_strnicmp( hb_itemGetCPtr( pItem ), "str", 3 ) == 0 )
                  return HB_IT_STRING;
               else
                  return HB_IT_SYMBOL;

            case 'B':
            case 'b':
               return HB_IT_BLOCK;

            case 'D':
            case 'd':
               if( hb_strnicmp( hb_itemGetCPtr( pItem ), "datet", 5 ) == 0 )
                  return HB_IT_TIMESTAMP;
               else
                  return HB_IT_DATE;

            case 'T':
            case 't':
               return HB_IT_TIMESTAMP;

            case 'L':
            case 'l':
               return HB_IT_LOGICAL;

            case 'I':
            case 'i':
               return HB_IT_NUMINT;

            case 'N':
            case 'n':
               if( hb_stricmp( hb_itemGetCPtr( pItem ), "nil" ) == 0 )
                  return HB_IT_NIL;
               else
                  return HB_IT_NUMERIC;

            case 'A':
            case 'a':
               return HB_IT_ARRAY;

            case 'P':
            case 'p':
               return HB_IT_POINTER;

            case 'H':
            case 'h':
               return HB_IT_HASH;
         }
      }
      else if( HB_IS_ARRAY( pItem ) )
      {
         if( pItem->item.asArray.value->uiClass == 0 )
            return HB_IT_ARRAY;
      }
      else if( HB_IS_NUMINT( pItem ) )
         return HB_IT_NUMINT;

      else if( HB_IS_NUMERIC( pItem ) )
         return HB_IT_NUMERIC;

      else if( HB_IS_DATE( pItem ) )
         return HB_IT_DATE;

      else if( HB_IS_TIMESTAMP( pItem ) )
         return HB_IT_TIMESTAMP;

      else if( HB_IS_LOGICAL( pItem ) )
         return HB_IT_LOGICAL;

      else if( HB_IS_BLOCK( pItem ) )
         return HB_IT_BLOCK;

      else if( HB_IS_POINTER( pItem ) )
         return HB_IT_POINTER;

      else if( HB_IS_SYMBOL( pItem ) )
         return HB_IT_SYMBOL;

      else if( HB_IS_NIL( pItem ) )
         return HB_IT_NIL;
   }

   return nDefault;
}

/* --- */

/*
 * <uiType>    HB_OO_MSG_METHOD     : standard method
 *             HB_OO_MSG_ONERROR    : error handler method
 *             HB_OO_MSG_DESTRUCTOR : destructor method
 *             HB_OO_MSG_INLINE     : inline (codeblock) method
 *             HB_OO_MSG_ASSIGN     : assign instance data
 *             HB_OO_MSG_ACCESS     : access instance data
 *             HB_OO_MSG_CLSASSIGN  : assign class data
 *             HB_OO_MSG_CLSACCESS  : access class data
 *             HB_OO_MSG_SUPER      : supercasting
 *             HB_OO_MSG_REALCLASS  : caller method real class casting
 *             HB_OO_MSG_PERFORM    : perform method
 *             HB_OO_MSG_VIRTUAL    : virtual method
 *             HB_OO_MSG_DELEGATE   : delegate method
 *
 * <uiScope>   HB_OO_CLSTP_EXPORTED        1 : default for data and method
 *             HB_OO_CLSTP_PROTECTED       2 : method or data protected
 *             HB_OO_CLSTP_HIDDEN          4 : method or data hidden
 *           * HB_OO_CLSTP_CTOR            8 : method constructor
 *             HB_OO_CLSTP_READONLY       16 : data read only
 *             HB_OO_CLSTP_SHARED         32 : (method or) data shared
 *             HB_OO_CLSTP_CLASS          64 : message is class message not object
 *           * HB_OO_CLSTP_SUPER         128 : message is inherited
 *             HB_OO_CLSTP_PERSIST       256 : message is persistent (PROPERTY)
 *             HB_OO_CLSTP_NONVIRTUAL    512 : Non Virtual message - should not be covered by subclass(es) messages with the same name when executed from a given class message
 *             HB_OO_CLSTP_OVERLOADED   1024 : message overload NONVIRTUAL one
 *             HB_OO_CLSTP_SYNC         2048 : message synchronized by object or class mutex
 *
 * <pFunction> HB_OO_MSG_METHOD     : \
 *             HB_OO_MSG_ONERROR    :  > Pointer to function
 *             HB_OO_MSG_DESTRUCTOR : /
 *             HB_OO_MSG_INLINE     : Code block
 *             HB_OO_MSG_ASSIGN     :  Index to instance area array 1 based (without offset)
 *             HB_OO_MSG_ACCESS     : /
 *             HB_OO_MSG_CLSASSIGN  :  Index class data array
 *             HB_OO_MSG_CLSACCESS  : /
 *             HB_OO_MSG_SUPER      : Instance area offset for class casting
 *             HB_OO_MSG_DELEGATE   : Delegated message symbol
 *
 * <pInit>     HB_OO_MSG_ACCESS     :  Optional initializer for (Class)DATA
 *             HB_OO_MSG_CLSACCESS  : /
 *             HB_OO_MSG_ASSIGN     :  Item type restriction in assignment
 *             HB_OO_MSG_CLSASSIGN  : /
 *             HB_OO_MSG_SUPER      : Superclass handle
 *             HB_OO_MSG_DELEGATE   : Object symbol for delegated message
 */
static HB_BOOL hb_clsAddMsg( HB_USHORT uiClass, const char * szMessage,
                             HB_USHORT uiType, HB_USHORT uiScope,
                             PHB_ITEM pFunction, PHB_ITEM pInit )
{
   if( szMessage && uiClass && uiClass <= s_uiClasses )
   {
      PCLASS    pClass   = s_pClasses[ uiClass ];

      PHB_DYNS  pMessage;
      PMETHOD   pNewMeth;
      HB_USHORT uiOperator, uiSprClass = 0, uiIndex = 0, uiPrevCls, uiPrevMth;
      PHB_SYMB  pOpSym, pFuncSym = NULL;
      HB_BOOL   fOK;
      HB_U32    nOpFlags = 0;

      if( pClass->fLocked )
         return HB_FALSE;

      if( ! ( uiScope & ( HB_OO_CLSTP_EXPORTED | HB_OO_CLSTP_PROTECTED | HB_OO_CLSTP_HIDDEN ) ) )
         uiScope |= HB_OO_CLSTP_EXPORTED;

      /* translate names of operator overloading messages */
      if( uiType == HB_OO_MSG_DESTRUCTOR )
         pMessage = s___msgDestructor.pDynSym;
      else if( uiType == HB_OO_MSG_ONERROR )
         pMessage = s___msgOnError.pDynSym;
      else if( strcmp( "+", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_PLUS )->pDynSym;
      else if( strcmp( "-", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_MINUS )->pDynSym;
      else if( strcmp( "*", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_MULT )->pDynSym;
      else if( strcmp( "/", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_DIVIDE )->pDynSym;
      else if( strcmp( "%", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_MOD )->pDynSym;
      else if( strcmp( "^", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_POWER )->pDynSym;
      else if( strcmp( "**", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_POWER )->pDynSym;
      else if( strcmp( "++", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_INC )->pDynSym;
      else if( strcmp( "--", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_DEC )->pDynSym;
      else if( strcmp( "==", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_EXACTEQUAL )->pDynSym;
      else if( strcmp( "=", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_EQUAL )->pDynSym;
      else if( strcmp( "!=", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_NOTEQUAL )->pDynSym;
      else if( strcmp( "<>", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_NOTEQUAL )->pDynSym;
      else if( strcmp( "#", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_NOTEQUAL )->pDynSym;
      else if( strcmp( "<", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_LESS )->pDynSym;
      else if( strcmp( "<=", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_LESSEQUAL )->pDynSym;
      else if( strcmp( ">", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_GREATER )->pDynSym;
      else if( strcmp( ">=", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_GREATEREQUAL )->pDynSym;
      else if( strcmp( ":=", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_ASSIGN )->pDynSym;
      else if( strcmp( "$", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_INSTRING )->pDynSym;
      else if( strcmp( "$$", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_INCLUDE )->pDynSym;
      else if( strcmp( "!", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_NOT )->pDynSym;
      else if( hb_stricmp( ".NOT.", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_NOT )->pDynSym;
      else if( hb_stricmp( ".AND.", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_AND )->pDynSym;
      else if( hb_stricmp( ".OR.", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_OR )->pDynSym;
      else if( strcmp( "[]", szMessage ) == 0 )
         pMessage = ( s_opSymbols + HB_OO_OP_ARRAYINDEX )->pDynSym;
      else
         pMessage = hb_dynsymGet( szMessage );

      for( uiOperator = 0, pOpSym = s_opSymbols;
           uiOperator <= HB_OO_MAX_OPERATOR; ++uiOperator, ++pOpSym )
      {
         if( pOpSym->pDynSym == pMessage )
         {
            nOpFlags |= 1 << uiOperator;
            break;
         }
      }

      /* basic parameter validation */
      switch( uiType )
      {
         case HB_OO_MSG_METHOD:
         case HB_OO_MSG_ONERROR:
         case HB_OO_MSG_DESTRUCTOR:
            pFuncSym = hb_objGetFuncSym( pFunction );
            fOK = pFuncSym != NULL;
            break;

         case HB_OO_MSG_INLINE:
            fOK = pFunction && HB_IS_BLOCK( pFunction );
            break;

         case HB_OO_MSG_SUPER:
            uiIndex = ( HB_USHORT ) hb_itemGetNI( pFunction );
            uiSprClass = ( HB_USHORT ) hb_itemGetNI( pInit );
            fOK = uiSprClass && uiSprClass <= s_uiClasses &&
                  uiIndex <= pClass->uiDatas;
            break;

         case HB_OO_MSG_ASSIGN:
         case HB_OO_MSG_ACCESS:
            uiIndex = ( HB_USHORT ) hb_itemGetNI( pFunction );
            /* This validation can break buggy .prg code which wrongly
             * sets data offsets but IMHO it will help to clean the code.
             * [druzus]
             */
            fOK = uiIndex && uiIndex <= pClass->uiDatas - pClass->uiDataFirst;
            break;

         case HB_OO_MSG_CLSASSIGN:
         case HB_OO_MSG_CLSACCESS:
            uiIndex = ( HB_USHORT ) hb_itemGetNI( pFunction );
            fOK = uiIndex != 0;
            break;

         case HB_OO_MSG_DELEGATE:
         {
            PHB_DYNS pDelegMsg = hb_objGetMsgSym( pFunction );
            if( pDelegMsg )
            {
               pNewMeth = hb_clsFindMsg( pClass, pDelegMsg );
               if( pNewMeth )
                  uiIndex = ( HB_USHORT ) ( pNewMeth - pClass->pMethods );
            }
            fOK = pFunction == NULL || HB_IS_NIL( pFunction ) || uiIndex != 0;
            if( fOK )
            {
               pDelegMsg = hb_objGetMsgSym( pInit );
               if( pDelegMsg )
               {
                  pNewMeth = hb_clsFindMsg( pClass, pDelegMsg );
                  if( pNewMeth )
                     uiSprClass = ( HB_USHORT ) ( pNewMeth - pClass->pMethods );
               }
               fOK = ( pInit == NULL || HB_IS_NIL( pInit ) || uiSprClass != 0 ) &&
                     ( uiIndex != 0 || uiSprClass != 0 );
            }
            break;
         }
         case HB_OO_MSG_REALCLASS:
         case HB_OO_MSG_VIRTUAL:
         case HB_OO_MSG_PERFORM:
            fOK = HB_TRUE;
            break;

         default:
            fOK = HB_FALSE;
      }

      if( ! fOK )
      {
         hb_errRT_BASE( EG_ARG, 3000, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
         return HB_FALSE;
      }

      pNewMeth = hb_clsAllocMsg( pClass, pMessage );

      uiPrevCls = uiClass;
      uiPrevMth = ( HB_USHORT ) ( pClass->pMethods - pNewMeth );

#ifndef HB_VIRTUAL_HIDDEN
      if( uiScope & HB_OO_CLSTP_HIDDEN )
         uiScope |= HB_OO_CLSTP_NONVIRTUAL;
#endif

      if( ! pNewMeth->pMessage )
         pClass->uiMethods++;           /* One more message */
      else
      {
         HB_BOOL fOverLoad = ( pNewMeth->uiScope & HB_OO_CLSTP_OVERLOADED ) ||
                             ( ( pNewMeth->uiScope & HB_OO_CLSTP_NONVIRTUAL ) &&
                               pNewMeth->uiSprClass != uiClass );

         uiPrevCls = pNewMeth->uiPrevCls;
         uiPrevMth = pNewMeth->uiPrevMth;
         if( ! hb_clsCanClearMethod( pNewMeth, HB_TRUE ) )
            return HB_FALSE;

         memset( pNewMeth, 0, sizeof( METHOD ) );
         if( fOverLoad )
            uiScope |= HB_OO_CLSTP_OVERLOADED;
      }
      pNewMeth->pMessage = pMessage;
      pNewMeth->uiSprClass = uiClass;
      pNewMeth->uiPrevCls = uiPrevCls;
      pNewMeth->uiPrevMth = uiPrevMth;

      switch( uiType )
      {
         case HB_OO_MSG_METHOD:

            pNewMeth->pFuncSym = pFuncSym;
            pNewMeth->uiScope = uiScope;
            break;

         case HB_OO_MSG_ASSIGN:

            pNewMeth->uiScope = hb_clsUpdateScope( uiScope, HB_TRUE );
            /* Class(y) does not allow to write to HIDDEN+READONLY
               instance variables, [druzus] */
            if( pNewMeth->uiScope & HB_OO_CLSTP_READONLY &&
                pNewMeth->uiScope & HB_OO_CLSTP_HIDDEN )
               pNewMeth->pFuncSym = &s___msgScopeErr;
            else
            {
               pNewMeth->pFuncSym = &s___msgSetData;
               pNewMeth->uiData = uiIndex;
               pNewMeth->uiOffset = pClass->uiDataFirst;
               pNewMeth->itemType = hb_clsGetItemType( pInit, 0 );
            }
            break;

         case HB_OO_MSG_ACCESS:

            pNewMeth->uiScope = hb_clsUpdateScope( uiScope, HB_FALSE );
            pNewMeth->uiData = uiIndex;
            pNewMeth->uiOffset = pClass->uiDataFirst;
            hb_clsAddInitValue( pClass, pInit, HB_OO_MSG_DATA,
                                pNewMeth->uiData, pNewMeth->uiOffset, uiClass );
            pNewMeth->pFuncSym = &s___msgGetData;
            break;

         case HB_OO_MSG_CLSASSIGN:

            pNewMeth->uiData = uiIndex;
            pNewMeth->itemType = hb_clsGetItemType( pInit, 0 );
            pNewMeth->uiScope = hb_clsUpdateScope( uiScope, HB_TRUE );
            /* Class(y) does not allow to write to HIDDEN+READONLY
               instance variables, [druzus] */
            if( pNewMeth->uiScope & HB_OO_CLSTP_READONLY &&
                pNewMeth->uiScope & HB_OO_CLSTP_HIDDEN )
               pNewMeth->pFuncSym = &s___msgScopeErr;
            else if( pNewMeth->uiScope & HB_OO_CLSTP_SHARED )
            {
               if( hb_arrayLen( pClass->pSharedDatas ) < ( HB_SIZE ) pNewMeth->uiData )
                  hb_arraySize( pClass->pSharedDatas, pNewMeth->uiData );
               pNewMeth->pFuncSym = &s___msgSetShrData;
            }
            else
            {
               if( hb_arrayLen( pClass->pClassDatas ) < ( HB_SIZE ) pNewMeth->uiData )
                  hb_arraySize( pClass->pClassDatas, pNewMeth->uiData );
               pNewMeth->pFuncSym = &s___msgSetClsData;
            }
            break;

         case HB_OO_MSG_CLSACCESS:

            pNewMeth->uiScope = hb_clsUpdateScope( uiScope, HB_FALSE );
            pNewMeth->uiData = uiIndex;
            if( pNewMeth->uiScope & HB_OO_CLSTP_SHARED )
            {
               if( hb_arrayLen( pClass->pSharedDatas ) < ( HB_SIZE ) pNewMeth->uiData )
                  hb_arraySize( pClass->pSharedDatas, pNewMeth->uiData );

               if( pInit && ! HB_IS_NIL( pInit ) ) /* Initializer found */
               {
                  /* Shared Classdata need to be initialized only once
                   * ACCESS/ASSIGN methods will be inherited by subclasses
                   * and will operate on this value so it's not necessary
                   * to keep the init value. [druzus]
                   */
                  hb_itemCloneTo( hb_arrayGetItemPtr( pClass->pSharedDatas,
                                                      pNewMeth->uiData ), pInit );
               }
               pNewMeth->pFuncSym = &s___msgGetShrData;
            }
            else
            {
               if( hb_arrayLen( pClass->pClassDatas ) < ( HB_SIZE ) pNewMeth->uiData )
                  hb_arraySize( pClass->pClassDatas, pNewMeth->uiData );
               /* uiOffset is used to copy ancestor class data initializers when
                * new class is created
                */
               pNewMeth->uiOffset = hb_clsAddInitValue( pClass, pInit,
                           HB_OO_MSG_CLASSDATA, pNewMeth->uiData, 0, uiClass );
               pNewMeth->pFuncSym = &s___msgGetClsData;
            }
            break;

         case HB_OO_MSG_INLINE:

            pNewMeth->pFuncSym = &s___msgEvalInline;
            pNewMeth->uiScope = uiScope;
            hb_arrayAdd( pClass->pInlines, pFunction );
            pNewMeth->uiData = ( HB_USHORT ) hb_arrayLen( pClass->pInlines );
            break;

         case HB_OO_MSG_VIRTUAL:

            pNewMeth->pFuncSym = &s___msgVirtual;
            pNewMeth->uiScope = uiScope;
            break;

         case HB_OO_MSG_SUPER:

            pNewMeth->uiData = uiSprClass; /* store the super handle */
            pNewMeth->uiOffset = uiIndex; /* offset to instance area */
            pNewMeth->uiScope = uiScope;
            pNewMeth->pFuncSym = &s___msgSuper;
            break;

         case HB_OO_MSG_REALCLASS:

            pNewMeth->pFuncSym = &s___msgRealClass;
            pNewMeth->uiScope = uiScope;
            break;

         case HB_OO_MSG_PERFORM:
            pNewMeth->pFuncSym = &s___msgPerform;
            pNewMeth->uiScope = uiScope;
            break;

         case HB_OO_MSG_DELEGATE:

            pNewMeth->pFuncSym = &s___msgDelegate;
            pNewMeth->uiScope = uiScope;
            pNewMeth->uiData = uiIndex;
            break;

         case HB_OO_MSG_ONERROR:

            pNewMeth->pFuncSym = pFuncSym;
            pClass->fHasOnError = HB_TRUE;
            break;

         case HB_OO_MSG_DESTRUCTOR:

            pNewMeth->pFuncSym = pFuncSym;
            pClass->fHasDestructor = HB_TRUE;
            break;

         default:

            hb_errInternal( HB_EI_CLSINVMETHOD, NULL, "__clsAddMsg()", NULL );
      }

      pClass->nOpFlags |= nOpFlags;

      if( uiScope & HB_OO_CLSTP_SYNC )
      {
         pNewMeth->pRealSym = pNewMeth->pFuncSym;
         if( uiScope & HB_OO_CLSTP_CLASS )
         {
            if( ! pClass->pMutex )
               pClass->pMutex = hb_threadMutexCreate();
            pNewMeth->pFuncSym = &s___msgSyncClass;
         }
         else
         {
            if( ! pClass->uiMutexOffset )
               pClass->uiMutexOffset = pClass->uiDatas + 1;
            pNewMeth->pFuncSym = &s___msgSync;
         }
      }
   }

   return HB_TRUE;
}

/* __clsAddMsg( <hClass>, <cMessage>, <pFunction>, <nType>, [xInit], <uiScope>, [xType] )
 *
 * Add a message to the class.
 *
 * <hClass>    Class handle
 * <cMessage>  Message
 * <pFunction> HB_OO_MSG_METHOD     : \
 *             HB_OO_MSG_ONERROR    :  > Pointer to function
 *             HB_OO_MSG_DESTRUCTOR : /
 *             HB_OO_MSG_INLINE     : Code block
 *             HB_OO_MSG_DATA       : \
 *             HB_OO_MSG_ASSIGN     :  > Index to instance area array
 *             HB_OO_MSG_ACCESS     : /
 *             HB_OO_MSG_CLASSDATA  : \
 *             HB_OO_MSG_CLSASSIGN  :  > Index class data array
 *             HB_OO_MSG_CLSACCESS  : /
 *             HB_OO_MSG_SUPER      : Handle of super class
 *             HB_OO_MSG_DELEGATE   : delegated message symbol
 *
 * <nType>     see HB_OO_MSG_* above and:
 *             HB_OO_MSG_REALCLASS  : caller method real class casting
 *             HB_OO_MSG_PERFORM    : perform message
 *             HB_OO_MSG_VIRTUAL    : virtual message
 *             HB_OO_MSG_DELEGATE   : delegate method
 *
 * <xInit>     HB_OO_MSG_ACCESS     : \
 *             HB_OO_MSG_CLSACCESS  :   > Optional initializer for DATA
 *             HB_OO_MSG_DATA       :  /
 *             HB_OO_MSG_CLASSDATA  : /
 *             HB_OO_MSG_SUPER      : Superclass handle
 *             HB_OO_MSG_ASSIGN     : \ item type restriction in assignment not
 *             HB_OO_MSG_CLSASSIGN: :   empty character value where first letter
 *                                      is item type or item of a given value
 *
 * <uiScope>   HB_OO_CLSTP_EXPORTED        1 : default for data and method
 *             HB_OO_CLSTP_PROTECTED       2 : method or data protected
 *             HB_OO_CLSTP_HIDDEN          4 : method or data hidden
 *           * HB_OO_CLSTP_CTOR            8 : method constructor
 *             HB_OO_CLSTP_READONLY       16 : data read only
 *             HB_OO_CLSTP_SHARED         32 : (method or) data shared
 *           * HB_OO_CLSTP_CLASS          64 : message is class message not object
 *           * HB_OO_CLSTP_SUPER         128 : message is inherited
 *             HB_OO_CLSTP_PERSIST       256 : message is persistent (PROPERTY)
 *             HB_OO_CLSTP_NONVIRTUAL    512 : Class method constructor
 *             HB_OO_CLSTP_OVERLOADED   1024 : Class method constructor
 *             HB_OO_CLSTP_SYNC         2048 : message synchronized by object or class mutex
 *
 * <xType>     HB_OO_MSG_PROPERTY      :  > optional item type restriction in assignment
 *             HB_OO_MSG_CLASSPROPERTY : /
 */

HB_FUNC( __CLSADDMSG )
{
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );
   const char * szMessage = hb_parc( 2 );

   if( szMessage && uiClass && uiClass <= s_uiClasses )
   {
      HB_USHORT nType     = ( HB_USHORT ) hb_parni( 4 );
      HB_USHORT uiScope   = ( HB_USHORT ) hb_parni( 6 );
      PHB_ITEM  pFunction = hb_param( 3, HB_IT_ANY );
      PHB_ITEM  pInit     = hb_param( 5, HB_IT_ANY );

      if( nType == HB_OO_MSG_DATA )
      {
         nType = szMessage[ 0 ] == '_' ? HB_OO_MSG_ASSIGN : HB_OO_MSG_ACCESS;
      }
      else if( nType == HB_OO_MSG_CLASSDATA )
      {
         nType = szMessage[ 0 ] == '_' ? HB_OO_MSG_CLSASSIGN :
                                         HB_OO_MSG_CLSACCESS;
      }
      /* to make xHarbour users happy ;-) */
      else if( nType == HB_OO_MSG_PROPERTY ||
               nType == HB_OO_MSG_CLASSPROPERTY )
      {
         PHB_ITEM pType = hb_param( 7, HB_IT_ANY );
         char szAssign[ HB_SYMBOL_NAME_LEN + 1 ];
         int iLen = ( int ) hb_parclen( 2 );
         if( iLen >= HB_SYMBOL_NAME_LEN )
            iLen = HB_SYMBOL_NAME_LEN - 1;
         szAssign[ 0 ] = '_';
         memcpy( szAssign + 1, szMessage, iLen );
         szAssign[ iLen + 1 ] = '\0';

         uiScope = ( uiScope | HB_OO_CLSTP_EXPORTED ) &
                  ~( HB_OO_CLSTP_PROTECTED | HB_OO_CLSTP_HIDDEN );
         if( nType == HB_OO_MSG_PROPERTY )
         {
            hb_clsAddMsg( uiClass, szAssign, HB_OO_MSG_ASSIGN,
                          ( HB_USHORT ) ( uiScope & ~HB_OO_CLSTP_PERSIST ),
                          pFunction, pType );
            nType = HB_OO_MSG_ACCESS;
         }
         else
         {
            hb_clsAddMsg( uiClass, szAssign, HB_OO_MSG_CLSASSIGN,
                          ( HB_USHORT ) ( uiScope & ~HB_OO_CLSTP_PERSIST ),
                          pFunction, pType );
            nType = HB_OO_MSG_CLSACCESS;
         }
      }

      hb_clsAddMsg( uiClass, szMessage, nType, uiScope, pFunction, pInit );
   }
}

/* __clsNew( <szClassName>, <uiDatas>,
 *           [<pSuperArray>], [<pClassFunc>],
 *           [<fModuleFriendly>] ) --> <hClass>
 *
 * Create a new class
 *
 * <szClassName>     Name of the class
 * <uiDatas>         Number of DATAs in the class
 * <pSuperArray>     Optional array with handle(s) of superclass(es)
 * <pClassFunc>      Class function symbol, when NULL public function
 *                   with the same name as szClassName is used
 * <fModuleFriendly> when true all functions and classes from the same
 *                   module as pClassFunc are defined as friends
 */
static HB_USHORT hb_clsNew( const char * szClassName, HB_USHORT uiDatas,
                            PHB_ITEM pSuperArray, PHB_SYMB pClassFunc,
                            HB_BOOL fModuleFriendly )
{
   PCLASS pNewCls;
   PMETHOD pMethod;
   HB_USHORT ui, uiSuper, uiSuperCls;
   HB_USHORT * puiClassData = NULL, uiClassDataSize = 0;
   HB_BOOL fClsMutex = HB_FALSE;

   uiSuper  = ( HB_USHORT ) ( pSuperArray ? hb_arrayLen( pSuperArray ) : 0 );
   pClassFunc = hb_vmGetRealFuncSym( pClassFunc );

   pNewCls = ( PCLASS ) hb_xgrabz( sizeof( CLASS ) );

   HB_CLASS_LOCK();

   if( s_uiClasses == s_uiClsSize )
   {
      s_uiClsSize += HB_CLASS_POOL_RESIZE;
      s_pClasses = ( PCLASS * ) hb_xrealloc( s_pClasses, sizeof( PCLASS ) *
                                             ( ( HB_SIZE ) s_uiClsSize + 1 ) );
   }
   pNewCls->uiClass = s_uiClasses + 1;
   s_pClasses[ pNewCls->uiClass ] = pNewCls;
   ++s_uiClasses;

   HB_CLASS_UNLOCK();

   pNewCls->szName = hb_strdup( szClassName );
   pNewCls->pClassSym = hb_dynsymGet( pNewCls->szName );
   if( ! pClassFunc )
      pClassFunc = hb_vmGetRealFuncSym( pNewCls->pClassSym->pSymbol );
   pNewCls->pClassFuncSym = pClassFunc;
   if( fModuleFriendly )
      hb_vmFindModuleSymbols( pClassFunc, &pNewCls->pFriendModule,
                                          &pNewCls->uiFriendModule );

   for( ui = 1; ui <= uiSuper; ++ui )
   {
      uiSuperCls = ( HB_USHORT ) hb_arrayGetNI( pSuperArray, ui );
      if( uiSuperCls && uiSuperCls < pNewCls->uiClass )
      {
         PCLASS pSprCls;

         pSprCls = s_pClasses[ uiSuperCls ];
         if( ! hb_clsInited( pNewCls ) ) /* This is the first superclass */
         {
            hb_clsCopyClass( pNewCls, pSprCls );
         }
         else if( ! hb_clsHasParentClass( pNewCls, uiSuperCls ) )
         {
            HB_SIZE n, nLimit;
            HB_USHORT nLenClsDatas;
            HB_USHORT uiCount;

            /* create class data translation tables */
            nLenClsDatas = ( HB_USHORT ) hb_itemSize( pSprCls->pClassDatas );
            if( nLenClsDatas )
            {
               if( nLenClsDatas > uiClassDataSize )
               {
                  puiClassData = ( HB_USHORT * ) hb_xrealloc( puiClassData,
                                             sizeof( HB_USHORT ) * nLenClsDatas );
                  uiClassDataSize = nLenClsDatas;
               }
               memset( puiClassData, 0, sizeof( HB_USHORT ) * nLenClsDatas );
            }

            /* Copy super class handles */
            for( uiCount = 0; uiCount < pSprCls->uiSuperClasses; ++uiCount )
               hb_clsDefineSuperClass( pNewCls, pSprCls->pSuperClasses[ uiCount ].uiClass, HB_TRUE );
            hb_clsDefineSuperClass( pNewCls, uiSuperCls, HB_TRUE );

            /* Copy instance area init data */
            if( pSprCls->uiInitDatas )
            {
               HB_USHORT u;
               for( u = 0; u < pSprCls->uiInitDatas; ++u )
               {
                  if( pSprCls->pInitData[ u ].uiType == HB_OO_MSG_DATA )
                  {
                     HB_USHORT uiCls = pSprCls->pInitData[ u ].uiSprClass;
                     hb_clsAddInitValue( pNewCls,
                                 pSprCls->pInitData[ u ].pInitValue,
                                 HB_OO_MSG_DATA,
                                 pSprCls->pInitData[ u ].uiData,
                                 hb_clsParentInstanceOffset( pNewCls, uiCls ),
                                 uiCls );
                  }
               }
            }

            /* Now working on other methods */
            nLimit = hb_clsMthNum( pSprCls );
            for( n = 0; n < nLimit; ++n )
            {
               if( pSprCls->pMethods[ n ].pMessage )
               {
                  pMethod = hb_clsAllocMsg( pNewCls, pSprCls->pMethods[ n ].pMessage );

                  /* update instance area offset */
                  if( pMethod->pMessage && pMethod->pFuncSym == &s___msgSuper )
                     pMethod->uiOffset = hb_clsParentInstanceOffset( pNewCls, pMethod->uiData );

                  /* Ok, this bucket is empty */
                  if( pMethod->pMessage == NULL ||
                      ( hb_clsCanClearMethod( pMethod, HB_FALSE ) &&
                        ( pMethod->pFuncSym == &s___msgVirtual ||
                          ( s_uiObjectClass != 0 &&
                            pMethod->uiSprClass == s_uiObjectClass ) ) ) )
                  {
                     if( pMethod->pMessage == NULL )
                        /* Now, we can increment the msg count */
                        pNewCls->uiMethods++;

                     memcpy( pMethod, pSprCls->pMethods + n, sizeof( METHOD ) );
                     if( ! hb_clsUpdateHiddenMessages( pMethod, pMethod, pNewCls ) )
                     {
                        PHB_SYMB pFuncSym = pMethod->pFuncSym;

                        if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass )
                           pFuncSym = pMethod->pRealSym;

                        if( pFuncSym == &s___msgSetClsData ||
                            pFuncSym == &s___msgGetClsData )
                        {
                           if( pMethod->uiData > nLenClsDatas )
                              hb_errInternal( HB_EI_CLSINVMETHOD, NULL, "__clsNew()", NULL );

                           if( puiClassData[ pMethod->uiData - 1 ] == 0 )
                           {
                              puiClassData[ pMethod->uiData - 1 ] = ( HB_USHORT )
                                          hb_arrayLen( pNewCls->pClassDatas ) + 1;
                              hb_arraySize( pNewCls->pClassDatas,
                                            puiClassData[ pMethod->uiData - 1 ] );
                           }
                           if( pMethod->uiOffset )
                           {
                              pMethod->uiOffset = hb_clsAddInitValue( pNewCls,
                                 pSprCls->pInitData[ pMethod->uiOffset - 1 ].pInitValue,
                                 HB_OO_MSG_CLASSDATA, puiClassData[ pMethod->uiData - 1 ],
                                 0, uiSuperCls );
                           }
                           pMethod->uiData = puiClassData[ pMethod->uiData - 1 ];
                        }
                        else if( pFuncSym == &s___msgSetData ||
                                 pFuncSym == &s___msgGetData )
                        {
                           pMethod->uiOffset = hb_clsParentInstanceOffset( pNewCls,
                                                            pMethod->uiSprClass );
                        }
                        pMethod->uiScope |= HB_OO_CLSTP_SUPER;
                     }
                  }
                  else
                  {
                     if( pSprCls->pMethods[ n ].uiScope &
                         ( HB_OO_CLSTP_OVERLOADED | HB_OO_CLSTP_NONVIRTUAL ) )
                        pMethod->uiScope |= HB_OO_CLSTP_OVERLOADED;

                     hb_clsUpdateHiddenMessages( pSprCls->pMethods + n, pMethod, pNewCls );
                  }
               }
            }
            if( pSprCls->fHasOnError )
               pNewCls->fHasOnError = HB_TRUE;
            if( pSprCls->fHasDestructor )
               pNewCls->fHasDestructor = HB_TRUE;
            pNewCls->nOpFlags |= pSprCls->nOpFlags;
            if( pSprCls->uiMutexOffset )
               pNewCls->uiMutexOffset = 1;
            if( pSprCls->pMutex )
               fClsMutex = HB_TRUE;
         }
      }
   }
   if( puiClassData )
      hb_xfree( puiClassData );

   if( ! hb_clsInited( pNewCls ) )
   {
      hb_clsDictInit( pNewCls, HASH_KEY );
      pNewCls->pClassDatas  = hb_itemArrayNew( 0 );
      pNewCls->pSharedDatas = hb_itemArrayNew( 0 );
      pNewCls->pInlines     = hb_itemArrayNew( 0 );
   }

   /* add self class casting */
   pNewCls->uiDataFirst = pNewCls->uiDatas;
   hb_clsDefineSuperClass( pNewCls, pNewCls->uiClass, HB_FALSE );
   pNewCls->uiDatas += uiDatas;
   if( pNewCls->uiMutexOffset )
      pNewCls->uiMutexOffset = pNewCls->uiDatas + 1;
   if( fClsMutex && ! pNewCls->pMutex )
      pNewCls->pMutex = hb_threadMutexCreate();

   return pNewCls->uiClass;
}

/* __clsNew( <cClassName>, <nDatas>, [<ahSuper>], [<pClassFunc>], [<lModuleFriendly>] ) --> <hClass>
 *
 * Create a new class
 *
 * <cClassName> Name of the class
 * <nDatas>     Number of DATAs in the class
 * <ahSuper>    Optional array with handle(s) of superclass(es)
 * <pClassFunc> Class function symbol
 * <lModuleFriendly> when true all functions and classes from the same
 *                   module as pClassFunc are defined as friends
 */
HB_FUNC( __CLSNEW )
{
   const char * szClassName;
   PHB_ITEM pDatas, pSuperArray, pClassFunc, pModFriend;

   szClassName = hb_parc( 1 );

   pDatas = hb_param( 2, HB_IT_ANY );

   pSuperArray = hb_param( 3, HB_IT_ANY );
   if( pSuperArray && HB_IS_NIL( pSuperArray ) )
      pSuperArray = NULL;

   pClassFunc = hb_param( 4, HB_IT_ANY );
   if( pClassFunc && HB_IS_NIL( pClassFunc ) )
      pClassFunc = NULL;

   pModFriend = hb_param( 5, HB_IT_ANY );
   if( pModFriend && HB_IS_NIL( pModFriend ) )
      pModFriend = NULL;

   if( szClassName &&
       ( ! pDatas || HB_IS_NUMERIC( pDatas ) ) &&
       ( ! pSuperArray || HB_IS_ARRAY( pSuperArray ) ) &&
       ( ! pClassFunc || HB_IS_SYMBOL( pClassFunc ) ) &&
       ( ! pModFriend || HB_IS_LOGICAL( pModFriend ) ) )
   {
      HB_STACK_TLS_PRELOAD
      HB_USHORT uiClass;
      uiClass = hb_clsNew( szClassName, ( HB_USHORT ) hb_itemGetNI( pDatas ),
                           pSuperArray, hb_itemGetSymbol( pClassFunc ),
                           hb_itemGetL( pModFriend ) );
      hb_retni( uiClass );
   }
   else
      hb_errRT_BASE( EG_ARG, 3000, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

/* __clsAddFriend( <hClass>, <sFuncSym> )
 *
 * Add friend function
 */
HB_FUNC( __CLSADDFRIEND )
{
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );

   if( uiClass && uiClass <= s_uiClasses )
   {
      PCLASS pClass = s_pClasses[ uiClass ];

      if( ! pClass->fLocked )
      {
         PHB_SYMB pSym = hb_vmGetRealFuncSym( hb_itemGetSymbol( hb_param( 2,
                                                         HB_IT_SYMBOL ) ) );
         if( pSym )
            hb_clsAddFriendSymbol( pClass, pSym );
      }
   }
}

/* __clsDelMsg( <hClass>, <cMessage> )
 *
 * Delete message (only for INLINE and METHOD)
 *
 * <hClass>   class handle
 * <cMessage> message
 */
HB_FUNC( __CLSDELMSG )
{
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );
   PHB_ITEM pString = hb_param( 2, HB_IT_STRING );

   if( uiClass && uiClass <= s_uiClasses && pString &&
       ! s_pClasses[ uiClass ]->fLocked )
   {
      PHB_DYNS pMsg = hb_dynsymFindName( pString->item.asString.value );

      if( pMsg )
         hb_clsFreeMsg( s_pClasses[ uiClass ], pMsg );
   }
}


/* hb_clsInst( <hClass> ) --> <pObjectItm>
 *
 * Create a new object from class definition <hClass>
 */
static PHB_ITEM hb_clsInst( HB_USHORT uiClass )
{
   PHB_ITEM pSelf = NULL;

   if( uiClass && uiClass <= s_uiClasses )
   {
      PCLASS    pClass = s_pClasses[ uiClass ];
      HB_USHORT uiDatas = pClass->uiDatas;

      if( pClass->uiMutexOffset )
         ++uiDatas;
      pSelf = hb_itemNew( NULL );
      hb_arrayNew( pSelf, uiDatas );
      pSelf->item.asArray.value->uiClass = uiClass;

      if( pClass->uiMutexOffset )
      {
         PHB_ITEM pMutex = hb_threadMutexCreate();
         hb_arraySet( pSelf, pClass->uiMutexOffset, pMutex );
         hb_itemRelease( pMutex );
      }
      /* Initialise value if initialisation was requested */
      if( pClass->uiInitDatas )
      {
         PINITDATA pInitData = pClass->pInitData;
         HB_USHORT ui = pClass->uiInitDatas;
         PHB_ITEM pDestItm;

         do
         {
            if( pInitData->uiType == HB_OO_MSG_DATA )
               pDestItm = hb_arrayGetItemPtr( pSelf,
                                    pInitData->uiData + pInitData->uiOffset );
            else if( pInitData->uiType == HB_OO_MSG_CLASSDATA )
            {
               pDestItm = hb_arrayGetItemPtr( pClass->pClassDatas,
                                              pInitData->uiData );
               /* do not initialize it again */
               pInitData->uiType = HB_OO_MSG_INITIALIZED;
            }
            else
               pDestItm = NULL;

            if( pDestItm )
               hb_itemCloneTo( pDestItm, pInitData->pInitValue );

            ++pInitData;
         }
         while( --ui );
      }
   }

   return pSelf;
}

/* __clsInst( <hClass> ) --> <oNewObject>
 *
 * Create a new object from class definition <hClass>
 */
HB_FUNC( __CLSINST )
{
   PHB_ITEM pSelf = hb_clsInst( ( HB_USHORT ) hb_parni( 1 ) );

   if( pSelf )
      hb_itemReturnRelease( pSelf );
}

/* __clsLock( <hClass> )
 *
 * Block farther class modifications
 */
HB_FUNC( __CLSLOCK )
{
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );

   if( uiClass && uiClass <= s_uiClasses )
      s_pClasses[ uiClass ]->fLocked = HB_TRUE;
}

/* __clsModMsg( <hClass>, <cMessage>, <pFunc> )
 *
 * Modify message (only for INLINE and METHOD)
 */
HB_FUNC( __CLSMODMSG )
{
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );
   PHB_ITEM pString = hb_param( 2, HB_IT_STRING );

   if( uiClass && uiClass <= s_uiClasses && pString &&
       ! s_pClasses[ uiClass ]->fLocked )
   {
      PHB_DYNS pMsg = hb_dynsymFindName( pString->item.asString.value );

      if( pMsg )
      {
         PCLASS  pClass  = s_pClasses[ uiClass ];
         PMETHOD pMethod = hb_clsFindMsg( pClass, pMsg );

         if( pMethod )
         {
            PHB_SYMB pFuncSym = pMethod->pFuncSym;

            if( pFuncSym == &s___msgSetData || pFuncSym == &s___msgGetData )
            {
               hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a DATA item", HB_ERR_FUNCNAME, 0 );
            }
            else if( pFuncSym == &s___msgSetClsData || pFuncSym == &s___msgGetClsData )
            {
               hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a CLASSDATA item", HB_ERR_FUNCNAME, 0 );
            }
            else if( pFuncSym == &s___msgSetShrData || pFuncSym == &s___msgGetShrData )
            {
               hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a SHARED DATA item", HB_ERR_FUNCNAME, 0 );
            }
            else if( pFuncSym == &s___msgSuper || pFuncSym == &s___msgRealClass )
            {
               hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a SUPER class casting", HB_ERR_FUNCNAME, 0 );
            }
            else if( pFuncSym == &s___msgDestructor )
            {
               hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a DESTRUCTOR method", HB_ERR_FUNCNAME, 0 );
            }
            else if( pFuncSym == &s___msgOnError )
            {
               hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a ONERROR method", HB_ERR_FUNCNAME, 0 );
            }
            else if( pFuncSym == &s___msgScopeErr )
            {
               hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a SCOPE ERROR method", HB_ERR_FUNCNAME, 0 );
            }
            else if( pFuncSym == &s___msgPerform )
            {
               hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a PERFORM method", HB_ERR_FUNCNAME, 0 );
            }
            else if( pFuncSym == &s___msgDelegate )
            {
               hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a DELEGATE method", HB_ERR_FUNCNAME, 0 );
            }
            else if( pFuncSym == &s___msgSync )
            {
               hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a SYNC method", HB_ERR_FUNCNAME, 0 );
            }
            else if( pFuncSym == &s___msgSyncClass )
            {
               hb_errRT_BASE( EG_ARG, 3004, "Cannot modify a CLASS SYNC method", HB_ERR_FUNCNAME, 0 );
            }
            else
            {
               PHB_ITEM pBlock = hb_param( 3, HB_IT_BLOCK );
               if( pBlock )
               {
                  if( pFuncSym == &s___msgEvalInline &&
                      pMethod->uiSprClass == uiClass )
                  {
                     hb_arraySet( s_pClasses[ pMethod->uiSprClass ]->pInlines,
                                  pMethod->uiData, pBlock );
                  }
                  else
                  {
                     hb_arrayAdd( pClass->pInlines, pBlock );
                     pMethod->uiData = ( HB_USHORT ) hb_arrayLen( pClass->pInlines );
                  }
               }
               else
               {
                  pFuncSym = hb_objGetFuncSym( hb_param( 3, HB_IT_ANY ) );
                  if( pFuncSym )
                  {
                     pMethod->pFuncSym = pFuncSym;
                     pMethod->uiData = 0;
                  }
                  else
                     hb_errRT_BASE( EG_ARG, 3000, NULL, HB_ERR_FUNCNAME, 0 );
               }
            }
         }
      }
   }
}


/* __objGetClsName( <hClass> | <oObj> ) --> <cClassName>
 *
 * Returns class name of <oObj> or <hClass>
 */
HB_FUNC( __OBJGETCLSNAME )
{
   HB_STACK_TLS_PRELOAD
   PHB_ITEM pObject = hb_param( 1, HB_IT_OBJECT );
   HB_USHORT uiClass;

   if( pObject )
      uiClass = pObject->item.asArray.value->uiClass;
   else
      uiClass = ( HB_USHORT ) hb_parni( 1 );

   hb_retc( hb_clsName( uiClass ) );
}


/* __objHasMsg( <oObj>, <cMsgName> | <sMsgName> ) --> <lRet>
 *
 * Is <cSymbol> a valid message for the <oObj>
 */
HB_FUNC( __OBJHASMSG )
{
   PHB_DYNS pMessage = hb_objGetMsgSym( hb_param( 2, HB_IT_ANY ) );

   if( pMessage )
   {
      HB_STACK_TLS_PRELOAD
      hb_retl( hb_objHasMessage( hb_param( 1, HB_IT_ANY ), pMessage ) );
   }
   else
      hb_errRT_BASE_SubstR( EG_ARG, 1099, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

/* __objHasMsgAssigned( <oObj>, <cMsgName> | <sMsgName> ) --> <lExists>
 *
 * checks if function exists and is not virtual
 */
HB_FUNC( __OBJHASMSGASSIGNED )
{
   PHB_DYNS pMessage = hb_objGetMsgSym( hb_param( 2, HB_IT_ANY ) );

   if( pMessage )
   {
      HB_STACK_TLS_PRELOAD
      PHB_SYMB pExecSym = hb_objGetMethod( hb_param( 1, HB_IT_ANY ),
                                           pMessage->pSymbol, NULL );
      hb_retl( pExecSym && pExecSym != &s___msgVirtual );
   }
   else
      hb_errRT_BASE_SubstR( EG_ARG, 1099, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

/* __objSendMsg( <oObj>, <cMsgName> | <sMsgName>, <xArg,..> ) --> <xRet>
 *
 * Send a message to an object
 */
HB_FUNC( __OBJSENDMSG )
{
   PHB_DYNS pMessage = hb_objGetMsgSym( hb_param( 2, HB_IT_ANY ) );

   if( pMessage )
   {
      HB_STACK_TLS_PRELOAD
      HB_USHORT uiPCount = hb_pcount();
      HB_USHORT uiParam;

      hb_vmPushSymbol( pMessage->pSymbol );     /* Push message symbol */
      hb_vmPush( hb_param( 1, HB_IT_ANY ) );    /* Push object */

      for( uiParam = 3; uiParam <= uiPCount; ++uiParam )    /* Push arguments on stack */
         hb_vmPush( hb_stackItemFromBase( uiParam ) );

      hb_vmSend( ( HB_USHORT ) ( uiPCount - 2 ) );             /* Execute message */
   }
   else
      hb_errRT_BASE( EG_ARG, 3000, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

/* __objClone( <oSource> ) --> <oNew>
 *
 * Clone an object. Note the similarity with aClone ;-)
 */
HB_FUNC( __OBJCLONE )
{
   HB_STACK_TLS_PRELOAD
   PHB_ITEM pObject = hb_param( 1, HB_IT_OBJECT );

   if( pObject )
      hb_arrayCloneTo( hb_stackReturnItem(), pObject );
   else
      hb_errRT_BASE( EG_ARG, 3001, NULL, HB_ERR_FUNCNAME, 0 );
}

/* __clsInstSuper( <cClassName> | <sClassFunc> ) --> <hClass>
 *
 * Instance super class and return class handle
 */
HB_FUNC( __CLSINSTSUPER )
{
   HB_STACK_TLS_PRELOAD
   PHB_ITEM pItem = hb_param( 1, HB_IT_STRING | HB_IT_SYMBOL );
   HB_USHORT uiClassH = 0, uiClass;
   PHB_SYMB pClassFuncSym = NULL;
   char szDesc[ 128 ];

   if( pItem )
   {
      if( HB_IS_SYMBOL( pItem ) )
         pClassFuncSym = hb_itemGetSymbol( pItem );
      else if( HB_IS_STRING( pItem ) )
      {
         PHB_DYNS pDynSym = hb_dynsymFindName( hb_itemGetCPtr( pItem ) );
         if( pDynSym )
            pClassFuncSym = pDynSym->pSymbol;
      }
      pClassFuncSym = hb_vmGetRealFuncSym( pClassFuncSym );
   }

   if( pClassFuncSym )
   {
      uiClassH = hb_clsFindClassByFunc( pClassFuncSym );
      if( uiClassH == 0 )
      {
         hb_vmPushSymbol( pClassFuncSym );
         hb_vmPushNil();
         hb_vmProc( 0 ); /* Execute super class */

         if( hb_vmRequestQuery() == 0 )
         {
            PHB_ITEM pObject = hb_stackReturnItem();

            if( HB_IS_OBJECT( pObject ) )
            {
               uiClass = pObject->item.asArray.value->uiClass;

               if( s_pClasses[ uiClass ]->pClassFuncSym == pClassFuncSym )
                  uiClassH = uiClass;
               else
               {
                  uiClassH = hb_clsFindClassByFunc( pClassFuncSym );
                  /* still not found, try to send NEW() message */
                  if( uiClassH == 0 )
                  {
                     hb_vmPushSymbol( &s___msgNew );
                     hb_vmPush( pObject );
                     hb_vmSend( 0 );

                     pObject = hb_stackReturnItem();
                     if( HB_IS_OBJECT( pObject ) )
                     {
                        uiClass = pObject->item.asArray.value->uiClass;
                        if( s_pClasses[ uiClass ]->pClassFuncSym == pClassFuncSym )
                           uiClassH = uiClass;
                     }
                  }
               }
            }

            /* This disables destructor execution for this object */
            if( uiClassH && HB_IS_OBJECT( pObject ) )
               pObject->item.asArray.value->uiClass = 0;
            else if( hb_vmRequestQuery() == 0 )
            {
               hb_snprintf( szDesc, sizeof( szDesc ),
                            "Super class '%s' does not return an object",
                            pClassFuncSym->szName );
               hb_errRT_BASE( EG_ARG, 3002, szDesc, HB_ERR_FUNCNAME, 0 );
            }
         }
      }
   }
   else
   {
      const char * pszName;

      pClassFuncSym = hb_itemGetSymbol( pItem );
      if( pClassFuncSym )
         pszName = pClassFuncSym->szName;
      else
         pszName = hb_itemGetCPtr( pItem );
      hb_snprintf( szDesc, sizeof( szDesc ),
                   "Cannot find super class '%s'", pszName );
      hb_errRT_BASE( EG_ARG, 3003, szDesc, HB_ERR_FUNCNAME, 0 );
   }

   hb_retni( uiClassH );
}

/* __clsAssocType( <hClass>, <cType> ) --> <lOK>
 *
 * Associate class with given basic type
 */
HB_FUNC( __CLSASSOCTYPE )
{
   HB_STACK_TLS_PRELOAD
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );
   PHB_ITEM pType = hb_param( 2, HB_IT_ANY );
   HB_BOOL fResult = HB_FALSE;

   if( uiClass && uiClass <= s_uiClasses && pType )
   {
      HB_TYPE nType = hb_clsGetItemType( pType, HB_IT_ANY );

      if( s_pClasses[ uiClass ]->uiDatas )
         hb_errRT_BASE( EG_ARG, 3005, "Scalar class can not contain instance variables", HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
      else if( nType != HB_IT_ANY )
      {
         switch( nType )
         {
            case HB_IT_ARRAY:
               s_uiArrayClass = uiClass;
               break;
            case HB_IT_BLOCK:
               s_uiBlockClass = uiClass;
               break;
            case HB_IT_STRING:
               s_uiCharacterClass = uiClass;
               break;
            case HB_IT_DATE:
               s_uiDateClass = uiClass;
               break;
            case HB_IT_TIMESTAMP:
               s_uiTimeStampClass = uiClass;
               break;
            case HB_IT_HASH:
               s_uiHashClass = uiClass;
               break;
            case HB_IT_LOGICAL:
               s_uiLogicalClass = uiClass;
               break;
            case HB_IT_NIL:
               s_uiNilClass = uiClass;
               break;
            case HB_IT_NUMERIC:
               s_uiNumericClass = uiClass;
               break;
            case HB_IT_SYMBOL:
               s_uiSymbolClass = uiClass;
               break;
            case HB_IT_POINTER:
               s_uiPointerClass = uiClass;
               break;
            default:
               uiClass = 0;
         }
         fResult = uiClass != 0;
      }
   }

   hb_retl( fResult );
}

/* __clsCntClasses() --> <nCount>
 *
 * Return number of classes
 */
HB_FUNC( __CLSCNTCLASSES )
{
   HB_STACK_TLS_PRELOAD
   hb_retni( ( int ) s_uiClasses );
}

/* __cls_CntClsData( <hClass> ) --> <nCount>
 *
 * Return number of class datas
 */
HB_FUNC( __CLS_CNTCLSDATA )
{
   HB_STACK_TLS_PRELOAD
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );

   hb_retni( uiClass && uiClass <= s_uiClasses ?
                  ( HB_USHORT ) hb_arrayLen( s_pClasses[ uiClass ]->pClassDatas ) : 0 );
}

/* __cls_CntShrData( <hClass> ) --> <nCount>
 *
 * Return number of class datas
 */
HB_FUNC( __CLS_CNTSHRDATA )
{
   HB_STACK_TLS_PRELOAD
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );

   hb_retni( uiClass && uiClass <= s_uiClasses ?
                  ( HB_USHORT ) hb_arrayLen( s_pClasses[ uiClass ]->pSharedDatas ) : 0 );
}

/* __cls_CntData( <hClass> ) --> <nCount>
 *
 * Return number of datas
 */
HB_FUNC( __CLS_CNTDATA )
{
   HB_STACK_TLS_PRELOAD
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );

   hb_retni( uiClass && uiClass <= s_uiClasses ?
             s_pClasses[ uiClass ]->uiDatas : 0 );
}

/* __cls_DecData( <hClass> ) --> <nCount>
 *
 * Decrease number of datas and return new value
 */
HB_FUNC( __CLS_DECDATA )
{
   HB_STACK_TLS_PRELOAD
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );

   if( uiClass && uiClass <= s_uiClasses &&
       s_pClasses[ uiClass ]->uiDatas > s_pClasses[ uiClass ]->uiDataFirst )
   {
      if( ! s_pClasses[ uiClass ]->fLocked )
         s_pClasses[ uiClass ]->uiDatas--;
      hb_retni( s_pClasses[ uiClass ]->uiDatas - s_pClasses[ uiClass ]->uiDataFirst );
   }
   else
      hb_retni( 0 );
}

/* __cls_IncData( <hClass> ) --> <nCount>
 *
 * Increase number of datas and return offset to new value
 */
HB_FUNC( __CLS_INCDATA )
{
   HB_STACK_TLS_PRELOAD
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );

   if( uiClass && uiClass <= s_uiClasses )
   {
      if( ! s_pClasses[ uiClass ]->fLocked )
         s_pClasses[ uiClass ]->uiDatas++;
      hb_retni( s_pClasses[ uiClass ]->uiDatas - s_pClasses[ uiClass ]->uiDataFirst );
   }
   else
      hb_retni( 0 );
}

/* NOTE: Undocumented Clipper function */
/* see for parameter compatibility with Clipper. */

HB_FUNC_TRANSLATE( __CLASSNEW, __CLSNEW )

/* NOTE: Undocumented Clipper function */

HB_FUNC_TRANSLATE( __CLASSINSTANCE, __CLSINST )

/* NOTE: Undocumented Clipper function */

HB_FUNC_TRANSLATE( __CLASSADD, __CLSADDMSG )

/* NOTE: Undocumented Clipper function */

HB_FUNC( __CLASSNAME )
{
   HB_STACK_TLS_PRELOAD
   hb_retc( hb_clsName( ( HB_USHORT ) hb_parni( 1 ) ) );
}

/* NOTE: Undocumented Clipper function */

HB_FUNC( __CLASSSEL )
{
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );
   PHB_ITEM pReturn = hb_itemNew( NULL );

   if( uiClass && uiClass <= s_uiClasses )
   {
      PCLASS pClass = s_pClasses[ uiClass ];
      PMETHOD pMethod = pClass->pMethods;
      HB_SIZE nLimit = hb_clsMthNum( pClass ), nPos = 0;

      hb_arrayNew( pReturn, pClass->uiMethods ); /* Create a transfer array */

      do
      {
         if( pMethod->pMessage )    /* Hash Entry used ? */
            hb_arraySetC( pReturn, ++nPos, pMethod->pMessage->pSymbol->szName );
         ++pMethod;
      }
      while( --nLimit );

      if( nPos < ( HB_SIZE ) pClass->uiMethods )
         hb_arraySize( pReturn, nPos );
   }

   hb_itemReturnRelease( pReturn );
}

/* to be used from Classes ERROR HANDLER method */
HB_FUNC( __GETMESSAGE )
{
   HB_STACK_TLS_PRELOAD
   hb_retc( hb_stackItem ( hb_stackBaseItem()->item.asSymbol.stackstate->nBaseItem )->item.asSymbol.value->szName );
}

/* __clsParent( <hClass>, <cParentClass> ) --> <lIsParent>
 * Checks if <cParentClass> is parent of <hClass>
 */
HB_FUNC( __CLSPARENT )
{
   HB_STACK_TLS_PRELOAD
   const char * szParentName = hb_parc( 2 );

   hb_retl( szParentName &&
            hb_clsIsParent( ( HB_USHORT ) hb_parni( 1 ), szParentName ) );
}

/* __Sender() --> <obj> | NIL
 * returns sender object
 */
HB_FUNC( __SENDER )
{
   HB_STACK_TLS_PRELOAD
   HB_ISIZ nOffset = hb_stackBaseProcOffset( 2 );

   if( nOffset > 0 )
   {
      PHB_ITEM pSelf = hb_stackItem( nOffset + 1 );

      /* Is it inline method? */
      if( nOffset > 0 && HB_IS_BLOCK( pSelf ) &&
          hb_stackItem( nOffset )->item.asSymbol.value == &hb_symEval )
      {
         pSelf = hb_stackItem( hb_stackItem( nOffset )->
                               item.asSymbol.stackstate->nBaseItem + 1 );
      }

      if( HB_IS_OBJECT( pSelf ) )
      {
         hb_itemReturn( pSelf );
      }
   }
}

HB_FUNC( __CLSSYNCSIGNAL )
{
#if defined( HB_MT_VM )
   hb_threadMutexSyncSignal( hb_param( 1, HB_IT_ANY ) );
#endif /* HB_MT_VM */
}

HB_FUNC( __CLSSYNCWAIT )
{
#if defined( HB_MT_VM )
   HB_STACK_TLS_PRELOAD
   PHB_ITEM pMutex = NULL;
   HB_ULONG ulMilliSec = HB_THREAD_INFINITE_WAIT;
   HB_ISIZ nOffset = hb_stackBaseProcOffset( 2 );

   if( nOffset > 0 )
   {
      PHB_ITEM pBase = hb_stackItem( nOffset );
      PHB_STACK_STATE pStack = pBase->item.asSymbol.stackstate;
      HB_USHORT uiClass = pStack->uiClass;

      if( uiClass && uiClass <= s_uiClasses )
      {
         PCLASS pClass = s_pClasses[ uiClass ];
         PMETHOD pMethod = pClass->pMethods + pStack->uiMethod;

         if( pMethod->pFuncSym == &s___msgSync )
         {
            PHB_ITEM pSelf = hb_stackItem( nOffset + 1 );

            /* Is it inline method? */
            if( HB_IS_BLOCK( pSelf ) && pBase->item.asSymbol.value == &hb_symEval )
               pSelf = hb_stackItem( pBase->item.asSymbol.stackstate->nBaseItem + 1 );

            uiClass = hb_objGetClass( pSelf );
            if( uiClass && uiClass <= s_uiClasses )
               pMutex = hb_arrayGetItemPtr( pSelf, s_pClasses[ uiClass ]->uiMutexOffset );
         }
         else if( pMethod->pFuncSym == &s___msgSyncClass )
            pMutex = pClass->pMutex;
      }
   }

   if( HB_ISNUM( 2 ) )
   {
      double dTimeOut = hb_parnd( 2 );
      if( dTimeOut > 0 )
         ulMilliSec = ( HB_ULONG ) ( dTimeOut * 10 );
   }

   hb_retl( hb_threadMutexSyncWait( hb_param( 1, HB_IT_ANY ), ulMilliSec, pMutex ) );
#endif /* HB_MT_VM */
}

/* __classH( <obj> ) --> <hClass>
 *
 * Returns class handle of <obj>
 */
HB_FUNC( __CLASSH )
{
   HB_STACK_TLS_PRELOAD
   PHB_ITEM pObject = hb_param( 1, HB_IT_ANY );

   hb_retni( pObject ? hb_objGetClassH( pObject ) : 0 );
}

/* --- */

/* <hClass> := <obj>:ClassH()
 *
 * Returns class handle of <obj>
 */
HB_FUNC_STATIC( msgClassH )
{
   HB_STACK_TLS_PRELOAD
   hb_retni( hb_stackBaseItem()->item.asSymbol.stackstate->uiClass );
}


/* <cClassName> := <obj>:ClassName()
 *
 * Return class name of <obj>. Can also be used for all types.
 */
HB_FUNC_STATIC( msgClassName )
{
   HB_STACK_TLS_PRELOAD
   HB_USHORT uiClass = hb_stackBaseItem()->item.asSymbol.stackstate->uiClass;

   if( uiClass )
      hb_retc( s_pClasses[ uiClass ]->szName );
   else
      hb_retc( hb_objGetClsName( hb_stackSelfItem() ) );
}


static int hb_methodType( PMETHOD pMethod )
{
   PHB_SYMB pFuncSym = pMethod->pFuncSym;

   if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass )
      pFuncSym = pMethod->pRealSym;

   if     ( pFuncSym == &s___msgSetClsData ||
            pFuncSym == &s___msgGetClsData ||
            pFuncSym == &s___msgSetShrData ||
            pFuncSym == &s___msgGetShrData )
      return HB_OO_MSG_CLASSDATA;

   else if( pFuncSym == &s___msgSetData ||
            pFuncSym == &s___msgGetData )
      return HB_OO_MSG_DATA;

   else if( pFuncSym == &s___msgEvalInline )
      return HB_OO_MSG_INLINE;

   else if( pFuncSym == &s___msgVirtual )
      return HB_OO_MSG_VIRTUAL;

   else if( pFuncSym == &s___msgSuper )
      return HB_OO_MSG_SUPER;

   else if( pFuncSym == &s___msgRealClass )
      return HB_OO_MSG_REALCLASS;

   else if( pFuncSym == &s___msgDelegate )
      return HB_OO_MSG_DELEGATE;

   else if( pFuncSym == &s___msgPerform )
      return HB_OO_MSG_PERFORM;

   else if( pMethod->pMessage == s___msgOnError.pDynSym )
      return HB_OO_MSG_ONERROR;

   else if( pMethod->pMessage == s___msgDestructor.pDynSym )
      return HB_OO_MSG_DESTRUCTOR;

   else
      return HB_OO_MSG_METHOD;
}

/* <aMessages> := <obj>:ClassSel()
 *
 * Returns all the messages in <obj>
 */
HB_FUNC_STATIC( msgClassSel )
{
   HB_STACK_TLS_PRELOAD
   HB_USHORT uiClass = hb_stackBaseItem()->item.asSymbol.stackstate->uiClass;

   if( uiClass && uiClass <= s_uiClasses )
   {
      PHB_ITEM pReturn;
      PCLASS pClass = s_pClasses[ uiClass ];
      PMETHOD pMethod = pClass->pMethods;
      HB_SIZE nLimit = hb_clsMthNum( pClass ), nPos = 0;
      HB_USHORT nParam, nScope;
      HB_BOOL lFull;

      nParam = ( HB_USHORT ) hb_parnidef( 1, HB_MSGLISTALL );
      nScope = ( HB_USHORT ) hb_parni( 2 );
      lFull = hb_parl( 3 );
      pReturn = hb_itemArrayNew( pClass->uiMethods );

      do
      {
         if( pMethod->pMessage )  /* Hash Entry used ? */
         {
            if( ( nParam == HB_MSGLISTALL ) ||
                ( nParam == HB_MSGLISTCLASS &&
                  hb_methodType( pMethod ) == HB_OO_MSG_CLASSDATA ) ||
                ( nParam == HB_MSGLISTPURE &&
                  hb_methodType( pMethod ) != HB_OO_MSG_CLASSDATA ) )
            {
               if( nScope == 0 || ( pMethod->uiScope & nScope ) != 0 )
               {
                  if( lFull )
                  {
                     PHB_ITEM pItem = hb_arrayGetItemPtr( pReturn, ++nPos );
                     if( pItem )
                     {
                        hb_arrayNew( pItem, 4 );
                        hb_arraySetC( pItem, HB_OO_DATA_SYMBOL,
                                      pMethod->pMessage->pSymbol->szName );
                        hb_arraySetNI( pItem, HB_OO_DATA_TYPE, hb_methodType( pMethod ) );
                        hb_arraySetNI( pItem, HB_OO_DATA_SCOPE, pMethod->uiScope );
                     }
                  }
                  else
                     hb_arraySetC( pReturn, ++nPos,
                                   pMethod->pMessage->pSymbol->szName );
               }
            }
         }
         ++pMethod;
      }
      while( --nLimit && nPos < ( HB_SIZE ) pClass->uiMethods );

      if( nPos < ( HB_SIZE ) pClass->uiMethods )
         hb_arraySize( pReturn, nPos );
      hb_itemReturnRelease( pReturn );
   }
}

#if 0

/* __msgClass()
 *
 * Internal function to return Self at Self:Class call (classy compatibility)
 */
HB_FUNC_STATIC( msgClass )
{
   hb_itemReturnForward( hb_stackSelfItem() );
}

/* Added by JfL&RaC
 * <logical> <= <obj>:IsDerivedFrom( xParam )
 *
 * Return true if <obj> is derived from xParam.
 * xParam can be either an obj or a classname
 */
HB_FUNC_STATIC( msgClassParent )
{
   HB_BOOL fHasParent = HB_FALSE;
   PHB_ITEM pItem;
   HB_USHORT uiClass;

   uiClass = hb_stackBaseItem()->item.asSymbol.stackstate->uiClass;
   pItemParam = hb_param( 1, HB_IT_ANY );

   if( pItemParam && uiClass && uiClass <= s_uiClasses )
   {
      if( HB_IS_OBJECT( pItemParam ) )
         fHasParent = hb_clsHasParentClass( s_pClasses[ uiClass ],
                                   pItemParam->item.asArray.value->uiClass );
      else if( HB_IS_STRING( pItemParam ) )
         fHasParent = hb_clsIsParent( uiClass, hb_parc( pItemParam ) )
   }

   hb_retl( fHasParent );
}

#endif


/* __msgEvalInline()
 *
 * Internal function executed for inline methods
 */
HB_FUNC_STATIC( msgEvalInline )
{
   HB_STACK_TLS_PRELOAD
   PHB_STACK_STATE pStack = hb_stackBaseItem()->item.asSymbol.stackstate;
   PCLASS pClass   = s_pClasses[ pStack->uiClass ];
   PMETHOD pMethod = pClass->pMethods + pStack->uiMethod;
   HB_USHORT uiPCount = hb_pcount(), uiParam;
   PHB_ITEM pBlock;

   hb_vmPushEvalSym();

   hb_vmPush( hb_arrayGetItemPtr( s_pClasses[ pMethod->uiSprClass ]->pInlines,
                                  pMethod->uiData ) );
   pBlock = hb_stackItemFromTop( -1 );    /* Push block */
   pBlock->item.asBlock.hclass = pStack->uiClass;
   pBlock->item.asBlock.method = pStack->uiMethod;

   hb_vmPush( hb_stackSelfItem() );       /* Push self as first argument */

   for( uiParam = 1; uiParam <= uiPCount; uiParam++ )
   {
      hb_vmPush( hb_stackItemFromBase( uiParam ) );
   }

   hb_vmEval( ( HB_USHORT ) ( uiPCount + 1 ) );
}

HB_FUNC_STATIC( msgPerform )
{
   HB_STACK_TLS_PRELOAD
   PHB_ITEM pItem = hb_param( 1, HB_IT_ANY );

   if( pItem )
   {
      HB_USHORT uiPCount = hb_pcount(), uiParam;
      PHB_SYMB pSym = NULL;

      if( HB_IS_SYMBOL( pItem ) )
         pSym = pItem->item.asSymbol.value;

      else if( HB_IS_OBJECT( pItem ) &&
               s_pClasses[ pItem->item.asArray.value->uiClass ]->pClassSym ==
               s___msgSymbol.pDynSym )
      {
         /* Dirty hack */
         pItem = hb_arrayGetItemPtr( pItem, 1 );
         if( pItem && HB_IS_SYMBOL( pItem ) )
            pSym = pItem->item.asSymbol.value;
      }

      if( pSym )
      {
         hb_vmPushSymbol( pSym );
         hb_vmPush( hb_stackSelfItem() );

         for( uiParam = 2; uiParam <= uiPCount; uiParam++ )
         {
            hb_vmPush( hb_stackItemFromBase( uiParam ) );
         }
         hb_vmSend( ( HB_USHORT ) ( uiPCount - 1 ) );
      }
   }
}

HB_FUNC_STATIC( msgDelegate )
{
   HB_STACK_TLS_PRELOAD
   PHB_STACK_STATE pStack = hb_stackBaseItem()->item.asSymbol.stackstate;
   PCLASS pClass   = s_pClasses[ pStack->uiClass ];
   PMETHOD pMethod = pClass->pMethods + pStack->uiMethod;
   PHB_SYMB pExecSym = pClass->pMethods[ pMethod->uiData ].pFuncSym;

   if( pExecSym )
      HB_VM_FUNCUNREF( pExecSym );
   if( pExecSym && HB_VM_ISFUNC( pExecSym ) )
   {
      HB_VM_EXECUTE( pExecSym );
   }
   else
   {
      HB_FUNC_EXEC( msgNoMethod );
   }
}

HB_FUNC_STATIC( msgSync )
{
   HB_STACK_TLS_PRELOAD
   PHB_STACK_STATE pStack = hb_stackBaseItem()->item.asSymbol.stackstate;
   PCLASS pClass = s_pClasses[ pStack->uiClass ];
   PMETHOD pMethod = pClass->pMethods + pStack->uiMethod;
   PHB_SYMB pExecSym = pMethod->pRealSym;

   if( pExecSym )
      HB_VM_FUNCUNREF( pExecSym );
   if( pExecSym && HB_VM_ISFUNC( pExecSym ) )
   {
      PHB_ITEM pObject = hb_stackSelfItem();
      HB_USHORT uiClass = hb_objGetClass( pObject );
      PHB_ITEM pMutex = NULL;

      if( uiClass && uiClass <= s_uiClasses )
         pMutex = hb_arrayGetItemPtr( pObject, s_pClasses[ uiClass ]->uiMutexOffset );

      if( ! pMutex || hb_threadMutexLock( pMutex ) )
      {
         HB_VM_EXECUTE( pExecSym );
         if( pMutex )
            hb_threadMutexUnlock( pMutex );
      }
   }
   else
   {
      HB_FUNC_EXEC( msgNoMethod );
   }
}

HB_FUNC_STATIC( msgSyncClass )
{
   HB_STACK_TLS_PRELOAD
   PHB_STACK_STATE pStack = hb_stackBaseItem()->item.asSymbol.stackstate;
   PCLASS pClass = s_pClasses[ pStack->uiClass ];
   PMETHOD pMethod = pClass->pMethods + pStack->uiMethod;
   PHB_SYMB pExecSym = pMethod->pRealSym;

   if( pExecSym )
      HB_VM_FUNCUNREF( pExecSym );
   if( pExecSym && HB_VM_ISFUNC( pExecSym ) )
   {
      if( ! pClass->pMutex || hb_threadMutexLock( pClass->pMutex ) )
      {
         HB_VM_EXECUTE( pExecSym );
         if( pClass->pMutex )
            hb_threadMutexUnlock( pClass->pMutex );
      }
   }
   else
   {
      HB_FUNC_EXEC( msgNoMethod );
   }
}

/* __msgNoMethod()
 *
 * Internal function for generating error when not existing message is sent
 */
HB_FUNC_STATIC( msgNoMethod )
{
   HB_STACK_TLS_PRELOAD
   PHB_SYMB pSym = hb_itemGetSymbol( hb_stackBaseItem() );

#if 1  /* Clipper compatible error message */
   if( pSym->szName[ 0 ] == '_' )
      hb_errRT_BASE_SubstR( EG_NOVARMETHOD, 1005, NULL, pSym->szName + 1, HB_ERR_ARGS_SELFPARAMS );
   else
      hb_errRT_BASE_SubstR( EG_NOMETHOD, 1004, NULL, pSym->szName, HB_ERR_ARGS_SELFPARAMS );
#else
   char szDesc[ 40 + HB_SYMBOL_NAME_LEN ];

   if( pSym->szName[ 0 ] == '_' )
   {
      hb_snprintf( szDesc, sizeof( szDesc ), "Class: '%s' has no property", hb_objGetClsName( hb_stackSelfItem() ) );
      hb_errRT_BASE_SubstR( EG_NOVARMETHOD, 1005, szDesc, pSym->szName + 1, HB_ERR_ARGS_BASEPARAMS );
   }
   else
   {
      hb_snprintf( szDesc, sizeof( szDesc ), "Class: '%s' has no exported method", hb_objGetClsName( hb_stackSelfItem() ) );
      hb_errRT_BASE_SubstR( EG_NOMETHOD, 1004, szDesc, pSym->szName, HB_ERR_ARGS_BASEPARAMS );
   }
#endif
}

/* __msgScopeErr()
 *
 * Internal function for generating error when not existing message is sent
 */
HB_FUNC_STATIC( msgScopeErr )
{
   HB_STACK_TLS_PRELOAD
   char * pszProcName;
   PHB_ITEM pObject = hb_stackSelfItem();
   PMETHOD pMethod = s_pClasses[
      hb_stackBaseItem()->item.asSymbol.stackstate->uiClass ]->pMethods +
      hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod;

   pszProcName = hb_xstrcpy( NULL, hb_objGetClsName( pObject ), ":",
                             pMethod->pMessage->pSymbol->szName, NULL );
   if( pMethod->uiScope & HB_OO_CLSTP_HIDDEN )
      hb_errRT_BASE( EG_NOMETHOD, 41, "Scope violation (hidden)", pszProcName, 0 );
   else
      hb_errRT_BASE( EG_NOMETHOD, 42, "Scope violation (protected)", pszProcName, 0 );
   hb_xfree( pszProcName );
}

HB_FUNC_STATIC( msgTypeErr )
{
   HB_STACK_TLS_PRELOAD
   char * pszProcName;
   PHB_ITEM pObject = hb_stackSelfItem();
   PMETHOD pMethod = s_pClasses[
      hb_stackBaseItem()->item.asSymbol.stackstate->uiClass ]->pMethods +
      hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod;

   pszProcName = hb_xstrcpy( NULL, hb_objGetClsName( pObject ), ":",
                             pMethod->pMessage->pSymbol->szName + 1, NULL );
   hb_errRT_BASE( EG_NOMETHOD, 44, "Assigned value is wrong class", pszProcName, HB_ERR_ARGS_BASEPARAMS );
   hb_xfree( pszProcName );
}

/* __msgSuper()
 *
 * Internal function to return a superobject
 */
HB_FUNC_STATIC( msgSuper )
{
   HB_STACK_TLS_PRELOAD
   PHB_STACK_STATE pStack = hb_stackBaseItem()->item.asSymbol.stackstate;

   hb_clsMakeSuperObject( hb_stackReturnItem(), hb_stackSelfItem(),
      s_pClasses[ pStack->uiClass ]->pMethods[ pStack->uiMethod ].uiData );
}

/* __msgRealClass()
 *
 * Internal function to return a superobject of class where the method was
 * defined
 */
HB_FUNC_STATIC( msgRealClass )
{
   HB_STACK_TLS_PRELOAD
   PHB_ITEM pObject = hb_stackSelfItem();
   HB_USHORT uiClass = hb_clsSenderMethodClass();
   HB_USHORT uiCurClass = hb_objGetClassH( pObject );

   if( uiClass && uiClass != uiCurClass &&
       hb_clsSenderObjectClass() == uiCurClass )
   {
      hb_clsMakeSuperObject( hb_stackReturnItem(), pObject, uiClass );
   }
   else
   {
      hb_itemReturnForward( pObject );
   }
}

/* __msgGetClsData()
 *
 * Internal function to return a CLASSDATA
 */
HB_FUNC_STATIC( msgGetClsData )
{
   HB_STACK_TLS_PRELOAD
   PCLASS pClass   = s_pClasses[
                  hb_stackBaseItem()->item.asSymbol.stackstate->uiClass ];
   PMETHOD pMethod = pClass->pMethods +
                  hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod;

   hb_arrayGet( pClass->pClassDatas, pMethod->uiData, hb_stackReturnItem() );
}


/* __msgSetClsData()
 *
 * Internal function to set a CLASSDATA
 */
HB_FUNC_STATIC( msgSetClsData )
{
   HB_STACK_TLS_PRELOAD
   PCLASS pClass   = s_pClasses[
                  hb_stackBaseItem()->item.asSymbol.stackstate->uiClass ];
   PMETHOD pMethod = pClass->pMethods +
                  hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod;
   PHB_ITEM pReturn = hb_param( 1, HB_IT_ANY );

   if( ! pReturn )
      hb_arrayGet( pClass->pClassDatas, pMethod->uiData, hb_stackReturnItem() );

   else
   {
      if( pMethod->itemType &&
          ! ( pMethod->itemType & HB_ITEM_TYPERAW( pReturn ) ) )
      {
         if( pMethod->itemType == HB_IT_NUMINT && HB_IS_NUMERIC( pReturn ) )
            hb_itemPutNInt( pReturn, hb_itemGetNInt( pReturn ) );
         else
         {
            ( s___msgTypeErr.value.pFunPtr )();
            return;
         }
      }

      hb_arraySet( pClass->pClassDatas, pMethod->uiData, pReturn );
      hb_itemReturn( pReturn );
   }
}

/* __msgGetShrData()
 *
 * Internal function to return a SHAREDDATA
 */
HB_FUNC_STATIC( msgGetShrData )
{
   HB_STACK_TLS_PRELOAD
   PCLASS pClass   = s_pClasses[
                  hb_stackBaseItem()->item.asSymbol.stackstate->uiClass ];
   PMETHOD pMethod = pClass->pMethods +
                  hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod;

   hb_arrayGet( s_pClasses[ pMethod->uiSprClass ]->pSharedDatas,
                pMethod->uiData, hb_stackReturnItem() );
}

/* __msgSetShrData()
 *
 * Internal function to set a SHAREDDATA
 */
HB_FUNC_STATIC( msgSetShrData )
{
   HB_STACK_TLS_PRELOAD
   PCLASS pClass   = s_pClasses[
                  hb_stackBaseItem()->item.asSymbol.stackstate->uiClass ];
   PMETHOD pMethod = pClass->pMethods +
                  hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod;
   PHB_ITEM pReturn = hb_param( 1, HB_IT_ANY );

   if( ! pReturn )
      hb_arrayGet( s_pClasses[ pMethod->uiSprClass ]->pSharedDatas,
                   pMethod->uiData, hb_stackReturnItem() );
   else
   {
      if( pMethod->itemType &&
          ! ( pMethod->itemType & HB_ITEM_TYPERAW( pReturn ) ) )
      {
         if( pMethod->itemType == HB_IT_NUMINT && HB_IS_NUMERIC( pReturn ) )
            hb_itemPutNInt( pReturn, hb_itemGetNInt( pReturn ) );
         else
         {
            ( s___msgTypeErr.value.pFunPtr )();
            return;
         }
      }

      hb_arraySet( s_pClasses[ pMethod->uiSprClass ]->pSharedDatas,
                   pMethod->uiData, pReturn );
      hb_itemReturn( pReturn );
   }
}

/* __msgGetData()
 *
 * Internal function to return a DATA
 */
HB_FUNC_STATIC( msgGetData )
{
   HB_STACK_TLS_PRELOAD
   PHB_ITEM pObject  = hb_stackSelfItem();

   if( HB_IS_ARRAY( pObject ) )
   {
      HB_USHORT uiObjClass = pObject->item.asArray.value->uiClass;
      HB_USHORT uiClass    = hb_stackBaseItem()->item.asSymbol.stackstate->uiClass;
      PCLASS pClass        = s_pClasses[ uiClass ];
      PMETHOD pMethod      = pClass->pMethods +
                             hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod;
      HB_SIZE nIndex       = pMethod->uiData;

      if( uiClass != uiObjClass )
      {
         nIndex += hb_clsParentInstanceOffset( s_pClasses[ uiObjClass ],
                                               pMethod->uiSprClass );
      }
      else
      {
         nIndex += pMethod->uiOffset;
      }

      hb_arrayGet( pObject, nIndex, hb_stackReturnItem() );
   }
}

/* __msgSetData()
 *
 * Internal function to set a DATA
 */
HB_FUNC_STATIC( msgSetData )
{
   HB_STACK_TLS_PRELOAD
   PHB_ITEM pObject  = hb_stackSelfItem();

   if( HB_IS_ARRAY( pObject ) )
   {
      PHB_ITEM pReturn     = hb_param( 1, HB_IT_ANY );
      HB_USHORT uiObjClass = pObject->item.asArray.value->uiClass;
      HB_USHORT uiClass    = hb_stackBaseItem()->item.asSymbol.stackstate->uiClass;
      PCLASS pClass        = s_pClasses[ uiClass ];
      PMETHOD pMethod      = pClass->pMethods +
                             hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod;
      HB_SIZE nIndex       = pMethod->uiData;

      if( uiClass != uiObjClass )
      {
         nIndex += hb_clsParentInstanceOffset( s_pClasses[ uiObjClass ],
                                               pMethod->uiSprClass );
      }
      else
      {
         nIndex += pMethod->uiOffset;
      }

      if( ! pReturn )
         hb_arrayGet( pObject, nIndex, hb_stackReturnItem() );

      else
      {
         if( pMethod->itemType &&
             ! ( pMethod->itemType & HB_ITEM_TYPERAW( pReturn ) ) )
         {
            if( pMethod->itemType == HB_IT_NUMINT && HB_IS_NUMERIC( pReturn ) )
               hb_itemPutNInt( pReturn, hb_itemGetNInt( pReturn ) );
            else
            {
               ( s___msgTypeErr.value.pFunPtr )();
               return;
            }
         }

         /* will arise only if the class has been modified after first instance */
         if( nIndex > hb_arrayLen( pObject ) ) /* Resize needed ? */
            hb_arraySize( pObject, nIndex );   /* Make large enough */
         hb_arraySet( pObject, nIndex, pReturn );
         hb_itemReturn( pReturn );
      }
   }
}

/* No comment :-) */
HB_FUNC_STATIC( msgVirtual )
{
   #if 0
   hb_ret(); /* NOTE: It's safe to have this commented out. */
   #endif
}

HB_FUNC_STATIC( msgNull )
{
}

#ifndef HB_NO_PROFILER
void hb_mthAddTime( HB_ULONG ulClockTicks )
{
   HB_STACK_TLS_PRELOAD
   PHB_ITEM pObject = hb_stackSelfItem();
   PCLASS pClass = s_pClasses[ hb_objGetClassH( pObject ) ];
   HB_USHORT uiMethod = hb_stackBaseItem()->item.asSymbol.stackstate->uiMethod;

   if( pClass && uiMethod < hb_clsMthNum( pClass ) )
   {
      PMETHOD pMethod = pClass->pMethods + uiMethod;
      pMethod->ulCalls++;
      pMethod->ulTime += ulClockTicks;
      return;
   }

   if( HB_IS_BLOCK( pObject ) )
   {
      PHB_SYMB pSym = hb_stackBaseItem()->item.asSymbol.value;

      if( pSym == &hb_symEval || pSym->pDynSym == hb_symEval.pDynSym )
      {
         pSym->pDynSym->ulCalls++;
         if( --pSym->pDynSym->ulRecurse == 0 )
            pSym->pDynSym->ulTime += ulClockTicks;
      }
   }
}
#endif

/* __GetMsgPrf( <hClass>, <cMsg> ) --> <aMethodInfo> { { <nTimes>, <nTime> }, ... } */
HB_FUNC( __GETMSGPRF ) /* profiler: returns a method called and consumed times */
{
   HB_STACK_TLS_PRELOAD
#ifndef HB_NO_PROFILER
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );
   const char * cMsg = hb_parc( 2 );

   hb_reta( 2 );
   if( uiClass && uiClass <= s_uiClasses && cMsg && *cMsg )
   {
      PHB_DYNS pMsg = hb_dynsymFindName( cMsg );

      if( pMsg )
      {
         PMETHOD pMethod = hb_clsFindMsg( s_pClasses[ uiClass ], pMsg );

         if( pMethod )
         {
            hb_storvnl( pMethod->ulCalls, -1, 1 );
            hb_storvnl( pMethod->ulTime, -1, 2 );
            return;
         }
      }
   }
#else
   hb_reta( 2 );
#endif
   hb_storvnl( 0, -1, 1 );
   hb_storvnl( 0, -1, 2 );
}

typedef struct
{
   PMETHOD   pMethod;
   HB_USHORT uiClass;
   HB_USHORT uiStatus;
}
HB_IVARINFO, * PHB_IVARINFO;

static PHB_ITEM hb_objGetIVars( PHB_ITEM pObject,
                                HB_USHORT uiScope, HB_BOOL fChanged )
{
   PHB_IVARINFO pIndex, pInfo;
   PCLASS pClass;
   PMETHOD pMethod;
   PHB_ITEM pReturn, pItem;
   HB_SIZE nLimit, nLen, nCount, nSize, nIndex, nOffset;
   HB_USHORT uiClass, uiSuperClasses;

   if( ! pObject || ! HB_IS_OBJECT( pObject ) )
      return NULL;

   uiClass = pObject->item.asArray.value->uiClass;
   pClass = s_pClasses[ uiClass ];
   nLen = nCount = hb_arrayLen( pObject );
   nSize = 0;
   pIndex = nLen ? ( PHB_IVARINFO ) hb_xgrabz( nLen * sizeof( HB_IVARINFO ) ) : NULL;

   if( fChanged && pClass->uiInitDatas )
   {
      PINITDATA pInitData = pClass->pInitData;

      nLimit = pClass->uiInitDatas;
      do
      {
         if( pInitData->uiType == HB_OO_MSG_DATA )
         {
            nIndex = pInitData->uiData + pInitData->uiOffset;
            pItem = hb_arrayGetItemPtr( pObject, nIndex );
            if( pItem )
            {
               if( hb_itemEqual( pItem, pInitData->pInitValue ) )
               {
                  pIndex[ nIndex - 1 ].uiStatus = 3;
                  --nCount;
               }
               else
                  pIndex[ nIndex - 1 ].uiStatus = 1;
            }
         }
         ++pInitData;
      }
      while( --nLimit );
   }

   uiSuperClasses = pClass->uiSuperClasses;
   nOffset = 0;
   nLimit = hb_clsMthNum( pClass );
   pMethod = pClass->pMethods;
   while( nCount && nLimit )
   {
      if( pMethod->pMessage &&
          ( uiScope == 0 || ( pMethod->uiScope & uiScope ) != 0 ) &&
          ( uiClass == pClass->uiClass || uiClass == pMethod->uiSprClass ) )
      {
         PHB_SYMB pFuncSym = pMethod->pFuncSym;

         if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass )
            pFuncSym = pMethod->pRealSym;

         if( pFuncSym == &s___msgGetData || pFuncSym == &s___msgSetData )
         {
            HB_USHORT uiStatus = pFuncSym == &s___msgGetData ? 3 : 2;

            nIndex = ( uiClass == pClass->uiClass ?
                     ( HB_SIZE ) pMethod->uiOffset : nOffset ) + pMethod->uiData;
            if( nIndex == 0 || nIndex > nLen )
               hb_errInternal( HB_EI_CLSINVMETHOD, NULL, "__objGetIVars()", NULL );

            pInfo = &pIndex[ nIndex - 1 ];
            if( pInfo->uiStatus < uiStatus )
            {
               pItem = hb_arrayGetItemPtr( pObject, nIndex );
               if( ! pItem || ( pInfo->uiStatus == 0 && HB_IS_NIL( pItem ) ) )
                  uiStatus = 3;
               else
               {
                  if( ! pInfo->pMethod )
                     ++nSize;
                  pInfo->pMethod = pMethod;
                  pInfo->uiClass = uiClass;
               }
               pInfo->uiStatus = uiStatus;
               if( uiStatus == 3 )
                  --nCount;
            }
         }
      }
      ++pMethod;
      if( --nLimit == 0 )
      {
         if( uiSuperClasses-- )
         {
            if( uiClass == pClass->pSuperClasses[ uiSuperClasses ].uiClass )
               if( uiSuperClasses-- == 0 )
                  break;
            uiClass = pClass->pSuperClasses[ uiSuperClasses ].uiClass;
            nOffset = pClass->pSuperClasses[ uiSuperClasses ].uiOffset;
            nLimit = hb_clsMthNum( s_pClasses[ uiClass ] );
            pMethod = s_pClasses[ uiClass ]->pMethods;
         }
      }
   }

   nCount = 0;
   pReturn = hb_itemArrayNew( nSize );
   for( nIndex = 1; nIndex <= nLen && nCount < nSize; ++nIndex )
   {
      pInfo = &pIndex[ nIndex - 1 ];
      if( pInfo->pMethod )
      {
         const char * pszVar = pInfo->pMethod->pMessage->pSymbol->szName;
         PHB_ITEM pValue = hb_arrayGetItemPtr( pReturn, ++nCount );

         hb_arrayNew( pValue, 2 );
         if( pInfo->uiClass != pClass->uiClass )
         {
            char * pszCast = hb_xstrcpy( NULL, s_pClasses[ pInfo->uiClass ]->szName,
                                         ":", pszVar, NULL );
            hb_arraySetCPtr( pValue, 1, pszCast );
         }
         else
            hb_arraySetCConst( pValue, 1, pszVar );
         hb_arraySet( pValue, 2, hb_arrayGetItemPtr( pObject, nIndex ) );
      }
   }

   if( pIndex )
      hb_xfree( pIndex );

   return pReturn;
}

static void hb_objSetIVars( PHB_ITEM pObject, PHB_ITEM pArray )
{
   if( pObject && HB_IS_OBJECT( pObject ) &&
       pArray && HB_IS_ARRAY( pArray ) &&
       pArray->item.asArray.value->uiClass == 0 )
   {
      HB_USHORT uiClass = pObject->item.asArray.value->uiClass;
      HB_SIZE nPos, nIndex, nLen;
      PHB_ITEM pValue;

      nPos = 0;
      while( ( pValue = hb_arrayGetItemPtr( pArray, ++nPos ) ) != NULL )
      {
         const char * pszMethod = hb_arrayGetCPtr( pValue, 1 );
         PHB_DYNS pVarSym = hb_dynsymFind( pszMethod );
         PHB_ITEM pNewVal = hb_arrayGetItemPtr( pValue, 2 );
         HB_USHORT uiSuper = uiClass;

         if( ! pVarSym )
         {
            const char * pszClass = strchr( pszMethod, ':' );
            if( pszClass )
            {
               nLen = pszClass - pszMethod;
               if( nLen )
               {
                  PHB_DYNS pParentSym;
                  char szClassName[ HB_SYMBOL_NAME_LEN + 1 ];

                  if( nLen > HB_SYMBOL_NAME_LEN )
                     nLen = HB_SYMBOL_NAME_LEN;
                  memcpy( szClassName, pszMethod, nLen );
                  szClassName[ nLen ] = '\0';
                  pParentSym = hb_dynsymFindName( szClassName );
                  uiSuper = pParentSym == NULL ? 0 :
                            hb_clsGetParent( s_pClasses[ uiClass ], pParentSym );
               }
               pVarSym = hb_dynsymFindName( pszClass + 1 );
            }
            else
               pVarSym = hb_dynsymFindName( pszMethod );
         }
         if( uiSuper && pNewVal && pVarSym &&
             ( nIndex = hb_clsGetVarIndexEx( uiClass, pVarSym, uiSuper ) ) != 0 )
         {
            hb_arraySet( pObject, nIndex, pNewVal );
         }
      }
   }
}

/* __objGetIVars( <oObject>, [<nScope>], [<lChanged>] )
 *          --> <aIVars> { { <cName>, <xVal> }, ... }
 */
HB_FUNC( __OBJGETIVARS )
{
   PHB_ITEM pObject = hb_param( 1, HB_IT_OBJECT );
   HB_USHORT uiScope = ( HB_USHORT ) hb_parni( 2 );
   HB_BOOL fChanged = hb_parldef( 3, HB_TRUE );

   hb_itemReturnRelease( hb_objGetIVars( pObject, uiScope, fChanged ) );
}

/* __objSetIVars( <oObject> | <hClass> | <cClassName> | <sClassFunc>,
 *                <aIVars> ) --> <oObject>
 */
HB_FUNC( __OBJSETIVARS )
{
   PHB_ITEM pObject = hb_param( 1, HB_IT_ANY );
   PHB_ITEM pArray = hb_param( 2, HB_IT_ARRAY );

   if( pObject && pArray )
   {
      PHB_ITEM pNewObj = NULL;

      if( HB_IS_NUMERIC( pObject ) )
         pObject = pNewObj = hb_clsInst( ( HB_USHORT ) hb_itemGetNI( pObject ) );
      else if( HB_IS_STRING( pObject ) )
         pObject = pNewObj = hb_clsInst( hb_clsFindClass( hb_itemGetCPtr( pObject ), NULL ) );
      else if( HB_IS_SYMBOL( pObject ) )
         pObject = pNewObj = hb_clsInst( hb_clsFindClassByFunc( hb_itemGetSymbol( pObject ) ) );
      else if( ! HB_IS_OBJECT( pObject ) )
         pObject = NULL;

      hb_objSetIVars( pObject, pArray );

      if( pObject )
         hb_itemReturn( pObject );
      if( pNewObj )
         hb_itemRelease( pNewObj );
   }
}

/* __objRestoreIVars( <aIVars>, <hClass> | <sClassFunc> |
                                <cClassName>[, <cClassFuncName>] ) --> <oObject>
 */
HB_FUNC( __OBJRESTOREIVARS )
{
   PHB_ITEM pArray = hb_param( 1, HB_IT_ARRAY );
   PHB_ITEM pClass = hb_param( 2, HB_IT_NUMERIC | HB_IT_STRING | HB_IT_SYMBOL );

   if( pClass && pArray && pArray->item.asArray.value->uiClass == 0 )
   {
      PHB_ITEM pObject = NULL;


      if( HB_IS_NUMERIC( pClass ) )
         pObject = hb_clsInst( ( HB_USHORT ) hb_itemGetNI( pClass ) );
      else if( HB_IS_STRING( pClass ) )
         pObject = hb_clsInst( hb_clsFindClass( hb_itemGetCPtr( pClass ), hb_parc( 3 ) ) );
      else if( HB_IS_SYMBOL( pClass ) )
         pObject = hb_clsInst( hb_clsFindClassByFunc( hb_itemGetSymbol( pClass ) ) );

      if( pObject )
      {
         hb_objSetIVars( pObject, pArray );
         hb_arraySwap( pObject, pArray );
         hb_itemRelease( pObject );
      }
   }

   hb_itemReturn( pArray );
}

/* __clsGetProperties( <nClassHandle>, [<lAllExported>] ) --> <acProperties>
 * Notice that this function works quite similar to __classSel()
 * except that just returns the name of the datas and methods
 * that have been declared as PROPERTY (PERSISTENT) or also EXPORTED
 * if second parameter <lAllExported> is true and message has corresponding
 * assign message (with "_" prefix)
 */
HB_FUNC( __CLSGETPROPERTIES )
{
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );
   PHB_ITEM pReturn = hb_itemNew( NULL );

   if( uiClass && uiClass <= s_uiClasses )
   {
      PCLASS pClass = s_pClasses[ uiClass ];
      PMETHOD pMethod, pAccMth;
      HB_SIZE nLimit, nCount;
      HB_USHORT uiScope = HB_OO_CLSTP_PERSIST;

      if( hb_parl( 2 ) )
         uiScope |= HB_OO_CLSTP_EXPORTED;

      nCount = 0;
      nLimit = hb_clsMthNum( pClass );
      pMethod = pClass->pMethods;
      do
      {
         if( pMethod->pMessage && ( pMethod->uiScope & uiScope ) != 0 )
         {
            if( ( pMethod->uiScope & HB_OO_CLSTP_PERSIST ) != 0 )
               ++nCount;
            else if( pMethod->pMessage->pSymbol->szName[ 0 ] == '_' )
            {
               if( ! pMethod->pAccMsg )
                  pMethod->pAccMsg = hb_dynsymGetCase( pMethod->pMessage->pSymbol->szName + 1 );
               pAccMth = hb_clsFindMsg( pClass, pMethod->pAccMsg );
               if( pAccMth && ( pAccMth->uiScope & HB_OO_CLSTP_PERSIST ) == 0 )
                  ++nCount;
            }
         }
         ++pMethod;
      }
      while( --nLimit );

      hb_arrayNew( pReturn, nCount );

      nCount = 0;
      nLimit = hb_clsMthNum( pClass );
      pMethod = pClass->pMethods;
      do
      {
         if( pMethod->pMessage && ( pMethod->uiScope & uiScope ) != 0 )
         {
            if( ( pMethod->uiScope & HB_OO_CLSTP_PERSIST ) != 0 )
               hb_arraySetC( pReturn, ++nCount, pMethod->pMessage->pSymbol->szName );
            else if( pMethod->pMessage->pSymbol->szName[ 0 ] == '_' &&
                     pMethod->pAccMsg )
            {
               pAccMth = hb_clsFindMsg( pClass, pMethod->pAccMsg );
               if( pAccMth && ( pAccMth->uiScope & HB_OO_CLSTP_PERSIST ) == 0 )
                  hb_arraySetC( pReturn, ++nCount, pMethod->pMessage->pSymbol->szName + 1 );
            }
         }
         ++pMethod;
      }
      while( --nLimit );
   }

   hb_itemReturnRelease( pReturn );
}

/* __clsGetAncestors( <nClass> ) --> { <nSuper1>, <nSuper2>, ... } */
HB_FUNC( __CLSGETANCESTORS )
{
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 ), uiCount;

   if( uiClass && uiClass <= s_uiClasses )
   {
      HB_STACK_TLS_PRELOAD
      PHB_ITEM pReturn = hb_stackReturnItem();
      PCLASS pClass = s_pClasses[ uiClass ];
      HB_SIZE nPos = 0;

      uiCount = pClass->uiSuperClasses;
      hb_arrayNew( pReturn, uiCount );
      while( uiCount-- )
      {
         HB_USHORT uiSuperCls = pClass->pSuperClasses[ uiCount ].uiClass;
         if( uiSuperCls != uiClass )
            hb_arraySetNI( pReturn, ++nPos, uiSuperCls );
      }
      hb_arraySize( pReturn, nPos );
   }
}

/* __clsMsgType( <hClass>, <cMsgName> | <sMsgName> ) --> <nType>
 *
 * return type of method attached to given message,
 * <nType> is one of HB_OO_MSG_* values defined in hboo.ch or
 * -1 if message is not supported.
 */
HB_FUNC( __CLSMSGTYPE )
{
   PHB_DYNS pMessage = hb_objGetMsgSym( hb_param( 2, HB_IT_ANY ) );

   if( pMessage )
   {
      HB_STACK_TLS_PRELOAD
      HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );
      PMETHOD pMethod = NULL;

      if( uiClass && uiClass <= s_uiClasses )
         pMethod = hb_clsFindMsg( s_pClasses[ uiClass ], pMessage );

      hb_retni( pMethod ? hb_methodType( pMethod ) : -1 );
   }
   else
      hb_errRT_BASE_SubstR( EG_ARG, 1099, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}

/* extend the size of classes buffer to given value to avoid later
 * RT reallocations. It may be useful in some very seldom cases
 * for MT programs which will allocate dynamically at runtime
 * more then 16386 classes. In practice rather impossible though
 * who knows ;-)
 * __clsPreallocate( [<nMaxClasses>] ) --> <nMaxClasses>
 */
HB_FUNC( __CLSPREALLOCATE )
{
   HB_STACK_TLS_PRELOAD
   HB_LONG lNewSize = hb_parnl( 1 );

   if( lNewSize > ( HB_LONG ) USHRT_MAX )
      lNewSize = USHRT_MAX;

   HB_CLASS_LOCK();

   if( lNewSize > ( HB_LONG ) s_uiClsSize )
   {
      s_uiClsSize = ( HB_USHORT ) lNewSize;
      s_pClasses = ( PCLASS * ) hb_xrealloc( s_pClasses, sizeof( PCLASS ) *
                                             ( ( HB_SIZE ) s_uiClsSize + 1 ) );
   }

   HB_CLASS_UNLOCK();

   hb_retnl( s_uiClsSize );
}

/* __clsLockDef( <clsItem> ) --> <lLocked> */
HB_FUNC( __CLSLOCKDEF )
{
   HB_STACK_TLS_PRELOAD
   PHB_ITEM pClsItm = hb_param( 1, HB_IT_BYREF );
   HB_BOOL fLocked = HB_FALSE;

   if( pClsItm && HB_IS_NIL( pClsItm ) )
   {
      if( ! s_pClassMtx || hb_threadMutexLock( s_pClassMtx ) )
      {
         if( HB_IS_NIL( pClsItm ) )
            fLocked = HB_TRUE;
         else if( s_pClassMtx )
            hb_threadMutexUnlock( s_pClassMtx );
      }
   }
   hb_retl( fLocked );
}

/* __clsUnlockDef( @<clsItem>, <clsDef> ) */
HB_FUNC( __CLSUNLOCKDEF )
{
   PHB_ITEM pClsDst = hb_param( 1, HB_IT_BYREF ),
            pClsSrc = hb_param( 2, HB_IT_ANY );

   if( pClsDst && pClsSrc && HB_IS_NIL( pClsDst ) && ! HB_ISBYREF( 2 ) )
   {
      /* special core code only macro used to eliminate race condition
       * in unprotected readonly access to pClsDst variable.
       */
      hb_itemSafeMove( pClsDst, pClsSrc );
   }

   if( s_pClassMtx )
      hb_threadMutexUnlock( s_pClassMtx );
}

/* Dirty functions which converts array to object of given class
 * __objSetClass( <oObject>, <cClassName> [, <cClassFuncName> ] ) --> <oObject>
 */
HB_FUNC( __OBJSETCLASS )
{
   PHB_ITEM pObject = hb_param( 1, HB_IT_ARRAY );

   if( pObject && pObject->item.asArray.value->uiClass == 0 )
   {
      const char * szClass = hb_parc( 2 );

      if( szClass )
         hb_objSetClass( pObject, szClass, hb_parc( 3 ) );
   }

   hb_itemReturn( pObject );
}

/* Real dirty function, though very useful under certain circumstances:
 * It allows to change the class handle of an object into another class handle,
 * so the object behaves like a different Class of object.
 * Based on objects.lib SetClsHandle()
 * __objSetClassHandle( <oObject>, <nClassHandle> ) --> <nPrevClassHandle>
 */
HB_FUNC( __OBJSETCLASSHANDLE )
{
   HB_STACK_TLS_PRELOAD
   PHB_ITEM pObject = hb_param( 1, HB_IT_OBJECT );
   HB_USHORT uiPrevClassHandle = 0;

   if( pObject )
   {
      HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 2 );

      uiPrevClassHandle = pObject->item.asArray.value->uiClass;
      if( uiClass <= s_uiClasses )
         pObject->item.asArray.value->uiClass = uiClass;
   }

   hb_retnl( uiPrevClassHandle );
}

#if defined( HB_LEGACY_LEVEL5 )
HB_FUNC_TRANSLATE( HB_SETCLSHANDLE, __OBJSETCLASSHANDLE )
#endif

/* Harbour equivalent for Clipper internal __mdCreate() */
HB_USHORT hb_clsCreate( HB_USHORT usSize, const char * szClassName )
{
   return hb_clsNew( szClassName, usSize, NULL, NULL, HB_FALSE );
}

/* Harbour equivalent for Clipper internal __mdAdd() */
void hb_clsAdd( HB_USHORT usClassH, const char * szMethodName, PHB_FUNC pFuncPtr )
{
   PHB_SYMB pExecSym;
   PHB_ITEM pFuncItem;

   /* We can use empty name "" for this symbol in hb_symbolNew()
    * It's only envelop for function with additional execution
    * information for HVM not registered symbol. [druzus]
    */
   pExecSym = hb_symbolNew( "" );
   pExecSym->value.pFunPtr = pFuncPtr;
   pFuncItem = hb_itemPutSymbol( NULL, pExecSym );

   hb_clsAddMsg( usClassH, szMethodName, HB_OO_MSG_METHOD, 0, pFuncItem, NULL );

   hb_itemRelease( pFuncItem );
}

/* Harbour equivalent for Clipper internal __mdAssociate() */
void hb_clsAssociate( HB_USHORT usClassH )
{
   PHB_ITEM pSelf = hb_clsInst( usClassH );

   if( pSelf )
      hb_itemReturnRelease( pSelf );
   else
   {
      HB_STACK_TLS_PRELOAD
      hb_ret();
   }
}

HB_FUNC( __CLSVERIFY )
{
   HB_USHORT uiClass = ( HB_USHORT ) hb_parni( 1 );
   PHB_ITEM pReturn = hb_itemNew( NULL );

   if( uiClass && uiClass <= s_uiClasses )
   {
      PCLASS pClass = s_pClasses[ uiClass ];
      PMETHOD pMethod = pClass->pMethods;
      HB_SIZE nLimit = hb_clsMthNum( pClass ), nPos = 0;

      hb_arrayNew( pReturn, pClass->uiMethods );
      do
      {
         if( pMethod->pMessage )
         {
            PHB_DYNS pDynSym = hb_dynsymFind( pMethod->pMessage->pSymbol->szName );

            if( pMethod->pMessage != pDynSym ||
                hb_clsFindMsg( pClass, pDynSym ) != pMethod )
               hb_arraySetC( pReturn, ++nPos, pMethod->pMessage->pSymbol->szName );
         }
         ++pMethod;
      }
      while( --nLimit );

      if( nPos < ( HB_SIZE ) pClass->uiMethods )
         hb_arraySize( pReturn, nPos );
   }

   hb_itemReturnRelease( pReturn );
}

#if 0
/* return real function name ignoring aliasing */
const char * hb_clsRealMethodName( void )
{
   HB_ISIZ nOffset = hb_stackBaseProcOffset( 1 );
   const char * szName = NULL;

   if( nOffset > 0 )
   {
      PHB_STACK_STATE pStack = hb_stackItem( nOffset )->item.asSymbol.stackstate;

      if( pStack->uiClass && pStack->uiClass <= s_uiClasses )
      {
         PCLASS pClass = s_pClasses[ pStack->uiClass ];

         if( ( HB_SIZE ) pStack->uiMethod < hb_clsMthNum( pClass ) )
         {
            PMETHOD pMethod = pClass->pMethods + pStack->uiMethod;

            if( pMethod->pMessage )
               szName = pMethod->pMessage->pSymbol->szName;
         }
      }
   }
   return szName;
}
#endif
