// global product version

#define PRODUCT_VERSION_RC11		11	// RC11
#define PRODUCT_VERSION_RC16		12	// RC16
#define PRODUCT_VERSION_RC18_1		13	// RC18.1 (gold?)
#define PRODUCT_VERSION_7_FINAL		20	// ts7 final build ( gold1)
#define PRODUCT_VERSION_7_FINAL_2	21	// ts7 final build ( gold3)
#define PRODUCT_VERSION_7_FINAL_4	21	// ts7 final build ( gold4)
#define PRODUCT_VERSION_7_01		22	// ts7 v.01 (gold8)
#define PRODUCT_VERSION_7_02		23	// ts7 v.02 (beta 3.1)
#define PRODUCT_VERSION_7_6			25	// ts7.6 Gold

#define PRODUCT_VERSION		PRODUCT_VERSION_7_6

/////////////////////////////////////////////////////////////////////////////////////////
/// GUID macros

/// RS_DEFINE_GUID
/// Define a GUID
///
/// Parameters
///     name - name of the GUID to be defined.
///     l, ..., b8 - the GUID numbers.

#define RS_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
        EXTERN_C const GUID DECLSPEC_SELECTANY name \
                = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }

/// DEF_GUIDNAME_PTR
/// Returns pointer to GUID from an interface:
#define DEF_GUIDNAME_PTR(n)    ((GUID *)&__uuidof(n))

/// DEF_GUIDNAME:
/// see __uuidof (ms-help://MS.VSCC/MS.MSDNQTR.2002JAN.1033/vclang/html/_pluslang_Function.2d.Call_Operator.htm)
#define DEF_GUIDNAME(n)        __uuidof(n)


/// Declare dispatch interface implementation by using plain inheritance. Use as prefered method.
/// If you declared interface properly (all methods have id attribute, all objects in parameters 
/// are valid IDispatch interfaces) MIDL will inject IDispatch code directly to header and therefore
/// no type library is required.
/// YOU ALLWAYS HAVE TO TRY AND EVALUATE GENERATED CODE BY USING /Fx COMPILER PARAMETER!!!
#define IMPLEMENT_DISPATCH(INTERFACE) public   INTERFACE   

///Alternative method to setting dispatch interface using type library. It attempts to force load of type library instead of using registers.
///Might or might not work correctly in script - it depends entirely on the interface.
///Therefore you should always write test case script that tests the interface.
#define IMPLEMENT_DISPATCH_TYPELIB(INTERFACE) public IDispatchImpl<INTERFACE, &__uuidof(INTERFACE), &CAtlModule::m_libid, 0xFFFF, 0xFFFF>

/// add coclass atribute the proper way:
#define ATTRIBUTE_COCLASS coclass, noncreatable


/////////////////////////////////////////////////////////////////////////////////////////
/// BSTR macros


/// RS_COPY_BSTR
/// Create copy of gived BSTR
///
/// Parameters
///     bstr - Pointer to a BSTR to be copied.
///
/// Return Value
/// Points to a copy of the string, or NULL if insufficient memory exists.
#define RS_COPY_BSTR(bstr)          SysAllocStringLen(bstr, SysStringLen(bstr))


/// RS_DECLARE_IRS_OBJECT
/// Declare standart IRsObject interface
///
/// Parameters:
///     iguid   - interface from which will be the guid defined.
///     clsname - class name for the interface.
///
/// Example:
///     RS_DECLARE_IRS_OBJECT(IRsBaseNode, L"Base Node")

#define RS_DECLARE_IRS_OBJECT(iguid, clsname)       \
STDMETHOD (get_ClassId)(GUID* pVal)                 \
{                                                   \
    *pVal = DEF_GUIDNAME(iguid);                    \
    return S_OK;                                    \
}                                                   \
                                                    \
STDMETHOD (get_ClassName)(BSTR* pVal)               \
{                                                   \
    if (pVal == NULL)                               \
        return ERROR_BAD_ARGUMENTS;                 \
                                                    \
    *pVal = SysAllocString(clsname);                \
                                                    \
    return *pVal != NULL ? S_OK : E_OUTOFMEMORY;    \
}

/// RS_DECLARE_PACKAGE_VERSION(pckVersion)
#define RS_DECLARE_PACKAGE_VERSION(productVersion, pckVersion)				\
STDMETHOD (Version)(RtDWORD* pdwVersion)									\
{																			\
	*pdwVersion = ((RtDWORD)(RtUshort)(pckVersion) | ((RtUlong)(RtUshort)(productVersion) << 16));	\
    return S_OK;															\
}  

#define RS_PACKAGE_DESCRIPTION(szDescription)		\
STDMETHOD(GetDescription)(BSTR* pVal)				\
{                                                   \
    if (pVal == NULL)								\
        return ERROR_BAD_ARGUMENTS;                 \
                                                    \
    *pVal = SysAllocString(szDescription);			\
                                                    \
    return *pVal != NULL ? S_OK : E_OUTOFMEMORY;    \
}


/// file object header info: 
#define RS_DECLARE_FILE_HEADER_INFO(_ObjFileVersion)                     \
STDMETHOD(GetFileHeaderInfo)(RtObjFileHeaderInfo *pcbSize)               \
{                                                                        \
    pcbSize->objFileVersion = static_cast<RtObjFileVer>(_ObjFileVersion);\
    return S_OK;                                                         \
}

/// external examples, (does nothing):
#define RS_DOC_SAMPLES(exampleId) (exampleId)

/**
    TODO: write documentation when functionality will be stable.
*/
#define BEGIN_NODE_DESC_MAP()                       \
    static const RtNodeDesc _nodeDesc[] = {

#define NODE_DESC_ENTRY(x, p, pObjDest, flags, id2D)                      \
    {(&__uuidof(x)), (&__uuidof(p)), static_cast<const RtObjDesc*>(pObjDest), static_cast<RtNodeDescFlags>(flags), static_cast<RtUshort>(id2D)},

#define END_NODE_DESC_MAP()                         \
    &IID_NULL, &IID_NULL, static_cast<RtObjDesc*>(0),  static_cast<RtNodeDescFlags>(0), 0};


/**
    TODO: write documentation when functionality will be stable.
*/

#define BEGIN_COMMAND_DESC_MAP()                    \
    static const RtCmdDesc _cmdDesc[] = {

#define COMMAND_DESC_ENTRY(x, p, pObjDest, flags, id2D)                       \
    {(&__uuidof(x)), (&__uuidof(p)), static_cast<const RtObjDesc*>(pObjDest), static_cast<RtCmdDescFlags>(flags), static_cast<RtUshort>(id2D)},

#define END_COMMAND_DESC_MAP()                      \
     &IID_NULL, &IID_NULL, static_cast<RtObjDesc*>(0), static_cast<RtCmdDescFlags>(0), static_cast<RtUshort>(0)};


/**
    TODO: write documentation when functionality will be stable.
*/

#define BEGIN_DATAOBJ_DESC_MAP()                    \
    static const RtDataObjDesc _dataObjDesc[] = {

#define DATAOBJ_ENTRY(x, p, pObjDest, flags)                     \
    {(&__uuidof(x)), (&__uuidof(p)), static_cast<const RtObjDesc*>(pObjDest), static_cast<RtDataObjDescFlags>(flags)},

#define END_DATAOBJ_DESC_MAP()                      \
     &IID_NULL, &IID_NULL, static_cast<RtObjDesc*>(0), static_cast<RtDataObjDescFlags>(0)};


/**
    TODO: write documentation when functionality will be stable.
*/

#define BEGIN_LANGOBJ_DESC_MAP()                    \
    static const RtLangObjDesc _langObjDesc[] = {

#define LANGOBJ_ENTRY(x, flags)                     \
    {(&__uuidof(x)), static_cast<RtLangObjDescFlags>(flags)},

#define END_LANGOBJ_DESC_MAP()                      \
     &IID_NULL, static_cast<RtLangObjDescFlags>(0)};


/**
    TODO: write documentation when functionality will be stable.
*/

// BEGIN_NODE_MAP definition:
#define BEGIN_NODE_MAP()        \
{                               \
    if (false){}

// NODE_ENTRY definition:
#define NODE_ENTRY(_riid, _ppNode, _interface, _impl)               \
    else if (::InlineIsEqualGUID(*_riid, DEF_GUIDNAME(_interface))) \
    {                                                               \
        CComObject<_impl>* pNodeObj = NULL;                         \
        HRESULT hRes = CComObject<_impl>::CreateInstance(&pNodeObj);\
        if (SUCCEEDED(hRes))                                        \
            return pNodeObj->QueryInterface(_ppNode);               \
    }

// END_NODE_MAP definition:
#define END_NODE_MAP()  \
}

/**
    TODO: write documentation when functionality will be stable.
*/

// BEGIN_COMMAND_MAP definition:
#define BEGIN_COMMAND_MAP() \
{                           \
    if (false){}

// COMMAND_ENTRY definition:
#define COMMAND_ENTRY(_riid, _ppCommand, _interface, _impl)             \
    else if (::InlineIsEqualGUID(*_riid, DEF_GUIDNAME(_interface)))     \
    {                                                                   \
        CComObject<_impl>* pCommandObj = NULL;                          \
        HRESULT hRes = CComObject<_impl>::CreateInstance(&pCommandObj); \
        if (SUCCEEDED(hRes))                                            \
            return pCommandObj->QueryInterface(_ppCommand);             \
    }

#define COMMAND_ENTRY_1(_riid, _ppCommand, common_name)  COMMAND_ENTRY(_riid, _ppCommand, I##common_name, C##common_name)

// END_COMMAND_MAP definition:
#define END_COMMAND_MAP()  \
}

// BEGIN_DATAOBJECT_MAP definition:
#define BEGIN_DATAOBJECT_MAP()        \
{                               \
	if (false){}

// DATAOBJECT_ENTRY definition:
#define DATAOBJECT_ENTRY(_riid, _ppDataObj, _interface, _impl)               \
	else if (::InlineIsEqualGUID(*_riid, DEF_GUIDNAME(_interface))) \
	{                                                               \
	CComObject<_impl>* pDataObj = NULL;                         \
	HRESULT hRes = CComObject<_impl>::CreateInstance(&pDataObj);\
	if (SUCCEEDED(hRes))                                        \
	return pDataObj->QueryInterface(_ppDataObj);               \
	}

// END_DATAOBJECT_MAP definition:
#define END_DATAOBJECT_MAP()  \
}


// Macros for ACCESS_TO_VALUE and ACCESS_TO_NODE_VALUE macros:
#define VT_RtChar   VT_I1
#define V_RtChar    V_I1
#define VT_RtUchar  VT_UI1
#define V_RtUchar   V_UI1
#define VT_RtBYTE   VT_UI1
#define V_RtBYTE    V_UI1
#define VT_RtShort  VT_I2
#define V_RtShort   V_I2
#define VT_RtUshort VT_UI2
#define V_RtUshort  V_UI2
#define VT_RtLong   VT_I4
#define V_RtLong    V_I4
#define VT_RtUlong  VT_UI4
#define V_RtUlong   V_UI4
#define VT_RtDWORD  VT_UI4
#define V_RtDWORD   V_UI4
#define VT_RtFloat  VT_R4
#define V_RtFloat   V_R4
#define VT_RtDouble VT_R8
#define V_RtDouble  V_R8
#define VT_RtBOOL   VT_UI4
#define V_RtBOOL    V_UI4
#define VT_RtBool   VT_UI1
#define V_RtBool    V_UI1
#define VT_RtFlags  VT_UI4
#define V_RtFlags   V_UI4

/////////////////////////////////////////////////////////////////////////
// Implementation of GetValueXxxx and SetValueXxxx methods:

#define ACCESS_TO_VALUE(Type, pBase)                                    \
STDMETHOD (GetValue##Type)(CONID giudCon, ##Type *pVal)                 \
{                                                                       \
    HRESULT                 hr = E_FAIL;                                \
    CComVariant             vValue;                                     \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                           \
    ATLASSERT(spBase);                                                  \
                                                                        \
    if (pVal && SUCCEEDED(hr = spBase->GetValue(giudCon, &vValue)))     \
    {                                                                   \
        if (FAILED(hr = vValue.ChangeType(VT_##Type)))                  \
            return hr;                                                  \
        if (V_VT(&vValue) == VT_##Type)                                 \
        {                                                               \
            (*pVal) = V_##Type(&vValue);                                \
            return S_OK;                                                \
        }                                                               \
        else                                                            \
        {                                                               \
            hr = E_FAIL;                                                \
        }                                                               \
    }                                                                   \
    return hr;                                                          \
}                                                                       \
                                                                        \
STDMETHOD (SetValue##Type)(CONID giudCon, ##Type newVal)                \
{                                                                       \
    CComVariant             vValue(newVal);                             \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                           \
    ATLASSERT(spBase);                                                  \
                                                                        \
    return (spBase) ? spBase->SetValue(giudCon, vValue) : E_FAIL;       \
}

#define ACCESS_TO_VALUE_WITH_EXISTENCE_CHECK(Type, pBase)                                   \
ACCESS_TO_VALUE(Type, pBase)                                                                \
                                                                                            \
STDMETHOD (GetValue##Type)(CONID giudCon, ##Type *pVal, ##Type defaultVal, RtConDesc *pDesc) \
{                                                                                           \
    HRESULT     hr = E_FAIL;                                                                \
                                                                                            \
    CComPtr<IRsConnector> spConnector;                                                      \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                                               \
                                                                                            \
    hr = spBase->FindConById( giudCon, &spConnector);                                       \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = spBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                \
            return hr;                                                                      \
        if (FAILED(hr = spBase->CreateConnector(ConDescriptor, &spConnector)))              \
            return hr;                                                                      \
        if (FAILED(hr = spBase->AddConnector(spConnector)))                                 \
            return hr;                                                                      \
        if ( FAILED( hr = SetValue##Type(giudCon, defaultVal)))                             \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return GetValue##Type(giudCon, pVal);                                                   \
}                                                                                           \
                                                                                            \
STDMETHOD (GetValue##Type)(CONID giudCon, ##Type *pVal, ##Type defaultVal, LPWSTR szName, LPWSTR szDescriptor, RtFlags uFlags) \
{                                                                                           \
    RtConDesc sDesc = {&giudCon, szName, szDescriptor, VT_##Type, NULL, uFlags};            \
                                                                                            \
    return GetValue##Type(giudCon, pVal, defaultVal, &sDesc);                               \
}                                                                                           \
                                                                                            \
STDMETHOD (SetValue##Type)(CONID giudCon, ##Type newVal, RtConDesc *pDesc)                  \
{                                                                                           \
    CComPtr<IRsConnector> spConnector;                                                      \
                                                                                            \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                                               \
    HRESULT hr = spBase->FindConById( giudCon, &spConnector);                               \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = spBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                \
            return hr;                                                                      \
        if (FAILED(hr = spBase->CreateConnector(ConDescriptor, &spConnector)))              \
            return hr;                                                                      \
        if (FAILED(hr = spBase->AddConnector(spConnector)))                                 \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return SetValue##Type(giudCon, newVal);                                                 \
}                                                                                           \
                                                                                            \
STDMETHOD (SetValue##Type)(IRsBaseNode *pBase, CONID giudCon, ##Type newVal, LPWSTR szName, LPWSTR szDescriptor, RtFlags uFlags) \
{                                                                                           \
    RtConDesc sDesc = {&giudCon, szName, szDescriptor, VT_##Type, NULL, uFlags};            \
                                                                                            \
    return SetValue##Type(giudCon, newVal, &sDesc);                                         \
}

// End of macro for implementation of GetValueXxxx and SetValueXxxx.
/////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////
// Implementation of GetValueBSTR and SetValueBSTR methods:

#define ACCESS_TO_VALUE_BSTR(pBase)                                     \
STDMETHOD (GetValueBSTR)(CONID giudCon, BSTR *pVal)                     \
{                                                                       \
    HRESULT                 hr = E_FAIL;                                \
    CComVariant             vValue;                                     \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                           \
    ATLASSERT(spBase);                                                  \
                                                                        \
    if (pVal && SUCCEEDED(hr = spBase->GetValue(giudCon, &vValue)))     \
    {                                                                   \
        if (FAILED(hr = vValue.ChangeType(VT_BSTR)))                    \
            return hr;                                                  \
        if (V_VT(&vValue) == VT_BSTR)                                   \
        {                                                               \
            (*pVal) = RS_COPY_BSTR(V_BSTR(&vValue));                    \
            return S_OK;                                                \
        }                                                               \
        else                                                            \
        {                                                               \
            hr = E_FAIL;                                                \
        }                                                               \
    }                                                                   \
    return hr;                                                          \
}                                                                       \
                                                                        \
STDMETHOD (SetValueBSTR)(CONID giudCon, BSTR newVal)                    \
{                                                                       \
    CComVariant             vValue(newVal);                             \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                           \
    ATLASSERT(spBase);                                                  \
                                                                        \
    return (spBase) ? spBase->SetValue(giudCon, vValue) : E_FAIL;       \
}

#define ACCESS_TO_VALUE_BSTR_WITH_EXISTENCE_CHECK( pBase)                                   \
ACCESS_TO_VALUE_BSTR(pBase)                                                                 \
                                                                                            \
STDMETHOD (GetValueBSTR)(CONID giudCon, BSTR *pVal, BSTR defaultVal, RtConDesc *pDesc)      \
{                                                                                           \
    HRESULT     hr = E_FAIL;                                                                \
                                                                                            \
    CComPtr<IRsConnector> spConnector;                                                      \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                                               \
                                                                                            \
    hr = spBase->FindConById( giudCon, &spConnector);                                       \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = spBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                \
            return hr;                                                                      \
        if (FAILED(hr = spBase->CreateConnector(ConDescriptor, &spConnector)))              \
            return hr;                                                                      \
        if (FAILED(hr = spBase->AddConnector(spConnector)))                                 \
            return hr;                                                                      \
        if ( FAILED( hr = SetValueBSTR(giudCon, defaultVal)))                               \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return GetValueBSTR(giudCon, pVal);                                                     \
}                                                                                           \
                                                                                            \
STDMETHOD (GetValueBSTR)(CONID giudCon, BSTR *pVal, BSTR defaultVal, LPWSTR szName, LPWSTR szDescriptor, RtFlags uFlags) \
{                                                                                           \
    RtConDesc sDesc = {&giudCon, szName, szDescriptor, VT_BSTR, NULL, uFlags};              \
                                                                                            \
    return GetValueBSTR(giudCon, pVal, defaultVal, &sDesc);                                 \
}                                                                                           \
                                                                                            \
STDMETHOD (SetValueBSTR)(CONID giudCon, BSTR newVal, RtConDesc *pDesc)                      \
{                                                                                           \
    CComPtr<IRsConnector> spConnector;                                                      \
                                                                                            \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                                               \
    HRESULT hr = spBase->FindConById( giudCon, &spConnector);                               \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = spBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                \
            return hr;                                                                      \
        if (FAILED(hr = spBase->CreateConnector(ConDescriptor, &spConnector)))              \
            return hr;                                                                      \
        if (FAILED(hr = spBase->AddConnector(spConnector)))                                 \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return SetValueBSTR(giudCon, newVal);                                                   \
}                                                                                           \
                                                                                            \
STDMETHOD (SetValueBSTR)(IRsBaseNode *pBase, CONID giudCon, BSTR newVal, LPWSTR szName, LPWSTR szDescriptor, RtFlags uFlags) \
{                                                                                           \
    RtConDesc sDesc = {&giudCon, szName, szDescriptor, VT_BSTR, NULL, uFlags};              \
                                                                                            \
    return SetValueBSTR(giudCon, newVal, &sDesc);                                           \
}

// End of macro for implementation of GetValueBSTR and SetValueBSTR.
/////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////
// Implementation of GetDataObjXxxx and SetDataObjXxxx methods:

#define ACCESS_TO_DATA_OBJ(IdType, pBase)                               \
STDMETHOD (GetDataObj##IdType)(CONID giudCon, ##IdType** pVal)          \
{                                                                       \
    HRESULT                     hr = E_FAIL;                            \
    CComVariant                 vValue;                                 \
    CComQIPtr<IRsDataObject>    spDataItem;                             \
    CComQIPtr<IRsBaseNode>      spBase = (pBase);                       \
    ATLASSERT(spBase);                                                  \
                                                                        \
    if (pVal && SUCCEEDED(hr = spBase->GetValue(giudCon, &vValue)))     \
    {                                                                   \
        if (V_VT(&vValue) == VT_UNKNOWN)                                \
        {                                                               \
            spDataItem = V_UNKNOWN(&vValue);                            \
            ATLASSERT((spDataItem) || (!"Query for IRsDataObject failed"));                 \
            if (spDataItem)                                                                 \
                return spDataItem->QueryInterface(pVal);                                    \
            else                                                                            \
                return E_NOINTERFACE;                                                       \
        }                                                               \
        else                                                            \
        {                                                               \
            hr = E_FAIL;                                                \
        }                                                               \
    }                                                                   \
    return hr;                                                          \
}                                                                       \
                                                                        \
STDMETHOD (SetDataObj##IdType)(CONID giudCon, ##IdType* newVal)         \
{                                                                       \
    CComVariant             vValue(newVal);                             \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                           \
    ATLASSERT(spBase);                                                  \
                                                                        \
    return (spBase) ? spBase->SetValue(giudCon, vValue) : E_FAIL;       \
}

#define ACCESS_TO_DATA_OBJ_WITH_EXISTENCE_CHECK( IdType, pBase)                             \
ACCESS_TO_DATA_OBJ( IdType, pBase)                                                          \
                                                                                            \
STDMETHOD (GetDataObj##IdType)(CONID giudCon, ##IdType **pVal, ##IdType * defaultVal, RtConDesc *pDesc)            \
{                                                                                           \
    HRESULT     hr = E_FAIL;                                                                \
                                                                                            \
    CComPtr<IRsConnector> spConnector;                                                      \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                                               \
                                                                                            \
    hr = spBase->FindConById( giudCon, &spConnector);                                       \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = spBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                \
            return hr;                                                                      \
        if (FAILED(hr = spBase->CreateConnector(ConDescriptor, &spConnector)))              \
            return hr;                                                                      \
        if (FAILED(hr = spBase->AddConnector(spConnector)))                                 \
            return hr;                                                                      \
        CComVariant defaultData;                                                            \
        if (FAILED(hr = spBase->GetDefaultValue(giudCon, &defaultData)))                    \
            return hr;                                                                      \
        if (FAILED(hr = spBase->SetValue(giudCon, defaultData)))                            \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return GetDataObj##IdType(giudCon, pVal);                                               \
}                                                                                           \
                                                                                            \
STDMETHOD (SetDataObj##IdType)(CONID giudCon, ##IdType *newVal, RtConDesc *pDesc)           \
{                                                                                           \
    CComPtr<IRsConnector> spConnector;                                                      \
                                                                                            \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                                               \
    HRESULT hr = spBase->FindConById( giudCon, &spConnector);                               \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = spBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                \
            return hr;                                                                      \
        if (FAILED(hr = spBase->CreateConnector(ConDescriptor, &spConnector)))              \
            return hr;                                                                      \
        if (FAILED(hr = spBase->AddConnector(spConnector)))                                 \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return SetDataObj##IdType(giudCon, newVal);                                             \
}

#define STATIC_ACCESS_TO_DATA_OBJ(IdType, pBase)                        \
static HRESULT (GetDataObj##IdType)(CONID giudCon, ##IdType** pVal)     \
{                                                                       \
    HRESULT                     hr = E_FAIL;                            \
    CComVariant                 vValue;                                 \
    CComQIPtr<IRsDataObject>    spDataItem;                             \
    CComQIPtr<IRsBaseNode>      spBase = (pBase);                       \
    ATLASSERT(spBase);                                                  \
                                                                        \
    if (pVal && SUCCEEDED(hr = spBase->GetValue(giudCon, &vValue)))     \
    {                                                                   \
        if (V_VT(&vValue) == VT_UNKNOWN)                                \
        {                                                               \
            spDataItem = V_UNKNOWN(&vValue);                            \
            ATLASSERT((spDataItem) || (!"Query for IRsDataObject failed")); \
            if (spDataItem)                                             \
                return spDataItem->QueryInterface(pVal);                \
            else                                                        \
                return E_NOINTERFACE;                                   \
        }                                                               \
        else                                                            \
        {                                                               \
            hr = E_FAIL;                                                \
        }                                                               \
    }                                                                   \
    return hr;                                                          \
}                                                                       \
                                                                        \
static HRESULT (SetDataObj##IdType)(CONID giudCon, ##IdType* newVal)    \
{                                                                       \
    CComVariant             vValue(newVal);                             \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                           \
    ATLASSERT(spBase);                                                  \
                                                                        \
    return (spBase) ? spBase->SetValue(giudCon, vValue) : E_FAIL;       \
}

#define STATIC_ACCESS_TO_DATA_OBJ_WITH_EXISTENCE_CHECK( IdType, pBase)                      \
STATIC_ACCESS_TO_DATA_OBJ( IdType, pBase)                                                   \
                                                                                            \
static HRESULT (GetDataObj##IdType)(CONID giudCon, ##IdType **pVal, ##IdType * defaultVal, RtConDesc *pDesc) \
{                                                                                           \
    HRESULT     hr = E_FAIL;                                                                \
                                                                                            \
    CComPtr<IRsConnector> spConnector;                                                      \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                                               \
                                                                                            \
    hr = spBase->FindConById( giudCon, &spConnector);                                       \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = spBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                \
            return hr;                                                                      \
        if (FAILED(hr = spBase->CreateConnector(ConDescriptor, &spConnector)))              \
            return hr;                                                                      \
        if (FAILED(hr = spBase->AddConnector(spConnector)))                                 \
            return hr;                                                                      \
        CComVariant defaultData;                                                            \
        if (FAILED(hr = spBase->GetDefaultValue(giudCon, &defaultData)))                    \
            return hr;                                                                      \
        if (FAILED(hr = spBase->SetValue(giudCon, defaultData)))                            \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return GetDataObj##IdType(giudCon, pVal);                                               \
}                                                                                           \
                                                                                            \
static HRESULT (SetDataObj##IdType)(CONID giudCon, ##IdType *newVal, RtConDesc *pDesc)      \
{                                                                                           \
    CComPtr<IRsConnector> spConnector;                                                      \
                                                                                            \
    CComQIPtr<IRsBaseNode>  spBase = (pBase);                                               \
    HRESULT hr = spBase->FindConById( giudCon, &spConnector);                               \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = spBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                \
            return hr;                                                                      \
        if (FAILED(hr = spBase->CreateConnector(ConDescriptor, &spConnector)))              \
            return hr;                                                                      \
        if (FAILED(hr = spBase->AddConnector(spConnector)))                                 \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return SetDataObj##IdType(giudCon, newVal);                                             \
}

// End of macro for implementation of GetDataObjXxxx and SetDataObjXxxx.
/////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////////////
// Implementation of GetNodeValueXxxx and SetNodeValueXxxx methods:

#define ACCESS_TO_NODE_VALUE(Type)                                                          \
STDMETHOD (GetNodeValue##Type)(IRsBaseNode *pBase, CONID giudCon, ##Type *pVal)             \
{                                                                                           \
    HRESULT     hr = E_FAIL;                                                                \
    CComVariant vValue;                                                                     \
                                                                                            \
    if (pBase && pVal && SUCCEEDED(hr = pBase->GetValue(giudCon, &vValue)))                 \
    {                                                                                       \
        if (FAILED(hr = vValue.ChangeType(VT_##Type)))                                      \
            return hr;                                                                      \
        if (V_VT(&vValue) == VT_##Type)                                                     \
        {                                                                                   \
            (*pVal) = V_##Type(&vValue);                                                    \
            return S_OK;                                                                    \
        }                                                                                   \
        else                                                                                \
        {                                                                                   \
            hr = E_FAIL;                                                                    \
        }                                                                                   \
    }                                                                                       \
    return hr;                                                                              \
}                                                                                           \
                                                                                            \
STDMETHOD (SetNodeValue##Type)(IRsBaseNode *pBase, CONID giudCon, ##Type newVal)            \
{                                                                                           \
    CComVariant vValue(newVal);                                                             \
                                                                                            \
    return (pBase) ? pBase->SetValue(giudCon, vValue) : E_FAIL;                             \
}

#define ACCESS_TO_NODE_VALUE_WITH_EXISTENCE_CHECK(Type)                                     \
ACCESS_TO_NODE_VALUE(Type)                                                                  \
                                                                                            \
STDMETHOD (GetNodeValue##Type)(IRsBaseNode *pBase, CONID giudCon, ##Type *pVal, ##Type defaultVal, RtConDesc *pDesc) \
{                                                                                           \
    HRESULT     hr = E_FAIL;                                                                \
                                                                                            \
    CComPtr<IRsConnector> spConnector;                                                      \
                                                                                            \
    hr = pBase->FindConById( giudCon, &spConnector);                                        \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = pBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                 \
            return hr;                                                                      \
        if (FAILED(hr = pBase->CreateConnector(ConDescriptor, &spConnector)))               \
            return hr;                                                                      \
        if (FAILED(hr = pBase->AddConnector(spConnector)))                                  \
            return hr;                                                                      \
        if ( FAILED( hr = SetNodeValue##Type(pBase, giudCon, defaultVal)))                  \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return GetNodeValue##Type(pBase, giudCon, pVal);                                        \
}                                                                                           \
                                                                                            \
STDMETHOD (GetNodeValue##Type)(IRsBaseNode *pBase, CONID giudCon, ##Type *pVal, ##Type defaultVal, LPWSTR szName, LPWSTR szDescriptor, RtFlags uFlags) \
{                                                                                           \
    RtConDesc sDesc = {&giudCon, szName, szDescriptor, VT_##Type, NULL, uFlags};            \
                                                                                            \
    return GetNodeValue##Type(pBase, giudCon, pVal, defaultVal, &sDesc);                    \
}                                                                                           \
                                                                                            \
STDMETHOD (SetNodeValue##Type)(IRsBaseNode *pBase, CONID giudCon, ##Type newVal, RtConDesc *pDesc) \
{                                                                                           \
    CComPtr<IRsConnector> spConnector;                                                      \
                                                                                            \
    HRESULT hr = pBase->FindConById( giudCon, &spConnector);                                \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = pBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                 \
            return hr;                                                                      \
        if (FAILED(hr = pBase->CreateConnector(ConDescriptor, &spConnector)))               \
            return hr;                                                                      \
        if (FAILED(hr = pBase->AddConnector(spConnector)))                                  \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return SetNodeValue##Type(pBase, giudCon, newVal);                                      \
}                                                                                           \
                                                                                            \
STDMETHOD (SetNodeValue##Type)(IRsBaseNode *pBase, CONID giudCon, ##Type newVal, LPWSTR szName, LPWSTR szDescriptor, RtFlags uFlags) \
{                                                                                           \
    RtConDesc sDesc = {&giudCon, szName, szDescriptor, VT_##Type, NULL, uFlags};            \
                                                                                            \
    return SetNodeValue##Type(pBase, giudCon, newVal, &sDesc);                              \
}

// End of macro for implementation of GetNodeValueXxxx and SetNodeValueXxxx.
/////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////
// Implementation of GetNodeValueBSTR and SetNodeValueBSTR methods:

#define ACCESS_TO_NODE_VALUE_BSTR                                                           \
STDMETHOD (GetNodeValueBSTR)(IRsBaseNode *pBase, CONID giudCon, BSTR *pVal)                 \
{                                                                                           \
    HRESULT     hr = E_FAIL;                                                                \
    CComVariant vValue;                                                                     \
                                                                                            \
    if (pBase && pVal && SUCCEEDED(hr = pBase->GetValue(giudCon, &vValue)))                 \
    {                                                                                       \
        if (FAILED(hr = vValue.ChangeType(VT_BSTR)))                                        \
            return hr;                                                                      \
        if (V_VT(&vValue) == VT_BSTR)                                                       \
        {                                                                                   \
            (*pVal) = RS_COPY_BSTR(V_BSTR(&vValue));                                        \
            return S_OK;                                                                    \
        }                                                                                   \
        else                                                                                \
        {                                                                                   \
            hr = E_FAIL;                                                                    \
        }                                                                                   \
    }                                                                                       \
    return hr;                                                                              \
}                                                                                           \
                                                                                            \
STDMETHOD (SetNodeValueBSTR)(IRsBaseNode *pBase, CONID giudCon, BSTR newVal)                \
{                                                                                           \
    CComVariant vValue(newVal);                                                             \
                                                                                            \
    return (pBase) ? pBase->SetValue(giudCon, vValue) : E_FAIL;                             \
}

#define ACCESS_TO_NODE_VALUE_BSTR_WITH_EXISTENCE_CHECK                                      \
ACCESS_TO_NODE_VALUE_BSTR                                                                   \
                                                                                            \
STDMETHOD (GetNodeValueBSTR)(IRsBaseNode *pBase, CONID giudCon, BSTR *pVal, BSTR defaultVal, RtConDesc *pDesc) \
{                                                                                           \
    HRESULT     hr = E_FAIL;                                                                \
                                                                                            \
    CComPtr<IRsConnector> spConnector;                                                      \
                                                                                            \
    hr = pBase->FindConById( giudCon, &spConnector);                                        \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = pBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                 \
            return hr;                                                                      \
        if (FAILED(hr = pBase->CreateConnector(ConDescriptor, &spConnector)))               \
            return hr;                                                                      \
        if (FAILED(hr = pBase->AddConnector(spConnector)))                                  \
            return hr;                                                                      \
        if ( FAILED( hr = SetNodeValueBSTR(pBase, giudCon, defaultVal)))                    \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return GetNodeValueBSTR(pBase, giudCon, pVal);                                          \
}                                                                                           \
                                                                                            \
STDMETHOD (GetNodeValueBSTR)(IRsBaseNode *pBase, CONID giudCon, BSTR *pVal, BSTR defaultVal, LPWSTR szName, LPWSTR szDescriptor, RtFlags uFlags) \
{                                                                                           \
    RtConDesc sDesc = {&giudCon, szName, szDescriptor, VT_BSTR, NULL, uFlags};              \
                                                                                            \
    return GetNodeValueBSTR(pBase, giudCon, pVal, defaultVal, &sDesc);                      \
}                                                                                           \
                                                                                            \
STDMETHOD (SetNodeValueBSTR)(IRsBaseNode *pBase, CONID giudCon, BSTR newVal, RtConDesc *pDesc) \
{                                                                                           \
    CComPtr<IRsConnector> spConnector;                                                      \
                                                                                            \
    HRESULT hr = pBase->FindConById( giudCon, &spConnector);                                \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = pBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                 \
            return hr;                                                                      \
        if (FAILED(hr = pBase->CreateConnector(ConDescriptor, &spConnector)))               \
            return hr;                                                                      \
        if (FAILED(hr = pBase->AddConnector(spConnector)))                                  \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return SetNodeValueBSTR(pBase, giudCon, newVal);                                        \
}                                                                                           \
                                                                                            \
STDMETHOD (SetNodeValueBSTR)(IRsBaseNode *pBase, CONID giudCon, BSTR newVal, LPWSTR szName, LPWSTR szDescriptor, RtFlags uFlags) \
{                                                                                           \
    RtConDesc sDesc = {&giudCon, szName, szDescriptor, VT_BSTR, NULL, uFlags};              \
                                                                                            \
    return SetNodeValueBSTR(pBase, giudCon, newVal, &sDesc);                                \
}

// End of macro for implementation of GetNodeValueBSTR and SetNodeValueBSTR.
/////////////////////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////////////////////
// Implementation of GetNodeDataObjXxxx and SetNodeDataObjXxxx methods:

#define ACCESS_TO_NODE_DATA_OBJ(IdType)                                                     \
STDMETHOD (GetNodeDataObj##IdType)(IRsBaseNode *pBase, CONID giudCon, ##IdType **pVal)      \
{                                                                                           \
    HRESULT                     hr = E_FAIL;                                                \
    CComVariant                 vValue;                                                     \
    CComQIPtr<IRsDataObject>    spDataItem;                                                 \
                                                                                            \
    if (pVal && SUCCEEDED(hr = pBase->GetValue(giudCon, &vValue)))                          \
    {                                                                                       \
        if (V_VT(&vValue) == VT_UNKNOWN)                                                    \
        {                                                                                   \
            spDataItem = V_UNKNOWN(&vValue);                                                \
            ATLASSERT((spDataItem) || (!"Query for IRsDataObject failed"));                 \
            if (spDataItem)                                                                 \
                return spDataItem->QueryInterface(pVal);                                    \
            else                                                                            \
                return E_NOINTERFACE;                                                       \
        }                                                                                   \
        else                                                                                \
        {                                                                                   \
            hr = E_FAIL;                                                                    \
        }                                                                                   \
    }                                                                                       \
    return hr;                                                                              \
}                                                                                           \
                                                                                            \
STDMETHOD (SetNodeDataObj##IdType)(IRsBaseNode *pBase, CONID giudCon, ##IdType *newVal)     \
{                                                                                           \
    CComVariant vValue(newVal);                                                             \
    return (pBase) ? pBase->SetValue(giudCon, vValue) : E_FAIL;                             \
}

#define STATIC_ACCESS_TO_NODE_DATA_OBJ(IdType)                                              \
static HRESULT (GetNodeDataObj##IdType)(IRsBaseNode *pBase, CONID giudCon, ##IdType **pVal) \
{                                                                                           \
    HRESULT                     hr = E_FAIL;                                                \
    CComVariant                 vValue;                                                     \
    CComQIPtr<IRsDataObject>    spDataItem;                                                 \
                                                                                            \
    if (pVal && SUCCEEDED(hr = pBase->GetValue(giudCon, &vValue)))                          \
    {                                                                                       \
        if (V_VT(&vValue) == VT_UNKNOWN)                                                    \
        {                                                                                   \
            spDataItem = V_UNKNOWN(&vValue);                                                \
            ATLASSERT((spDataItem) || (!"Query for IRsDataObject failed"));                 \
            if (spDataItem)                                                                 \
                return spDataItem->QueryInterface(pVal);                                    \
            else                                                                            \
                return E_NOINTERFACE;                                                       \
        }                                                                                   \
        else                                                                                \
        {                                                                                   \
            hr = E_FAIL;                                                                    \
        }                                                                                   \
    }                                                                                       \
    return hr;                                                                              \
}                                                                                           \
                                                                                            \
static HRESULT (SetNodeDataObj##IdType)(IRsBaseNode *pBase, CONID giudCon, ##IdType *newVal) \
{                                                                                           \
    CComVariant vValue(newVal);                                                             \
    return (pBase) ? pBase->SetValue(giudCon, vValue) : E_FAIL;                             \
}

#define STATIC_ACCESS_TO_NODE_DATA_OBJ_WITH_EXISTENCE_CHECK(Type)                           \
STATIC_ACCESS_TO_NODE_DATA_OBJ(Type)                                                        \
                                                                                            \
static HRESULT  (GetNodeDataObj##Type)(IRsBaseNode *pBase, CONID giudCon, ##Type **pVal, ##Type *defaultVal, RtConDesc *pDesc) \
{                                                                                           \
    HRESULT     hr = E_FAIL;                                                                \
                                                                                            \
    CComPtr<IRsConnector> spConnector;                                                      \
                                                                                            \
    hr = pBase->FindConById( giudCon, &spConnector);                                        \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = pBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                 \
            return hr;                                                                      \
        if (FAILED(hr = pBase->CreateConnector(ConDescriptor, &spConnector)))               \
            return hr;                                                                      \
        if (FAILED(hr = pBase->AddConnector(spConnector)))                                  \
            return hr;                                                                      \
        if ( FAILED( hr = SetNodeDataObj##Type(pBase, giudCon, defaultVal)))                \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return GetNodeDataObj##Type(pBase, giudCon, pVal);                                      \
}                                                                                           \
                                                                                            \
static HRESULT  (GetNodeDataObj##Type)(IRsBaseNode *pBase, CONID giudCon, ##Type **pVal, ##Type *defaultVal, LPWSTR szName, LPWSTR szDescriptor, RtFlags uFlags) \
{                                                                                           \
    RtConDesc sDesc = {&giudCon, szName, szDescriptor, VT_UNKNOWN, NULL, uFlags};           \
                                                                                            \
    return GetNodeDataObj##Type(pBase, giudCon, pVal, defaultVal, &sDesc);                  \
}                                                                                           \
                                                                                            \
static HRESULT (SetNodeDataObj##Type)(IRsBaseNode *pBase, CONID giudCon, ##Type *newVal, RtConDesc *pDesc) \
{                                                                                           \
    CComPtr<IRsConnector> spConnector;                                                      \
                                                                                            \
    HRESULT hr = pBase->FindConById( giudCon, &spConnector);                                \
                                                                                            \
    if ( hr == TYPE_E_ELEMENTNOTFOUND)                                                      \
    {                                                                                       \
        CComQIPtr<IRsConDescriptor> ConDescriptor;                                          \
        if (FAILED(hr = pBase->CreateConnectorDescriptor(pDesc, &ConDescriptor)))                 \
            return hr;                                                                      \
        if (FAILED(hr = pBase->CreateConnector(ConDescriptor, &spConnector)))               \
            return hr;                                                                      \
        if (FAILED(hr = pBase->AddConnector(spConnector)))                                  \
            return hr;                                                                      \
    }                                                                                       \
                                                                                            \
    return SetNodeDataObj##Type(pBase, giudCon, newVal);                                    \
}                                                                                           \
                                                                                            \
static HRESULT (SetNodeDataObj##Type)(IRsBaseNode *pBase, CONID giudCon, ##Type *newVal, LPWSTR szName, LPWSTR szDescriptor, RtFlags uFlags) \
{                                                                                           \
    RtConDesc sDesc = {&giudCon, szName, szDescriptor, VT_UNKNOWN, NULL, uFlags};           \
                                                                                            \
    return SetNodeDataObj##Type(pBase, giudCon, newVal, &sDesc);                            \
}
// End of macro for implementation of GetNodeDataObjXxxx and SetNodeDataObjXxxx.
/////////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////////
/// Objects names constants:
#define NMSRV_NUMBER_SEPARATOR L','     /// object name numbering separator "," ("Object, 1").
#define NMSRV_WHITE_SPACE      L' '     /// object name white space ' '.
#define NMSRV_COMPLETTE_SEP    L", "    /// string that will be added after name.
#define NMSRV_FIRST_NUMBER     1        /// the first object name number.
#define NMSRV_NAME_SEPARATOR   L"/"     /// object name separator (e.g. "kernel/space3d/sphere, 1").
#define NMSRV_DEFAULT_NAME     L"Object"/// name used for automatic name generating if class name is not defined.
/// End of objects names constants
/////////////////////////////////////////////////////////////////////////////////////////////

// logging support: 


#define RS_LOG_ACCESS(pBase)                                                               \
static HRESULT MyLogEntry(RtLogLevel ll, HRESULT hRes, BSTR bsText, const char *File, const DWORD Line)   \
{                                                                                           \
    ATLASSERT((pBase) != NULL);                                                   \
    CComQIPtr<IRsLogger> spLogger;                                           \
    (pBase)->GetLogger(&spLogger);                                        \
    if (!spLogger)  \
        return E_FAIL; \
    RtLogEntry le;                  \
    le.logLevel = ll;               \
    le.stText = bsText;             \
    CComBSTR bsFile(File);          \
    le.stSourceFileName = bsFile;   \
    le.ulSourceLine = Line;         \
    le.hRes = hRes;                 \
    return spLogger->AddLogEntry(le);\
}                                   \
//#define RS_LOG(lev, hr, text) ##_pckId::MyLogEntry(lev, hr, text, __FILE__, __LINE__);   

#ifndef RS_PERFORMANCE_INFO_DEFINED
#define RS_PERFORMANCE_INFO_DEFINED

#ifdef _DEBUG

#ifdef RS_RELEASE_PERFORMANCE
#undef RS_RELEASE_PERFORMANCE
#endif

#else	//	_DEBUG

#ifdef RS_DEBUG_PERFORMANCE
#undef RS_DEBUG_PERFORMANCE
#endif

#endif	//	_DEBUG

template <class CStringW>
class CRsPerformanceInfo
{
public:
#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)

#ifdef RS_DEBUG_PERFORMANCE_LONG_PRECISION
	LARGE_INTEGER m_StartTime;
	LARGE_INTEGER m_FinishTime;
#else	//	RS_DEBUG_PERFORMANCE_LONG_PRECISION
	DWORD m_StartTime;
	DWORD m_FinishTime;
#endif	//	RS_DEBUG_PERFORMANCE_LONG_PRECISION
	CStringW m_strInfoText;
	CStringW m_strNodeText;
	bool m_bHasNodeText;
	bool m_bFinished;
	bool m_bUseAssert;
	__int64 m_AssertTime;

#ifdef RS_RELEASE_PERFORMANCE_BUFFER
	static CStringW m_strBuffer;
#endif	// RS_RELEASE_PERFORMANCE_BUFFER

#endif	//	defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)

#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
	virtual ~CRsPerformanceInfo()
	{
		if ( !m_bFinished)
			Finish();
	}
#endif	//	defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)

	CRsPerformanceInfo()
	{
#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
		m_bFinished = false;

#ifdef RS_DEBUG_PERFORMANCE_DEFAULT_ASSERT_TIME
		m_bUseAssert = true;
		m_AssertTime = RS_DEBUG_PERFORMANCE_DEFAULT_ASSERT_TIME;
#else	//	RS_DEBUG_PERFORMANCE_DEFAULT_ASSERT_TIME
		m_bUseAssert = false;
#endif	//	RS_DEBUG_PERFORMANCE_DEFAULT_ASSERT_TIME

#endif	//	defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
	}

#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
	CRsPerformanceInfo( CStringW strInfoText, IRsBaseNode *pNode)
	{
		Init( strInfoText, pNode);
	}
#endif

#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
	void Init( CStringW strInfoText, IRsBaseNode *pNode)
	{
		if ( pNode)
		{
			CComBSTR name;
			if ( SUCCEEDED( pNode->GetFullName( NULL, &name)))
				Init( strInfoText, CStringW( name));
			else
				Init( strInfoText);
		}
		else
			Init( strInfoText);
	}

	CRsPerformanceInfo( CStringW strInfoText, IRsObject *pNode)
	{
		CComQIPtr<IRsBaseNode> spNode = pNode;

		Init( strInfoText, spNode);
	}

	CRsPerformanceInfo( CStringW strInfoText, IRsNode *pNode)
	{
		CComQIPtr<IRsBaseNode> spNode = pNode;

		Init( strInfoText, spNode);
	}
#endif

	CRsPerformanceInfo( CStringW strInfoText, IUnknown *pNode)
	{
#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
		CComQIPtr<IRsBaseNode> spNode = pNode;

		Init( strInfoText, spNode);
#endif
	}

	CRsPerformanceInfo( CStringW strInfoText, CStringW strNodeText)
	{
#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
		Init( strInfoText, strNodeText);
#endif
	}

#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
	void Init( CStringW strInfoText, CStringW strNodeText)
	{
		m_bHasNodeText = true;
		m_strNodeText = strNodeText;

		Init( strInfoText);
	}
#endif

	void Init( CStringW strInfoText)
	{
#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
		Start( strInfoText);
		m_bFinished = false;
#ifdef RS_DEBUG_PERFORMANCE_DEFAULT_ASSERT_TIME
		m_bUseAssert = true;
		m_AssertTime = RS_DEBUG_PERFORMANCE_DEFAULT_ASSERT_TIME;
#else
		m_bUseAssert = false;
#endif
#endif
	}

	CRsPerformanceInfo( CStringW strInfoText)
	{
#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
		m_bHasNodeText = false;
		Init( strInfoText);
#endif
	}

	CRsPerformanceInfo( CStringW strInfoText, __int64 assertTime)
	{
#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
		m_bHasNodeText = false;
		Start( strInfoText);
		m_bFinished = false;
		m_bUseAssert = true;
		m_AssertTime = assertTime;
#endif
	}

	void Start( CStringW strInfoText)
	{
#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
		m_strInfoText = strInfoText;
		GetTime( m_StartTime);

#ifdef _DEBUG

#ifdef RS_DEBUG_PERFORMANCE_TAB_COUNTER
		for ( int i = 0; i < RS_DEBUG_PERFORMANCE_TAB_COUNTER; i++)
			ATLTRACE( L"\t");

		RS_DEBUG_PERFORMANCE_TAB_COUNTER++;
#endif	//RS_DEBUG_PERFORMANCE_TAB_COUNTER

		ATLTRACE( L"[stamp:");
		CStringW helper;
		FormatTime( m_StartTime, helper);
		ATLTRACE( helper);
		ATLTRACE( L"]");
		ATLTRACE( m_strInfoText);
		ATLTRACE( L" started.\n");
#else	// _DEBUG
		CStringW text;

#ifdef RS_DEBUG_PERFORMANCE_TAB_COUNTER
		for ( int i = 0; i < RS_DEBUG_PERFORMANCE_TAB_COUNTER; i++)
			text += L"\t";

		RS_DEBUG_PERFORMANCE_TAB_COUNTER++;
#endif	// RS_DEBUG_PERFORMANCE_TAB_COUNTER

		CStringW helper;
		FormatTime( m_StartTime, helper);

#ifdef RS_RELEASE_PERFORMANCE_XML
		text = L"<stamp time='";
		text += helper;
		text += L"' info='";
		text += m_strInfoText;
		text += L"'>";
		if ( m_bHasNodeText)
		{
			text += L"\r\n<node name='";
			text += m_strNodeText;
			text += L"'/>";
		};

#else	// RS_RELEASE_PERFORMANCE_XML
		text += L"[stamp:";
		text += helper;
		text += L"]";
		text += m_strInfoText;
		text += L" started.";
#endif	// RS_RELEASE_PERFORMANCE_XML

		SaveToFile( text, false);
#endif	// _DEBUG

#endif	// defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
	};

#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
#ifdef RS_DEBUG_PERFORMANCE_LONG_PRECISION
	virtual void GetTime( LARGE_INTEGER &value)
	{
		QueryPerformanceCounter( &value);
	}

	virtual void FormatTime( LARGE_INTEGER &value, CStringW &res)
	{
		LARGE_INTEGER freq;
		QueryPerformanceFrequency( &freq);

		double d = (( double)value.QuadPart) / (( double)freq.QuadPart);
		d *= 1000.f;

		CStringW str;
		str.Format( L"%.3fms", d);

		res = str;
	}

	virtual double GetMS( LARGE_INTEGER &value)
	{
		LARGE_INTEGER freq;
		QueryPerformanceFrequency( &freq);

		double d = (( double)value.QuadPart) / (( double)freq.QuadPart);
		d *= 1000.f;

		return d;
	}

	virtual void ConvertDiffTimeToInt64( LARGE_INTEGER &value1, LARGE_INTEGER &value2, __int64 &res)
	{
		res = ( __int64)( value2.QuadPart - value1.QuadPart);
	}
#else
	virtual void GetTime( DWORD &value)
	{
		value = GetTickCount();
	}

	virtual void FormatTime( DWORD &value, CStringW &res)
	{
		CStringW str;
		str.Format( L"%d ms", ( int)value);

		res = str;
	}

	virtual double GetMS( DWORD &value)
	{
		return ( double)value;
	}

	virtual void ConvertDiffTimeToInt64( DWORD &value1, DWORD &value2, __int64 &res)
	{
		res = ( __int64)( value2 - value1);
	}
#endif
#endif

	void Finish()
	{
#if defined( RS_DEBUG_PERFORMANCE) || defined( RS_RELEASE_PERFORMANCE)
		m_bFinished = true;
		GetTime( m_FinishTime);

		__int64 iDiff;
		ConvertDiffTimeToInt64( m_StartTime, m_FinishTime, iDiff);

#ifdef RS_DEBUG_PERFORMANCE_LONG_PRECISION
		LARGE_INTEGER diff;
		diff.QuadPart = m_FinishTime.QuadPart - m_StartTime.QuadPart;
#else
		DWORD diff;
		diff = m_FinishTime - m_StartTime;
#endif

#ifndef _DEBUG
		CStringW text;
#endif

		bool bForceSave = true;

#ifdef RS_DEBUG_PERFORMANCE_TAB_COUNTER
		RS_DEBUG_PERFORMANCE_TAB_COUNTER--;

		for ( int i = 0; i < RS_DEBUG_PERFORMANCE_TAB_COUNTER; i++)
#ifdef _DEBUG
			ATLTRACE( L"\t");
#else
			text += L"\t";
#endif
		bForceSave = !RS_DEBUG_PERFORMANCE_TAB_COUNTER;
#endif

#ifdef _DEBUG
		ATLTRACE( L"[stamp:");
		CStringW helper;
		FormatTime( m_FinishTime, helper);
		ATLTRACE( helper);
		ATLTRACE( L"]");

		ATLTRACE( m_strInfoText);
		ATLTRACE( L" finished in ");

		FormatTime( diff, helper);
		ATLTRACE( helper);

		ATLTRACE( L".\n");

		if ( m_bUseAssert)
			ATLASSERT( m_AssertTime > iDiff);
#else

		CStringW helper;
		FormatTime( m_FinishTime, helper);

#ifdef RS_RELEASE_PERFORMANCE_XML
		text = L"<endTime time='";
		text += helper;
		text += L"' info='";
		text += m_strInfoText;
		text += L"'/>";

		FormatTime( diff, helper);

		text += L"<diffTime time='";
		if ( GetMS( diff) > 1000.0f)
			text += L"**** !!!! **** ";
		text += helper;
		text += L"'/>";

		text += L"</stamp>";

#else	// RS_RELEASE_PERFORMANCE_XML
		text += L"[stamp:";
		text += helper;
		text += L"]";

		text += m_strInfoText;
		text += L" finished in ";

		FormatTime( diff, helper);
		text += helper;

		text += L".";
#endif	// RS_RELEASE_PERFORMANCE_XML

		SaveToFile( text, bForceSave);

#endif
#endif
	};

	void SaveToFile(CStringW &strText, bool bForceSave) 
	{
#if defined( RS_RELEASE_PERFORMANCE)

#ifdef RS_RELEASE_PERFORMANCE_BUFFER
		if ( !bForceSave)
		{
			m_strBuffer += strText + L"\r\n";
			return;
		}
#endif	// RS_RELEASE_PERFORMANCE_DO_NOT_BUFFER

		if (!strText.IsEmpty())
		{
#ifdef RS_RELEASE_PERFORMANCE_XML
			HANDLE hLogFileHandle = CreateFile("C:\\RosettaPerformance.xml", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
#else
			HANDLE hLogFileHandle = CreateFile("C:\\RosettaPerformance.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
#endif
			SetFilePointer(hLogFileHandle, 0, NULL, FILE_END);
			ATLASSERT(hLogFileHandle); 

			DWORD tmpSize = (DWORD)sizeof(strText.GetAt(0));
			DWORD bWritten;

#ifdef RS_RELEASE_PERFORMANCE_BUFFER
			if ( m_strBuffer.GetLength() > 0)
			{
				WriteFile(hLogFileHandle, m_strBuffer, tmpSize*m_strBuffer.GetLength(), &bWritten, NULL);
				SetFilePointer(hLogFileHandle, 0, NULL, FILE_END);
				m_strBuffer.Empty();
			}
#endif	// RS_RELEASE_PERFORMANCE_DO_NOT_BUFFER

			WriteFile(hLogFileHandle, strText, tmpSize*strText.GetLength(), &bWritten, NULL);
			SetFilePointer(hLogFileHandle, 0, NULL, FILE_END);
			CStringW szEOL = L"\r\n";
			WriteFile(hLogFileHandle, szEOL, tmpSize*szEOL.GetLength(), &bWritten, NULL);
			FlushFileBuffers(hLogFileHandle);
			CloseHandle(hLogFileHandle);
		}
#endif
	}

	void FinishFile()
	{
		m_bFinished = true;
		SaveToFile( CStringW( L"</stamps>"), true);
	}

	void InitFile()
	{
#if defined( RS_RELEASE_PERFORMANCE)
		CStringW strText = L"<?xml version=\"1.0\" encoding=\"UTF-16\"?>\r\n<stamps>";
#ifdef RS_RELEASE_PERFORMANCE_XML
		HANDLE hLogFileHandle = CreateFile("C:\\RosettaPerformance.xml", GENERIC_WRITE, FILE_SHARE_READ, NULL, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#else
		HANDLE hLogFileHandle = CreateFile("C:\\RosettaPerformance.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#endif
		SetFilePointer(hLogFileHandle, 0, NULL, FILE_END);
		ATLASSERT(hLogFileHandle); 

		DWORD tmpSize = (DWORD)sizeof(strText.GetAt(0));
		DWORD bWritten;

		BYTE ch = 0xff;
		WriteFile(hLogFileHandle, &ch, 1, &bWritten, NULL);
		ch = 0xfe;
		WriteFile(hLogFileHandle, &ch, 1, &bWritten, NULL);

		WriteFile(hLogFileHandle, strText, tmpSize*strText.GetLength(), &bWritten, NULL);
		SetFilePointer(hLogFileHandle, 0, NULL, FILE_END);
		CStringW szEOL = L"\r\n";
		WriteFile(hLogFileHandle, szEOL, tmpSize*szEOL.GetLength(), &bWritten, NULL);
		FlushFileBuffers(hLogFileHandle);
		CloseHandle(hLogFileHandle);
#endif
	}
};

#endif
