Как обобщить наследуемые объекты COM?

174
03 июня 2019, 00:00

Базовый класс для всех COM объектов:

public class ComObject<T> : IDisposable
{
    protected T NativeObject;
    protected internal ComObject(object nativeObject)
    {
        NativeObject = (T)nativeObject;
    }
    protected virtual void ReleaseUnmanagedResources()
    {
        if(NativeObject == default)
        {
            return;
        }
        Marshal.ReleaseComObject(NativeObject);
        NativeObject = default;
    }
    public void Dispose()
    {
        ReleaseUnmanagedResources();
        GC.SuppressFinalize(this);
    }
}

Где T — интерфейс IUnknown.

Далее, есть несколько обобщенных интерфейсов таких как ID2D1Rendertarget, ID2D1HwndRenderTarget, ID2D1BitmapRenderTarget и т.д.

Задача состоит в том, что мне необходимо чтобы фабрика умела создавать объекты обобщенного типа, одним методом, с несколькими перегрузками.

На данном этапе не могу решить как правильно это провернуть.

То что я надумал:

Базовый интерфейс для описанных выше интерфейсов, является интерфейс ID2D1Resource, по моему мнению, у класса Resource должно быть 2 перегрузки:

public class Resource : Resource<ID2D1Resource>
{
    protected internal Resource(object nativeObject) : base(nativeObject)
    {
    }
}
public class Resource<T> : ComObject<T>
{
    protected internal Resource(object nativeObject) : base(nativeObject)
    {
    }
    public Factory Factory
    {
        get
        {
            Marshal.ThrowExceptionForHR(((ID2D1Resource)NativeObject).GetFactory(out object factoryObject));
            return new Factory(factoryObject);
        }
    }
}

Но я считаю что здесь что-то не так как должно быть...

Как реализовать правильно такое наследование?

UPD:

На данный момент реализовал такое представление:

public class ComObject<T> : IDisposable
{
    protected internal object NativeObject;
    protected internal ComObject(object nativeObject)
    {
        NativeObject = nativeObject;
    }
    protected internal T2 As<T2>() => (T2)NativeObject;
    protected virtual void ReleaseUnmanagedResources()
    {
        Marshal.ReleaseComObject(NativeObject);
    }
    public void Dispose()
    {
        ReleaseUnmanagedResources();
        GC.SuppressFinalize(this);
    }
}
public class Resource : ComObject<ID2D1Resource>
{
    protected internal Resource(object nativeObject) :
        base(nativeObject)
    {
    }
    public ID2D1Factory Factory
    {
        get
        {
            Marshal.ThrowExceptionForHR(As<ID2D1Resource>().GetFactory(out object factoryObject));
            return (ID2D1Factory)factoryObject;
        }
    }
}
public class RenderTarget : Resource
{
    internal RenderTarget(object o) :
        base(o)
    {
    }
    public Bitmap CreateBitmap(SizeU size, IntPtr srcData, uint pitch, ref BitmapProperties bitmapProperties)
    {
        Marshal.ThrowExceptionForHR(As<ID2D1RenderTarget>().CreateBitmap(size, srcData, pitch, ref bitmapProperties, out object o));
        return new Bitmap(o);
    }
    public BitmapBrush CreateBitmapBrush(Bitmap bitmap, BitmapBrushProperties bitmapBrushProperties, BitmapProperties bitmapProperties)
    {
        Marshal.ThrowExceptionForHR(As<ID2D1RenderTarget>().CreateBitmapBrush(bitmap.NativeObject, ref bitmapBrushProperties, ref bitmapProperties, out object o));
        return new BitmapBrush(o);
    }
    public SolidColorBrush CreateSolidColorBrush(Color color, BrushProperties brushProperties)
    {
        Marshal.ThrowExceptionForHR(As<ID2D1RenderTarget>().CreateSolidColorBrush(ref color, ref brushProperties, out object o));
        return new SolidColorBrush(o);
    }
    public SizeF Size
    {
        get
        {
            return As<ID2D1RenderTarget>().GetSize();
        }
    }
    public SizeU PixelSize
    {
        get
        {
            return As<ID2D1RenderTarget>().GetPixelSize();
        }
    }
    public void Clear()
    {
        Clear(new Color(.0f, .0f,.0f));
    }
    public void Clear(Color color)
    {
        As<ID2D1RenderTarget>().Clear(ref color);
    }
    public void BeginDraw()
    {
        As<ID2D1RenderTarget>().BeginDraw();
    }
    public Tags EndDraw()
    {
        Tags tags = new Tags();
        As<ID2D1RenderTarget>().EndDraw(out tags.Tag1, out tags.Tag2);
        return tags;
    }
    public uint MaximumBitmapSize
    {
        get
        {
            return As<ID2D1RenderTarget>().GetMaximumBitmapSize();
        }
    }
    public Dpi Dpi
    {
        get
        {
            Dpi dpi = new Dpi();
            As<ID2D1RenderTarget>().GetDpi(out dpi.X, out dpi.Y);
            return dpi;
        }
        set
        {
            As<ID2D1RenderTarget>().SetDpi(value.X, value.Y);
        }
    }
    public void DrawRectangle(RectF rect, Brush brush, float strokeWidth)
    {
        As<ID2D1RenderTarget>().DrawRectangle(ref rect, (ID2D1Brush)brush.NativeObject, strokeWidth);
    }
    public void FillRectangle(RectF rect, Brush brush)
    {
        As<ID2D1RenderTarget>().FillRectangle(ref rect, (ID2D1Brush)brush.NativeObject);
    }
    public Matrix3X2F Transform
    {
        get
        {
            As<ID2D1RenderTarget>().GetTransform(out Matrix3X2F transform);
            return transform;
        }
        set
        {
            As<ID2D1RenderTarget>().SetTransform(ref value);
        }
    }
}

Но при таком раскладе, вызывая метод например FillRectangle, Direct2D засыпает окно отладки сообщениями о том что был передан не правильный ресурс.

Думаю где-то тут что-то не так.

D2D DEBUG ERROR - The given resource [069FDED0] is not of an expected type.

READ ALSO
Получение динамических данных Network(chrome) в коде

Получение динамических данных Network(chrome) в коде

значит имеем мы страничку, на ней плеер, чатпринцип работы, отправляет отрывки видео (длительностью в 2 секунды)(media

161
Вызов функций для элементов массива

Вызов функций для элементов массива

Сценарий следующий: пользователь отмечает "чекбоксами" варианты в соответствующем мета-поле в админпанели и на выходе (в зависимости от выбранного...

166