c++delphiinterfacedirect2dvmt

How to get address of C++ interface VMT


Context:

I'm trying to use a few COM Interface (Direct2D 1.1) from a Delphi application. For that purpose, I have to port the interfaces to Delphi. I have done that but I have a problem with one of the interfaces: the method I call is not the correct one. I verified that by writing the exact same piece of code in C++ and in Delphi. Running both under the debugger, I see that the code called by Delphi is not the same as the code called by C++. So I made a mistake in porting that interface.

To find out where my error is, I have the idea to dump all method pointers to compare the address shown by C++ and by Delphi. They should be the same as the point to the same DLL.

I don't know how to get hand on the VMT! I have read this but it is not applicable in my case: the .h file do not contain the C equivalent.

I'm looking for something similar to offsetof() and sizeof() that I use to check structures. And something to get the address of a given interface method.

Any help appreciated. PS: I hope that my English is understandable.


Solution

  • I found the solution, so I will answer my own question:

    Below is the code required to load the VMT of interface whose pointer is variable "Screen" into array of pointers VMT. The code assume there are 93 methods (That is actually the case). I have yet to know how to get the count of methods in a given interface to fully automate the process.

    UINT_PTR* Ptr1 = reinterpret_cast<UINT_PTR*>(Screen);
    UINT_PTR* Ptr2 = reinterpret_cast<UINT_PTR*>(*Ptr1);
    UINT_PTR* VMT[92];
    for (UINT I = 0; I < ARRAYSIZE(VMT); I++) {
        VMT[I] = reinterpret_cast<UINT_PTR*>(*Ptr2);
        Ptr2++;
    }
    

    I verifyed that this code is OK by using the debugger and loading Windows symbols. This gives the following result in VMT:

    +       [0] 0x6dd34e90 {d2d1.dll!ComObjectImpl<class RefCountedObject<class D2DDeviceContext,struct LockingRequired,struct LockFactoryOnReferenceReachedZero>,class type_list<struct ID2D1DeviceContext6,class type_list<struct ID2D1DeviceContext5,class type_list<struct ID2D1DeviceContext4,class type_list<struct ID2D1DeviceContext3,class type_list<struct ID2D1DeviceContext2,class type_list<struct ID2D1DeviceContext1,class type_list<struct ID2D1DeviceContext,class type_list<class IRenderTargetInternal,class type_list<struct ID2D1GdiInteropRenderTarget,class type_list<struct ID2D1ImagingDeviceContext,class type_list<struct ID2D1PrivateCompositorDeviceContext,class type_list<struct ID2D1PrivatePencilDeviceContext,class type_list<struct ID2D1PrivateTestDeviceContext,class type_list<struct ID2D1PrivateInkingDeviceContext,class type_list<struct CompoundCast<struct ID2D1RenderTarget,struct ID2D1DeviceContext6>,class type_list<struct CompoundCast<struct ID2D1Resource,struct ID2D1DeviceContext6>,class null_type> > > > > > > > > > > > > > > > >::QueryInterface(struct _GUID const &,void * *)} {...}    unsigned int *
    +       [1] 0x6dd208e0 {d2d1.dll!RefCountedObject<class D2DDeviceContext,struct LockingRequired,struct LockFactoryOnReferenceReachedZero>::AddRef(void)} {...}  unsigned int *
    +       [2] 0x6dcfc150 {d2d1.dll!RefCountedObject<class D2DDeviceContext,struct LockingRequired,struct LockFactoryOnReferenceReachedZero>::Release(void)} {...} unsigned int *
    +       [3] 0x6dda0aa0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::GetFactory(struct ID2D1Factory * *)const } {...}   unsigned int *
    +       [4] 0x6dd99f40 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::CreateBitmap(struct D2D_SIZE_U,void const *,unsigned int,struct D2D1_BITMAP_PROPERTIES const *,struct ID2D1Bitmap * *)} {...}  unsigned int *
    +       [5] 0x6dd29d40 {d2d1.dll!D2DDeviceContextBase<...>::CreateBitmapFromWicBitmap(void)} {2337640550}   unsigned int *
    +       [6] 0x6dd9cce0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::CreateSharedBitmap(struct _GUID const &,void *,struct D2D1_BITMAP_PROPERTIES const *,struct ID2D1Bitmap * *)} {...}    unsigned int *
    +       [7] 0x6dc75440 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::CreateBitmapBrush(struct ID2D1Bitmap *,struct D2D1_BITMAP_BRUSH_PROPERTIES const *,struct D2D1_BRUSH_PROPERTIES const *,struct ID2D1BitmapBrush * *)} {...}    unsigned int *
    +       [8] 0x6dcfe940 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::CreateSolidColorBrush(struct _D3DCOLORVALUE const *,struct D2D1_BRUSH_PROPERTIES const *,struct ID2D1SolidColorBrush * *)} {...}   unsigned int *
    +       [9] 0x6dd9b7a0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::CreateGradientStopCollection(struct D2D1_GRADIENT_STOP const *,unsigned int,enum D2D1_GAMMA,enum D2D1_EXTEND_MODE,struct ID2D1GradientStopCollection * *)} {...}   unsigned int *
    +       [10]    0x6dd9c490 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::CreateLinearGradientBrush(struct D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES const *,struct D2D1_BRUSH_PROPERTIES const *,struct ID2D1GradientStopCollection *,struct ID2D1LinearGradientBrush * *)} {...}   unsigned int *
    +       [11]    0x6dd9ca10 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::CreateRadialGradientBrush(struct D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES const *,struct D2D1_BRUSH_PROPERTIES const *,struct ID2D1GradientStopCollection *,struct ID2D1RadialGradientBrush * *)} {...}   unsigned int *
    +       [12]    0x6dd9aec0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::CreateCompatibleRenderTarget(struct D2D_SIZE_F const *,struct D2D_SIZE_U const *,struct D2D1_PIXEL_FORMAT const *,enum D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS,struct ID2D1BitmapRenderTarget * *)} {...}    unsigned int *
    +       [13]    0x6dd9c330 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::CreateLayer(struct D2D_SIZE_F const *,struct ID2D1Layer * *)} {...}    unsigned int *
    +       [14]    0x6dd9c6c0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::CreateMesh(struct ID2D1Mesh * *)} {...}    unsigned int *
    +       [15]    0x6dd9e5e0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::DrawLine(struct D2D_POINT_2F,struct D2D_POINT_2F,struct ID2D1Brush *,float,struct ID2D1StrokeStyle *)} {...}   unsigned int *
    +       [16]    0x6dd158b0 {d2d1.dll!D2DDeviceContextBase<...>::DrawRectangle(void)} {2337640550}   unsigned int *
    +       [17]    0x6dd12700 {d2d1.dll!D2DDeviceContextBase<...>::FillRectangle(void)} {2337640550}   unsigned int *
    +       [18]    0x6dd9e920 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::DrawRoundedRectangle(struct D2D1_ROUNDED_RECT const *,struct ID2D1Brush *,float,struct ID2D1StrokeStyle *)} {...}  unsigned int *
    +       [19]    0x6dd9fa50 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::FillRoundedRectangle(struct D2D1_ROUNDED_RECT const *,struct ID2D1Brush *)} {...}  unsigned int *
    +       [20]    0x6dd9db00 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::DrawEllipse(struct D2D1_ELLIPSE const *,struct ID2D1Brush *,float,struct ID2D1StrokeStyle *)} {...}    unsigned int *
    +       [21]    0x6dd9f3d0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::FillEllipse(struct D2D1_ELLIPSE const *,struct ID2D1Brush *)} {...}    unsigned int *
    +       [22]    0x6dcd8c00 {d2d1.dll!D2DDeviceContextBase<...>::DrawGeometry(void)} {2337640550}    unsigned int *
    +       [23]    0x6dcd1660 {d2d1.dll!D2DDeviceContextBase<...>::FillGeometry(void)} {2337640550}    unsigned int *
    +       [24]    0x6dd9f5f0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::FillMesh(struct ID2D1Mesh *,struct ID2D1Brush *)} {...}    unsigned int *
    +       [25]    0x6dd9f800 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::FillOpacityMask(struct ID2D1Bitmap *,struct ID2D1Brush *,enum D2D1_OPACITY_MASK_CONTENT,struct D2D_RECT_F const *,struct D2D_RECT_F const *)} {...}    unsigned int *
    +       [26]    0x6dd12080 {d2d1.dll!D2DDeviceContextBase<...>::DrawBitmap(void)} {2337640550}  unsigned int *
    +       [27]    0x6dcfafb0 {d2d1.dll!D2DDeviceContextBase<...>::DrawTextW(void)} {2337640550}   unsigned int *
    +       [28]    0x6dd9ef40 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::DrawTextLayout(struct D2D_POINT_2F,struct IDWriteTextLayout *,struct ID2D1Brush *,enum D2D1_DRAW_TEXT_OPTIONS)} {...}  unsigned int *
    +       [29]    0x6dc807c0 {d2d1.dll!D2DDeviceContextBase<...>::DrawGlyphRun(void)} {2337640550}    unsigned int *
    +       [30]    0x6dc7f650 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::SetTransform(struct D2D_MATRIX_3X2_F const *)} {...}   unsigned int *
    +       [31]    0x6dcfbe30 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::GetTransform(struct D2D_MATRIX_3X2_F *)const } {...}   unsigned int *
    +       [32]    0x6dcfcbb0 {d2d1.dll!D2DDeviceContextBase<...>::SetAntialiasMode(void)} {2337640550}    unsigned int *
    +       [33]    0x6dcfcd70 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::GetAntialiasMode(void)const } {...}    unsigned int *
    +       [34]    0x6dda3cf0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::SetTextAntialiasMode(enum D2D1_TEXT_ANTIALIAS_MODE)} {...} unsigned int *
    +       [35]    0x6dcfcf00 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::GetTextAntialiasMode(void)const } {...}    unsigned int *
    +       [36]    0x6dcfd870 {d2d1.dll!D2DDeviceContextBase<...>::SetTextRenderingParams(void)} {2337640550}  unsigned int *
    +       [37]    0x6dda1b40 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::GetTextRenderingParams(struct IDWriteRenderingParams * *)const } {...} unsigned int *
    +       [38]    0x6dda3a90 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::SetTags(unsigned __int64,unsigned __int64)} {...}  unsigned int *
    +       [39]    0x6dda1a40 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::GetTags(unsigned __int64 *,unsigned __int64 *)const } {...}    unsigned int *
    +       [40]    0x6dda2ac0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::PushLayer(struct D2D1_LAYER_PARAMETERS const *,struct ID2D1Layer *)} {...} unsigned int *
    +       [41]    0x6dd15c30 {d2d1.dll!D2DDeviceContextBase<...>::PopLayer(void)} {2337640550}    unsigned int *
    +       [42]    0x6dd13570 {d2d1.dll!D2DDeviceContextBase<...>::Flush(void)} {2337640550}   unsigned int *
    +       [43]    0x6dd189f0 {d2d1.dll!D2DDeviceContextBase<...>::SaveDrawingState(void)} {2337640550}    unsigned int *
    +       [44]    0x6dcfc180 {d2d1.dll!D2DDeviceContextBase<...>::RestoreDrawingState(void)} {2337640550} unsigned int *
    +       [45]    0x6dcf49d0 {d2d1.dll!D2DDeviceContextBase<...>::PushAxisAlignedClip(void)} {2337640550} unsigned int *
    +       [46]    0x6dd13340 {d2d1.dll!D2DDeviceContextBase<...>::PopAxisAlignedClip(void)} {2337640550}  unsigned int *
    +       [47]    0x6dcdb410 {d2d1.dll!D2DDeviceContextBase<...>::Clear(void)} {2337640550}   unsigned int *
    +       [48]    0x6dcd8720 {d2d1.dll!D2DDeviceContextBase<...>::BeginDraw(void)} {2337640550}   unsigned int *
    +       [49]    0x6dcd8900 {d2d1.dll!D2DDeviceContextBase<...>::EndDraw(void)} {2337640550} unsigned int *
    +       [50]    0x6dcd2b80 {d2d1.dll!D2DDeviceContextBase<ID2D1DeviceContext6,ID2D1DeviceContext6,null_type>::GetPixelFormat(void)} {...}   unsigned int *
    +       [51]    0x6dc81160 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::SetDpi(float,float)} {...} unsigned int *
    +       [52]    0x6dcfbd00 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::GetDpi(float *,float *)const } {...}   unsigned int *
    +       [53]    0x6dda1710 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::GetSize(void)const } {...} unsigned int *
    +       [54]    0x6dcd2230 {d2d1.dll!D2DDeviceContextBase<ID2D1DeviceContext6,ID2D1DeviceContext6,null_type>::GetPixelSize(void)} {...} unsigned int *
    +       [55]    0x6dda12d0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::GetMaximumBitmapSize(void)const } {...}    unsigned int *
    +       [56]    0x6dda1f40 {d2d1.dll!D2DDeviceContextBase<struct ID2D1BitmapRenderTarget,struct ID2D1BitmapRenderTarget,struct ID2D1DeviceContext6>::IsSupported(struct D2D1_RENDER_TARGET_PROPERTIES const *)const } {...} unsigned int *
    +       [57]    0x6dc89b50 {d2d1.dll!D2DDeviceContextBase<ID2D1DeviceContext6,ID2D1DeviceContext6,null_type>::CreateBitmap(void)} {...} unsigned int *
    +       [58]    0x6dcfe7f0 {d2d1.dll!D2DDeviceContextBase<ID2D1DeviceContext6,ID2D1DeviceContext6,null_type>::CreateBitmapFromWicBitmap(void)} {...}    unsigned int *
    +       [59]    0x6dda59d0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::CreateColorContext(enum D2D1_COLOR_SPACE,unsigned char const *,unsigned int,struct ID2D1ColorContext * *)} {...}  unsigned int *
    +       [60]    0x6dc835c0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::CreateColorContextFromFilename(unsigned short const *,struct ID2D1ColorContext * *)} {...}    unsigned int *
    +       [61]    0x6dda5ce0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::CreateColorContextFromWicColorContext(struct IWICColorContext *,struct ID2D1ColorContext * *)} {...}  unsigned int *
    +       [62]    0x6dcad780 {d2d1.dll!D2DDeviceContextBase<ID2D1DeviceContext6,ID2D1DeviceContext6,null_type>::CreateBitmapFromDxgiSurface(void)} {...}  unsigned int *
    +       [63]    0x6dcdce60 {d2d1.dll!D2DDeviceContextBase<ID2D1DeviceContext6,ID2D1DeviceContext6,null_type>::CreateEffect(void)} {...} unsigned int *
    +       [64]    0x6dda6230 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::CreateGradientStopCollection(struct D2D1_GRADIENT_STOP const *,unsigned int,enum D2D1_COLOR_SPACE,enum D2D1_COLOR_SPACE,enum D2D1_BUFFER_PRECISION,enum D2D1_EXTEND_MODE,enum D2D1_COLOR_INTERPOLATION_MODE,struct ID2D1GradientStopCollection1 * *)} {...}   unsigned int *
    +       [65]    0x6dc7d8b0 {d2d1.dll!D2DDeviceContextBase<ID2D1DeviceContext6,ID2D1DeviceContext6,null_type>::CreateImageBrush(void)} {...} unsigned int *
    +       [66]    0x6dc75640 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::CreateBitmapBrush(struct ID2D1Bitmap *,struct D2D1_BITMAP_BRUSH_PROPERTIES1 const *,struct D2D1_BRUSH_PROPERTIES const *,struct ID2D1BitmapBrush1 * *)} {...} unsigned int *
    +       [67]    0x6dc7d410 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::CreateCommandList(struct ID2D1CommandList * *)} {...} unsigned int *
    +       [68]    0x6dc7a100 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::IsDxgiFormatSupported(enum DXGI_FORMAT)const } {...}  unsigned int *
    +       [69]    0x6dc80620 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::IsBufferPrecisionSupported(enum D2D1_BUFFER_PRECISION)const } {...}   unsigned int *
    +       [70]    0x6dc6d0b0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::GetImageLocalBounds(struct ID2D1Image *,struct D2D_RECT_F *)const } {...} unsigned int *
    +       [71]    0x6dda8a10 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::GetImageWorldBounds(struct ID2D1Image *,struct D2D_RECT_F *)const } {...} unsigned int *
    +       [72]    0x6dcaad10 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::GetGlyphRunWorldBounds(struct D2D_POINT_2F,struct DWRITE_GLYPH_RUN const *,enum DWRITE_MEASURING_MODE,struct D2D_RECT_F *)const } {...}   unsigned int *
    +       [73]    0x6dc7e2a0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::GetDevice(struct ID2D1Device * *)const } {...}    unsigned int *
    +       [74]    0x6dcdc240 {d2d1.dll!D2DDeviceContextBase<ID2D1DeviceContext6,ID2D1DeviceContext6,null_type>::SetTarget(void)} {...}    unsigned int *
    +       [75]    0x6dc84990 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::GetTarget(struct ID2D1Image * *)const } {...} unsigned int *
    +       [76]    0x6dc804a0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::SetRenderingControls(struct D2D1_RENDERING_CONTROLS const *)} {...}   unsigned int *
    +       [77]    0x6dc832e0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::GetRenderingControls(struct D2D1_RENDERING_CONTROLS *)const } {...}   unsigned int *
    +       [78]    0x6dcfc740 {d2d1.dll!D2DDeviceContextBase<ID2D1DeviceContext6,ID2D1DeviceContext6,null_type>::SetPrimitiveBlend(void)} {...}    unsigned int *
    +       [79]    0x6dc7cd70 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::GetPrimitiveBlend(void)const } {...}  unsigned int *
    +       [80]    0x6dcfc810 {d2d1.dll!D2DDeviceContextBase<ID2D1DeviceContext6,ID2D1DeviceContext6,null_type>::SetUnitMode(void)} {...}  unsigned int *
    +       [81]    0x6dcfbda0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::GetUnitMode(void)const } {...}    unsigned int *
    +       [82]    0x6dcaaf30 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::DrawGlyphRun(struct D2D_POINT_2F,struct DWRITE_GLYPH_RUN const *,struct DWRITE_GLYPH_RUN_DESCRIPTION const *,struct ID2D1Brush *,enum DWRITE_MEASURING_MODE)} {...}   unsigned int *
    +       [83]    0x6dcda160 {d2d1.dll!D2DDeviceContextBase<ID2D1DeviceContext6,ID2D1DeviceContext6,null_type>::DrawImage(void)} {...}    unsigned int *
    +       [84]    0x6dda78d0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::DrawGdiMetafile(struct ID2D1GdiMetafile *,struct D2D_POINT_2F const *)} {...} unsigned int *
    +       [85]    0x6dda76a0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::DrawBitmap(struct ID2D1Bitmap *,struct D2D_RECT_F const *,float,enum D2D1_INTERPOLATION_MODE,struct D2D_RECT_F const *,struct D2D_MATRIX_4X4_F const *)} {...}    unsigned int *
    +       [86]    0x6dd0fac0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::PushLayer(struct D2D1_LAYER_PARAMETERS1 const *,struct ID2D1Layer *)} {...}   unsigned int *
    +       [87]    0x6dc66a30 {d2d1.dll!D2DDeviceContextBase<ID2D1DeviceContext6,ID2D1DeviceContext6,null_type>::InvalidateEffectInputRectangle(void)} {...}   unsigned int *
    +       [88]    0x6dc63180 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::GetEffectInvalidRectangleCount(struct ID2D1Effect *,unsigned int *)} {...}    unsigned int *
    +       [89]    0x6dc634d0 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::GetEffectInvalidRectangles(struct ID2D1Effect *,struct D2D_RECT_F *,unsigned int)} {...}  unsigned int *
    +       [90]    0x6dc62b50 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::GetEffectRequiredInputRectangles(struct ID2D1Effect *,struct D2D_RECT_F const *,struct D2D1_EFFECT_INPUT_DESCRIPTION const *,struct D2D_RECT_F *,unsigned int)} {...} unsigned int *
    +       [91]    0x6dda8420 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::FillOpacityMask(struct ID2D1Bitmap *,struct ID2D1Brush *,struct D2D_RECT_F const *,struct D2D_RECT_F const *)} {...}  unsigned int *
    +       [92]    0x6dda5f90 {d2d1.dll!D2DDeviceContextBase<struct ID2D1DeviceContext6,struct ID2D1DeviceContext6,class null_type>::CreateFilledGeometryRealization(struct ID2D1Geometry *,float,struct ID2D1GeometryRealization * *)} {...}  unsigned int *
    

    You can see that the 3 first entries are QueryInterface, AddRef and Release method which is what all interfaces have in their VMT.