Base class for all COM objects:
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); } } Where T is the IUnknown interface.
Further, there are several generalized interfaces such as ID2D1Rendertarget , ID2D1HwndRenderTarget , ID2D1BitmapRenderTarget , etc.
The task is that I need the factory to be able to create objects of a generalized type, by one method, with several overloads.
At this stage, I can not decide how to crank it.
What I thought up:
The base interface for the interfaces described above is the ID2D1Resource interface, in my opinion, the Resource class should have 2 overloads:
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); } } } But I think that something is wrong here as it should be ...
How to implement such inheritance correctly?
UPD:
Currently implemented this view:
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); } } } But in this situation, calling the method, for example, FillRectangle , Direct2D falls asleep to the debugging window with messages indicating that the wrong resource was transferred.
I think somewhere there is something wrong.
D2D DEBUG ERROR - The given resource [069FDED0] is not an anus type.