LoginSignup
9
7

More than 5 years have passed since last update.

COMのインターフェース

Posted at

D言語を使っていると、C言語のライブラリとか、COM(Windows)とかを使いたくなることが有ります。だれかが提供してくれている場合はいいですが、どうしても書かざるをえない場合もあります。
そんな時にはバインディングを書いたりするのですが、今回は、COMインターフェースのバインディングの書き方(とサボる方法)を少し説明します。

例として。ID2DFactory

d2d1.d
interface ID2D1Factory: IUnknown
{
    HRESULT ReloadSystemMetrics();
    void GetDesktopDpi(FLOAT *dpiX, FLOAT *dpiY);
    HRESULT CreateRectangleGeometry(const D2D1_RECT_F* rectangle, ID2D1RectangleGeometry* rectangleGeometry);
    void foo04(); //HRESULT CreateRoundedRectangleGeometry(const D2D1_ROUNDED_RECT *roundedRectangle, ID2D1RoundedRectangleGeometry **roundedRectangleGeometry);
    void foo05(); //HRESULT CreateEllipseGeometry(const D2D1_ELLIPSE *ellipse, ID2D1EllipseGeometry **ellipseGeometry);
    void foo06(); //HRESULT CreateGeometryGroup(D2D1_FILL_MODE fillMode, ID2D1Geometry **geometries, UINT geometriesCount, ID2D1GeometryGroup **geometryGroup);
    HRESULT CreateTransformedGeometry(ID2D1Geometry sourceGeometry, const D2D1_MATRIX_3X2_F* transform, ID2D1TransformedGeometry* transformedGeometry);
    HRESULT CreatePathGeometry(ID2D1PathGeometry* pathGeometry);
    void foo09(); //HRESULT CreateStrokeStyle(const D2D1_STROKE_STYLE_PROPERTIES *strokeStyleProperties, const FLOAT *dashes, UINT dashesCount, ID2D1StrokeStyle **strokeStyle);
    void foo10(); //HRESULT CreateDrawingStateBlock(const D2D1_DRAWING_STATE_DESCRIPTION *drawingStateDescription, IDWriteRenderingParams *textRenderingParams, ID2D1DrawingStateBlock **drawingStateBlock);
    HRESULT CreateWicBitmapRenderTarget(IWICBitmap target, const D2D1_RENDER_TARGET_PROPERTIES* renderTargetProperties, ID2D1RenderTarget* renderTarget);
    HRESULT CreateHwndRenderTarget(const D2D1_RENDER_TARGET_PROPERTIES* renderTargetProperties, const D2D1_HWND_RENDER_TARGET_PROPERTIES* hwndRenderTargetProperties, ID2D1HwndRenderTarget* hwndRenderTarget);
    void foo13(); //HRESULT CreateDxgiSurfaceRenderTarget(IDXGISurface *dxgiSurface, const D2D1_RENDER_TARGET_PROPERTIES *renderTargetProperties, ID2D1RenderTarget **renderTarget);
    HRESULT CreateDCRenderTarget(const D2D1_RENDER_TARGET_PROPERTIES* renderTargetProperties, ID2D1DCRenderTarget *dcRenderTarget);

final:
    HRESULT CreateRectangleGeometry(const ref D2D1_RECT_F rectangle, ref ID2D1RectangleGeometry rectangleGeometry) { return CreateRectangleGeometry(&rectangle, &rectangleGeometry); }

}

こんなかんじです。
ポイントは以下の点。

使わない関数は void fooXX(); とでもしておく(これ重要)。

重要なのは、仮想関数テーブルの枠を用意してあげることです。所定の場所に所定の関数ポインタを入れられる枠さえあれば、使わないなら別に名前はなんでもいいのです。
たとえば、サボらない場合、CreateRectangleGeometry関数を定義しようとするだけで、ID2D1RectangleGeometryインターフェースの定義が必要になります。それを定義するにはID2D1Geometryが必要で、それにはID2D1ResourceとかID2D1SimplifiedGeometrySinkとかが必要で…と自分で定義しなければならないものが無限に発散していきます。人間の寿命は80年ほどしか無いので、時間は大切にするべきです。サボりましょう。

I~から始まるのはinterface。ポインタをひとつ外す。

たとえば、CreateRectangleGeometry関数の第二引数にはID2D1RectangleGeometryインターフェースを保持する変数へのポインタを指定する必要があります。C++では仮引数の型がID2D1RectangleGeometry**となっているところ、D言語ではID2D1RectangleGeometry*と、ポインタをひとつ外す必要があります。これは、C++のインターフェース(純粋仮想関数のみ含まれる構造体/クラス)は値型で、D言語のインターフェースは参照型であるためです。参照型の正体は、ただのポインタです。

d2d1.h
HRESULT CreateRectangleGeometry(const D2D1_RECT_F* rectangle, ID2D1RectangleGeometry** rectangleGeometry);
d2d1.d
HRESULT CreateRectangleGeometry(const D2D1_RECT_F* rectangle, ID2D1RectangleGeometry* rectangleGeometry);

final:のあとは仮想関数にならない。

ので、ヘルパ関数を書くことができます。上記例はC++だと

d2d1.h
HRESULT CreateRectangleGeometry(const D2D1_RECT_F &rectangle, ID2D1RectangleGeometry **rectangleGeometry)
{ return CreateRectangleGeometry(&rectangle, rectangleGeometry); }

となるところ、D言語で

d2d1.d
HRESULT CreateRectangleGeometry(const ref D2D1_RECT_F rectangle, out ID2D1RectangleGeometry rectangleGeometry)
{ return CreateRectangleGeometry(&rectangle, &rectangleGeometry); }

という感じに書き換えたもの。

とにかくCOMはインターフェースの量が多い。こればかりはVisualStudioとかWindowsSDKとかインストールするだけで利用できるようになるC++が正直羨ましい。
一応D言語でも上記のようにバインディングを作ればCOMのあれそれを利用できるようになります。

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7