Базовый класс для всех 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.
Сборка персонального компьютера от Artline: умный выбор для современных пользователей