So my research into making a nice friendly to use COM interface wrapper for D has had a few odd turns and I am wondering if there is an answer to making the implementation nicer.

I discovered the 'alias foo this' syntax to let structs nearly seamlessly impersonate a member variable. This has turned out to solve most of my original need to wrap the functions, but it is imperfect.

The main problem with 'alias foo this' is that I am having is that I can't find a way to catch code reading the aliased variable, in cases of assignment or implicit conversion to foo type. I can catch writes just fine with opAssign, but finding a way to overload the reads have me stumped.

I did some experiments with wraping the methods with some mixin templates, but using 'alias foo this' is about 100% more useful, intuitive and 99.9% less code to write :)


Examples (The fully ComPtr code is down further):


// initializes to null by default
ComPtr!(ID3D11Device) device;
ComPtr!(ID3D11Device) otherdevice;

// The 'device' argument to D3D11CreateDevice is implemented as
// 'out ID3D11Device', and uses the 'alias p this' feature to
// auto-magically write directly into device.p;  Ideally
// I could hook this and either call SafeRelease here or assert
// that the p variable is null before being written to.
// This also represents the a case that you can write to the
// struct without detecting it.
HRESULT rslt = D3D11CreateDevice(
        null,
        D3D11_DRIVER_TYPE.HARDWARE,
        null,
        0 | D3D11_CREATE_DEVICE.DEBUG,
        null,
        0,
        D3D11_SDK_VERSION,
        device,
        &featureLevel,
        null);


// post-blit case, works
otherdevice = device;   


// gives me a copy of 'p' due to 'alias p this'
ID3D11Device rawdevice = device;        


// assignment back the other direction is caught by opAssign
// this is also the code path used if there are multiple COM
// interfaces in the hierarchy (IUnknown->ID3D11Resource->ID3D11Texture)
// and post-blit isn't used because the types are different.
device = rawdevice;






My current version of ComPtr:



struct ComPtr(T)
{
public:
static assert(is(T : std.c.windows.com.IUnknown) || is(T : win32.unknwn.IUnknown));
    T p;
    alias p this;

private:
    this(T inPtr)
    {
        p = inPtr;
    }

public:
    this(this)
    {
        if (p !is null)
        {
            p.AddRef();
        }
    }
    ~this()
    {
        SafeRelease();
    }

// Attach and Detach set/unset the pointer without messing with the refcount (unlike opAssign assignment)
    void Attach(T other)
    {
        SafeRelease();
        p = other;
    }
    T Detach()
    {
        T rval = p;
        p = null;
        return rval;
    }

    const bool HasData()
    {
        return (p !is null);
    }

    void opAssign(T other)
    {
        if (other !is null)
        {
            other.AddRef();
            SafeRelease();
            p = other;
        }
        else
        {
            SafeRelease();
        }
    }

    void SafeRelease()
    {
        if (p !is null)
        {
            p.Release();
            p = null;
        }
    }
}

Reply via email to