def make_handler_g_body(cls):
    csname = schema.cpp2csname(cls.get_name())
    iname = schema.get_iname(cls)

    funcs = get_funcs(cls)

    result = []

    # this dictionary used to keep object alive even when we doesn't reference object directly, but it can be referenced only from native side
    result.append(
        'private static Dictionary<IntPtr, %(csname)s> _roots = new Dictionary<IntPtr, %(csname)s>();'
        % {'csname': csname})
    result.append('')

    result.append('private int _refct;')
    result.append('private %s* _self;' % iname)
    # result.append('private bool _disposed;')
    result.append('')

    result.append('protected object SyncRoot { get { return this; } }')
    result.append('')

    if schema.is_reversible(cls):
        result.append('internal static %s FromNativeOrNull(%s* ptr)' %
                      (csname, iname))
        result.append('{')
        result.append(indent + '%s value = null;' % csname)
        result.append(indent + 'bool found;')
        result.append(indent + 'lock (_roots)')
        result.append(indent + '{')
        result.append(indent + indent +
                      'found = _roots.TryGetValue((IntPtr)ptr, out value);')
        result.append(indent + '}')
        result.append(indent + 'return found ? value : null;')
        result.append('}')
        result.append('')

        result.append('internal static %s FromNative(%s* ptr)' %
                      (csname, iname))
        result.append('{')
        result.append(indent + 'var value = FromNativeOrNull(ptr);')
        result.append(
            indent +
            'if (value == null) throw ExceptionBuilder.ObjectNotFound();')
        result.append(indent + 'return value;')
        result.append('}')
        result.append('')

    for func in funcs:
        result.append(
            'private %(iname)s.%(delegate_type)s %(delegate_slot)s;' % func)
    result.append('')

    # ctor
    result.append('protected %s()' % csname)
    result.append('{')
    result.append(indent + '_self = %s.Alloc();' % iname)
    result.append('')
    for func in funcs:
        result.append(
            indent +
            '%(delegate_slot)s = new %(iname)s.%(delegate_type)s(%(csn_name)s);'
            % func)
        result.append(
            indent +
            '_self->%(field_name)s = Marshal.GetFunctionPointerForDelegate(%(delegate_slot)s);'
            % func)
    result.append('}')
    result.append('')

    # finalizer & dispose
    result.append('~%s()' % csname)
    result.append('{')
    result.append(indent + 'Dispose(false);')
    result.append('}')
    result.append('')

    if schema.is_autodispose(cls):
        result.append('private void Dispose()')
        result.append('{')
        result.append(indent + 'Dispose(true);')
        result.append(indent + 'GC.SuppressFinalize(this);')
        result.append('}')
        result.append('')

    result.append('protected virtual void Dispose(bool disposing)')
    result.append('{')
    # result.append(indent + '_disposed = true;')
    result.append(indent + 'if (_self != null)')
    result.append(indent + '{')
    result.append(indent + indent + '%s.Free(_self);' % iname)
    result.append(indent + indent + '_self = null;')
    result.append(indent + '}')
    result.append('}')
    result.append('')

    # todo: this methods must throw exception if object already disposed
    # todo: verify self pointer in debug
    result.append('private void add_ref(%s* self)' % iname)
    result.append('{')
    result.append(indent + 'lock (SyncRoot)')
    result.append(indent + '{')
    result.append(indent + indent + 'var result = ++_refct;')
    result.append(indent + indent + 'if (result == 1)')
    result.append(indent + indent + '{')
    result.append(indent + indent + indent +
                  'lock (_roots) { _roots.Add((IntPtr)_self, this); }')
    result.append(indent + indent + '}')
    result.append(indent + '}')
    result.append('}')
    result.append('')

    result.append('private int release(%s* self)' % iname)
    result.append('{')
    result.append(indent + 'lock (SyncRoot)')
    result.append(indent + '{')
    result.append(indent + indent + 'var result = --_refct;')
    result.append(indent + indent + 'if (result == 0)')
    result.append(indent + indent + '{')
    result.append(indent + indent + indent +
                  'lock (_roots) { _roots.Remove((IntPtr)_self); }')
    if schema.is_autodispose(cls):
        result.append(indent + indent + indent + 'Dispose();')
    result.append(indent + indent + indent + 'return 1;')
    result.append(indent + indent + '}')
    result.append(indent + indent + 'return 0;')
    result.append(indent + '}')
    result.append('}')
    result.append('')

    result.append('private int has_one_ref(%s* self)' % iname)
    result.append('{')
    result.append(indent + 'lock (SyncRoot) { return _refct == 1 ? 1 : 0; }')
    result.append('}')
    result.append('')

    result.append('private int has_at_least_one_ref(%s* self)' % iname)
    result.append('{')
    result.append(indent + 'lock (SyncRoot) { return _refct != 0 ? 1 : 0; }')
    result.append('}')
    result.append('')

    result.append('internal %s* ToNative()' % iname)
    result.append('{')
    result.append(indent + 'add_ref(_self);')
    result.append(indent + 'return _self;')
    result.append('}')
    result.append('')

    result.append('[Conditional("DEBUG")]')
    result.append('private void CheckSelf(%s* self)' % iname)
    result.append('{')
    result.append(
        indent +
        'if (_self != self) throw ExceptionBuilder.InvalidSelfReference();')
    result.append('}')
    result.append('')

    return result
def make_handler_g_body(cls):
    csname = schema.cpp2csname(cls.get_name())
    iname = schema.get_iname(cls)

    funcs = get_funcs(cls)

    result = []

    # this dictionary used to keep object alive even when we doesn't reference object directly, but it can be referenced only from native side
    result.append('private static Dictionary<IntPtr, %(csname)s> _roots = new Dictionary<IntPtr, %(csname)s>();' % { 'csname' : csname })
    result.append('')

    result.append('private int _refct;')
    result.append('private %s* _self;' % iname)
    # result.append('private bool _disposed;')
    result.append('')

    result.append('protected object SyncRoot { get { return this; } }')
    result.append('')

    if schema.is_reversible(cls):
        result.append('internal static %s FromNativeOrNull(%s* ptr)' % (csname, iname))
        result.append('{')
        result.append(indent + '%s value = null;' % csname)
        result.append(indent + 'bool found;')
        result.append(indent + 'lock (_roots)')
        result.append(indent + '{')
        result.append(indent + indent + 'found = _roots.TryGetValue((IntPtr)ptr, out value);')
        result.append(indent + '}')
        result.append(indent + 'return found ? value : null;')
        result.append('}')
        result.append('')

        result.append('internal static %s FromNative(%s* ptr)' % (csname, iname))
        result.append('{')
        result.append(indent + 'var value = FromNativeOrNull(ptr);')
        result.append(indent + 'if (value == null) throw ExceptionBuilder.ObjectNotFound();')
        result.append(indent + 'return value;')
        result.append('}')
        result.append('')

    for func in funcs:
        result.append('private %(iname)s.%(delegate_type)s %(delegate_slot)s;' % func)
    result.append('')

    # ctor
    result.append('protected %s()' % csname)
    result.append('{')
    result.append(indent + '_self = %s.Alloc();' % iname)
    result.append('');
    for func in funcs:
        result.append(indent + '%(delegate_slot)s = new %(iname)s.%(delegate_type)s(%(csn_name)s);' % func)
        result.append(indent + '_self->%(field_name)s = Marshal.GetFunctionPointerForDelegate(%(delegate_slot)s);' % func)
    result.append('}')
    result.append('')

    # finalizer & dispose
    result.append('~%s()' % csname)
    result.append('{')
    result.append(indent + 'Dispose(false);')
    result.append('}')
    result.append('')

    result.append('protected virtual void Dispose(bool disposing)')
    result.append('{')
    # result.append(indent + '_disposed = true;')
    result.append(indent + 'if (_self != null)')
    result.append(indent + '{')
    result.append(indent + indent + '%s.Free(_self);' % iname)
    result.append(indent + indent + '_self = null;')
    result.append(indent + '}')
    result.append('}')
    result.append('')

    # todo: this methods must throw exception if object already disposed
    # todo: verify self pointer in debug
    result.append('private int add_ref(%s* self)' % iname)
    result.append('{')
    result.append(indent + 'lock (SyncRoot)')
    result.append(indent + '{')
    result.append(indent + indent + 'var result = ++_refct;')
    result.append(indent + indent + 'if (result == 1)')
    result.append(indent + indent + '{')
    result.append(indent + indent + indent + 'lock (_roots) { _roots.Add((IntPtr)_self, this); }')
    result.append(indent + indent + '}')
    result.append(indent + indent + 'return result;')
    result.append(indent + '}')
    result.append('}')
    result.append('')

    result.append('private int release(%s* self)' % iname)
    result.append('{')
    result.append(indent + 'lock (SyncRoot)')
    result.append(indent + '{')
    result.append(indent + indent + 'var result = --_refct;')
    result.append(indent + indent + 'if (result == 0)')
    result.append(indent + indent + '{')
    result.append(indent + indent + indent + 'lock (_roots) { _roots.Remove((IntPtr)_self); }')
    result.append(indent + indent + '}')
    result.append(indent + indent + 'return result;')
    result.append(indent + '}')
    result.append('}')
    result.append('')

    result.append('private int get_refct(%s* self)' % iname)
    result.append('{')
    result.append(indent + 'return _refct;')
    result.append('}')
    result.append('')

    result.append('internal %s* ToNative()' % iname)
    result.append('{')
    result.append(indent + 'add_ref(_self);')
    result.append(indent + 'return _self;')
    result.append('}')
    result.append('')

    result.append('[Conditional("DEBUG")]')
    result.append('private void CheckSelf(%s* self)' % iname)
    result.append('{')
    result.append(indent + 'if (_self != self) throw ExceptionBuilder.InvalidSelfReference();')
    result.append('}')
    result.append('')

    return result